summaryrefslogtreecommitdiff
path: root/addons/web/static/src
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2017-09-11 14:02:19 +0200
committerChristophe Simonis <chs@odoo.com>2017-09-11 14:02:19 +0200
commitbd08d4f0522c6322ee38c2c65921ff0b3c3193a9 (patch)
treeffe604f3f9f0b58fc01e4a7227dfe4ba41f02d38 /addons/web/static/src
parentecbfcb6dcf2226b476cc0fca4d21f7a58cf97cc1 (diff)
parent3ac2a1106c8c776a951337b174a056f817246f98 (diff)
[MERGE] forward port branch saas-16 up to 3ac2a1106c8
Diffstat (limited to 'addons/web/static/src')
-rw-r--r--addons/web/static/src/js/fields/relational_fields.js4
-rw-r--r--addons/web/static/src/js/services/data_manager.js16
-rw-r--r--addons/web/static/src/js/views/basic/basic_model.js140
-rw-r--r--addons/web/static/src/js/views/kanban/kanban_column.js2
-rw-r--r--addons/web/static/src/js/views/kanban/kanban_model.js35
-rw-r--r--addons/web/static/src/js/views/list/list_controller.js44
-rw-r--r--addons/web/static/src/js/views/list/list_editable_renderer.js7
-rw-r--r--addons/web/static/src/js/widgets/debug_manager.js2
-rw-r--r--addons/web/static/src/less/kanban_dashboard.less5
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