diff options
| author | Christophe Simonis <chs@odoo.com> | 2017-08-10 18:07:47 +0200 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2017-08-10 18:07:47 +0200 |
| commit | 1fa8680286262cea52d26ff8616b72d2862dab07 (patch) | |
| tree | 54ef67a0d819120fb5dcbbaa98ad91232cbc2116 /addons/web/static/src | |
| parent | 39ae81141777071329623dbc3ca89172b960f295 (diff) | |
| parent | 48b2ce60ed12b9b0f3aaa0322465504798bd154e (diff) | |
[MERGE] forward port branch saas-17 up to 48b2ce60ed1
Diffstat (limited to 'addons/web/static/src')
10 files changed, 103 insertions, 57 deletions
diff --git a/addons/web/static/src/js/chrome/view_manager.js b/addons/web/static/src/js/chrome/view_manager.js index a4a1d65f7b6..5962bb28acb 100644 --- a/addons/web/static/src/js/chrome/view_manager.js +++ b/addons/web/static/src/js/chrome/view_manager.js @@ -20,7 +20,7 @@ var ViewManager = Widget.extend(ControlPanelMixin, { custom_events: { execute_action: function(event) { var data = event.data; - this.do_execute_action(data.action_data, data.model, data.res_ids, data.on_closed) + this.do_execute_action(data.action_data, data.env, data.on_closed) .then(data.on_success, data.on_fail); }, search: function(event) { @@ -554,16 +554,19 @@ var ViewManager = Widget.extend(ControlPanelMixin, { * @param {string} [action_data.effect] if given, a visual effect (a * rainbowman by default) will be displayed when the action is complete, * with the string (evaluated) given as options. - * @param {DataSet} dataset a dataset object used to communicate with the server - * @param {integer[]} [res_ids] the res_ids of the objects on which the action is to be applied (fallback on env.ids if not set) + * @param {Object} env + * @param {string} env.model the model of the record(s) triggering the action + * @param {integer[]} [env.resIDs] the current ids in the environment where the action is triggered + * @param {integer} [env.currentID] the id of the record triggering the action + * @param {Object} [env.context] a context to pass to the action * @param {Function} on_closed callback to execute when dialog is closed or when the action does not generate any result (no new action) */ - do_execute_action: function (action_data, model, res_ids, on_closed) { + do_execute_action: function (action_data, env, on_closed) { var self = this; var result_handler = on_closed || function () {}; - var context = new Context(this.env.context, action_data.context || {}); + var context = new Context(env.context, action_data.context || {}); // OR NULL hereunder: pyeval waits specifically for a null value, different from undefined - var record_id = res_ids && res_ids[0] || null; + var recordID = env.currentID || null; // response handler var handler = function (action) { @@ -585,11 +588,11 @@ var ViewManager = Widget.extend(ControlPanelMixin, { })) ); ncontext.add(action_data.context || {}); - ncontext.add({active_model: self.env.modelName}); - if (res_ids) { + ncontext.add({active_model: env.model}); + if (recordID) { ncontext.add({ - active_id: record_id, - active_ids: res_ids, + active_id: recordID, + active_ids: [recordID], }); } ncontext.add(action.context || {}); @@ -611,7 +614,7 @@ var ViewManager = Widget.extend(ControlPanelMixin, { if (action_data.special) { return handler({"type":"ir.actions.act_window_close"}); } else if (action_data.type === "object") { - var args = res_ids ? [res_ids] : [this.env.ids]; + var args = recordID ? [[recordID]] : [env.resIDs]; if (action_data.args) { try { // Warning: quotes and double quotes problem due to json and xml clash @@ -623,13 +626,13 @@ var ViewManager = Widget.extend(ControlPanelMixin, { } } args.push(context); - var dataset = new data.DataSet(this, model, this.env.context); + var dataset = new data.DataSet(this, env.model, env.context); return dataset.call_button(action_data.name, args).then(handler); } else if (action_data.type === "action") { return data_manager.load_action(action_data.name, _.extend(pyeval.eval('context', context), { - active_model: this.env.modelName, - active_ids: this.env.ids, - active_id: record_id, + active_model: env.model, + active_ids: env.resIDs, + active_id: recordID, })).then(handler); } }, diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js index 64049d8b1ec..0dce6ec2bb4 100644 --- a/addons/web/static/src/js/fields/relational_fields.js +++ b/addons/web/static/src/js/fields/relational_fields.js @@ -219,10 +219,16 @@ var FieldMany2One = AbstractField.extend({ /** * @private * @param {string} name + * @returns {Deferred} resolved after the name_create or when the slowcreate + * modal is closed. */ _quickCreate: function (name) { var self = this; - var slowCreate = this._searchCreatePopup.bind(this, "form", false, this._createContext(name)); + var def = $.Deferred(); + var slowCreate = function () { + var dialog = self._searchCreatePopup.bind(self, "form", false, self._createContext(name)); + dialog.on('closed', self, def.resolve.bind(def)); + }; if (this.nodeOptions.quick_create) { this.trigger_up('mutexify', { action: function () { @@ -235,12 +241,16 @@ var FieldMany2One = AbstractField.extend({ if (self.mode === "edit") { self.reinitialize({id: result[0], display_name: result[1]}); } - }, slowCreate); + def.resolve(); + }).fail(function () { + slowCreate(); + }); }, }); } else { slowCreate(); } + return def; }, /** * @private diff --git a/addons/web/static/src/js/views/abstract_view.js b/addons/web/static/src/js/views/abstract_view.js index 8de118b29b7..644ba8ac985 100644 --- a/addons/web/static/src/js/views/abstract_view.js +++ b/addons/web/static/src/js/views/abstract_view.js @@ -29,6 +29,7 @@ var ajax = require('web.ajax'); var AbstractModel = require('web.AbstractModel'); var AbstractRenderer = require('web.AbstractRenderer'); var AbstractController = require('web.AbstractController'); +var Context = require('web.Context'); var AbstractView = Class.extend({ // name displayed in view switchers @@ -152,9 +153,9 @@ var AbstractView = Class.extend({ }); }, /** - * Returns the view model or create an instance of it if there is noney + * Returns the view model or create an instance of it if none * - * @param {Widget} parent the parent of the model + * @param {Widget} parent the parent of the model, if it has to be created * @return {Object} instance of the view model */ getModel: function (parent) { @@ -167,7 +168,7 @@ var AbstractView = Class.extend({ /** * Returns the a new view renderer instance * - * @param {Widget} parent the parent of the model + * @param {Widget} parent the parent of the model, if it has to be created * @param {Object} state the information related to the rendered view * @return {Object} instance of the view renderer */ @@ -239,7 +240,7 @@ var AbstractView = Class.extend({ * Loads the subviews for x2many fields when they are not inline * * @private - * @param {Widget} parent the parent of the model + * @param {Widget} parent the parent of the model, if it has to be created * @returns {Deferred} */ _loadSubviews: function (parent) { 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 3a47f65ab03..6ba9dbea477 100644 --- a/addons/web/static/src/js/views/basic/basic_controller.js +++ b/addons/web/static/src/js/views/basic/basic_controller.js @@ -232,13 +232,17 @@ var BasicController = AbstractController.extend(FieldManagerMixin, { return self.isDestroyed() ? $.when() : self.reload(); }; record = record || this.model.get(this.handle); - 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], + env: { + context: record.getContext(), + currentID: record.data.id, + model: record.model, + resIDs: record.res_ids, + }, on_closed: function (reason) { if (!_.isObject(reason)) { reload(reason); 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 04fe384afdc..8755805f993 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -649,7 +649,7 @@ var BasicModel = AbstractModel.extend({ var element = this.localData[id]; if (element.type === 'record') { - if ('currentId' in options && !options.currentId) { + if (!options.currentId && (('currentId' in options) || this.isNew(id))) { var params = { context: element.context, fieldsInfo: element.fieldsInfo, @@ -2310,12 +2310,20 @@ var BasicModel = AbstractModel.extend({ }); list = this._applyX2ManyOperations(list); if (type === 'many2many' || list._forceM2MLink) { + var relRecordCreated = _.filter(relRecordAdded, function (rec) { + return typeof rec.res_id === 'string'; + }); + var realIDs = _.difference(list.res_ids, _.pluck(relRecordCreated, 'res_id')); // deliberately generate a single 'replace' command instead // of a 'delete' and a 'link' commands with the exact diff // because 1) performance-wise it doesn't change anything // and 2) to guard against concurrent updates (policy: force // a complete override of the actual value of the m2m) - commands[fieldName].push(x2ManyCommands.replace_with(list.res_ids)); + commands[fieldName].push(x2ManyCommands.replace_with(realIDs)); + _.each(relRecordCreated, function (relRecord) { + var changes = self._generateChanges(relRecord, options); + commands[fieldName].push(x2ManyCommands.create(changes)); + }); // generate update commands for records that have been // updated (it may happen with editable lists) _.each(relRecordUpdated, function (relRecord) { @@ -2435,6 +2443,12 @@ var BasicModel = AbstractModel.extend({ */ _getDomain: function (element, options) { if (options && options.fieldName) { + if (element._domains[options.fieldName]) { + return Domain.prototype.stringToArray( + element._domains[options.fieldName], + this._getEvalContext(element, true) + ); + } var viewType = options.viewType || element.viewType; var fieldInfo = element.fieldsInfo[viewType][options.fieldName]; if (fieldInfo && fieldInfo.domain) { @@ -2697,6 +2711,7 @@ var BasicModel = AbstractModel.extend({ var dataPoint = { _cache: type === 'list' ? {} : undefined, _changes: null, + _domains: {}, aggregateValues: params.aggregateValues || {}, context: params.context || {}, count: params.count || res_ids.length, @@ -2870,6 +2885,9 @@ var BasicModel = AbstractModel.extend({ r._changes = _.defaults(value[2], r.data); for (var name in r._changes) { + if (r._changes[name] === null) { + continue; + } var isFieldInView = name in r.fields; if (isFieldInView && r.fields[name].type === 'many2one') { var rec = self._makeDataPoint({ @@ -3021,12 +3039,7 @@ var BasicModel = AbstractModel.extend({ record._warning = true; } if (result.domain) { - var fieldsInfo = record.fieldsInfo[viewType || record.viewType]; - for (var fieldName in result.domain) { - if (fieldsInfo[fieldName]) { - fieldsInfo[fieldName].domain = result.domain[fieldName]; - } - } + record._domains = _.extend(record._domains, result.domain); } return self._applyOnChange(result.value, record).then(function () { return result; @@ -3083,7 +3096,9 @@ var BasicModel = AbstractModel.extend({ */ _readGroup: function (list) { var self = this; - var fields = _.uniq(list.getFieldNames().concat(list.groupedBy)); + var groupByField = list.groupedBy[0]; + var rawGroupBy = groupByField.split(':')[0]; + var fields = _.uniq(list.getFieldNames().concat(rawGroupBy)); return this._rpc({ model: list.model, method: 'read_group', @@ -3094,8 +3109,6 @@ var BasicModel = AbstractModel.extend({ lazy: true, }) .then(function (groups) { - var groupByField = list.groupedBy[0]; - var rawGroupBy = groupByField.split(':')[0]; var previousGroups = _.map(list.data, function (groupID) { return self.localData[groupID]; }); diff --git a/addons/web/static/src/js/views/calendar/calendar_renderer.js b/addons/web/static/src/js/views/calendar/calendar_renderer.js index 4f5719063ff..5fb79cfa3a0 100644 --- a/addons/web/static/src/js/views/calendar/calendar_renderer.js +++ b/addons/web/static/src/js/views/calendar/calendar_renderer.js @@ -322,10 +322,11 @@ return AbstractRenderer.extend({ element.addClass($render.attr('class')); var display_hour = ''; if (!event.allDay) { - display_hour = (event.start.format('HH:mm') === '00:00' ? event.r_start.format('HH:mm') : event.start.format('HH:mm')) + ' - ' + - (event.end && event.end.format('HH:mm') !== '00:00' ? event.end.format('HH:mm') : event.r_end.format('HH:mm')); + var start = event.r_start || event.start; + var end = event.r_end || event.end; + display_hour = start.format('HH:mm') + ' - ' + end.format('HH:mm'); if (display_hour === '00:00 - 00:00') { - display_hour = _t('All the day'); + display_hour = _t('All day'); } } element.find('.fc-content .fc-time').text(display_hour); diff --git a/addons/web/static/src/js/views/form/form_controller.js b/addons/web/static/src/js/views/form/form_controller.js index cdfe2cb8d5d..0718b4e202e 100644 --- a/addons/web/static/src/js/views/form/form_controller.js +++ b/addons/web/static/src/js/views/form/form_controller.js @@ -217,7 +217,7 @@ var FormController = BasicController.extend({ * * @private * @override method from field manager mixin - * @param {string} id + * @param {string} id - id of the previously changed record * @returns {Deferred} */ _confirmSave: function (id) { @@ -228,15 +228,21 @@ var FormController = BasicController.extend({ return this._setMode('readonly'); } } else { - // a subrecord changed, so update the corresponding relational field + // A subrecord has changed, so update the corresponding relational field // i.e. the one whose value is a record with the given id or a list // having a record with the given id in its data var record = this.model.get(this.handle); - var fieldsChanged = _.findKey(record.data, function (d) { - return _.isObject(d) && - (d.id === id || _.findWhere(d.data, {id: id})); - }); - return this.renderer.confirmChange(record, record.id, [fieldsChanged]); + + // Callback function which returns true + // if a value recursively contains a record with the given id. + // This will be used to determine the list of fields to reload. + var containsChangedRecord = function (value) { + return _.isObject(value) && + (value.id === id || _.find(value.data, containsChangedRecord)); + }; + + var changedFields = _.findKey(record.data, containsChangedRecord); + return this.renderer.confirmChange(record, record.id, [changedFields]); } }, /** diff --git a/addons/web/static/src/js/views/kanban/kanban_controller.js b/addons/web/static/src/js/views/kanban/kanban_controller.js index 2cf6a94285e..6870dbbbe24 100644 --- a/addons/web/static/src/js/views/kanban/kanban_controller.js +++ b/addons/web/static/src/js/views/kanban/kanban_controller.js @@ -237,8 +237,12 @@ var KanbanController = BasicController.extend({ } this.trigger_up('execute_action', { action_data: attrs, - model: record.model, - res_ids: [record.res_id], + env: { + context: record.getContext(), + currentID: record.res_id, + model: record.model, + resIDs: record.res_ids, + }, on_closed: function () { self.model.reload(record.id).then(function (db_id) { var data = self.model.get(db_id); 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 3977ac0df87..71402fc92ec 100644 --- a/addons/web/static/src/js/views/kanban/kanban_model.js +++ b/addons/web/static/src/js/views/kanban/kanban_model.js @@ -240,7 +240,7 @@ var KanbanModel = BasicModel.extend({ */ _readTooltipFields: function (list) { var self = this; - var groupedByField = list.fields[list.groupedBy[0]]; + var groupedByField = list.fields[list.groupedBy[0].split(':')[0]]; if (groupedByField.type !== 'many2one') { return $.when(); } 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 4851870c8f8..3ef48792f06 100644 --- a/addons/web/static/src/js/views/list/list_renderer.js +++ b/addons/web/static/src/js/views/list/list_renderer.js @@ -282,15 +282,19 @@ var ListRenderer = BasicRenderer.extend({ this._registerModifiers(node, record, $button); - // TODO this should be moved to a handler - var self = this; - $button.on("click", function (e) { - e.stopPropagation(); - self.trigger_up('button_clicked', { - attrs: node.attrs, - record: record, + if (record.res_id) { + // TODO this should be moved to a handler + var self = this; + $button.on("click", function (e) { + e.stopPropagation(); + self.trigger_up('button_clicked', { + attrs: node.attrs, + record: record, + }); }); - }); + } else { + $button.prop('disabled', true); + } return $button; }, |
