[FIX] web: various small issues in form view onchange/one2many

- Issue: Edit sale.order form view, add new line, change product who have
  taxes and click quickly on save (with slow network) => error message.
  Because some deferreds are lost.
- reduce number of reads and onchange for x2m widgets
- remove before_save method and use commit_value (the issue was that if the
  before_save and the change trigger an onchange, the onchange deferred is not
  checked before saving the content.
This commit is contained in:
Christophe Matthieu
2016-03-14 10:14:16 +01:00
committed by Géry Debongnie
parent bbbf3db581
commit feeac2a4f1
5 changed files with 44 additions and 58 deletions
+6 -8
View File
@@ -833,9 +833,10 @@ var BufferedDataSet = DataSetStatic.extend({
});
}
this.delete_all = false;
_.each(_.clone(this.running_reads), function(el) {
el.reject();
});
this.cancel_read();
},
cancel_read: function () {
_.invoke(_.clone(this.running_reads), 'reject');
},
read_ids: function (ids, fields, options) {
// read what is necessary from the server to have ids and the given
@@ -897,11 +898,8 @@ var BufferedDataSet = DataSetStatic.extend({
});
var _super = this._super;
this.mutex.exec(function () {
_super.call(self, to_get, fields, options).then(function() {
def.resolve.apply(def, arguments);
}, function() {
def.reject.apply(def, arguments);
});
if (def.state() !== "pending") return;
_super.call(self, to_get, fields, options).then(_.bind(def.resolve, def), _.bind(def.reject, def));
return def;
});
return def.then(function(records) {
@@ -632,12 +632,6 @@ var FieldInterface = {
the field to save its value before reading it using get_value(). Must return a promise.
*/
commit_value: function() {},
/*
The form view call before_save before save data and if before_save return a deferred,
the form view wait that all deferred are resolve or fail.
If the deferred is rejected, the field is invalidate
*/
before_save: function() {},
};
/**
@@ -489,8 +489,13 @@ var AbstractManyField = common.AbstractField.extend({
}
var tmp = this.no_rerender;
this.no_rerender = true;
this.data_replace(ids.slice());
var def = this.data_replace(ids.slice());
this.no_rerender = tmp;
return def;
},
commit_value: function() {
return this.mutex.def;
},
/*
@@ -859,13 +864,9 @@ var FieldX2Many = AbstractManyField.extend({
commit_value: function() {
var view = this.get_active_view();
if (view && view.type === "list" && view.controller.__focus) {
var def = $.Deferred();
view.controller._on_blur_one2many().always(function () {
def.resolve();
});
return def;
return $.when(this.mutex.def, view.controller._on_blur_one2many());
}
return $.when(false);
return this.mutex.def;
},
is_syntax_valid: function() {
var view = this.get_active_view();
@@ -971,6 +972,8 @@ var X2ManyListView = ListView.extend({
var valid = _.every(cached_records, function(record){
_.each(fields, function(field){
var value = record.values[field.name];
field._inhibit_on_change_flag = true;
field.no_rerender = true;
field.set_value(_.isArray(value) && _.isArray(value[0]) ? [COMMANDS.delete_all()].concat(value) : value);
});
return _.every(fields, function(field){
@@ -1269,7 +1272,7 @@ var One2ManyFormView = FormView.extend({
});
var FieldOne2Many = FieldX2Many.extend({
init: function() {
init: function() {
this._super.apply(this, arguments);
this.x2many_views = {
form: One2ManyFormView,
@@ -1281,12 +1284,15 @@ var FieldOne2Many = FieldX2Many.extend({
this.$el.addClass('oe_form_field_one2many');
return this._super.apply(this, arguments);
},
before_save: function() {
if(this.viewmanager.active_view.type === "list"
&& this.viewmanager.active_view.controller.editable()) {
return this.viewmanager.active_view.controller.save_edition();
commit_value: function() {
var self = this;
var view = this.viewmanager.active_view;
if(view.type === "list" && view.controller.editable()) {
return this.mutex.def.then(function () {
return view.controller.save_edition();
});
}
return $.when();
return this.mutex.def;
},
});
@@ -1388,7 +1394,6 @@ var FieldMany2ManyTags = AbstractManyField.extend(common.CompletionFieldMixin, c
this._super(field_manager, node);
common.CompletionFieldMixin.init.call(this);
this.set({"value": []});
this._display_orderer = new utils.DropMisordered();
var self = this;
// We need to know if the field 'color' exists on the model
@@ -1398,6 +1403,10 @@ var FieldMany2ManyTags = AbstractManyField.extend(common.CompletionFieldMixin, c
});
});
},
commit_value: function() {
this.dataset.cancel_read();
return this._super();
},
initialize_content: function() {
if(!this.get("effective_readonly")) {
this.many2one = new FieldMany2One(this.field_manager, this.node);
@@ -1434,10 +1443,9 @@ var FieldMany2ManyTags = AbstractManyField.extend(common.CompletionFieldMixin, c
},
get_render_data: function(ids){
var self = this;
return this.mutex.exec(function(){
var fields = self.fields.color ? ['display_name', 'name', 'color'] : ['display_name', 'name']; // TODO master: remove useless 'name'
return self.dataset.read_ids(ids, fields);
});
this.dataset.cancel_read();
var fields = this.fields.color ? ['display_name', 'name', 'color'] : ['display_name', 'name']; // TODO master: remove useless 'name'
return this.dataset.read_ids(ids, fields);
},
render_tag: function(data) {
this.$('.badge').remove();
@@ -1457,7 +1465,7 @@ var FieldMany2ManyTags = AbstractManyField.extend(common.CompletionFieldMixin, c
self.render_tag(data);
};
if (!values || values.length > 0) {
return this._display_orderer.add(self.get_render_data(values)).done(handle_names);
return self.get_render_data(values).done(handle_names);
} else {
handle_names([]);
}
+9 -23
View File
@@ -584,9 +584,8 @@ var FormView = View.extend(common.FieldManagerMixin, {
field.node.attrs.domain = domain;
});
if (!_.isEmpty(result.value)) {
this._internal_set_values(result.value);
}
var def = $.when(!_.isEmpty(result.value) && this._internal_set_values(result.value));
// FIXME XXX a list of warnings?
if (!_.isEmpty(result.warning)) {
this.warning_displayed = true;
@@ -601,7 +600,7 @@ var FormView = View.extend(common.FieldManagerMixin, {
});
}
return $.Deferred().resolve();
return def;
} catch(e) {
console.error(e);
crash_manager.show_message(e);
@@ -611,18 +610,18 @@ var FormView = View.extend(common.FieldManagerMixin, {
_process_operations: function() {
var self = this;
return this.mutating_mutex.exec(function() {
function onchanges_mutex () {return self.onchanges_mutex.def;}
function iterate() {
var mutex = new utils.Mutex();
mutex.exec(onchanges_mutex);
_.each(self.fields, function(field) {
self.onchanges_mutex.def.then(function(){
mutex.exec(function(){
return field.commit_value();
});
mutex.exec(function(){
return field.commit_value();
});
mutex.exec(onchanges_mutex);
});
return mutex.def.then(function () { return self.onchanges_mutex.def; }).then(function() {
return mutex.def.then(function() {
var save_obj = self.save_list.pop();
if (save_obj) {
return self._process_save(save_obj).then(function() {
@@ -863,19 +862,6 @@ var FormView = View.extend(common.FieldManagerMixin, {
readonly_values = {},
deferred = [];
_.each(self.fields, function (f) {
var res = f.before_save();
if (res) {
deferred.push(res);
res.fail(function () {
form_invalid = true;
if (!first_invalid_field) {
first_invalid_field = f;
}
});
}
});
$.when.apply($, deferred).always(function () {
_.each(self.fields, function (f) {
+2 -2
View File
@@ -155,7 +155,7 @@ var FieldTextHtmlSimple = widget.extend({
is_false: function() {
return !this.get('value') || this.get('value') === "<p><br/></p>" || !this.get('value').match(/\S/);
},
before_save: function() {
commit_value: function() {
if (this.options['style-inline']) {
transcoder.class_to_style(this.$content);
transcoder.font_to_img(this.$content);
@@ -361,7 +361,7 @@ var FieldTextHtml = widget.extend({
is_false: function() {
return this.get('value') === false || !this.$content.html() || !this.$content.html().match(/\S/);
},
before_save: function () {
commit_value: function () {
if (this.lang !== 'en_US' && this.$body.find('.o_dirty').length) {
this.internal_set_value( this.view.datarecord[this.name] );
this._dirty_flag = false;