diff --git a/CHANGELOG b/CHANGELOG index e7c66543f3..eb50a48bbf 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Validate dictionary items * Add (i)like support to domain inversion * Improve loading strategy by using views * Add support of width attribute on tree view diff --git a/src/model.js b/src/model.js index 15c6e777cc..3106d877d0 100644 --- a/src/model.js +++ b/src/model.js @@ -2461,6 +2461,11 @@ Sao.field.Dict = Sao.class_(Sao.field.Field, { _default: {}, + init: function(description) { + Sao.field.Dict._super.init.call(this, description); + this.schema_model = new Sao.Model(description.schema_model); + this.keys = {}; + }, set: function(record, value) { if (value) { // Order keys to allow comparison with stringify @@ -2504,6 +2509,75 @@ }, time_format: function(record) { return '%X'; + }, + add_keys: function(keys, record) { + var schema_model = this.description.schema_model; + var context = this.get_context(record); + var domain = this.get_domain(record); + var batchlen = Math.min(10, Sao.config.limit); + + keys = jQuery.extend([], keys); + var get_keys = function(key_ids) { + return this.schema_model.execute('get_keys', + [key_ids], context).then(update_keys); + }.bind(this); + var update_keys = function(values) { + for (var i = 0, len = values.length; i < len; i++) { + var k = values[i]; + this.keys[k.name] = k; + } + }.bind(this); + + var prms = []; + while (keys.length > 0) { + var sub_keys = keys.splice(0, batchlen); + prms.push(this.schema_model.execute('search', + [[['name', 'in', sub_keys], domain], + 0, Sao.config.limit, null], context) + .then(get_keys)); + } + return jQuery.when.apply(jQuery, prms); + }, + add_new_keys: function(ids, record) { + var context = this.get_context(record); + return this.schema_model.execute('get_keys', [ids], context) + .then(function(new_fields) { + var names = []; + new_fields.forEach(function(new_field) { + this.keys[new_field.name] = new_field; + names.push(new_field.name); + }.bind(this)); + return names; + }.bind(this)); + }, + validate: function(record, softvalidation, pre_validate) { + var valid = Sao.field.Dict._super.validate.call( + this, record, softvalidation, pre_validate); + + if (this.description.readonly) { + return valid; + } + + var decoder = new Sao.PYSON.Decoder(); + var field_value = this.get_eval(record); + var domain = []; + for (var key in field_value) { + if (!(key in this.keys)) { + continue; + } + var key_domain = this.keys[key].domain; + if (key_domain) { + domain.push(decoder.decode(key_domain)); + } + } + + var inversion = new Sao.common.DomainInversion(); + var valid_value = inversion.eval_domain(domain, field_value); + if (!valid_value) { + this.get_state_attrs(record).invalid = 'domain'; + } + + return valid && valid_value; } }); }()); diff --git a/src/view/form.js b/src/view/form.js index 45e0eaeb99..f6b493a0fd 100644 --- a/src/view/form.js +++ b/src/view/form.js @@ -1052,17 +1052,19 @@ function eval_pyson(value){ } else { this.el.removeClass('readonly'); } + var required_el = this._required_el(); this.set_required(required); if (!readonly && required) { - this.el.addClass('required'); + required_el.addClass('required'); } else { - this.el.removeClass('required'); + required_el.removeClass('required'); } var invalid = state_attrs.invalid; + var invalid_el = this._invalid_el(); if (!readonly && invalid) { - this.el.addClass('has-error'); + invalid_el.addClass('has-error'); } else { - this.el.removeClass('has-error'); + invalid_el.removeClass('has-error'); } if (invisible === undefined) { invisible = field.get_state_attrs(record).invisible; @@ -1072,6 +1074,12 @@ function eval_pyson(value){ } this.set_invisible(invisible); }, + _required_el: function () { + return this.el; + }, + _invalid_el: function() { + return this.el; + }, record: function() { if (this.view && this.view.screen) { return this.view.screen.current_record; @@ -3980,8 +3988,7 @@ function eval_pyson(value){ Sao.View.Form.Dict._super.init.call( this, field_name, model, attributes); - this.schema_model = new Sao.Model(attributes.schema_model); - this.keys = {}; + this.schema_model = attributes.schema_model; this.fields = {}; this.rows = {}; @@ -4038,6 +4045,12 @@ function eval_pyson(value){ this._readonly = false; this._record_id = null; }, + _required_el: function() { + return this.wid_text; + }, + _invalid_el: function() { + return this.wid_text; + }, add: function() { var context = this.field().get_context(this.record()); var value = this.wid_text.val(); @@ -4054,7 +4067,7 @@ function eval_pyson(value){ }.bind(this); var parser = new Sao.common.DomainParser(); - var win = new Sao.Window.Search(this.schema_model.name, + var win = new Sao.Window.Search(this.schema_model, callback, { sel_multi: true, context: context, @@ -4065,19 +4078,17 @@ function eval_pyson(value){ }); }, add_new_keys: function(ids) { - var context = this.field().get_context(this.record()); - this.schema_model.execute('get_keys', [ids], context) - .then(function(new_fields) { + var field = this.field(); + field.add_new_keys(ids, this.record()) + .then(function(new_names) { var focus = false; - new_fields.forEach(function(new_field) { - if (this.fields[new_field.name]) { - return; - } - this.keys[new_field.name] = new_field; - this.add_line(new_field.name); - if (!focus) { - this.fields[new_field.name].input.focus(); - focus = true; + new_names.forEach(function(name) { + if (!(name in this.fields)) { + this.add_line(name); + if (!focus) { + this.fields[name].input.focus(); + focus = true; + } } }.bind(this)); }.bind(this)); @@ -4130,13 +4141,14 @@ function eval_pyson(value){ }, add_line: function(key) { var field, row; - this.fields[key] = field = new (this.get_entries( - this.keys[key].type_))(key, this); + var key_schema = this.field().keys[key]; + this.fields[key] = field = new ( + this.get_entries(key_schema.type_))(key, this); this.rows[key] = row = jQuery('
', { 'class': 'row' }); // TODO RTL - var text = this.keys[key].string + Sao.i18n.gettext(':'); + var text = key_schema.string + Sao.i18n.gettext(':'); var label = jQuery('