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

Reply via email to