diff options
| author | Christophe Simonis <chs@odoo.com> | 2017-10-25 14:57:24 +0200 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2017-10-25 14:57:24 +0200 |
| commit | 693f8dc68add34663f798370b4aea305f573f16d (patch) | |
| tree | dbd47871d9412317dc96fd4ba349196badab199c /addons/web/static/src | |
| parent | c7a6409fac80a2d33006ab56fe40d27f2acd2cfd (diff) | |
| parent | 7bfde6e05d12be959d04f4842237bfcc05f3c93f (diff) | |
[MERGE] forward port branch saas-16 up to 7bfde6e05d1
Diffstat (limited to 'addons/web/static/src')
13 files changed, 88 insertions, 25 deletions
diff --git a/addons/web/static/src/js/fields/abstract_field.js b/addons/web/static/src/js/fields/abstract_field.js index cef45c2a976..fc29ba77466 100644 --- a/addons/web/static/src/js/fields/abstract_field.js +++ b/addons/web/static/src/js/fields/abstract_field.js @@ -391,6 +391,8 @@ var AbstractField = Widget.extend({ * Please do not use this flag unless you really need it. Our only use * case is currently the pad widget, which does a _setValue in the * renderEdit method. + * @param {boolean} [options.notifyChange=true] if false, the basic model + * will not notify and not trigger the onchange, even though it was changed. * @param {boolean} [options.forceChange=false] if true, the change event will be * triggered even if the new value is the same as the old one * @returns {Deferred} @@ -421,6 +423,7 @@ var AbstractField = Widget.extend({ changes: changes, viewType: this.viewType, doNotSetDirty: options && options.doNotSetDirty, + notifyChange: !options || options.notifyChange !== false, onSuccess: def.resolve.bind(def), onFailure: def.reject.bind(def), }); diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js index 8eae8f5b8f1..549b2e256be 100644 --- a/addons/web/static/src/js/fields/basic_fields.js +++ b/addons/web/static/src/js/fields/basic_fields.js @@ -205,7 +205,7 @@ var InputField = DebouncedField.extend({ if (!event || event === this.lastChangeEvent) { this.isDirty = false; } - if (this.isDirty || (event && event.target === this)) { + if (this.isDirty || (event && event.target === this && event.data.changes[this.name] === this.value)) { return $.when(); } else { return this._render(); diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js index c4422285ae7..f2cacb3327f 100644 --- a/addons/web/static/src/js/fields/relational_fields.js +++ b/addons/web/static/src/js/fields/relational_fields.js @@ -1033,13 +1033,25 @@ var FieldX2Many = AbstractField.extend({ */ _onResequence: function (event) { var self = this; - _.each(event.data.rowIDs, function (rowID, index) { + var rowIDs = event.data.rowIDs.slice(); + var rowID = rowIDs.pop(); + var defs = _.map(rowIDs, function (rowID, index) { var data = {}; data[event.data.handleField] = event.data.offset + index; - self._setValue({ + return self._setValue({ operation: 'UPDATE', id: rowID, data: data, + }, { + notifyChange: false, + }); + }); + $.when.apply($, defs).then(function () { + // trigger only once the onchange for parent record + self._setValue({ + operation: 'UPDATE', + id: rowID, + data: _.object([event.data.handleField], [event.data.offset + rowIDs.length]), }); }); }, 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 c899530de07..5fc68e3124e 100644 --- a/addons/web/static/src/js/views/basic/basic_controller.js +++ b/addons/web/static/src/js/views/basic/basic_controller.js @@ -447,7 +447,11 @@ var BasicController = AbstractController.extend(FieldManagerMixin, { */ _setMode: function (mode, recordID) { if ((recordID || this.handle) === this.handle) { - return this.update({mode: mode}, {reload: false}); + return this.update({mode: mode}, {reload: false}).then(function () { + // necessary to allow all sub widgets to use their dimensions in + // layout related activities, such as autoresize on fieldtexts + core.bus.trigger('DOM_updated'); + }); } return $.when(); }, 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 1df118ecfd9..f3b23bdab7a 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -1092,6 +1092,9 @@ var BasicModel = AbstractModel.extend({ * @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 {boolean} [options.notifyChange=true] if this flag is set to + * false, then we will not notify and not trigger the onchange, even though + * it was changed. * @param {string} [options.viewType] current viewType. If not set, we will assume * main viewType from the record * @returns {Deferred} @@ -1119,6 +1122,10 @@ var BasicModel = AbstractModel.extend({ } } + if (options.notifyChange === false) { + return $.when(); + } + return $.when.apply($, defs).then(function () { var onChangeFields = []; // the fields that have changed and that have an on_change for (var fieldName in changes) { @@ -2305,6 +2312,7 @@ var BasicModel = AbstractModel.extend({ var ids = record.data[fieldName] || []; var list = self._makeDataPoint({ count: ids.length, + context: record.context, fieldsInfo: fieldsInfo, fields: view ? view.fields : fieldInfo.relatedFields, limit: fieldInfo.limit, 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 08d03c037f0..f76f40460a1 100644 --- a/addons/web/static/src/js/views/calendar/calendar_controller.js +++ b/addons/web/static/src/js/views/calendar/calendar_controller.js @@ -56,7 +56,6 @@ var CalendarController = AbstractController.extend({ // Public //-------------------------------------------------------------------------- - /** * Render the buttons according to the CalendarView.buttons template and * add listeners on it. Set this.$buttons with the produced jQuery element @@ -160,10 +159,10 @@ var CalendarController = AbstractController.extend({ } this.quickCreating = true; this.model.createRecord(event) - .then(function (id) { + .then(function () { self.quick.destroy(); self.quick = null; - self.reload(id); + self.reload(); }) .fail(function (error, errorEvent) { // This will occurs if there are some more fields required @@ -215,7 +214,6 @@ var CalendarController = AbstractController.extend({ if(!options.disableQuickCreate && !event.data.disableQuickCreate && this.quickAddPop) { this.quick = new QuickCreate(this, true, options, data, event.data); - this.quick.on('added', this, this.reload.bind(this)); this.quick.open(); this.quick.focus(); return; 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 4374421d7b3..b32374057bb 100644 --- a/addons/web/static/src/js/views/calendar/calendar_model.js +++ b/addons/web/static/src/js/views/calendar/calendar_model.js @@ -322,6 +322,7 @@ return AbstractModel.extend({ // List authorized values for every field // fields with an active 'all' filter are skipped var authorizedValues = {}; + var avoidValues = {}; _.each(this.data.filters, function (filter) { // Skip 'all' filters because they do not affect the domain @@ -329,11 +330,20 @@ return AbstractModel.extend({ // Loop over subfilters to complete authorizedValues _.each(filter.filters, function (f) { - if (!authorizedValues[filter.fieldName]) - authorizedValues[filter.fieldName] = []; + if (filter.write_model) { + if (!authorizedValues[filter.fieldName]) + authorizedValues[filter.fieldName] = []; + + if (f.active) { + authorizedValues[filter.fieldName].push(f.value); + } + } else { + if (!avoidValues[filter.fieldName]) + avoidValues[filter.fieldName] = []; - if (f.active) { - authorizedValues[filter.fieldName].push(f.value); + if (!f.active) { + avoidValues[filter.fieldName].push(f.value); + } } }); }); @@ -343,6 +353,9 @@ return AbstractModel.extend({ for (var field in authorizedValues) { domain.push([field, 'in', authorizedValues[field]]); } + for (var field in avoidValues) { + domain.push([field, 'not in', avoidValues[field]]); + } return domain; }, diff --git a/addons/web/static/src/js/views/field_manager_mixin.js b/addons/web/static/src/js/views/field_manager_mixin.js index aaf7e4a5859..2909308cf29 100644 --- a/addons/web/static/src/js/views/field_manager_mixin.js +++ b/addons/web/static/src/js/views/field_manager_mixin.js @@ -46,7 +46,7 @@ var FieldManagerMixin = { */ _applyChanges: function (dataPointID, changes, event) { var self = this; - var options = _.pick(event.data, 'viewType', 'doNotSetDirty'); + var options = _.pick(event.data, 'viewType', 'doNotSetDirty', 'notifyChange'); return this.model.notifyChanges(dataPointID, changes, options) .then(function (result) { if (event.data.force_save) { diff --git a/addons/web/static/src/js/views/form/form_renderer.js b/addons/web/static/src/js/views/form/form_renderer.js index 5224a6c149a..7e18849af3f 100644 --- a/addons/web/static/src/js/views/form/form_renderer.js +++ b/addons/web/static/src/js/views/form/form_renderer.js @@ -800,10 +800,6 @@ var FormRenderer = BasicRenderer.extend({ this.$el.toggleClass('o_form_editable', this.mode === 'edit'); this.$el.toggleClass('o_form_readonly', this.mode === 'readonly'); - // Necessary to allow all sub widgets to use their dimensions in - // layout related activities, such as autoresize on fieldtexts - core.bus.trigger('DOM_updated'); - // Attach the tooltips on the fields' label _.each(this.allFieldWidgets[this.state.id], function (widget) { var idForLabel = self.idsForLabels[widget.name]; 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 b0ddbdcd385..c1ef23b6b5e 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 @@ -101,6 +101,7 @@ ListRenderer.include({ }); var $row = self.$('.o_data_row:nth(' + rowIndex + ')'); self._setDecorationClasses(state.data[rowIndex], $row); + self._updateFooter(); } return widgets; }); @@ -542,12 +543,21 @@ ListRenderer.include({ _resequence: function (event, ui) { var self = this; var movedRecordID = ui.item.data('id'); - var rowIDs = _.pluck(this.state.data, 'id'); - rowIDs = _.without(rowIDs, movedRecordID); - rowIDs.splice(ui.item.index(), 0, movedRecordID); - var sequences = _.map(this.state.data, function(record) { - return record.data[self.handleField]; - }); + var rows = this.state.data; + 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); + } 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), 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 d37120339d6..8b24d265be8 100644 --- a/addons/web/static/src/js/views/list/list_renderer.js +++ b/addons/web/static/src/js/views/list/list_renderer.js @@ -682,6 +682,17 @@ var ListRenderer = BasicRenderer.extend({ }); }, /** + * Update the footer aggregate values. This method should be called each + * time the state of some field is changed, to make sure their sum are kept + * in sync. + * + * @private + */ + _updateFooter: function () { + this._computeAggregates(); + this.$('tfoot').replaceWith(this._renderFooter(!!this.state.groupedBy.length)); + }, + /** * Whenever we change the state of the selected rows, we need to call this * method to keep the this.selection variable in sync, and also to recompute * the aggregates. @@ -695,8 +706,7 @@ var ListRenderer = BasicRenderer.extend({ return $(row).data('id'); }); this.trigger_up('selection_changed', { selection: this.selection }); - this._computeAggregates(); - this.$('tfoot').replaceWith(this._renderFooter(!!this.state.groupedBy.length)); + this._updateFooter(); }, //-------------------------------------------------------------------------- diff --git a/addons/web/static/src/less/form_view.less b/addons/web/static/src/less/form_view.less index 9bfbd6c535e..cd9d550843a 100644 --- a/addons/web/static/src/less/form_view.less +++ b/addons/web/static/src/less/form_view.less @@ -203,6 +203,7 @@ &.disabled { opacity: 1.0; color: @text-muted; + pointer-events: none; border-left: 1px solid @gray-lighter-dark; } diff --git a/addons/web/static/src/less/list_view.less b/addons/web/static/src/less/list_view.less index 82debf1a035..395bf633e45 100644 --- a/addons/web/static/src/less/list_view.less +++ b/addons/web/static/src/less/list_view.less @@ -138,6 +138,14 @@ // consider this later if needed. z-index: 1; + // The in-edition elements will overflow other elements (the rows below, + // the content below the list view, ...). As those might be using + // position: relative, the in-edition elements have to define a z-index. + // Technically, creating a stacking context for a meaningful parent + // (maybe the .o_content) might be required for safety but we should + // consider this later if needed. + z-index: 1; + // Field widgets override > .o_field_widget { .o-position-absolute(0, 0, auto, 0); |
