changeset 8345380bb435 in sao:default
details: https://hg.tryton.org/sao?cmd=changeset;node=8345380bb435
description:
Use synchronous calls for on_change's and Field.set
Those calls can be triggered by event like focus-out. So to ensure a
correct
order of the flow, we must defer the processing of the result.
issue8482
review273571002
diffstat:
src/model.js | 361 ++++++++++++++++++++++----------------------------
src/screen.js | 10 +-
src/view/calendar.js | 5 +-
src/view/form.js | 24 +-
4 files changed, 176 insertions(+), 224 deletions(-)
diffs (604 lines):
diff -r 2de13120296f -r 8345380bb435 src/model.js
--- a/src/model.js Sat Jul 13 00:20:31 2019 +0200
+++ b/src/model.js Wed Jul 17 22:40:48 2019 +0200
@@ -115,10 +115,9 @@
record._changed.id = true;
});
var root_group = this.root_group;
- this.changed().then(function() {
- root_group.screens.forEach(function(screen) {
- screen.display();
- });
+ this.changed();
+ root_group.screens.forEach(function(screen) {
+ screen.display();
});
}
};
@@ -233,17 +232,9 @@
}));
}
this.parent._changed[this.child_name] = true;
- var changed_prm = this.parent.model.fields[this.child_name]
- .changed(this.parent);
- // One2Many.changed could return undefined
- if (!changed_prm) {
- changed_prm = jQuery.when();
- }
- return changed_prm.then(function() {
- this.parent.validate(null, true).done(function() {
- return this.parent.group.changed();
- }.bind(this));
- }.bind(this));
+ this.parent.model.fields[this.child_name].changed(this.parent);
+ this.parent.validate(null, true, false, true);
+ this.parent.group.changed();
};
array.delete_ = function(records) {
if (jQuery.isEmptyObject(records)) {
@@ -742,7 +733,6 @@
validate = true;
}
var name, value;
- var promises = [];
var rec_named_fields = ['many2one', 'one2one', 'reference'];
var later = {};
var fieldnames = [];
@@ -772,22 +762,18 @@
var related = name + '.';
this._values[related] = values[related] || {};
}
- promises.push(this.model.fields[name].set(this, value));
+ this.model.fields[name].set(this, value);
+ this._loaded[name] = true;
fieldnames.push(name);
}
for (name in later) {
value = later[name];
- promises.push(this.model.fields[name].set(this, value));
+ this.model.fields[name].set(this, value);
+ this._loaded[name] = true;
}
- return jQuery.when.apply(jQuery, promises.filter(Boolean))
- .then(function() {
- for (var i = 0; i < fieldnames.length; i++) {
- this._loaded[fieldnames[i]] = true;
- }
- if (validate) {
- return this.validate(fieldnames, true);
- }
- }.bind(this));
+ if (validate) {
+ this.validate(fieldnames, true, false, false);
+ }
},
get: function() {
var value = {};
@@ -897,24 +883,22 @@
fieldnames.push(fname);
}
return jQuery.when.apply(jQuery, promises).then(function() {
- return this.on_change(fieldnames).then(function() {
- return this.on_change_with(fieldnames).then(function() {
- var callback = function() {
- if (display) {
- return this.group.root_group.screens
- .forEach(function(screen) {
- return screen.display();
- });
- }
- }.bind(this);
- if (validate) {
- return this.validate(null, true)
- .then(callback);
- } else {
- return callback();
- }
- }.bind(this));
- }.bind(this));
+ this.on_change(fieldnames);
+ this.on_change_with(fieldnames);
+ var callback = function() {
+ if (display) {
+ return this.group.root_group.screens
+ .forEach(function(screen) {
+ return screen.display();
+ });
+ }
+ }.bind(this);
+ if (validate) {
+ return this.validate(null, true)
+ .then(callback);
+ } else {
+ return callback();
+ }
}.bind(this));
},
get_timestamp: function() {
@@ -982,23 +966,22 @@
}
}.bind(this));
if (!jQuery.isEmptyObject(values)) {
- var prm;
- if (fieldnames.length == 1) {
- prm = this.model.execute(
- 'on_change_' + fieldnames[0],
- [values], this.get_context())
- .then(this.set_on_change.bind(this));
- } else {
- prm = this.model.execute('on_change',
- [values, fieldnames], this.get_context())
- .then(function(changes) {
- return jQuery.when.apply(jQuery,
- changes.map(this.set_on_change.bind(this)));
- }.bind(this));
+ var changes;
+ try {
+ if (fieldnames.length == 1) {
+ changes = [];
+ changes.push(this.model.execute(
+ 'on_change_' + fieldnames[0],
+ [values], this.get_context(), false));
+ } else {
+ changes = this.model.execute(
+ 'on_change',
+ [values, fieldnames], this.get_context(), false);
+ }
+ } catch (e) {
+ return;
}
- return prm;
- } else {
- return jQuery.when();
+ changes.forEach(this.set_on_change, this);
}
},
on_change_with: function(field_names) {
@@ -1039,48 +1022,43 @@
delete this._values[fieldname + '.'];
}
}
- var prms = [];
- var prm;
- var set_on_change = function(fieldname) {
- return function(result) {
- return this.model.fields[fieldname].set_on_change(
- this, result);
- };
- };
+ var result;
fieldnames = Object.keys(fieldnames);
if (fieldnames) {
- if (fieldnames.length == 1) {
- prm = this.model.execute(
- 'on_change_with_' + fieldnames[0],
- [values], this.get_context());
-
prms.push(prm.then(set_on_change(fieldnames[0]).bind(this)));
- } else {
- prm = this.model.execute(
- 'on_change_with',
- [values, fieldnames], this.get_context());
- prms.push(prm.then(this.set_on_change.bind(this)));
+ try {
+ if (fieldnames.length == 1) {
+ fieldname = fieldnames[0];
+ result = {};
+ result[fieldname] = this.model.execute(
+ 'on_change_with_' + fieldname,
+ [values], this.get_context(), false);
+ } else {
+ result = this.model.execute(
+ 'on_change_with',
+ [values, fieldnames], this.get_context(), false);
+ }
+ } catch (e) {
+ return;
}
+ this.set_on_change(result);
}
for (fieldname in later) {
- if (!later.hasOwnProperty(fieldname)) {
- continue;
- }
on_change_with = this.model.fields[fieldname]
.description.on_change_with;
values = this._get_on_change_args(on_change_with);
- prm = this.model.execute('on_change_with_' + fieldname,
- [values], this.get_context());
- prms.push(prm.then(set_on_change(fieldname).bind(this)));
+ try {
+ result = this.model.execute(
+ 'on_change_with_' + fieldname,
+ [values], this.get_context(), false);
+ } catch (e) {
+ return;
+ }
+ this.model.fields[fieldname].set_on_change(this, result);
}
- return jQuery.when.apply(jQuery, prms);
},
set_on_change: function(values) {
var fieldname, value;
- var promises = [];
for (fieldname in values) {
- if (!values.hasOwnProperty(fieldname)) {
- continue;
- }
value = values[fieldname];
if (!(fieldname in this.model.fields)) {
continue;
@@ -1092,46 +1070,41 @@
var related = fieldname + '.';
this._values[related] = values[related] || {};
}
- promises.push(
- this.model.fields[fieldname].set_on_change(this, value));
+ this.model.fields[fieldname].set_on_change(this, value);
}
- return jQuery.when.apply(jQuery, promises);
},
autocomplete_with: function(fieldname) {
- var promises = [];
for (var fname in this.model.fields) {
var field = this.model.fields[fname];
var autocomplete = field.description.autocomplete || [];
if (!~autocomplete.indexOf(fieldname)) {
continue;
}
- promises.push(this.do_autocomplete(fname));
+ this.do_autocomplete(fname);
}
- return jQuery.when.apply(jQuery, promises);
},
do_autocomplete: function(fieldname) {
this.autocompletion[fieldname] = [];
var field = this.model.fields[fieldname];
var autocomplete = field.description.autocomplete;
var values = this._get_on_change_args(autocomplete);
- var prm = this.model.execute(
- 'autocomplete_' + fieldname, [values], this.get_context());
- return prm.then(function(result) {
- this.autocompletion[fieldname] = result;
- }.bind(this));
+ var result;
+ try {
+ result = this.model.execute(
+ 'autocomplete_' + fieldname, [values], this.get_context(),
+ false);
+ } catch (e) {
+ result = [];
+ }
+ this.autocompletion[fieldname] = result;
},
reset: function(value) {
this.cancel();
- return this.set(value, true).then(function() {
- var promises = [];
- if (this.group.parent) {
- promises.push(this.group.parent.on_change(
- [this.group.child_name]));
- promises.push(this.group.parent.on_change_with(
- [this.group.child_name]));
- }
- return jQuery.when.apply(jQuery, promises);
- }.bind(this));
+ this.set(value, true);
+ if (this.group.parent) {
+ this.group.parent.on_change([this.group.child_name]);
+ this.group.parent.on_change_with([this.group.child_name]);
+ }
},
expr_eval: function(expr) {
if (typeof(expr) != 'string') return expr;
@@ -1396,20 +1369,16 @@
if (JSON.stringify(previous_value) !=
JSON.stringify(this.get(record))) {
record._changed[this.name] = true;
- this.changed(record).done(function() {
- record.validate(null, true).then(function() {
- record.group.changed();
- });
- });
+ this.changed(record);
+ record.validate(null, true, false, true);
+ record.group.changed();
} else if (force_change) {
record._changed[this.name] = true;
- this.changed(record).done(function() {
- record.validate(null, true).then(function() {
- var root_group = record.group.root_group;
- root_group.screens.forEach(function(screen) {
- screen.display();
- });
- });
+ this.changed(record);
+ record.validate(null, true, false, true);
+ var root_group = record.group.root_group;
+ root_group.screens.forEach(function(screen) {
+ screen.display();
});
}
},
@@ -1425,13 +1394,10 @@
record._changed[this.name] = true;
},
changed: function(record) {
- return record.on_change([this.name]).then(function() {
- return record.on_change_with([this.name]).then(function() {
- return record.autocomplete_with(this.name).then(function()
{
- record.set_field_context();
- });
- }.bind(this));
- }.bind(this));
+ record.on_change([this.name]);
+ record.on_change_with([this.name]);
+ record.autocomplete_with(this.name);
+ record.set_field_context();
},
get_timestamp: function(record) {
return {};
@@ -1959,39 +1925,35 @@
'.fields_get',
'params': [Object.keys(field_names), context]
};
- prm = Sao.rpc(args, record.model.session);
- }
- }
- var set_value = function(fields) {
- var promises = [];
- if (!jQuery.isEmptyObject(fields)) {
+ try {
+ fields = Sao.rpc(args, record.model.session, false);
+ } catch (e) {
+ return;
+ }
group.add_fields(fields);
}
- if (mode == 'list ids') {
- for (var i = 0, len = group.length; i < len; i++) {
- var old_record = group[i];
- if (!~value.indexOf(old_record.id)) {
- group.remove(old_record, true);
- }
+ }
+ if (mode == 'list ids') {
+ for (var i = 0, len = group.length; i < len; i++) {
+ var old_record = group[i];
+ if (!~value.indexOf(old_record.id)) {
+ group.remove(old_record, true);
}
- group.load(value, modified);
- } else {
- value.forEach(function(vals) {
- var new_record = group.new_(false);
- if (default_) {
- // Don't validate as parent will validate
- promises.push(new_record.set_default(
- vals, false, false));
- group.add(new_record, -1, false);
- } else {
- promises.push(new_record.set(vals));
- group.push(new_record);
- }
- });
}
- return jQuery.when.apply(jQuery, promises);
- };
- return prm.then(set_value.bind(this));
+ group.load(value, modified);
+ } else {
+ value.forEach(function(vals) {
+ var new_record = group.new_(false);
+ if (default_) {
+ // Don't validate as parent will validate
+ new_record.set_default(vals, false, false);
+ group.add(new_record, -1, false);
+ } else {
+ new_record.set(vals);
+ group.push(new_record);
+ }
+ });
+ }
},
set: function(record, value, _default) {
if (_default === undefined) {
@@ -2009,7 +1971,7 @@
}
record._values[this.name] = undefined;
this._set_default_value(record, model);
- return this._set_value(record, value, _default);
+ this._set_value(record, value, _default);
},
get: function(record) {
var group = record._values[this.name];
@@ -2083,20 +2045,16 @@
this._set_value(record, value, false, modified);
if (modified) {
record._changed[this.name] = true;
- this.changed(record).done(function() {
- record.validate(null, true).then(function() {
- record.group.changed();
- });
- });
+ this.changed(record);
+ record.validate(null, true, false, true);
+ record.group.changed();
} else if (force_change) {
record._changed[this.name] = true;
- this.changed(record).done(function() {
- record.validate(null, true).then(function() {
- var root_group = record.group.root_group;
- root_group.screens.forEach(function(screen) {
- screen.display();
- });
- });
+ this.changed(record);
+ record.validate(null, true, false, true);
+ var root_group = record.group.root_group;
+ root_group.screens.forEach(function(screen) {
+ screen.display();
});
}
},
@@ -2109,15 +2067,15 @@
return this.set(record, value, true);
},
set_on_change: function(record, value) {
+ var fields;
record._changed[this.name] = true;
this._set_default_value(record);
if (value instanceof Array) {
return this._set_value(record, value, false, true);
}
- var prm = jQuery.when();
if (value.add || value.update) {
var context = this.get_context(record);
- var fields = record._values[this.name].model.fields;
+ fields = record._values[this.name].model.fields;
var field_names = {};
var adding_values = [];
if (value.add) {
@@ -2144,7 +2102,13 @@
'.fields_get',
'params': [Object.keys(field_names), context]
};
- prm = Sao.rpc(args, record.model.session);
+ try {
+ fields = Sao.rpc(args, record.model.session, false);
+ } catch (e) {
+ return;
+ }
+ } else {
+ fields = {};
}
}
@@ -2168,33 +2132,28 @@
}.bind(this));
if (value.add || value.update) {
- prm = prm.then(function(fields) {
- var promises = [];
- group.add_fields(fields);
- if (value.add) {
- value.add.forEach(function(vals) {
- var index = vals[0];
- var data = vals[1];
- var new_record = group.new_(false);
- group.add(new_record, index, false);
- promises.push(new_record.set_on_change(data));
- });
- }
- if (value.update) {
- value.update.forEach(function(vals) {
- if (!vals.id) {
- return;
- }
- var record2 = group.get(vals.id);
- if (record2) {
- promises.push(record2.set_on_change(vals));
- }
- });
- }
- return jQuery.when.apply(jQuery, promises);
- }.bind(this));
+ group.add_fields(fields);
+ if (value.add) {
+ value.add.forEach(function(vals) {
+ var index = vals[0];
+ var data = vals[1];
+ var new_record = group.new_(false);
+ group.add(new_record, index, false);
+ new_record.set_on_change(data);
+ });
+ }
+ if (value.update) {
+ value.update.forEach(function(vals) {
+ if (!vals.id) {
+ return;
+ }
+ var record2 = group.get(vals.id);
+ if (record2) {
+ record2.set_on_change(vals);
+ }
+ });
+ }
}
- return prm;
},
_set_default_value: function(record, model) {
if (record._values[this.name] !== undefined) {
diff -r 2de13120296f -r 8345380bb435 src/screen.js
--- a/src/screen.js Sat Jul 13 00:20:31 2019 +0200
+++ b/src/screen.js Wed Jul 17 22:40:48 2019 +0200
@@ -1365,15 +1365,11 @@
return prm.then(function() {
group.add(record, this.new_model_position());
this.current_record = record;
- var prm = jQuery.when();
if (previous_view.view_type == 'calendar') {
- prm = previous_view.set_default_date(
- record, selected_date);
+ previous_view.set_default_date(record, selected_date);
}
- prm.then(function() {
- this.display().done(function() {
- this.set_cursor(true, true);
- }.bind(this));
+ this.display().done(function() {
+ this.set_cursor(true, true);
}.bind(this));
return record;
}.bind(this));
diff -r 2de13120296f -r 8345380bb435 src/view/calendar.js
--- a/src/view/calendar.js Sat Jul 13 00:20:31 2019 +0200
+++ b/src/view/calendar.js Wed Jul 17 22:40:48 2019 +0200
@@ -306,9 +306,8 @@
selected_date = Sao.Date(selected_date);
}
field.set(record, selected_date);
- return record.on_change([dtstart]).then(function() {
- return record.on_change_with([dtstart]);
- });
+ record.on_change([dtstart]);
+ record.on_change_with([dtstart]);
},
get_selected_date: function(){
return this.el.fullCalendar('getDate');
diff -r 2de13120296f -r 8345380bb435 src/view/form.js
--- a/src/view/form.js Sat Jul 13 00:20:31 2019 +0200
+++ b/src/view/form.js Wed Jul 17 22:40:48 2019 +0200
@@ -1301,22 +1301,20 @@
var record = this.record;
if (this.datalist) {
this.datalist.empty();
- var set_autocompletion = function() {
- var selection = [];
- if (record) {
- selection = record.autocompletion[this.field_name] ||
[];
+ var selection;
+ if (record) {
+ if (!(this.field_name in record.autocompletion)) {
+ record.do_autocomplete(this.field_name);
}
- selection.forEach(function(e) {
- jQuery('<option/>', {
- 'value': e
- }).appendTo(this.datalist);
- }.bind(this));
- }.bind(this);
- if (record && !(this.field_name in record.autocompletion)) {
-
record.do_autocomplete(this.field_name).done(set_autocompletion);
+ selection = record.autocompletion[this.field_name] || [];
} else {
- set_autocompletion();
+ selection = [];
}
+ selection.forEach(function(e) {
+ jQuery('<option/>', {
+ 'value': e
+ }).appendTo(this.datalist);
+ }.bind(this));
}
// Set size