diff options
Diffstat (limited to 'addons/web/static/src/js/views/basic')
| -rw-r--r-- | addons/web/static/src/js/views/basic/basic_controller.js | 25 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/basic/basic_model.js | 38 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/basic/basic_renderer.js | 24 |
3 files changed, 48 insertions, 39 deletions
diff --git a/addons/web/static/src/js/views/basic/basic_controller.js b/addons/web/static/src/js/views/basic/basic_controller.js index cc72816a85d..3a47f65ab03 100644 --- a/addons/web/static/src/js/views/basic/basic_controller.js +++ b/addons/web/static/src/js/views/basic/basic_controller.js @@ -8,7 +8,6 @@ odoo.define('web.BasicController', function (require) { */ var AbstractController = require('web.AbstractController'); -var concurrency = require('web.concurrency'); var core = require('web.core'); var Dialog = require('web.Dialog'); var FieldManagerMixin = require('web.FieldManagerMixin'); @@ -19,7 +18,6 @@ var _t = core._t; var BasicController = AbstractController.extend(FieldManagerMixin, { custom_events: _.extend({}, AbstractController.prototype.custom_events, FieldManagerMixin.custom_events, { discard_changes: '_onDiscardChanges', - mutexify: '_onMutexify', reload: '_onReload', sidebar_data_asked: '_onSidebarDataAsked', translate: '_onTranslate', @@ -39,7 +37,6 @@ var BasicController = AbstractController.extend(FieldManagerMixin, { FieldManagerMixin.init.call(this, this.model); this.handle = params.initialState.id; this.mode = params.mode || 'readonly'; - this.mutex = new concurrency.Mutex(); }, /** * @override @@ -238,7 +235,7 @@ var BasicController = AbstractController.extend(FieldManagerMixin, { var recordID = record.data.id; this.trigger_up('execute_action', { action_data: _.extend({}, attrs, { - context: record.getContext({additionalContext: attrs.context}), + context: record.getContext({additionalContext: attrs.context || {}}), }), model: record.model, res_ids: [recordID], @@ -362,17 +359,6 @@ var BasicController = AbstractController.extend(FieldManagerMixin, { }; }, /** - * Used by list and kanban views to determine whether or not to display - * the no content helper (if there is no data in the state to display) - * - * @private - * @param {Object} state - * @returns {boolean} - */ - _hasContent: function (state) { - return state.count !== 0; - }, - /** * Helper function to display a warning that some fields have an invalid * value. This is used when a save operation cannot be completed. * @@ -538,15 +524,6 @@ var BasicController = AbstractController.extend(FieldManagerMixin, { FieldManagerMixin._onFieldChanged.apply(this, arguments); }, /** - * @private - * @param {OdooEvent} ev - * @param {function} ev.data.action the function to execute in the mutex - */ - _onMutexify: function (ev) { - ev.stopPropagation(); // prevent other controllers from handling this request - this.mutex.exec(ev.data.action); - }, - /** * When a reload event triggers up, we need to reload the full view. * For example, after a form view dialog saved some data. * 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 8f679207f00..04fe384afdc 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -628,12 +628,12 @@ var BasicModel = AbstractModel.extend({ * * @param {string} record_id * @param {Object} changes a map field => new value - * @param {string} [viewType] current viewType. If not set, we will assume - * main viewType from the record + * @param {Object} [options] will be transferred to the applyChange method + * @see _applyChange * @returns {string[]} list of changed fields */ - notifyChanges: function (record_id, changes, viewType) { - return this.mutex.exec(this._applyChange.bind(this, record_id, changes, viewType)); + notifyChanges: function (record_id, changes, options) { + return this.mutex.exec(this._applyChange.bind(this, record_id, changes, options)); }, /** * Reload all data for a given resource @@ -956,23 +956,30 @@ var BasicModel = AbstractModel.extend({ * * @param {string} recordID * @param {Object} changes - * @param {string} [viewType] current viewType. If not set, we will assume + * @param {Object} [options] + * @param {boolean} [options.doNotSetDirty=false] if this flag is set to + * true, then we will not tag the record as dirty. This should be avoided + * for most situations. + * @param {string} [options.viewType] current viewType. If not set, we will assume * main viewType from the record * @returns {Deferred} */ - _applyChange: function (recordID, changes, viewType) { + _applyChange: function (recordID, changes, options) { var self = this; var record = this.localData[recordID]; var field; var defs = []; + options = options || {}; record._changes = record._changes || {}; - record._isDirty = true; + if (!options.doNotSetDirty) { + record._isDirty = true; + } // apply changes to local data for (var fieldName in changes) { field = record.fields[fieldName]; if (field.type === 'one2many' || field.type === 'many2many') { - defs.push(this._applyX2ManyChange(record, fieldName, changes[fieldName], viewType)); + defs.push(this._applyX2ManyChange(record, fieldName, changes[fieldName], options.viewType)); } else if (field.type === 'many2one' || field.type === 'reference') { defs.push(this._applyX2OneChange(record, fieldName, changes[fieldName])); } else { @@ -993,7 +1000,7 @@ var BasicModel = AbstractModel.extend({ } var onchangeDef; if (onChangeFields.length) { - onchangeDef = self._performOnChange(record, onChangeFields, viewType).then(function (result) { + onchangeDef = self._performOnChange(record, onChangeFields, options.viewType).then(function (result) { delete record._warning; return _.keys(changes).concat(Object.keys(result && result.value || {})); }); @@ -2196,7 +2203,7 @@ var BasicModel = AbstractModel.extend({ // remove readonly fields from the list of changes if (!withReadonly && fieldName in changes || fieldName in commands) { var editionViewType = record._editionViewType[fieldName] || viewType; - if (this._isFieldReadonly(record, fieldName, editionViewType)) { + if (this._isFieldProtected(record, fieldName, editionViewType)) { delete changes[fieldName]; continue; } @@ -2555,9 +2562,10 @@ var BasicModel = AbstractModel.extend({ return context; }, /** - * Returns true if the field is readonly (checking first in the modifiers, - * and if there is no readonly modifier, checking the readonly attribute of - * the field). + * Returns true if the field is protected against changes, looking for a + * readonly modifier unless there is a force_save modifier (checking first + * in the modifiers, and if there is no readonly modifier, checking the + * readonly attribute of the field). * * @private * @param {Object} record an element from the localData @@ -2566,12 +2574,12 @@ var BasicModel = AbstractModel.extend({ * main viewType from the record * @returns {boolean} */ - _isFieldReadonly: function (record, fieldName, viewType) { + _isFieldProtected: function (record, fieldName, viewType) { var fieldInfo = record.fieldsInfo[viewType || record.viewType][fieldName]; if (fieldInfo) { var rawModifiers = JSON.parse(fieldInfo.modifiers || "{}"); var modifiers = this._evalModifiers(record, rawModifiers); - return modifiers.readonly; + return modifiers.readonly && !fieldInfo.force_save; } else { return false; } diff --git a/addons/web/static/src/js/views/basic/basic_renderer.js b/addons/web/static/src/js/views/basic/basic_renderer.js index 8bbf9ae45a4..e040a5fa7f0 100644 --- a/addons/web/static/src/js/views/basic/basic_renderer.js +++ b/addons/web/static/src/js/views/basic/basic_renderer.js @@ -318,6 +318,16 @@ var BasicRenderer = AbstractRenderer.extend({ return _.findWhere(this.allModifiersData, {node: node}); }, /** + * Used by list and kanban renderers to determine whether or not to display + * the no content helper (if there is no data in the state to display) + * + * @private + * @returns {boolean} + */ + _hasContent: function () { + return this.state.count !== 0; + }, + /** * Registers or updates the modifiers data associated to the given node. * This method is quiet complex as it handles all the needs of the basic * renderers: @@ -487,6 +497,20 @@ var BasicRenderer = AbstractRenderer.extend({ return widget; }, /** + * Renders the nocontent helper. + * + * This method is a helper for renderers that want to display a help + * message when no content is available. + * + * @private + */ + _renderNoContentHelper: function () { + var $msg = $('<div>') + .addClass('oe_view_nocontent') + .html(this.noContentHelp); + this.$el.html($msg); + }, + /** * Actual rendering. Supposed to be overridden by concrete renderers. * The basic responsabilities of _renderView are: * - use the xml arch of the view to render a jQuery representation |
