diff options
| author | Christophe Simonis <chs@odoo.com> | 2018-01-03 14:05:48 +0100 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2018-01-03 14:05:48 +0100 |
| commit | 55b810dc70cccb23144986d54fd28bb5f91f2b1b (patch) | |
| tree | a83dda56dac7f02be26f6821dea5b2f1926ea7b0 /addons/web/static/src/js | |
| parent | 8bc7cebd9c19ae8f77378d115a8401d7b7de56b0 (diff) | |
| parent | 726b91b9fbc994c6b2f2cb45e36d4c224497f11b (diff) | |
[MERGE] forward port branch saas-11.1 up to 726b91b9fbc
Diffstat (limited to 'addons/web/static/src/js')
14 files changed, 180 insertions, 74 deletions
diff --git a/addons/web/static/src/js/chrome/action_manager.js b/addons/web/static/src/js/chrome/action_manager.js index c9eed9b2e64..e72db2c3a0c 100644 --- a/addons/web/static/src/js/chrome/action_manager.js +++ b/addons/web/static/src/js/chrome/action_manager.js @@ -941,7 +941,7 @@ var ActionManager = Widget.extend({ }); }); }, - ir_actions_act_url: function (action) { + ir_actions_act_url: function (action, options) { var url = action.url; if (session.debug && url && url.length && url[0] === '/') { url = $.param.querystring(url, {debug: session.debug}); @@ -952,6 +952,7 @@ var ActionManager = Widget.extend({ return $.Deferred(); // The action is finished only when the redirection is done } else { window.open(url, '_blank'); + options.on_close(); } return $.when(); }, diff --git a/addons/web/static/src/js/core/qweb.js b/addons/web/static/src/js/core/qweb.js index 50742075e05..253e948d8ac 100644 --- a/addons/web/static/src/js/core/qweb.js +++ b/addons/web/static/src/js/core/qweb.js @@ -5,7 +5,18 @@ var translation = require('web.translation'); var _t = translation._t; -function QWeb(debug, default_dict) { +/** + * @param {boolean} debug + * @param {Object} default_dict + * @param {boolean} [enableTranslation=true] if true (this is the default), + * the rendering will translate all strings that are not marked with + * t-translation=off. This is useful for the kanban view, which uses a + * template which is already translated by the server + */ +function QWeb(debug, default_dict, enableTranslation) { + if (enableTranslation === undefined) { + enableTranslation = true; + } var qweb = new QWeb2.Engine(); qweb.default_dict = _.extend({}, default_dict || {}, { '_' : _, @@ -16,7 +27,7 @@ function QWeb(debug, default_dict) { 'csrf_token': odoo.csrf_token, }); qweb.debug = debug; - qweb.preprocess_node = preprocess_node; + qweb.preprocess_node = enableTranslation ? preprocess_node : function () {}; return qweb; } diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js index de5f80b0e92..eb56844de14 100644 --- a/addons/web/static/src/js/fields/basic_fields.js +++ b/addons/web/static/src/js/fields/basic_fields.js @@ -576,8 +576,8 @@ var FieldMonetary = InputField.extend({ this.tagName = 'div'; this.className += ' o_input'; - // use the formatFloat function in edit - this.formatType = 'float'; + // do not display currency symbol in edit + this.formatOptions.noSymbol = true; } this.formatOptions.currency = this.currency; diff --git a/addons/web/static/src/js/fields/field_utils.js b/addons/web/static/src/js/fields/field_utils.js index bca74acc088..932ea997e6a 100644 --- a/addons/web/static/src/js/fields/field_utils.js +++ b/addons/web/static/src/js/fields/field_utils.js @@ -290,7 +290,7 @@ function formatMonetary(value, field, options) { digits: (currency && currency.digits) || options.digits, }); - if (!currency) { + if (!currency || options.noSymbol) { return formatted_value; } if (currency.position === "after") { diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js index 52654c4ce3a..677663a4967 100644 --- a/addons/web/static/src/js/fields/relational_fields.js +++ b/addons/web/static/src/js/fields/relational_fields.js @@ -95,6 +95,7 @@ var FieldMany2One = AbstractField.extend({ template: 'FieldMany2One', custom_events: _.extend({}, AbstractField.prototype.custom_events, { 'closed_unset': '_onDialogClosedUnset', + 'field_changed': '_onFieldChanged', 'quick_create': '_onQuickCreate', 'search_create_popup': '_onSearchCreatePopup', }), @@ -124,6 +125,12 @@ var FieldMany2One = AbstractField.extend({ // 'recordParams' is a dict of params used when calling functions // 'getDomain' and 'getContext' on this.record this.recordParams = {fieldName: this.name, viewType: this.viewType}; + // We need to know if the widget is dirty (i.e. if the user has changed + // the value, and those changes haven't been acknowledged yet by the + // environment), to prevent erasing that new value on a reset (e.g. + // coming by an onchange on another field) + this.isDirty = false; + this.lastChangeEvent = undefined; }, start: function () { // booleean indicating that the content of the input isn't synchronized @@ -151,9 +158,31 @@ var FieldMany2One = AbstractField.extend({ * TODO */ reinitialize: function (value) { + this.isDirty = false; this.floating = false; this._setValue(value); }, + /** + * Re-renders the widget if it isn't dirty. The widget is dirty if the user + * changed the value, and that change hasn't been acknowledged yet by the + * environment. For example, another field with an onchange has been updated + * and this field is updated before the onchange returns. Two '_setValue' + * are done (this is sequential), the first one returns and this widget is + * reset. However, it has pending changes, so we don't re-render. + * + * @override + */ + reset: function (record, event) { + this._reset(record, event); + if (!event || event === this.lastChangeEvent) { + this.isDirty = false; + } + if (this.isDirty) { + return $.when(); + } else { + return this._render(); + } + }, //-------------------------------------------------------------------------- // Private @@ -238,6 +267,16 @@ var FieldMany2One = AbstractField.extend({ return value.split('\n')[0]; }, /** + * Listens to events 'field_changed' to keep track of the last event that + * has been trigerred. This allows to detect that all changes have been + * acknowledged by the environment. + * + * @param {OdooEvent} event 'field_changed' event + */ + _onFieldChanged: function (event) { + this.lastChangeEvent = event; + }, + /** * @private * @param {string} name * @returns {Deferred} resolved after the name_create or when the slowcreate @@ -476,6 +515,7 @@ var FieldMany2One = AbstractField.extend({ * @private */ _onDialogClosedUnset: function () { + this.isDirty = false; this.floating = false; this._render(); }, @@ -544,6 +584,7 @@ var FieldMany2One = AbstractField.extend({ // confirmation that the many2one is not properly set. return; } + this.isDirty = true; if (this.$input.val() === "") { this.reinitialize(false); } else if (this._getDisplayName(this.m2o_value) !== this.$input.val()) { @@ -796,7 +837,7 @@ var FieldX2Many = AbstractField.extend({ this.currentColInvisibleFields = this._evalColumnInvisibleFields(); this.renderer = new ListRenderer(this, this.value, { arch: arch, - mode: this.mode, + editable: this.mode === 'edit' && arch.attrs.editable, addCreateLine: !this.isReadonly && this.activeActions.create, addTrashIcon: !this.isReadonly && this.activeActions.delete, isMany2Many: this.isMany2Many, @@ -1337,12 +1378,12 @@ var FieldMany2ManyBinaryMultiFiles = AbstractField.extend({ throw _.str.sprintf(msg, this.field.string); } + this.uploadedFiles = {}; this.uploadingFiles = []; this.fileupload_id = _.uniqueId('oe_fileupload_temp'); $(window).on(this.fileupload_id, this._onFileLoaded.bind(this)); this.metadata = {}; - this._generatedMetadata(); }, destroy: function () { @@ -1372,10 +1413,10 @@ var FieldMany2ManyBinaryMultiFiles = AbstractField.extend({ _generatedMetadata: function () { var self = this; _.each(this.value.data, function (record) { - // attachments are tagged `allowUnlink` because only new attachments - // will be unlinked after deletion + // tagging `allowUnlink` ascertains if the attachment was user + // uploaded or was an existing or system generated attachment self.metadata[record.id] = { - allowUnlink: false, + allowUnlink: self.uploadedFiles[record.data.id] || false, url: self._getFileUrl(record.data), }; }); @@ -1387,6 +1428,7 @@ var FieldMany2ManyBinaryMultiFiles = AbstractField.extend({ _render: function () { // render the attachments ; as the attachments will changes after each // _setValue, we put the rendering here to ensure they will be updated + this._generatedMetadata(); this.$('.oe_placeholder_files, .oe_attachments') .replaceWith($(qweb.render('FieldBinaryFileUploader.files', { widget: this, @@ -1494,6 +1536,7 @@ var FieldMany2ManyBinaryMultiFiles = AbstractField.extend({ self.do_warn(_t('Uploading Error'), file.error); } else { attachment_ids.push(file.id); + self.uploadedFiles[file.id] = true; } }); 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 c16f635a604..39f1be0d107 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -1495,7 +1495,8 @@ var BasicModel = AbstractModel.extend({ def = this._rpc({ model: list.model, method: 'read', - args: [_.pluck(data, 'id'), fieldNames] + args: [_.pluck(data, 'id'), fieldNames], + context: record.context, }).then(function (records) { _.each(records, function (record) { list_records[record.id].data = record; @@ -1743,22 +1744,21 @@ var BasicModel = AbstractModel.extend({ /** * Fetch all name_gets for the many2ones in a group * - * @param {Object} group a valid resource object + * @param {Object[]} groups a list of object with context and record sub keys * @returns {Deferred} */ - _fetchMany2OneGroup: function (group) { - var ids = _.uniq(_.pluck(group, 'res_id')); - + _fetchMany2OneGroup: function (groups) { + var ids = _.uniq(_.pluck(_.pluck(groups, 'record'), 'res_id')); return this._rpc({ - model: group[0].model, + model: groups[0].record.model, method: 'name_get', args: [ids], - context: group[0].context + context: groups[0].context }) .then(function (name_gets) { - _.each(group, function (record) { - var nameGet = _.find(name_gets, function (n) { return n[0] === record.res_id;}); - record.data.display_name = nameGet[1]; + _.each(groups, function (obj) { + var nameGet = _.find(name_gets, function (n) { return n[0] === obj.record.res_id;}); + obj.record.data.display_name = nameGet[1]; }); }); }, @@ -2019,14 +2019,17 @@ var BasicModel = AbstractModel.extend({ if (!relatedRecord) { return; } - toBeFetched.push(relatedRecord); + toBeFetched.push({ + context: record.getContext({fieldName: name, viewType: record.viewType}), + record: relatedRecord + }); } }); // group them by model and context. Using the context as key is // necessary to make sure the correct context is used for the rpc; - var groups = _.groupBy(toBeFetched, function (rec) { - return [rec.model, JSON.stringify(rec.context)].join(); + var groups = _.groupBy(toBeFetched, function (elem) { + return [elem.record.model, JSON.stringify(elem.context)].join(); }); return $.when.apply($, _.map(groups, this._fetchMany2OneGroup.bind(this))); @@ -2416,7 +2419,7 @@ var BasicModel = AbstractModel.extend({ model: field.relation, method: 'read', args: [ids, fieldNames], - context: {}, // FIXME + context: list.getContext() || {}, }); } else { def = $.when(_.map(ids, function (id) { 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 a6d5172bfe1..042d85d414a 100644 --- a/addons/web/static/src/js/views/basic/basic_renderer.js +++ b/addons/web/static/src/js/views/basic/basic_renderer.js @@ -251,13 +251,12 @@ var BasicRenderer = AbstractRenderer.extend({ function _apply(element) { // If the view is in edit mode and that a widget have to switch // its "readonly" state, we have to re-render it completely - if ('readonly' in modifiers - && self.mode === "edit" - && element.widget - && (element.widget.mode === 'readonly') !== modifiers.readonly) - { - self._rerenderFieldWidget(element.widget, record); - return; // Rerendering already applied the modifiers, no need to go further + if ('readonly' in modifiers && element.widget) { + var mode = modifiers.readonly ? 'readonly' : modifiersData.baseMode; + if (mode !== element.widget.mode) { + self._rerenderFieldWidget(element.widget, record, mode); + return; // Rerendering already applied the modifiers, no need to go further + } } // Toggle modifiers CSS classes if necessary @@ -429,6 +428,12 @@ var BasicRenderer = AbstractRenderer.extend({ this.allModifiersData.push(modifiersData); } } + // we register here the base mode of the node. This is a field widget + // specific settings which represents the generic mode for the widget, + // regardless of its modifiers. The interesting case is the list view: + // all widgets are supposed to be in the baseMode 'readonly', except the + // ones that are in the line that is currently being edited. + modifiersData.baseMode = (options && options.mode) || this.mode; // Evaluate if necessary if (!modifiersData.evaluatedModifiers[record.id]) { @@ -454,7 +459,7 @@ var BasicRenderer = AbstractRenderer.extend({ } modifiersData.elementsByRecord[record.id].push(newElement); - this._applyModifiers(modifiersData, record, newElement); + this._applyModifiers(modifiersData, record, newElement, options); } return modifiersData.evaluatedModifiers[record.id]; @@ -493,22 +498,20 @@ var BasicRenderer = AbstractRenderer.extend({ * @param {Object} node * @param {Object} record * @param {Object} [options] - * @param {Object} [modifiersOptions] * @returns {jQueryElement} */ - _renderFieldWidget: function (node, record, options, modifiersOptions) { + _renderFieldWidget: function (node, record, options) { var fieldName = node.attrs.name; - // Register the node-associated modifiers - var modifiers = this._registerModifiers(node, record); - + var mode = options && options.mode || this.mode; + var modifiers = this._registerModifiers(node, record, null, options); // Initialize and register the widget // Readonly status is known as the modifiers have just been registered var Widget = record.fieldsInfo[this.viewType][fieldName].Widget; - var widget = new Widget(this, fieldName, record, _.extend({ - mode: modifiers.readonly ? 'readonly' : this.mode, + var widget = new Widget(this, fieldName, record, { + mode: modifiers.readonly ? 'readonly' : mode, viewType: this.viewType, - }, options || {})); + }); // Register the widget so that it can easily be found again if (this.allFieldWidgets[record.id] === undefined) { @@ -534,15 +537,16 @@ var BasicRenderer = AbstractRenderer.extend({ if (async) { $el.replaceWith(widget.$el); } - self._registerModifiers(node, record, widget, _.extend({ + self._registerModifiers(node, record, widget, { callback: function (element, modifiers, record) { element.$el.toggleClass('o_field_empty', !!( record.data.id - && (modifiers.readonly || self.mode === 'readonly') + && (modifiers.readonly || mode === 'readonly') && !element.widget.isSet() )); }, - }, modifiersOptions || {})); + mode: mode + }); self._postProcessField(widget, node); }); @@ -610,10 +614,11 @@ var BasicRenderer = AbstractRenderer.extend({ * @private * @param {Widget} widget * @param {Object} record + * @param {string} mode either 'readonly' or 'edit' */ - _rerenderFieldWidget: function (widget, record) { + _rerenderFieldWidget: function (widget, record, mode) { // Render the new field widget - var $el = this._renderFieldWidget(widget.__node, record); + var $el = this._renderFieldWidget(widget.__node, record, {mode: mode}); widget.$el.replaceWith($el); // Destroy the old widget and position the new one at the old one's diff --git a/addons/web/static/src/js/views/graph/graph_model.js b/addons/web/static/src/js/views/graph/graph_model.js index a6d2b057d0e..0518e279637 100644 --- a/addons/web/static/src/js/views/graph/graph_model.js +++ b/addons/web/static/src/js/views/graph/graph_model.js @@ -67,7 +67,6 @@ return AbstractModel.extend({ domain: params.domain, context: params.context, }; - this.defaultGroupedBy = params.groupedBy; return this._loadGraph(); }, /** @@ -96,7 +95,7 @@ return AbstractModel.extend({ this.chart.domain = params.domain; } if ('groupBy' in params) { - this.chart.groupedBy = params.groupBy.length ? params.groupBy : this.defaultGroupedBy; + this.chart.groupedBy = params.groupBy.length ? params.groupBy : this.initialGroupBys; } if ('measure' in params) { this.chart.measure = params.measure; @@ -121,7 +120,7 @@ return AbstractModel.extend({ * @returns {Deferred} */ _loadGraph: function () { - var groupedBy = this.chart.groupedBy.length ? this.chart.groupedBy : this.initialGroupBys; + var groupedBy = this.chart.groupedBy; var fields = _.map(groupedBy, function (groupBy) { return groupBy.split(':')[0]; }); diff --git a/addons/web/static/src/js/views/kanban/kanban_column.js b/addons/web/static/src/js/views/kanban/kanban_column.js index d39a3b280e1..0e50e37194f 100644 --- a/addons/web/static/src/js/views/kanban/kanban_column.js +++ b/addons/web/static/src/js/views/kanban/kanban_column.js @@ -41,7 +41,7 @@ var KanbanColumn = Widget.extend({ this.data = data; var value = data.value; - this.id = data.res_id || value; + this.id = data.res_id; this.folded = !data.isOpen; this.has_active_field = 'active' in data.fields; this.fields = data.fields; diff --git a/addons/web/static/src/js/views/kanban/kanban_renderer.js b/addons/web/static/src/js/views/kanban/kanban_renderer.js index 029cef7cf0b..0f91fb2ae14 100644 --- a/addons/web/static/src/js/views/kanban/kanban_renderer.js +++ b/addons/web/static/src/js/views/kanban/kanban_renderer.js @@ -94,7 +94,7 @@ var KanbanRenderer = BasicRenderer.extend({ this._super.apply(this, arguments); this.widgets = []; - this.qweb = new QWeb(session.debug, {_s: session.origin}); + this.qweb = new QWeb(session.debug, {_s: session.origin}, false); var templates = findInNode(this.arch, function (n) { return n.tag === 'templates';}); transformQwebTemplate(templates, state.fields); this.qweb.add_template(utils.json_node_to_xml(templates)); @@ -235,6 +235,10 @@ var KanbanRenderer = BasicRenderer.extend({ } }); + // remove previous sorting + if(this.$el.sortable('instance') !== undefined) { + this.$el.sortable('destroy'); + } if (this.groupedByM2O) { // Enable column sorting this.$el.sortable({ @@ -249,7 +253,10 @@ var KanbanRenderer = BasicRenderer.extend({ stop: function () { var ids = []; self.$('.o_kanban_group').each(function (index, u) { - ids.push($(u).data('id')); + // Ignore 'Undefined' column + if (_.isNumber($(u).data('id'))) { + ids.push($(u).data('id')); + } }); self.trigger_up('resequence_columns', {ids: ids}); }, diff --git a/addons/web/static/src/js/views/kanban/kanban_renderer_mobile.js b/addons/web/static/src/js/views/kanban/kanban_renderer_mobile.js index e2b08fc0da9..7614d6bca95 100644 --- a/addons/web/static/src/js/views/kanban/kanban_renderer_mobile.js +++ b/addons/web/static/src/js/views/kanban/kanban_renderer_mobile.js @@ -12,6 +12,7 @@ var config = require('web.config'); var core = require('web.core'); var KanbanRenderer = require('web.KanbanRenderer'); +var _t = core._t; var qweb = core.qweb; if (!config.device.isMobile) { @@ -107,8 +108,9 @@ KanbanRenderer.include({ var updateFunc = animate ? 'animate' : 'css'; self.$('.o_kanban_mobile_tab').removeClass('o_current'); _.each(self.widgets, function (column, index) { - var $column = self.$('.o_kanban_group[data-id=' + column.id + ']'); - var $tab = self.$('.o_kanban_mobile_tab[data-id=' + column.id + ']'); + var columnID = column.id || column.db_id; + var $column = self.$('.o_kanban_group[data-id="' + columnID + '"]'); + var $tab = self.$('.o_kanban_mobile_tab[data-id="' + columnID + '"]'); if (index === moveToIndex - 1) { $column[updateFunc]({left: '-100%'}); $tab[updateFunc]({left: '0%'}); @@ -137,8 +139,19 @@ KanbanRenderer.include({ * @private */ _renderGrouped: function (fragment) { + var data = []; + _.each(this.state.data, function (group) { + if (!group.value) { + group = _.extend({}, group, {value: _t('Undefined')}); + data.unshift(group); + } + else { + data.push(group); + } + }); + var $tabs = $(qweb.render('KanbanView.MobileTabs', { - data: this.state.data, + data: data, })); $tabs.appendTo(fragment); return this._super.apply(this, arguments); diff --git a/addons/web/static/src/js/views/list/list_editable_renderer.js b/addons/web/static/src/js/views/list/list_editable_renderer.js index 964b7ba7bbe..91a914be8df 100644 --- a/addons/web/static/src/js/views/list/list_editable_renderer.js +++ b/addons/web/static/src/js/views/list/list_editable_renderer.js @@ -58,7 +58,7 @@ ListRenderer.include({ * @returns {Deferred} */ start: function () { - if (this.mode === 'edit') { + if (this._isEditable()) { this.$el.css({height: '100%'}); core.bus.on('click', this, this._onWindowClicked.bind(this)); } @@ -299,12 +299,7 @@ ListRenderer.include({ renderInvisible: editMode, renderWidgets: editMode, }; - if (!editMode) { - // Force 'readonly' mode for widgets in readonly rows as - // otherwise they default to the view mode which is 'edit' for - // an editable list view - options.mode = 'readonly'; - } + options.mode = editMode ? 'edit' : 'readonly'; // Switch each cell to the new mode; note: the '_renderBodyCell' // function might fill the 'this.defs' variables with multiple deferred @@ -421,7 +416,7 @@ ListRenderer.include({ * @returns {boolean} */ _isEditable: function () { - return this.mode === 'edit' && !this.state.groupedBy.length && this.arch.attrs.editable; + return !this.state.groupedBy.length && this.editable; }, /** * Move the cursor on the end of the previous line, if possible. @@ -554,21 +549,49 @@ ListRenderer.include({ var row = _.findWhere(rows, {id: movedRecordID}); var index0 = rows.indexOf(row); var index1 = ui.item.index(); - rows = rows.slice(Math.min(index0, index1), Math.max(index0, index1) + 1); - rows = _.without(rows, row); - if (index0 > index1) { - rows.unshift(row); + var lower = Math.min(index0, index1); + var upper = Math.max(index0, index1) + 1; + + var order = _.findWhere(self.state.orderedBy, {name: self.handleField}); + var asc = !order || order.asc; + var reorderAll = false; + var sequence = (asc ? -1 : 1) * Infinity; + + // determine if we need to reorder all lines + _.each(rows, function (row, index) { + if ((index < lower || index >= upper) && + ((asc && sequence >= row.data[self.handleField]) || + (!asc && sequence <= row.data[self.handleField]))) { + reorderAll = true; + } + sequence = row.data[self.handleField]; + }); + + if (reorderAll) { + rows = _.without(rows, row); + rows.splice(index1, 0, row); } else { - rows.push(row); + rows = rows.slice(lower, upper); + rows = _.without(rows, row); + if (index0 > index1) { + rows.unshift(row); + } else { + rows.push(row); + } } var sequences = _.pluck(_.pluck(rows, 'data'), self.handleField); var rowIDs = _.pluck(rows, 'id'); - this.trigger_up('resequence', { - rowIDs: rowIDs, - offset: _.min(sequences), - handleField: this.handleField, + if (!asc) { + rowIDs.reverse(); + } + this.unselectRow().then(function () { + self.trigger_up('resequence', { + rowIDs: rowIDs, + offset: _.min(sequences), + handleField: self.handleField, + }); }); }, /** 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 b836da253c3..6b9e4aebe56 100644 --- a/addons/web/static/src/js/views/list/list_renderer.js +++ b/addons/web/static/src/js/views/list/list_renderer.js @@ -59,6 +59,7 @@ var ListRenderer = BasicRenderer.extend({ this.hasSelectors = params.hasSelectors; this.selection = []; this.pagers = []; // instantiated pagers (only for grouped lists) + this.editable = params.editable; }, //-------------------------------------------------------------------------- @@ -260,7 +261,7 @@ var ListRenderer = BasicRenderer.extend({ // We register modifiers on the <td> element so that it gets the correct // modifiers classes (for styling) - var modifiers = this._registerModifiers(node, record, $td); + var modifiers = this._registerModifiers(node, record, $td, _.pick(options, 'mode')); // If the invisible modifiers is true, the <td> element is left empty. // Indeed, if the modifiers was to change the whole cell would be // rerendered anyway. diff --git a/addons/web/static/src/js/views/list/list_view.js b/addons/web/static/src/js/views/list/list_view.js index b2295affb98..8a989dad35e 100644 --- a/addons/web/static/src/js/views/list/list_view.js +++ b/addons/web/static/src/js/views/list/list_view.js @@ -48,7 +48,7 @@ var ListView = BasicView.extend({ this.rendererParams.arch = arch; this.rendererParams.hasSelectors = 'hasSelectors' in params ? params.hasSelectors : true; - this.rendererParams.mode = mode; + this.rendererParams.editable = params.readonly ? false : arch.attrs.editable; this.loadParams.limit = this.loadParams.limit || 80; this.loadParams.type = 'list'; |
