[FIX] web: use mutex to wait for onchanges

This fix is related to c12a2e1d16

Mutex allow to wait sequentially for mutex
Besides, if one of the onchanges deferreds fails, it does not resolve the mutex until all deferreds of the mutex are resolved.

Besides, we now wait for the onchanges mutex between each field commited value (line 596) in case the commited value leaded to a new onchanges, that we should wait for before commiting the rest of the values.
This commit is contained in:
Denis Ledoux 2014-11-28 13:36:42 +01:00
parent 479d94ea14
commit 45551cf78c
1 changed files with 46 additions and 48 deletions

View File

@ -103,7 +103,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
this.fields_order = []; this.fields_order = [];
this.datarecord = {}; this.datarecord = {};
this._onchange_specs = {}; this._onchange_specs = {};
this.onchanges_defs = []; this.onchanges_mutex = new $.Mutex();
this.default_focus_field = null; this.default_focus_field = null;
this.default_focus_button = null; this.default_focus_button = null;
this.fields_registry = instance.web.form.widgets; this.fields_registry = instance.web.form.widgets;
@ -509,44 +509,45 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
def = self.alive(new instance.web.Model(self.dataset.model).call( def = self.alive(new instance.web.Model(self.dataset.model).call(
"onchange", [ids, values, trigger_field_name, onchange_specs, context])); "onchange", [ids, values, trigger_field_name, onchange_specs, context]));
} }
var onchange_def = def.then(function(response) { this.onchanges_mutex.exec(function(){
if (widget && widget.field['change_default']) { return def.then(function(response) {
var fieldname = widget.name; if (widget && widget.field['change_default']) {
var value_; var fieldname = widget.name;
if (response.value && (fieldname in response.value)) { var value_;
// Use value from onchange if onchange executed if (response.value && (fieldname in response.value)) {
value_ = response.value[fieldname]; // Use value from onchange if onchange executed
} else { value_ = response.value[fieldname];
// otherwise get form value for field } else {
value_ = self.fields[fieldname].get_value(); // otherwise get form value for field
} value_ = self.fields[fieldname].get_value();
var condition = fieldname + '=' + value_; }
var condition = fieldname + '=' + value_;
if (value_) { if (value_) {
return self.alive(new instance.web.Model('ir.values').call( return self.alive(new instance.web.Model('ir.values').call(
'get_defaults', [self.model, condition] 'get_defaults', [self.model, condition]
)).then(function (results) { )).then(function (results) {
if (!results.length) { if (!results.length) {
return response;
}
if (!response.value) {
response.value = {};
}
for(var i=0; i<results.length; ++i) {
// [whatever, key, value]
var triplet = results[i];
response.value[triplet[1]] = triplet[2];
}
return response; return response;
} });
if (!response.value) { }
response.value = {};
}
for(var i=0; i<results.length; ++i) {
// [whatever, key, value]
var triplet = results[i];
response.value[triplet[1]] = triplet[2];
}
return response;
});
} }
} return response;
return response; }).then(function(response) {
}).then(function(response) { return self.on_processed_onchange(response);
return self.on_processed_onchange(response); });
}); });
this.onchanges_defs.push(onchange_def); return this.onchanges_mutex.def;
return onchange_def;
} catch(e) { } catch(e) {
console.error(e); console.error(e);
instance.webclient.crashmanager.show_message(e); instance.webclient.crashmanager.show_message(e);
@ -587,21 +588,18 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
var self = this; var self = this;
return this.mutating_mutex.exec(function() { return this.mutating_mutex.exec(function() {
function iterate() { function iterate() {
var start = $.Deferred();
start.resolve(); var mutex = new $.Mutex();
start = _.reduce(self.onchanges_defs, function(memo, d){
return memo.then(function(){
return d;
}, function(){
return d;
});
}, start);
var defs = [start];
_.each(self.fields, function(field) { _.each(self.fields, function(field) {
defs.push(field.commit_value()); self.onchanges_mutex.def.then(function(){
mutex.exec(function(){
return field.commit_value();
});
});
}); });
var args = _.toArray(arguments); var args = _.toArray(arguments);
return $.when.apply($, defs).then(function() { return $.when.apply(null, [mutex.def, self.onchanges_mutex.def]).then(function() {
var save_obj = self.save_list.pop(); var save_obj = self.save_list.pop();
if (save_obj) { if (save_obj) {
return self._process_save(save_obj).then(function() { return self._process_save(save_obj).then(function() {
@ -655,7 +653,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
* if the current record is not yet saved. It will then stay in create mode. * if the current record is not yet saved. It will then stay in create mode.
*/ */
to_edit_mode: function() { to_edit_mode: function() {
this.onchanges_defs = []; this.onchanges_mutex = new $.Mutex();
this._actualize_mode("edit"); this._actualize_mode("edit");
}, },
/** /**