diff options
| author | Raphael Collet <rco@openerp.com> | 2014-07-06 16:44:26 +0200 |
|---|---|---|
| committer | Antony Lesuisse <al@openerp.com> | 2014-07-06 17:05:41 +0200 |
| commit | cbe2dbb672a6c55d86f2e515f9d1cdfee426ef80 (patch) | |
| tree | d6ff62b719fce32392397783c961b734b1e4c50e /addons/web/static/src/js | |
| parent | d78192c489d3be66cd6487b39f5ce7ba4733a187 (diff) | |
[MERGE] new v8 api by rco
A squashed merge is required as the conversion of the apiculture branch from
bzr to git was not correctly done. The git history contains irrelevant blobs
and commits. This branch brings a lot of changes and fixes, too many to list
exhaustively.
- New orm api, objects are now used instead of ids
- Environements to encapsulates cr uid context while maintaining backward compatibility
- Field compute attribute is a new object oriented way to define function fields
- Shared browse record cache
- New onchange protocol
- Optional copy flag on fields
- Documentation update
- Dead code cleanup
- Lots of fixes
Diffstat (limited to 'addons/web/static/src/js')
| -rw-r--r-- | addons/web/static/src/js/chrome.js | 5 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_form.js | 308 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_list_editable.js | 2 | ||||
| -rw-r--r-- | addons/web/static/src/js/views.js | 6 |
4 files changed, 178 insertions, 143 deletions
diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index 39c7395556e..f5f8129d502 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -958,6 +958,8 @@ instance.web.Menu = instance.web.Widget.extend({ id: id, previous_menu_id: this.current_menu // Here we don't know if action will fail (in which case we have to revert menu) }, $item); + } else { + console.log('Menu no action found web test 04 will fail'); } this.open_menu(id); }, @@ -1378,8 +1380,7 @@ instance.web.WebClient = instance.web.Client.extend({ var first_menu_id = self.menu.$el.find("a:first").data("menu"); if(first_menu_id) { self.menu.menu_click(first_menu_id); - } - } + } } }); }); } else { diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 7372e8a3783..e3b8e3ead0d 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -102,6 +102,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM this.fields = {}; this.fields_order = []; this.datarecord = {}; + this._onchange_specs = {}; this.default_focus_field = null; this.default_focus_button = null; this.fields_registry = instance.web.form.widgets; @@ -117,7 +118,6 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM }); this.is_initialized = $.Deferred(); this.mutating_mutex = new $.Mutex(); - this.on_change_list = []; this.save_list = []; this.reload_mutex = new $.Mutex(); this.__clicked_inside = false; @@ -125,6 +125,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM this.rendering_engine = new instance.web.form.FormRenderingEngine(this); self.set({actual_mode: self.options.initial_mode}); this.has_been_loaded.done(function() { + self._build_onchange_specs(); self.on("change:actual_mode", self, self.check_actual_mode); self.check_actual_mode(); self.on("change:actual_mode", self, self.init_pager); @@ -335,15 +336,8 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM }); return $.when.apply(null, set_values).then(function() { if (!record.id) { - // New record: Second pass in order to trigger the onchanges - // respecting the fields order defined in the view - _.each(self.fields_order, function(field_name) { - if (record[field_name] !== undefined) { - var field = self.fields[field_name]; - field._dirty_flag = true; - self.do_onchange(field); - } - }); + // trigger onchanges + self.do_onchange(null); } self.on_form_changed(); self.rendering_engine.init_fields(); @@ -438,101 +432,83 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM $(".oe_form_pager_state", this.$pager).html(_.str.sprintf(_t("%d / %d"), this.dataset.index + 1, this.dataset.ids.length)); } }, - parse_on_change: function (on_change, widget) { - var self = this; - var onchange = _.str.trim(on_change); - var call = onchange.match(/^\s?(.*?)\((.*?)\)\s?$/); - if (!call) { - throw new Error(_.str.sprintf( _t("Wrong on change format: %s"), onchange )); - } - - var method = call[1]; - if (!_.str.trim(call[2])) { - return {method: method, args: []}; - } - - var argument_replacement = { - 'False': function () {return false;}, - 'True': function () {return true;}, - 'None': function () {return null;}, - 'context': function () { - return new instance.web.CompoundContext( - self.dataset.get_context(), - widget.build_context() ? widget.build_context() : {}); - } - }; - var parent_fields = null; - var args = _.map(call[2].split(','), function (a, i) { - var field = _.str.trim(a); - // literal constant or context - if (field in argument_replacement) { - return argument_replacement[field](); - } - // literal number - if (/^-?\d+(\.\d+)?$/.test(field)) { - return Number(field); - } - // form field - if (self.fields[field]) { - var value_ = self.fields[field].get_value(); - return value_ === null || value_ === undefined ? false : value_; - } - // parent field - var splitted = field.split('.'); - if (splitted.length > 1 && _.str.trim(splitted[0]) === "parent" && self.dataset.parent_view) { - if (parent_fields === null) { - parent_fields = self.dataset.parent_view.get_fields_values(); + _build_onchange_specs: function() { + var self = this; + var find = function(field_name, root) { + var fields = [root]; + while (fields.length) { + var node = fields.pop(); + if (!node) { + continue; } - var p_val = parent_fields[_.str.trim(splitted[1])]; - if (p_val !== undefined) { - return p_val === null || p_val === undefined ? false : p_val; + if (node.tag === 'field' && node.attrs.name === field_name) { + return node.attrs.on_change || ""; } + fields = _.union(fields, node.children); } - // string literal - var first_char = field[0], last_char = field[field.length-1]; - if ((first_char === '"' && last_char === '"') - || (first_char === "'" && last_char === "'")) { - return field.slice(1, -1); - } + return ""; + }; - throw new Error("Could not get field with name '" + field + - "' for onchange '" + onchange + "'"); + self._onchange_specs = {}; + _.each(this.fields, function(field, name) { + self._onchange_specs[name] = find(name, field.node); + _.each(field.field.views, function(view) { + _.each(view.fields, function(_, subname) { + self._onchange_specs[name + '.' + subname] = find(subname, view.arch); + }); + }); }); - - return { - method: method, - args: args - }; }, - do_onchange: function(widget, processed) { - var self = this; - this.on_change_list = [{widget: widget, processed: processed}].concat(this.on_change_list); - return this._process_operations(); + _get_onchange_values: function() { + var field_values = this.get_fields_values(); + if (field_values.id.toString().match(instance.web.BufferedDataSet.virtual_id_regex)) { + delete field_values.id; + } + if (this.dataset.parent_view) { + // this belongs to a parent view: add parent field if possible + var parent_view = this.dataset.parent_view; + var child_name = this.dataset.child_name; + var parent_name = parent_view.get_field_desc(child_name).relation_field; + if (parent_name) { + // consider all fields except the inverse of the parent field + var parent_values = parent_view.get_fields_values(); + delete parent_values[child_name]; + field_values[parent_name] = parent_values; + } + } + return field_values; }, - _process_onchange: function(on_change_obj) { + + do_onchange: function(widget) { var self = this; - var widget = on_change_obj.widget; - var processed = on_change_obj.processed; + var onchange_specs = self._onchange_specs; try { - var def; - processed = processed || []; - processed.push(widget.name); - var on_change = widget.node.attrs.on_change; - if (on_change) { - var change_spec = self.parse_on_change(on_change, widget); - var ids = []; + var def = $.when({}); + var change_spec = widget ? onchange_specs[widget.name] : null; + if (!widget || (!_.isEmpty(change_spec) && change_spec !== "0")) { + var ids = [], + trigger_field_name = widget ? widget.name : false, + values = self._get_onchange_values(), + context = new instance.web.CompoundContext(self.dataset.get_context()); + + if (widget && widget.build_context()) { + context.add(widget.build_context()); + } + if (self.dataset.parent_view) { + var parent_name = self.dataset.parent_view.get_field_desc(self.dataset.child_name).relation_field; + context.add({field_parent: parent_name}); + } + if (self.datarecord.id && !instance.web.BufferedDataSet.virtual_id_regex.test(self.datarecord.id)) { // In case of a o2m virtual id, we should pass an empty ids list ids.push(self.datarecord.id); } def = self.alive(new instance.web.Model(self.dataset.model).call( - change_spec.method, [ids].concat(change_spec.args))); - } else { - def = $.when({}); + "onchange", [ids, values, trigger_field_name, onchange_specs, context])); } return def.then(function(response) { - if (widget.field['change_default']) { + if (widget && widget.field['change_default']) { var fieldname = widget.name; var value_; if (response.value && (fieldname in response.value)) { @@ -565,7 +541,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM } return response; }).then(function(response) { - return self.on_processed_onchange(response, processed); + return self.on_processed_onchange(response); }); } catch(e) { console.error(e); @@ -573,7 +549,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM return $.Deferred().reject(); } }, - on_processed_onchange: function(result, processed) { + on_processed_onchange: function(result) { try { var fields = this.fields; _(result.domain).each(function (domain, fieldname) { @@ -581,10 +557,11 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM if (!field) { return; } field.node.attrs.domain = domain; }); - - if (result.value) { - this._internal_set_values(result.value, processed); + + if (!_.isEmpty(result.value)) { + this._internal_set_values(result.value); } + // FIXME XXX a list of warnings? if (!_.isEmpty(result.warning)) { new instance.web.Dialog(this, { size: 'medium', @@ -606,21 +583,12 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM var self = this; return this.mutating_mutex.exec(function() { function iterate() { - var on_change_obj = self.on_change_list.shift(); - if (on_change_obj) { - return self._process_onchange(on_change_obj).then(function() { - return iterate(); - }); - } var defs = []; _.each(self.fields, function(field) { defs.push(field.commit_value()); }); var args = _.toArray(arguments); return $.when.apply($, defs).then(function() { - if (self.on_change_list.length !== 0) { - return iterate(); - } var save_obj = self.save_list.pop(); if (save_obj) { return self._process_save(save_obj).then(function() { @@ -639,8 +607,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM return iterate(); }); }, - _internal_set_values: function(values, exclude) { - exclude = exclude || []; + _internal_set_values: function(values) { for (var f in values) { if (!values.hasOwnProperty(f)) { continue; } var field = this.fields[f]; @@ -652,9 +619,6 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM field.set_value(value_); field._inhibit_on_change_flag = false; field._dirty_flag = true; - if (!_.contains(exclude, field.name)) { - this.do_onchange(field, exclude); - } } } } @@ -3328,11 +3292,14 @@ instance.web.form.CompletionFieldMixin = { var self = this; var dataset = new instance.web.DataSet(this, this.field.relation, self.build_context()); - var blacklist = this.get_search_blacklist(); this.last_query = search_val; + var exclusion_domain = [], ids_blacklist = this.get_search_blacklist(); + if (!_(ids_blacklist).isEmpty()) { + exclusion_domain.push(['id', 'not in', ids_blacklist]); + } return this.orderer.add(dataset.name_search( - search_val, new instance.web.CompoundDomain(self.build_domain(), [["id", "not in", blacklist]]), + search_val, new instance.web.CompoundDomain(self.build_domain(), exclusion_domain), 'ilike', this.limit + 1, self.build_context())).then(function(data) { self.last_search = data; // possible selections for the m2o @@ -4151,28 +4118,41 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({ reload_current_view: function() { var self = this; self.is_loaded = self.is_loaded.then(function() { - var active_view = self.viewmanager.active_view; - var view = self.viewmanager.views[active_view].controller; - if(active_view === "list") { - return view.reload_content(); - } else if (active_view === "form") { + var view = self.get_active_view(); + if (view.type === "list") { + return view.controller.reload_content(); + } else if (view.type === "form") { if (self.dataset.index === null && self.dataset.ids.length >= 1) { self.dataset.index = 0; } var act = function() { - return view.do_show(); + return view.controller.do_show(); }; self.form_last_update = self.form_last_update.then(act, act); return self.form_last_update; - } else if (view.do_search) { - return view.do_search(self.build_domain(), self.dataset.get_context(), []); + } else if (view.controller.do_search) { + return view.controller.do_search(self.build_domain(), self.dataset.get_context(), []); } }, undefined); return self.is_loaded; }, + get_active_view: function () { + /** + * Returns the current active view if any. + */ + if (this.viewmanager && this.viewmanager.views && this.viewmanager.active_view && + this.viewmanager.views[this.viewmanager.active_view] && + this.viewmanager.views[this.viewmanager.active_view].controller) { + return { + type: this.viewmanager.active_view, + controller: this.viewmanager.views[this.viewmanager.active_view].controller + }; + } + }, set_value: function(value_) { value_ = value_ || []; var self = this; + var view = this.get_active_view(); this.dataset.reset_ids([]); var ids; if(value_.length >= 1 && value_[0] instanceof Array) { @@ -4257,33 +4237,32 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({ return this.save_any_view(); }, save_any_view: function() { - if (this.viewmanager && this.viewmanager.views && this.viewmanager.active_view && - this.viewmanager.views[this.viewmanager.active_view] && - this.viewmanager.views[this.viewmanager.active_view].controller) { - var view = this.viewmanager.views[this.viewmanager.active_view].controller; + var view = this.get_active_view(); + if (view) { if (this.viewmanager.active_view === "form") { - if (view.is_initialized.state() !== 'resolved') { + if (view.controller.is_initialized.state() !== 'resolved') { return $.when(false); } - return $.when(view.save()); + return $.when(view.controller.save()); } else if (this.viewmanager.active_view === "list") { - return $.when(view.ensure_saved()); + return $.when(view.controller.ensure_saved()); } } return $.when(false); }, is_syntax_valid: function() { - if (! this.viewmanager || ! this.viewmanager.views[this.viewmanager.active_view]) + var view = this.get_active_view(); + if (!view){ return true; - var view = this.viewmanager.views[this.viewmanager.active_view].controller; + } switch (this.viewmanager.active_view) { case 'form': - return _(view.fields).chain() + return _(view.controller.fields).chain() .invoke('is_valid') .all(_.identity) .value(); case 'list': - return view.is_valid(); + return view.controller.is_valid(); } return true; }, @@ -4673,10 +4652,21 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(in } }); }, + // WARNING: duplicated in 4 other M2M widgets set_value: function(value_) { value_ = value_ || []; if (value_.length >= 1 && value_[0] instanceof Array) { - value_ = value_[0][2]; + // value_ is a list of m2m commands. We only process + // LINK_TO and REPLACE_WITH in this context + var val = []; + _.each(value_, function (command) { + if (command[0] === commands.LINK_TO) { + val.push(command[1]); // (4, id[, _]) + } else if (command[0] === commands.REPLACE_WITH) { + val = command[2]; // (6, _, ids) + } + }); + value_ = val; } this._super(value_); }, @@ -4807,10 +4797,21 @@ instance.web.form.FieldMany2Many = instance.web.form.AbstractField.extend(instan this.list_view.destroy(); this.list_view = undefined; }, + // WARNING: duplicated in 4 other M2M widgets set_value: function(value_) { value_ = value_ || []; if (value_.length >= 1 && value_[0] instanceof Array) { - value_ = value_[0][2]; + // value_ is a list of m2m commands. We only process + // LINK_TO and REPLACE_WITH in this context + var val = []; + _.each(value_, function (command) { + if (command[0] === commands.LINK_TO) { + val.push(command[1]); // (4, id[, _]) + } else if (command[0] === commands.REPLACE_WITH) { + val = command[2]; // (6, _, ids) + } + }); + value_ = val; } this._super(value_); }, @@ -4937,10 +4938,21 @@ instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend( }); }); }, + // WARNING: duplicated in 4 other M2M widgets set_value: function(value_) { value_ = value_ || []; if (value_.length >= 1 && value_[0] instanceof Array) { - value_ = value_[0][2]; + // value_ is a list of m2m commands. We only process + // LINK_TO and REPLACE_WITH in this context + var val = []; + _.each(value_, function (command) { + if (command[0] === commands.LINK_TO) { + val.push(command[1]); // (4, id[, _]) + } else if (command[0] === commands.REPLACE_WITH) { + val = command[2]; // (6, _, ids) + } + }); + value_ = val; } this._super(value_); }, @@ -5719,10 +5731,21 @@ instance.web.form.FieldMany2ManyBinaryMultiFiles = instance.web.form.AbstractFie this._super(this); this.$el.on('change', 'input.oe_form_binary_file', this.on_file_change ); }, + // WARNING: duplicated in 4 other M2M widgets set_value: function(value_) { value_ = value_ || []; if (value_.length >= 1 && value_[0] instanceof Array) { - value_ = value_[0][2]; + // value_ is a list of m2m commands. We only process + // LINK_TO and REPLACE_WITH in this context + var val = []; + _.each(value_, function (command) { + if (command[0] === commands.LINK_TO) { + val.push(command[1]); // (4, id[, _]) + } else if (command[0] === commands.REPLACE_WITH) { + val = command[2]; // (6, _, ids) + } + }); + value_ = val; } this._super(value_); }, @@ -6083,13 +6106,24 @@ instance.web.form.FieldMany2ManyCheckBoxes = instance.web.form.AbstractField.ext if (! _.isEqual(new_value, this.get("value"))) this.internal_set_value(new_value); }, - set_value: function(value) { - value = value || []; - if (value.length >= 1 && value[0] instanceof Array) { - value = value[0][2]; + // WARNING: (mostly) duplicated in 4 other M2M widgets + set_value: function(value_) { + value_ = value_ || []; + if (value_.length >= 1 && value_[0] instanceof Array) { + // value_ is a list of m2m commands. We only process + // LINK_TO and REPLACE_WITH in this context + var val = []; + _.each(value_, function (command) { + if (command[0] === commands.LINK_TO) { + val.push(command[1]); // (4, id[, _]) + } else if (command[0] === commands.REPLACE_WITH) { + val = command[2]; // (6, _, ids) + } + }); + value_ = val; } var formatted = {}; - _.each(value, function(el) { + _.each(value_, function(el) { formatted[JSON.stringify(el)] = true; }); this._super(formatted); diff --git a/addons/web/static/src/js/view_list_editable.js b/addons/web/static/src/js/view_list_editable.js index 144de8eb21c..a83e9042199 100644 --- a/addons/web/static/src/js/view_list_editable.js +++ b/addons/web/static/src/js/view_list_editable.js @@ -783,7 +783,7 @@ this.record = null; this.form.do_hide(); return $.when(record); - } + }, }); instance.web.ListView.Groups.include(/** @lends instance.web.ListView.Groups# */{ diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index 1c563d1d0b3..8a6c8def9ca 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -954,12 +954,12 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({ url: '/web/tests?mod=*' }); break; - case 'perm_read': + case 'get_metadata': var ids = current_view.get_selected_ids(); if (ids.length === 1) { - this.dataset.call('perm_read', [ids]).done(function(result) { + this.dataset.call('get_metadata', [ids]).done(function(result) { var dialog = new instance.web.Dialog(this, { - title: _.str.sprintf(_t("View Log (%s)"), self.dataset.model), + title: _.str.sprintf(_t("Metadata (%s)"), self.dataset.model), size: 'medium', }, QWeb.render('ViewManagerDebugViewLog', { perm : result[0], |
