[FIX] web: handle mutexify in standalone widgets

The rev. https://github.com/odoo/odoo/commit/99ae418bf24171fbc6bb27584059c27efb857e77
introduced a trigger_up `mutexify` when quick creating a record in a many2one ;
this broke the behaviour when the many2one was standalone (because it has no
BasicController and mutexify is handled in the latter).

An attempt to fix this issue has been made in the rev. https://github.com/odoo/odoo/commit/e83c3e2678500c9bf2c17b4d23ae9a294ebafaa7
by adding an option `standalone` in the field widget options. In this case,
the action was directly executed instead of the trigger_up. While this correctly
works, this implies that the option needs to be added in every standalone
many2one (and only many2one as the others won't use the option), which is not
very convenient.

An other attempt is made in this rev. by moving the mutexify handler from the
BasicController to the FieldManagerMixin ; as a widget that instantiates a field
widget needs to extend this mixin, both cases will work and we won't need to
specify the option anymore.

This commit thus partially reverts the rev. https://github.com/odoo/odoo/commit/e83c3e2678500c9bf2c17b4d23ae9a294ebafaa7
This commit is contained in:
Martin Geubelle
2017-08-02 08:49:12 +02:00
parent 8d89148d13
commit 211961c374
5 changed files with 37 additions and 40 deletions
@@ -65,12 +65,10 @@ var AbstractField = Widget.extend({
* @constructor
* @param {Widget} parent
* @param {string} name The field name defined in the model
* @param {Object} record A record object (result of the get method of
* @param {Object} record A record object (result of the get method of
* a basic model)
* @param {Object} [options]
* @param {string} [options.mode=readonly] should be 'readonly' or 'edit'
* @param {string} [options.standalone=false] this flag indicates that the
* field does not have a controller to delegate to
*/
init: function (parent, name, record, options) {
this._super(parent);
@@ -160,10 +158,6 @@ var AbstractField = Widget.extend({
// calls to the format (resp. parse) function.
this.formatOptions = {};
this.parseOptions = {};
// standalone is a flag indicating that the field does not have a
// controller to delegate actions to
this.standalone = options.standalone;
},
/**
* When a field widget is appended to the DOM, its start method is called,
@@ -223,25 +223,21 @@ var FieldMany2One = AbstractField.extend({
_quickCreate: function (name) {
var self = this;
var slowCreate = this._searchCreatePopup.bind(this, "form", false, this._createContext(name));
var action = function () {
return self._rpc({
model: self.field.relation,
method: 'name_create',
args: [name],
context: self.record.getContext(self.recordParams),
}).then(function (result) {
if (self.mode === "edit") {
self.reinitialize({id: result[0], display_name: result[1]});
}
}, slowCreate);
};
if (this.nodeOptions.quick_create) {
if (this.standalone) {
action();
} else {
this.trigger_up('mutexify', {action: action});
}
this.trigger_up('mutexify', {
action: function () {
return self._rpc({
model: self.field.relation,
method: 'name_create',
args: [name],
context: self.record.getContext(self.recordParams),
}).then(function (result) {
if (self.mode === "edit") {
self.reinitialize({id: result[0], display_name: result[1]});
}
}, slowCreate);
},
});
} else {
slowCreate();
}
@@ -8,7 +8,6 @@ odoo.define('web.BasicController', function (require) {
*/
var AbstractController = require('web.AbstractController');
var concurrency = require('web.concurrency');
var core = require('web.core');
var Dialog = require('web.Dialog');
var FieldManagerMixin = require('web.FieldManagerMixin');
@@ -19,7 +18,6 @@ var _t = core._t;
var BasicController = AbstractController.extend(FieldManagerMixin, {
custom_events: _.extend({}, AbstractController.prototype.custom_events, FieldManagerMixin.custom_events, {
discard_changes: '_onDiscardChanges',
mutexify: '_onMutexify',
reload: '_onReload',
sidebar_data_asked: '_onSidebarDataAsked',
translate: '_onTranslate',
@@ -39,7 +37,6 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
FieldManagerMixin.init.call(this, this.model);
this.handle = params.initialState.id;
this.mode = params.mode || 'readonly';
this.mutex = new concurrency.Mutex();
},
/**
* @override
@@ -526,15 +523,6 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
}
FieldManagerMixin._onFieldChanged.apply(this, arguments);
},
/**
* @private
* @param {OdooEvent} ev
* @param {function} ev.data.action the function to execute in the mutex
*/
_onMutexify: function (ev) {
ev.stopPropagation(); // prevent other controllers from handling this request
this.mutex.exec(ev.data.action);
},
/**
* When a reload event triggers up, we need to reload the full view.
* For example, after a form view dialog saved some data.
@@ -9,11 +9,13 @@ odoo.define('web.FieldManagerMixin', function (require) {
*/
var BasicModel = require('web.BasicModel');
var concurrency = require('web.concurrency');
var FieldManagerMixin = {
custom_events: {
field_changed: '_onFieldChanged',
load: '_onLoad',
mutexify: '_onMutexify',
},
/**
* A FieldManagerMixin can be initialized with an instance of a basicModel.
@@ -23,6 +25,7 @@ var FieldManagerMixin = {
*/
init: function (model) {
this.model = model || new BasicModel(this);
this.mutex = new concurrency.Mutex();
},
//--------------------------------------------------------------------------
@@ -130,6 +133,15 @@ var FieldManagerMixin = {
data.on_success(self.model.get(db_id));
});
},
/**
* @private
* @param {OdooEvent} ev
* @param {function} ev.data.action the function to execute in the mutex
*/
_onMutexify: function (ev) {
ev.stopPropagation(); // prevent other field managers from handling this request
this.mutex.exec(ev.data.action);
},
};
return FieldManagerMixin;
@@ -6,6 +6,7 @@ var concurrency = require('web.concurrency');
var FormView = require('web.FormView');
var ListView = require('web.ListView');
var relationalFields = require('web.relational_fields');
var StandaloneFieldManagerMixin = require('web.StandaloneFieldManagerMixin');
var testUtils = require('web.test_utils');
var Widget = require('web.Widget');
@@ -565,7 +566,7 @@ QUnit.module('relational_fields', {
form.destroy();
});
QUnit.test('many2one field with option standalone', function (assert) {
QUnit.test('standalone many2one field', function (assert) {
assert.expect(3);
var done = assert.async();
@@ -593,7 +594,14 @@ QUnit.module('relational_fields', {
},
}).then(function (recordID) {
var record = model.get(recordID);
var parent = new Widget();
// create a new widget that uses the StandaloneFieldManagerMixin
var StandaloneWidget = Widget.extend(StandaloneFieldManagerMixin, {
init: function (parent) {
this._super.apply(this, arguments);
StandaloneFieldManagerMixin.init.call(this, parent);
},
});
var parent = new StandaloneWidget(model);
testUtils.addMockEnvironment(parent, {
data: self.data,
mockRPC: function (route, args) {
@@ -607,7 +615,6 @@ QUnit.module('relational_fields', {
record,
{
mode: 'edit',
standalone: true,
});
relField.appendTo(fixture);