diff options
Diffstat (limited to 'addons/web/static/src')
8 files changed, 93 insertions, 41 deletions
diff --git a/addons/web/static/src/js/fields/abstract_field.js b/addons/web/static/src/js/fields/abstract_field.js index fc29ba77466..2534f8ae90a 100644 --- a/addons/web/static/src/js/fields/abstract_field.js +++ b/addons/web/static/src/js/fields/abstract_field.js @@ -43,6 +43,15 @@ var AbstractField = Widget.extend({ custom_events: { navigation_move: '_onNavigationMove', }, + + /** + * An object representing fields to be fetched by the model eventhough not present in the view + * This object contains "field name" as key and an object as value. + * That value object must contain the key "type" + * see FieldBinaryImage for an example. + */ + fieldDependencies: {}, + /** * If this flag is set to true, the field widget will be reset on every * change which is made in the view (if the view supports it). This is diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js index 549b2e256be..817c76323d5 100644 --- a/addons/web/static/src/js/fields/basic_fields.js +++ b/addons/web/static/src/js/fields/basic_fields.js @@ -20,6 +20,7 @@ var framework = require('web.framework'); var session = require('web.session'); var utils = require('web.utils'); var view_dialogs = require('web.view_dialogs'); +var field_utils = require('web.field_utils'); var qweb = core.qweb; var _t = core._t; @@ -1169,6 +1170,10 @@ var AbstractFieldBinary = AbstractField.extend({ }); var FieldBinaryImage = AbstractFieldBinary.extend({ + fieldDependencies: _.extend({}, AbstractFieldBinary.prototype.fieldDependencies, { + __last_update: {type: 'datetime'}, + }), + template: 'FieldBinaryImage', placeholder: "/web/static/src/img/placeholder.png", events: _.extend({}, AbstractFieldBinary.prototype.events, { @@ -1191,7 +1196,7 @@ var FieldBinaryImage = AbstractFieldBinary.extend({ id: JSON.stringify(this.res_id), field: this.nodeOptions.preview_image || this.name, // unique forces a reload of the image when the record has been updated - unique: (this.recordData.__last_update || '').replace(/[^0-9]/g, ''), + unique: field_utils.format.datetime(this.recordData.__last_update).replace(/[^0-9]/g, ''), }); } } diff --git a/addons/web/static/src/js/services/data_manager.js b/addons/web/static/src/js/services/data_manager.js index 911e1c5582f..32d526e160d 100644 --- a/addons/web/static/src/js/services/data_manager.js +++ b/addons/web/static/src/js/services/data_manager.js @@ -388,6 +388,11 @@ return core.Class.extend({ } } } + + if (attrs.Widget.prototype.fieldDependencies) { + attrs.fieldDependencies = attrs.Widget.prototype.fieldDependencies; + } + return attrs; }, /** @@ -414,6 +419,15 @@ return core.Class.extend({ if (node.tag === 'field') { fieldsInfo[node.attrs.name] = self._processField(viewType, fields[node.attrs.name], node.attrs ? _.clone(node.attrs) : {}); + + if (fieldsInfo[node.attrs.name].fieldDependencies) { + var deps = fieldsInfo[node.attrs.name].fieldDependencies; + for (var dependency_name in deps) { + if (!(dependency_name in fieldsInfo)) { + fieldsInfo[dependency_name] = {'name': dependency_name, 'type': deps[dependency_name].type}; + } + } + } return false; } return node.tag !== 'arch'; diff --git a/addons/web/static/src/js/views/basic/basic_model.js b/addons/web/static/src/js/views/basic/basic_model.js index 9f8ea3227f5..4412d29c455 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -1109,6 +1109,10 @@ var BasicModel = AbstractModel.extend({ if (!options.doNotSetDirty) { record._isDirty = true; } + var initialData = {}; + this._visitChildren(record, function (elem) { + initialData[elem.id] = $.extend(true, {}, _.pick(elem, 'data', '_changes')); + }); // apply changes to local data for (var fieldName in changes) { @@ -1137,12 +1141,18 @@ var BasicModel = AbstractModel.extend({ } } } - var onchangeDef; + var onchangeDef = $.Deferred(); if (onChangeFields.length) { - onchangeDef = self._performOnChange(record, onChangeFields, options.viewType).then(function (result) { - delete record._warning; - return _.keys(changes).concat(Object.keys(result && result.value || {})); - }); + self._performOnChange(record, onChangeFields, options.viewType) + .then(function (result) { + delete record._warning; + onchangeDef.resolve(_.keys(changes).concat(Object.keys(result && result.value || {}))); + }).fail(function () { + self._visitChildren(record, function (elem) { + _.extend(elem, initialData[elem.id]); + }); + onchangeDef.resolve({}); + }); } else { onchangeDef = $.Deferred().resolve(_.keys(changes)); } @@ -2653,13 +2663,21 @@ var BasicModel = AbstractModel.extend({ } commands[fieldName].push(command); } else if (_.contains(addedIds, list.res_ids[i])) { - // this is a new id + // this is a new id (maybe existing in DB, but new in JS) relRecord = _.findWhere(relRecordAdded, {res_id: list.res_ids[i]}); changes = this._generateChanges(relRecord, options); if ('id' in changes) { + // the subrecord already exists in db delete changes.id; - commands[fieldName].push(x2ManyCommands.update(relRecord.res_id, changes)); + if (this.isNew(record.id)) { + // if the main record is new, link the subrecord to it + commands[fieldName].push(x2ManyCommands.link_to(relRecord.res_id)); + } + if (!_.isEmpty(changes)) { + commands[fieldName].push(x2ManyCommands.update(relRecord.res_id, changes)); + } } else { + // the subrecord is new, so create it commands[fieldName].push(x2ManyCommands.create(relRecord.ref, changes)); } } @@ -2892,7 +2910,8 @@ var BasicModel = AbstractModel.extend({ * @returns {boolean} */ _isFieldProtected: function (record, fieldName, viewType) { - var fieldInfo = record.fieldsInfo[viewType || record.viewType][fieldName]; + var fieldInfo = record.fieldsInfo && + (record.fieldsInfo[viewType || record.viewType][fieldName]); if (fieldInfo) { var rawModifiers = fieldInfo.modifiers || {}; var modifiers = this._evalModifiers(record, rawModifiers); @@ -3249,15 +3268,18 @@ var BasicModel = AbstractModel.extend({ }); return $.when.apply($, defs) .then(function () { - return self._performOnChange(record, fields_key).then(function () { + var def = $.Deferred(); + self._performOnChange(record, fields_key).always(function () { if (record._warning) { if (params.allowWarning) { delete record._warning; } else { - return $.Deferred().reject(); + def.reject(); } } + def.resolve(); }); + return def; }) .then(function () { return self._fetchRelationalData(record); @@ -3324,10 +3346,7 @@ var BasicModel = AbstractModel.extend({ * @param {string[]} fields changed fields * @param {string} [viewType] current viewType. If not set, we will assume * main viewType from the record - * @returns {Deferred} Note: this deferred cannot fail. It is either in the - * 'success' or 'pending' state. If the onchange rpc fails, it will be - * resolved with an empty dictionary. Note that the initial change was - * already applied. + * @returns {Deferred} */ _performOnChange: function (record, fields, viewType) { var self = this; @@ -3347,9 +3366,7 @@ var BasicModel = AbstractModel.extend({ var context = this._getContext(record, options); var currentData = this._generateOnChangeData(record, {changesOnly: false}); - var def = $.Deferred(); - - self._rpc({ + return self._rpc({ model: record.model, method: 'onchange', args: [idList, currentData, fields, onchangeSpec, context], @@ -3374,12 +3391,9 @@ var BasicModel = AbstractModel.extend({ record._domains = _.extend(record._domains, result.domain); } return self._applyOnChange(result.value, record).then(function () { - def.resolve(result); + return result; }); - }).fail(function () { - def.resolve({}); }); - return def; }, /** * Once a record is created and some data has been fetched, we need to do diff --git a/addons/web/static/src/js/views/calendar/calendar_controller.js b/addons/web/static/src/js/views/calendar/calendar_controller.js index f76f40460a1..2b17710935c 100644 --- a/addons/web/static/src/js/views/calendar/calendar_controller.js +++ b/addons/web/static/src/js/views/calendar/calendar_controller.js @@ -115,7 +115,7 @@ var CalendarController = AbstractController.extend({ */ _onChangeDate: function (event) { var modelData = this.model.get(); - if (modelData.target_date.isSame(event.data.date)) { + if (modelData.target_date.format('YYYY-MM-DD') === event.data.date.format('YYYY-MM-DD')) { // When clicking on same date, toggle between the two views switch (modelData.scale) { case 'month': this.model.setScale('week'); break; diff --git a/addons/web/static/src/js/views/calendar/calendar_model.js b/addons/web/static/src/js/views/calendar/calendar_model.js index b32374057bb..a0f6515b98c 100644 --- a/addons/web/static/src/js/views/calendar/calendar_model.js +++ b/addons/web/static/src/js/views/calendar/calendar_model.js @@ -255,6 +255,8 @@ return AbstractModel.extend({ */ setDate: function (start, highlight) { this.data.start_date = this.data.end_date = this.data.target_date = this.data.highlight_date = start; + this.data.start_date.utc().add(this.getSession().getTZOffset(this.data.start_date), 'minutes'); + switch (this.data.scale) { case 'month': this.data.start_date = this.data.start_date.clone().startOf('month').startOf('week'); @@ -391,6 +393,12 @@ return AbstractModel.extend({ firstDay: moment().startOf('week').isoWeekday(), }; }, + /** + * Return a domain from the date range + * + * @private + * @returns {Array} + */ _getRangeDomain: function () { // Build OpenERP Domain to filter object by this.mapping.date_start field // between given start, end dates. @@ -623,8 +631,10 @@ return AbstractModel.extend({ date_stop = date_start.clone().add(date_delay,'hours'); } - date_start.add(this.getSession().getTZOffset(date_start), 'minutes'); - date_stop.add(this.getSession().getTZOffset(date_stop), 'minutes'); + if (!all_day) { + date_start.add(this.getSession().getTZOffset(date_start), 'minutes'); + date_stop.add(this.getSession().getTZOffset(date_stop), 'minutes'); + } if (this.mapping.all_day && evt[this.mapping.all_day]) { date_stop.add(1, 'days'); diff --git a/addons/web/static/src/js/views/form/form_controller.js b/addons/web/static/src/js/views/form/form_controller.js index a6248c827a2..7b53b60f90c 100644 --- a/addons/web/static/src/js/views/form/form_controller.js +++ b/addons/web/static/src/js/views/form/form_controller.js @@ -367,12 +367,23 @@ var FormController = BasicController.extend({ this._disableButtons(); + function saveAndExecuteAction () { + return self.saveRecord(self.handle, { + stayInEdit: true, + }).then(function () { + // we need to reget the record to make sure we have changes made + // by the basic model, such as the new res_id, if the record is + // new. + var record = self.model.get(event.data.record.id); + return self._callButtonAction(attrs, record); + }); + } var attrs = event.data.attrs; if (attrs.confirm) { var d = $.Deferred(); - Dialog.confirm(this, attrs.confirm, { confirm_callback: function () { - self._callButtonAction(attrs, event.data.record); - }}).on("closed", null, function () { + Dialog.confirm(this, attrs.confirm, { + confirm_callback: saveAndExecuteAction, + }).on("closed", null, function () { d.resolve(); }); def = d.promise(); @@ -380,15 +391,7 @@ var FormController = BasicController.extend({ def = this._callButtonAction(attrs, event.data.record); } else if (!attrs.special || attrs.special === 'save') { // save the record but don't switch to readonly mode - def = this.saveRecord(this.handle, { - stayInEdit: true, - }).then(function () { - // we need to reget the record to make sure we have changes made - // by the basic model, such as the new res_id, if the record is - // new. - var record = self.model.get(event.data.record.id); - return self._callButtonAction(attrs, record); - }); + def = saveAndExecuteAction(); } def.always(this._enableButtons.bind(this)); diff --git a/addons/web/static/src/js/views/list/list_renderer.js b/addons/web/static/src/js/views/list/list_renderer.js index 8b24d265be8..33c075fc77f 100644 --- a/addons/web/static/src/js/views/list/list_renderer.js +++ b/addons/web/static/src/js/views/list/list_renderer.js @@ -101,9 +101,6 @@ var ListRenderer = BasicRenderer.extend({ } else { data = this.state.data; } - if (data.length === 0) { - return; - } _.each(this.columns, this._computeColumnAggregates.bind(this, data)); }, @@ -145,7 +142,7 @@ var ListRenderer = BasicRenderer.extend({ } }); if (func === 'avg') { - aggregateValue = aggregateValue / count; + aggregateValue = count ? aggregateValue / count : aggregateValue; } column.aggregate = { help: attrs[func], |
