diff options
| author | Christophe Simonis <chs@odoo.com> | 2017-09-11 14:02:19 +0200 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2017-09-11 14:02:19 +0200 |
| commit | bd08d4f0522c6322ee38c2c65921ff0b3c3193a9 (patch) | |
| tree | ffe604f3f9f0b58fc01e4a7227dfe4ba41f02d38 /addons/web/static/src | |
| parent | ecbfcb6dcf2226b476cc0fca4d21f7a58cf97cc1 (diff) | |
| parent | 3ac2a1106c8c776a951337b174a056f817246f98 (diff) | |
[MERGE] forward port branch saas-16 up to 3ac2a1106c8
Diffstat (limited to 'addons/web/static/src')
9 files changed, 162 insertions, 93 deletions
diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js index 67218e5decd..9b1e930cef3 100644 --- a/addons/web/static/src/js/fields/relational_fields.js +++ b/addons/web/static/src/js/fields/relational_fields.js @@ -684,6 +684,7 @@ var FieldX2Many = AbstractField.extend({ if (command.operation === 'UPDATE' && command.data) { var state = record.data[this.name]; var fieldNames = state.getFieldNames(); + this._reset(record, ev); this.renderer.confirmChange(state, command.id, fieldNames, ev.initialEvent); return $.when(); } @@ -871,7 +872,8 @@ var FieldX2Many = AbstractField.extend({ */ _onEditLine: function (ev) { ev.stopPropagation(); - this.renderer.setRowMode(ev.data.recordID, 'edit') + var editedRecord = this.value.data[ev.data.index]; + this.renderer.setRowMode(editedRecord.id, 'edit') .done(ev.data.onSuccess); }, /** diff --git a/addons/web/static/src/js/services/data_manager.js b/addons/web/static/src/js/services/data_manager.js index 105d7f30d69..4bf1748fbab 100644 --- a/addons/web/static/src/js/services/data_manager.js +++ b/addons/web/static/src/js/services/data_manager.js @@ -336,20 +336,30 @@ return core.Class.extend({ attrs.mode = mode; if (mode in attrs.views) { var view = attrs.views[mode]; - // process the default_order, which is like 'name,id desc' - // but we need it like [{name: 'name', asc: true}, {name: 'id', asc: false}] var defaultOrder = view.arch.attrs.default_order; if (defaultOrder) { + // process the default_order, which is like 'name,id desc' + // but we need it like [{name: 'name', asc: true}, {name: 'id', asc: false}] attrs.orderedBy = _.map(defaultOrder.split(','), function (order) { order = order.trim().split(' '); return {name: order[0], asc: order[1] !== 'desc'}; }); + } else { + // if there is a field with widget `handle`, the x2many + // needs to be ordered by this field to correctly display + // the records + var handleField = _.find(view.arch.children, function (child) { + return child.attrs && child.attrs.widget === 'handle'; + }); + if (handleField) { + attrs.orderedBy = [{name: handleField.attrs.name, asc: true}]; + } } // detect editables list has they behave differently with respect // to the sorting (changes are not sorted directly) if (mode === 'list' && view.arch.attrs.editable) { attrs.keepChangesUnsorted = true; - } + } } } if (attrs.Widget.prototype.fieldsToFetch) { 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 9c4599f1683..cf5a18488a6 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -780,6 +780,55 @@ var BasicModel = AbstractModel.extend({ } }, /** + * Resequences records. + * + * @param {string} modelName the resIDs model + * @param {Array[integer]} resIDs the new sequence of ids + * @param {string} parentID the localID of the parent + * @param {object} [options] + * @param {integer} [options.offset] + * @param {string} [options.field] the field name used as sequence + * @returns {Deferred<string>} resolves to the local id of the parent + */ + resequence: function (modelName, resIDs, parentID, options) { + options = options || {}; + if ((resIDs.length <= 1)) { + return $.when(parentID); // there is nothing to sort + } + var self = this; + var data = this.localData[parentID]; + var params = { + model: modelName, + ids: resIDs, + }; + if (options.offset) { + params.offset = options.offset; + } + if (options.field) { + params.field = options.field; + } + return this._rpc({ + route: '/web/dataset/resequence', + params: params, + }) + .then(function () { + data.data = _.sortBy(data.data, function (d) { + return _.indexOf(resIDs, self.localData[d].res_id); + }); + data.res_ids = []; + _.each(data.data, function (d) { + var dataPoint = self.localData[d]; + if (dataPoint.type === 'record') { + data.res_ids.push(dataPoint.res_id); + } else { + data.res_ids = data.res_ids.concat(dataPoint.res_ids); + } + }); + self._updateParentResIDs(data); + return parentID; + }); + }, + /** * Save a local resource, if needed. This is a complicated operation, * - it needs to check all changes, * - generate commands for x2many fields, @@ -1185,6 +1234,7 @@ var BasicModel = AbstractModel.extend({ record._rawChanges[name] = val; return; } + var oldValue = record._changes[name] || record.data[name]; var id; if (field.type === 'many2one') { id = false; @@ -1197,29 +1247,42 @@ var BasicModel = AbstractModel.extend({ var data = _.isArray(val) ? {id: val[0], display_name: val[1]} : {id: val}; - rec = self._makeDataPoint({ - context: record.context, - data: data, - modelName: field.relation, - parentID: record.id, - }); - id = rec.id; + if (!oldValue || (self.localData[oldValue].res_id !== data.id)) { + // only register a change if the value has changed + rec = self._makeDataPoint({ + context: record.context, + data: data, + modelName: field.relation, + parentID: record.id, + }); + id = rec.id; + record._changes[name] = id; + } + } else { + record._changes[name] = false; } - record._changes[name] = id; } else if (field.type === 'reference') { id = false; if (val) { var ref = val.split(','); - rec = self._makeDataPoint({ - context: record.context, - data: {id: parseInt(ref[1])}, - modelName: ref[0], - parentID: record.id, - }); - defs.push(self._fetchNameGet(rec)); - id = rec.id; + var modelName = ref[0]; + var resID = parseInt(ref[1]); + if (!oldValue || self.localData[oldValue].res_id !== resID || + self.localData[oldValue].model !== modelName) { + // only register a change if the value has changed + rec = self._makeDataPoint({ + context: record.context, + data: {id: parseInt(ref[1])}, + modelName: modelName, + parentID: record.id, + }); + defs.push(self._fetchNameGet(rec)); + id = rec.id; + record._changes[name] = id; + } + } else { + record._changes[name] = id; } - record._changes[name] = id; } else if (field.type === 'one2many' || field.type === 'many2many') { var listId = record._changes[name] || record.data[name]; var list; @@ -1239,25 +1302,39 @@ var BasicModel = AbstractModel.extend({ viewType: fieldInfo.viewType, }); } + // TODO: before registering the changes, verify that the x2many + // value has changed record._changes[name] = list.id; var shouldLoad = false; list._changes = list._changes || []; _.each(val, function (command) { + var rec; if (command[0] === 0 || command[0] === 1) { // CREATE or UPDATE - var params = { - context: list.context, - fields: list.fields, - fieldsInfo: list.fieldsInfo, - modelName: list.model, - parentID: list.id, - viewType: list.viewType, - }; - if (command[0] === 1) { - params.res_id = command[1]; + if (command[0] === 1 && command[1]) { + // updating an existing record + var recID = _.find(list.data, function (childID) { + var child = self.localData[childID]; + return child.res_id === command[1]; + }); + rec = self.localData[recID]; + } + if (!rec) { + var params = { + context: list.context, + fields: list.fields, + fieldsInfo: list.fieldsInfo, + modelName: list.model, + parentID: list.id, + viewType: list.viewType, + }; + if (command[0] === 1) { + params.res_id = command[1]; + } + rec = self._makeDataPoint(params); + list._cache[rec.res_id] = rec.id; } - rec = self._makeDataPoint(params); - list._cache[rec.res_id] = rec.id; + list._changes.push({operation: 'ADD', id: rec.id}); if (command[0] === 1) { list._changes.push({operation: 'UPDATE', id: rec.id}); @@ -1278,7 +1355,10 @@ var BasicModel = AbstractModel.extend({ defs.push(self._readUngroupedList(list)); } } else { - record._changes[name] = self._parseServerValue(field, val); + var newValue = self._parseServerValue(field, val); + if (newValue !== oldValue) { + record._changes[name] = newValue; + } } }); return $.when.apply($, defs); 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 93165066614..8f201b2b5e6 100644 --- a/addons/web/static/src/js/views/kanban/kanban_column.js +++ b/addons/web/static/src/js/views/kanban/kanban_column.js @@ -110,7 +110,6 @@ var KanbanColumn = Widget.extend({ var record = ui.item.data('record'); var index = self.records.indexOf(record); record.$el.removeAttr('style'); // jqueryui sortable add display:block inline - ui.item.addClass('o_updating'); if (index >= 0) { if ($.contains(self.$el[0], record.$el[0])) { // resequencing records @@ -118,6 +117,7 @@ var KanbanColumn = Widget.extend({ } } else { // adding record to this column + ui.item.addClass('o_updating'); self.trigger_up('kanban_column_add_record', {record: record, ids: self._getIDs()}); } } diff --git a/addons/web/static/src/js/views/kanban/kanban_model.js b/addons/web/static/src/js/views/kanban/kanban_model.js index e21a1376e51..354657eb0d9 100644 --- a/addons/web/static/src/js/views/kanban/kanban_model.js +++ b/addons/web/static/src/js/views/kanban/kanban_model.js @@ -179,41 +179,6 @@ var KanbanModel = BasicModel.extend({ } return this._super(id, options); }, - /** - * Resequences records. - * - * @param {string} modelName - * @param {Array[integer]} resIDs the new sequence of ids - * @param {string]} parentID the localID of the parent - * @returns {Deferred<string>} resolves to the local id of the parent - */ - resequence: function (modelName, resIDs, parentID) { - if ((resIDs.length <= 1)) { - return $.when(parentID); // there is nothing to sort - } - var self = this; - var data = this.localData[parentID]; - return this._rpc({ - route: '/web/dataset/resequence', - params: {model: modelName, ids: resIDs}, - }) - .then(function () { - data.data = _.sortBy(data.data, function (d) { - return _.indexOf(resIDs, self.localData[d].res_id); - }); - data.res_ids = []; - _.each(data.data, function (d) { - var dataPoint = self.localData[d]; - if (dataPoint.type === 'record') { - data.res_ids.push(dataPoint.res_id); - } else { - data.res_ids = data.res_ids.concat(dataPoint.res_ids); - } - }); - self._updateParentResIDs(data); - return parentID; - }); - }, //-------------------------------------------------------------------------- // Private diff --git a/addons/web/static/src/js/views/list/list_controller.js b/addons/web/static/src/js/views/list/list_controller.js index 33637e53f52..2465b1ee3c5 100644 --- a/addons/web/static/src/js/views/list/list_controller.js +++ b/addons/web/static/src/js/views/list/list_controller.js @@ -372,9 +372,16 @@ var ListController = BasicController.extend({ * @param {OdooEvent} ev */ _onEditLine: function (ev) { + var self = this; ev.stopPropagation(); - this._setMode('edit', ev.data.recordID) - .done(ev.data.onSuccess); + this.trigger_up('mutexify', { + action: function () { + var record = self.model.get(self.handle); + var editedRecord = record.data[ev.data.index]; + self._setMode('edit', editedRecord.id) + .done(ev.data.onSuccess); + }, + }); }, /** * Opens the Export Dialog @@ -404,23 +411,24 @@ var ListController = BasicController.extend({ * @param {OdooEvent} event */ _onResequence: function (event) { - var data = this.model.get(this.handle); - var resIDs = _.map(event.data.rowIDs, function(rowID) { - return _.findWhere(data.data, {id: rowID}).res_id; - }) - return this._rpc({ - route: '/web/dataset/resequence', - params: { - model: this.modelName, - ids: resIDs, - offset: event.data.offset, - field: event.data.handleField, + var self = this; + + this.trigger_up('mutexify', { + action: function () { + var state = self.model.get(self.handle); + var resIDs = _.map(event.data.rowIDs, function(rowID) { + return _.findWhere(state.data, {id: rowID}).res_id; + }); + var options = { + offset: event.data.offset, + field: event.data.handleField, + }; + return self.model.resequence(self.modelName, resIDs, self.handle, options).then(function () { + self._updateEnv(); + state = self.model.get(self.handle); + return self.renderer.updateState(state, {noRender: true}); + }); }, - }).then(function () { - data.data = _.sortBy(data.data, function (d) { - return _.indexOf(resIDs, d.res_id); - }); - return this.handle; }); }, /** 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 c5f65ecc6e2..229c61733e5 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 @@ -437,11 +437,11 @@ ListRenderer.include({ var self = this; var movedRecordID = ui.item.data('id'); var rowIDs = _.pluck(this.state.data, 'id'); - rowIDs = _.without(rowIDs, movedRecordID) + rowIDs = _.without(rowIDs, movedRecordID); rowIDs.splice(ui.item.index(), 0, movedRecordID); var sequences = _.map(this.state.data, function(record) { return record.data[self.handleField]; - }) + }); this.trigger_up('resequence', { rowIDs: rowIDs, offset: _.min(sequences), @@ -516,10 +516,9 @@ ListRenderer.include({ var self = this; return this.unselectRow().then(function () { // Notify the controller we want to make a record editable - var record = self.state.data[rowIndex]; var def = $.Deferred(); self.trigger_up('edit_line', { - recordID: record.id, + index: rowIndex, onSuccess: def.resolve.bind(def), }); return def; diff --git a/addons/web/static/src/js/widgets/debug_manager.js b/addons/web/static/src/js/widgets/debug_manager.js index 0de80c8e3c6..c74ce95ac1b 100644 --- a/addons/web/static/src/js/widgets/debug_manager.js +++ b/addons/web/static/src/js/widgets/debug_manager.js @@ -390,7 +390,7 @@ DebugManager.include({ // or m2m if (!value || invisibleOrReadOnly || fieldInfo.type === 'one2many' || fieldInfo.type === 'many2many' || fieldInfo.type === 'binary' || - fieldsInfo[fieldName].options.isPassword) { + fieldsInfo[fieldName].options.isPassword || !_.isEmpty(fieldInfo.depends)) { return false; } return { diff --git a/addons/web/static/src/less/kanban_dashboard.less b/addons/web/static/src/less/kanban_dashboard.less index e86350f6b49..c1cc5047001 100644 --- a/addons/web/static/src/less/kanban_dashboard.less +++ b/addons/web/static/src/less/kanban_dashboard.less @@ -35,6 +35,11 @@ } } + &.o_kanban_dashboard { + // correctly display the no_content_helper in dashboards + .o-flex-flow(row, wrap); + } + &.o_kanban_dashboard.o_kanban_ungrouped, &.o_kanban_dashboard.o_kanban_grouped { // If invisible, elem will no take more than its original height |
