From e1f9b0c60031ca9ca6d9f7306838f546d6f31f1d Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 25 Jul 2011 11:10:49 +0200 Subject: [FIX] race condition introduced in nicolas.vanhoren@openerp.com-20110722154419-9g31mwfsuv67rjz3 if search view contains only synchronously-initialized widgets, 'self.ready.resolve()' is called before 'self' is set since 'self' is set *after* the $.when call move 'self'-setting to the top of the function, just in case bzr revid: xmo@openerp.com-20110725091049-q5lt2sgbfawphiuh --- addons/base/static/src/js/search.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'addons/base/static/src') diff --git a/addons/base/static/src/js/search.js b/addons/base/static/src/js/search.js index 026f19db5b1..779cd74c999 100644 --- a/addons/base/static/src/js/search.js +++ b/addons/base/static/src/js/search.js @@ -110,9 +110,10 @@ openerp.base.SearchView = openerp.base.Controller.extend({ } }, on_loaded: function(data) { - var lines = this.make_widgets( - data.fields_view['arch'].children, - data.fields_view.fields); + var self = this, + lines = this.make_widgets( + data.fields_view['arch'].children, + data.fields_view.fields); // for extended search view var ext = new openerp.base.search.ExtendedSearch(this, this.model); @@ -145,7 +146,6 @@ openerp.base.SearchView = openerp.base.Controller.extend({ }); // filters management - var self = this; return this.rpc('/base/searchview/get_filters', { model: this.dataset.model }).then(function(result) { -- cgit v1.2.3 From 2e9f2f138b52d74db2eb368804fc87ab77b08417 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 25 Jul 2011 11:15:06 +0200 Subject: [IMP] update aggregates when deleting a record bzr revid: xmo@openerp.com-20110725091506-h4u4kp3ut8h0a6vc --- addons/base/static/src/js/list.js | 1 + 1 file changed, 1 insertion(+) (limited to 'addons/base/static/src') diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index 1c3b1cfdc4c..8d7290b8c08 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -477,6 +477,7 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi var self = this; return $.when(this.dataset.unlink(ids)).then(function () { self.groups.drop_records(ids); + self.compute_aggregates(); }); }, /** -- cgit v1.2.3 From 6b9ba5d46e0d6ac25b3282d3c81799f313e4c55a Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 25 Jul 2011 11:19:07 +0200 Subject: [IMP] update list aggregates after button action called, in case action updated value in row bzr revid: xmo@openerp.com-20110725091907-j0sucdkv0dq83nsf --- addons/base/static/src/js/list.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'addons/base/static/src') diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index 8d7290b8c08..09be43ec24e 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -506,11 +506,17 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi * @param {Function} callback should be called after the action is executed, if non-null */ do_action: function (name, id, callback) { - var action = _.detect(this.columns, function (field) { + var self = this, + action = _.detect(this.columns, function (field) { return field.name === name; }); if (!action) { return; } - this.execute_action(action, this.dataset, this.session.action_manager, id, callback); + this.execute_action( + action, this.dataset, this.session.action_manager, id, function () { + $.when(callback.apply(this, arguments).then(function () { + self.compute_aggregates(); + })); + }); }, /** * Handles the activation of a record (clicking on it) @@ -669,7 +675,7 @@ openerp.base.ListView.List = openerp.base.Class.extend( /** @lends openerp.base. index = self.row_position($row); $(self).trigger('action', [field, record_id, function () { - self.reload_record(index, true); + return self.reload_record(index, true); }]); }) .delegate('tr', 'click', function (e) { @@ -807,7 +813,7 @@ openerp.base.ListView.List = openerp.base.Class.extend( /** @lends openerp.base. return $.when(read_p).then(function () { self.$current.children().eq(record_index) - .replaceWith(self.render_record(record_index)); }) + .replaceWith(self.render_record(record_index)); }); }, /** * Renders a list record to HTML -- cgit v1.2.3 From 5bc4c09c3a814f28458522c7f7ba79eb88732fac Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Mon, 25 Jul 2011 11:52:32 +0200 Subject: [imp] remember db on login screen bzr revid: nicolas.vanhoren@openerp.com-20110725095232-fzy7rs43y1udha4b --- addons/base/static/src/xml/base.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'addons/base/static/src') diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index 414dd0ed183..faab1eb3d6d 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -62,7 +62,7 @@ - + +

(Any existing filter with the same name will be replaced)

+ +
-- cgit v1.2.3 From 6a22efdef027c4c10937bda52b344efc6aaaca16 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Mon, 25 Jul 2011 14:09:40 +0200 Subject: [fix] wrong storage of session cookie bzr revid: nicolas.vanhoren@openerp.com-20110725120940-f6vfi6wu6xy9js8x --- addons/base/static/src/js/chrome.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'addons/base/static/src') diff --git a/addons/base/static/src/js/chrome.js b/addons/base/static/src/js/chrome.js index 67738d7a348..492e7c62b5d 100644 --- a/addons/base/static/src/js/chrome.js +++ b/addons/base/static/src/js/chrome.js @@ -425,7 +425,7 @@ openerp.base.Session = openerp.base.Controller.extend( /** @lends openerp.base.S for(var i=0; i Date: Mon, 25 Jul 2011 14:10:01 +0200 Subject: [imp] added manage filters link bzr revid: nicolas.vanhoren@openerp.com-20110725121001-95af30c1incqg4kl --- addons/base/static/src/js/search.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'addons/base/static/src') diff --git a/addons/base/static/src/js/search.js b/addons/base/static/src/js/search.js index 36f0aef1b90..b6d9e797ec0 100644 --- a/addons/base/static/src/js/search.js +++ b/addons/base/static/src/js/search.js @@ -211,7 +211,14 @@ openerp.base.SearchView = openerp.base.Controller.extend({ }); } else { // manage_filters select.val("_filters"); - //TODO niv + this.do_action({ + res_model: 'ir.filters', + views: [[false, 'list'], [false, 'form']], + type: 'ir.actions.act_window', + context: {"search_default_user_id": this.session.uid, + "search_default_model_id": this.dataset.model}, + target: "current" + }); } }, /** -- cgit v1.2.3 From a30bef7be660dc2665ae6497c07988252cf9a5d4 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Mon, 25 Jul 2011 14:18:23 +0200 Subject: [fix] made the managed filters auto_search bzr revid: nicolas.vanhoren@openerp.com-20110725121823-gekerf0s3pn78kqo --- addons/base/static/src/js/search.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'addons/base/static/src') diff --git a/addons/base/static/src/js/search.js b/addons/base/static/src/js/search.js index b6d9e797ec0..8a51abe1335 100644 --- a/addons/base/static/src/js/search.js +++ b/addons/base/static/src/js/search.js @@ -217,7 +217,9 @@ openerp.base.SearchView = openerp.base.Controller.extend({ type: 'ir.actions.act_window', context: {"search_default_user_id": this.session.uid, "search_default_model_id": this.dataset.model}, - target: "current" + target: "current", + limit : 80, + auto_search : true }); } }, -- cgit v1.2.3 From e29a5204f761a099d6a4929829c01d88177b8994 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 25 Jul 2011 15:35:53 +0200 Subject: [FIX] NaN values being displayed in list footers (aggregated values) bzr revid: xmo@openerp.com-20110725133553-bs4x2f747vdj1a02 --- addons/base/static/src/js/list.js | 3 +++ 1 file changed, 3 insertions(+) (limited to 'addons/base/static/src') diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index 4b0142ab365..7b12da67697 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -25,6 +25,9 @@ openerp.base.list = { } var record = row_data[column.id]; + + // If NaN value, display as with a `false` (empty cell) + if (isNaN(record.value)) { record.value = false; } switch (record.value) { case false: case Infinity: -- cgit v1.2.3 From f8b552e5b5d3ea96e49e3493479c318c4d715411 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 25 Jul 2011 16:06:56 +0200 Subject: [FIX] session initialization bzr revid: xmo@openerp.com-20110725140656-ow3mr78psuianqyc --- addons/base/static/src/js/chrome.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'addons/base/static/src') diff --git a/addons/base/static/src/js/chrome.js b/addons/base/static/src/js/chrome.js index 492e7c62b5d..34333abf1be 100644 --- a/addons/base/static/src/js/chrome.js +++ b/addons/base/static/src/js/chrome.js @@ -246,7 +246,7 @@ openerp.base.Session = openerp.base.Controller.extend( /** @lends openerp.base.S * @param port */ init: function(parent, element_id, server, port) { - this._super(element_id); + this._super(parent, element_id); this.server = (server == undefined) ? location.hostname : server; this.port = (port == undefined) ? location.port : port; this.rpc_mode = (server == location.hostname) ? "ajax" : "jsonp"; -- cgit v1.2.3 From 9c8a2c33abd0dcd93eb4fff9c40d5104cf68d351 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 25 Jul 2011 16:11:03 +0200 Subject: [FIX] check that a value is a number before checking for isNaN: strings are NaN and so are objects also alias 'record.value', so we don't have to go through the indirection 11 times bzr revid: xmo@openerp.com-20110725141103-2ix5mhec6lk47en6 --- addons/base/static/src/js/list.js | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'addons/base/static/src') diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index 7b12da67697..a2fca3aa89e 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -24,11 +24,13 @@ openerp.base.list = { ].join('') } - var record = row_data[column.id]; + var value = row_data[column.id].value; // If NaN value, display as with a `false` (empty cell) - if (isNaN(record.value)) { record.value = false; } - switch (record.value) { + if (typeof value === 'number' && isNaN(value)) { + value = false; + } + switch (value) { case false: case Infinity: case -Infinity: @@ -36,23 +38,23 @@ openerp.base.list = { } switch (column.widget || column.type) { case 'integer': - return _.sprintf('%d', record.value); + return _.sprintf('%d', value); case 'float': var precision = column.digits ? column.digits[1] : 2; - return _.sprintf('%.' + precision + 'f', record.value); + return _.sprintf('%.' + precision + 'f', value); case 'float_time': return _.sprintf("%02d:%02d", - Math.floor(record.value), - Math.round((record.value % 1) * 60)); + Math.floor(value), + Math.round((value % 1) * 60)); case 'progressbar': return _.sprintf( '%.2f%%', - record.value, record.value); + value, value); case 'many2one': // name_get value format - return record.value[1]; + return value[1]; default: - return record.value; + return value; } } }; -- cgit v1.2.3 From 8784297248e8f0a7cb0bd048bf1757fdf2613ddd Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Mon, 25 Jul 2011 16:28:05 +0200 Subject: [FIX] in do_action(), on_closed() callback not honored for new tabs bzr revid: fme@openerp.com-20110725142805-bsvio3q4tsgkc77b --- addons/base/static/src/js/views.js | 3 +++ 1 file changed, 3 insertions(+) (limited to 'addons/base/static/src') diff --git a/addons/base/static/src/js/views.js b/addons/base/static/src/js/views.js index d01d847843e..1b5452bb5a3 100644 --- a/addons/base/static/src/js/views.js +++ b/addons/base/static/src/js/views.js @@ -61,6 +61,9 @@ openerp.base.ActionManager = openerp.base.Controller.extend({ var url = window.location.protocol + "//" + window.location.host + window.location.pathname + "?" + jQuery.param({ s_action : "" + key }); window.open(url); + if (on_closed) { + on_closed(); + } }); } else { if (this.viewmanager) { -- cgit v1.2.3 From 5070784ba2b04d7ffb8935c9cf01dacfd7f03b26 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 26 Jul 2011 12:01:36 +0200 Subject: [FIX] correctly call on_close callback when clicking on a dialog's close button bzr revid: xmo@openerp.com-20110726100136-1i858bxyipiboz0o --- addons/base/static/src/js/chrome.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'addons/base/static/src') diff --git a/addons/base/static/src/js/chrome.js b/addons/base/static/src/js/chrome.js index 34333abf1be..cc28aea4157 100644 --- a/addons/base/static/src/js/chrome.js +++ b/addons/base/static/src/js/chrome.js @@ -532,6 +532,7 @@ openerp.base.Dialog = openerp.base.BaseWidget.extend({ dialog_title: "", identifier_prefix: 'dialog', init: function (parent, options) { + var self = this; this._super(parent); this.options = { modal: true, @@ -542,7 +543,10 @@ openerp.base.Dialog = openerp.base.BaseWidget.extend({ min_height: 0, max_height: '100%', autoOpen: false, - buttons: {} + buttons: {}, + close: function () { + self.stop(); + } }; for (var f in this) { if (f.substr(0, 10) == 'on_button_') { @@ -605,11 +609,7 @@ openerp.base.Dialog = openerp.base.BaseWidget.extend({ this.set_options(options); this.$dialog.dialog(this.options).dialog('open'); }, - close: function(options) { - this.$dialog.dialog('close'); - }, stop: function () { - this.close(); this.$dialog.dialog('destroy'); } }); -- cgit v1.2.3 From 8184aa0154a451d096f37f81ec0db014f8c3479a Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Tue, 26 Jul 2011 17:37:47 +0200 Subject: [imp] improved o2m, added auto-save bzr revid: nicolas.vanhoren@openerp.com-20110726153747-2zj63korpu6xct6e --- addons/base/static/src/js/data.js | 15 ++++++++++--- addons/base/static/src/js/form.js | 46 ++++++++++++++++++++++++++++++++++----- 2 files changed, 53 insertions(+), 8 deletions(-) (limited to 'addons/base/static/src') diff --git a/addons/base/static/src/js/data.js b/addons/base/static/src/js/data.js index 2e89dacceb8..385bd93d360 100644 --- a/addons/base/static/src/js/data.js +++ b/addons/base/static/src/js/data.js @@ -492,24 +492,33 @@ openerp.base.BufferedDataSet = openerp.base.DataSetStatic.extend({ this.to_create.push(cached); this.cache.push(cached); var to_return = $.Deferred().then(callback); - setTimeout(function() {to_return.resolve({result: cached.id});}, 0); + to_return.resolve({result: cached.id}); return to_return.promise(); }, write: function (id, data, callback) { var self = this; var record = _.detect(this.to_create, function(x) {return x.id === id;}); record = record || _.detect(this.to_write, function(x) {return x.id === id;}); + var dirty = false; if (record) { + for (k in data) { + if (record.values[k] === undefined || record.values[k] !== data[k]) { + dirty = true; + break; + } + } $.extend(record.values, data); } else { + dirty = true; record = {id: id, values: data}; self.to_write.push(record); } var cached = _.detect(this.cache, function(x) {return x.id === id;}); $.extend(cached.values, record.values); - this.on_change(); + if (dirty) + this.on_change(); var to_return = $.Deferred().then(callback); - setTimeout(function () {to_return.resolve({result: true});}, 0); + to_return.resolve({result: true}); return to_return.promise(); }, unlink: function(ids, callback, error_callback) { diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index 25dcca611bd..598cdd12c20 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -301,6 +301,7 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV if (!this.ready) { return false; } + var dirty = false; var invalid = false, values = {}, first_invalid_field = null; @@ -313,6 +314,7 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV first_invalid_field = f; } } else if (f.touched) { + dirty = true; values[f.name] = f.get_value(); } } @@ -320,18 +322,19 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV first_invalid_field.focus(); this.on_invalid(); return false; - } else { + } else if (dirty) { this.log("About to save", values); if (!this.datarecord.id) { - this.dataset.create(values, function(r) { + return this.dataset.create(values, function(r) { self.on_created(r, success, prepend_on_create); }); } else { - this.dataset.write(this.datarecord.id, values, function(r) { + return this.dataset.write(this.datarecord.id, values, function(r) { self.on_saved(r, success); }); } - return true; + } else { + return false; } }, do_save_edit: function() { @@ -1612,6 +1615,9 @@ openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({ controller.on_record_loaded.add_last(function() { once.resolve(); }); + controller.on_form_changed.add_last(function() { + self.save_form_view(); + }); } self.is_started.resolve(); }); @@ -1692,6 +1698,7 @@ openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({ var self = this; if (!this.dataset) return []; + this.save_form_view(); var val = this.dataset.delete_all ? [commands.delete_all()] : []; val = val.concat(_.map(this.dataset.ids, function(id) { var alter_order = _.detect(self.dataset.to_create, function(x) {return x.id === id;}); @@ -1708,9 +1715,38 @@ openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({ this.dataset.to_delete, function(x) { return commands['delete'](x.id);})); }, + save_form_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; + if (this.viewmanager.active_view === "form") { + var res = view.do_save(); + if (res === false) { + // ignore + } else if (res.isRejected()) { + throw "Save or create on one2many dataset is not supposed to fail."; + } else if (!res.isResolved()) { + throw "Asynchronous get_value() is not supported in form view."; + } + } + } + }, validate: function() { this.invalid = false; - // TODO niv + var self = this; + var view = self.viewmanager.views[self.viewmanager.active_view].controller; + if(self.viewmanager.active_view === "list") { + return; + } else if (self.viewmanager.active_view === "form") { + for (var f in view.fields) { + f = view.fields[f]; + if (f.invalid) { + this.invalid = true; + return; + } + } + } } }); -- cgit v1.2.3 From d0234fa5dd424e7722443fda7e41f955d857027a Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Tue, 26 Jul 2011 23:00:05 +0200 Subject: [IMP] new Sidebar controller Now, the views are responsible of the management of their own sidebar. There is one sidebar per view. The viewmanager creates the divs for each sidebar (as it does for each view). The new Sidebar controller allows custom section with their own controller. bzr revid: fme@openerp.com-20110726210005-xyalvw764y2xhvte --- addons/base/static/src/css/base.css | 4 + addons/base/static/src/js/form.js | 102 ++++++++++++++---------- addons/base/static/src/js/list.js | 19 +++-- addons/base/static/src/js/views.js | 149 +++++++++++++++++++++--------------- addons/base/static/src/xml/base.xml | 54 +++++++------ 5 files changed, 192 insertions(+), 136 deletions(-) (limited to 'addons/base/static/src') diff --git a/addons/base/static/src/css/base.css b/addons/base/static/src/css/base.css index dbb7d101f96..bbf8cba0fe7 100644 --- a/addons/base/static/src/css/base.css +++ b/addons/base/static/src/css/base.css @@ -1020,6 +1020,10 @@ background: linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* W3C */ .openerp .closed-sidebar .toggle-sidebar { border-left: none; } +.openerp li.oe_sidebar_print { + padding-left: 20px; + background: 1px 3px url(../img/icons/gtk-print.png) no-repeat; +} .openerp.kitten-mode-activated .main_table { background: url(http://placekitten.com/g/1500/800) repeat; diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index 25dcca611bd..e66a073643c 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -1,7 +1,7 @@ openerp.base.form = function (openerp) { openerp.base.views.add('form', 'openerp.base.FormView'); -openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormView# */{ +openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormView# */{ /** * Indicates that this view is not searchable, and thus that no search * view should be displayed (if there is one active). @@ -19,6 +19,7 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV */ init: function(parent, element_id, dataset, view_id, options) { this._super(parent, element_id); + this.set_default_options(); this.view_manager = parent || new openerp.base.NullViewManager(); this.dataset = dataset; this.model = dataset.model; @@ -53,10 +54,14 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV context.add(this.view_manager.action.context); } return this.rpc("/base/formview/load", {"model": this.model, "view_id": this.view_id, - toolbar:!!this.flags.sidebar, context: context}, this.on_loaded); + toolbar: this.options.sidebar, context: context}, this.on_loaded); } }, stop: function() { + if (this.sidebar) { + this.sidebar.attachments.stop(); + this.sidebar.stop(); + } _.each(this.widgets, function(w) { w.stop(); }); @@ -85,12 +90,16 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV $('' + openerp.base.json_node_to_xml(self.fields_view.arch, true) + '').dialog({ width: '95%', height: 600}); }); - if(this.view_manager.sidebar) - this.view_manager.sidebar.set_toolbar(data.fields_view.toolbar); + if (this.options.sidebar && this.options.sidebar_id) { + this.sidebar = new openerp.base.Sidebar(this, this.options.sidebar_id); + this.sidebar.start(); + this.sidebar.attachments = new openerp.base.form.SidebarAttachments(this.sidebar, this.sidebar.add_section("Attachments"), this); + this.sidebar.add_toolbar(data.fields_view.toolbar); + this.sidebar.do_unfold(); + } this.has_been_loaded.resolve(); }, do_show: function () { - var self = this; var promise; if (this.dataset.index === null) { // null index means we should start a new record @@ -98,13 +107,17 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV } else { promise = this.dataset.read_index(_.keys(this.fields_view.fields), this.on_record_loaded); } - self.$element.show(); - if(this.view_manager.sidebar) - this.view_manager.sidebar.do_refresh(true); + this.$element.show(); + if (this.sidebar) { + this.sidebar.$element.show(); + } return promise; }, do_hide: function () { this.$element.hide(); + if (this.sidebar) { + this.sidebar.$element.hide(); + } }, on_record_loaded: function(record) { if (!record) { @@ -144,7 +157,9 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV this.on_form_changed(); this.show_invalid = this.ready = true; this.do_update_pager(record.id == null); - this.do_update_sidebar(); + if (this.sidebar) { + this.sidebar.attachments.do_update(); + } if (this.default_focus_field) { this.default_focus_field.focus(); } @@ -389,7 +404,9 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV this.dataset.index = 0; } this.do_update_pager(); - this.do_update_sidebar(); + if (this.sidebar) { + this.sidebar.attachments.do_update(); + } this.notification.notify("Record created", "The record has been created with id #" + this.datarecord.id); if (success) { success(_.extend(r, {created: true})); @@ -406,34 +423,55 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV do_cancel: function () { this.notification.notify("Cancelling form"); }, - do_update_sidebar: function() { - if (this.flags.sidebar === false || this.view_manager.sidebar === undefined) { - return; + reload: function() { + if (this.datarecord.id) { + this.dataset.read_index(_.keys(this.fields_view.fields), this.on_record_loaded); + } else { + this.on_button_new(); } - if (!this.datarecord.id) { + }, + get_fields_values: function() { + var values = {}; + _.each(this.fields, function(value, key) { + var val = value.get_value(); + values[key] = val; + }); + return values; + } +}); + +/** @namespace */ +openerp.base.form = {}; + +openerp.base.form.SidebarAttachments = openerp.base.Controller.extend({ + init: function(parent, element_id, form_view) { + this._super(parent, element_id); + this.view = form_view; + }, + do_update: function() { + if (!this.view.datarecord.id) { this.on_attachments_loaded([]); } else { (new openerp.base.DataSetSearch( - this, 'ir.attachment', this.dataset.get_context(), - [['res_model', '=', this.dataset.model], - ['res_id', '=', this.datarecord.id], + this, 'ir.attachment', this.view.dataset.get_context(), + [['res_model', '=', this.view.dataset.model], + ['res_id', '=', this.view.datarecord.id], ['type', 'in', ['binary', 'url']]])).read_slice( ['name', 'url', 'type'], false, false, this.on_attachments_loaded); } }, on_attachments_loaded: function(attachments) { - this.$sidebar = this.view_manager.sidebar.$element.find('.sidebar-attachments'); this.attachments = attachments; - this.$sidebar.html(QWeb.render('FormView.sidebar.attachments', this)); - this.$sidebar.find('.oe-sidebar-attachment-delete').click(this.on_attachment_delete); - this.$sidebar.find('.oe-binary-file').change(this.on_attachment_changed); + this.$element.html(QWeb.render('FormView.sidebar.attachments', this)); + this.$element.find('.oe-binary-file').change(this.on_attachment_changed); + this.$element.find('.oe-sidebar-attachment-delete').click(this.on_attachment_delete); }, on_attachment_changed: function(e) { - window[this.element_id + '_iframe'] = this.do_update_sidebar; + window[this.element_id + '_iframe'] = this.do_update; var $e = $(e.target); if ($e.val() != '') { - this.$sidebar.find('form.oe-binary-form').submit(); + this.$element.find('form.oe-binary-form').submit(); $e.parent().find('input[type=file]').attr('disabled', 'true'); $e.parent().find('button').attr('disabled', 'true').find('img, span').toggle(); } @@ -450,27 +488,9 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV self.notification.notify("Delete an attachment", "The attachment '" + name + "' has been deleted"); }); } - }, - reload: function() { - if (this.datarecord.id) { - this.dataset.read_index(_.keys(this.fields_view.fields), this.on_record_loaded); - } else { - this.on_button_new(); - } - }, - get_fields_values: function() { - var values = {}; - _.each(this.fields, function(value, key) { - var val = value.get_value(); - values[key] = val; - }); - return values; } }); -/** @namespace */ -openerp.base.form = {}; - openerp.base.form.compute_domain = function(expr, fields) { var stack = []; for (var i = expr.length - 1; i >= 0; i--) { diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index a2fca3aa89e..a4e516721ca 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -102,6 +102,7 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi */ init: function(parent, element_id, dataset, view_id, options) { this._super(parent, element_id); + this.set_default_options(); this.view_manager = parent || new openerp.base.NullViewManager(); this.dataset = dataset; this.model = dataset.model; @@ -267,9 +268,11 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi }) .val(self._limit || 'NaN'); }); - if(this.view_manager.sidebar) - this.view_manager.sidebar.set_toolbar(data.fields_view.toolbar); - + if (this.options.sidebar && this.options.sidebar_id) { + this.sidebar = new openerp.base.Sidebar(this, this.options.sidebar_id); + this.sidebar.start(); + this.sidebar.add_toolbar(data.fields_view.toolbar); + } }, /** * Configures the ListView pager based on the provided dataset's information @@ -393,16 +396,20 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi }, do_show: function () { this.$element.show(); + if (this.sidebar) { + this.sidebar.$element.show(); + } if (this.hidden) { this.$element.find('.oe-listview-content').append( this.groups.apoptosis().render()); this.hidden = false; } - if(this.view_manager.sidebar) - this.view_manager.sidebar.do_refresh(true); }, do_hide: function () { this.$element.hide(); + if (this.sidebar) { + this.sidebar.$element.hide(); + } this.hidden = true; }, /** @@ -422,7 +429,7 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi model: this.model, view_id: this.view_id, context: this.dataset.get_context(), - toolbar: !!this.flags.sidebar + toolbar: this.options.sidebar }, callback); } }, diff --git a/addons/base/static/src/js/views.js b/addons/base/static/src/js/views.js index 1b5452bb5a3..b98b0bc637f 100644 --- a/addons/base/static/src/js/views.js +++ b/addons/base/static/src/js/views.js @@ -120,7 +120,6 @@ openerp.base.ViewManager = openerp.base.Controller.extend({ {return x instanceof Array? {view_id: x[0], view_type: x[1]} : x;}); this.views = {}; this.flags = this.flags || {}; - this.sidebar = new openerp.base.NullSidebar(); this.registry = openerp.base.views; }, /** @@ -134,7 +133,12 @@ openerp.base.ViewManager = openerp.base.Controller.extend({ self.on_mode_switch($(this).data('view-type')); }); _.each(this.views_src, function(view) { - self.views[view.view_type] = $.extend({}, view, {controller: null}); + self.views[view.view_type] = $.extend({}, view, { + controller : null, + options : _.extend({ + sidebar_id : self.element_id + '_sidebar_' + view.view_type + }, self.flags) + }); }); if (this.flags.views_switcher === false) { this.$element.find('.oe_vm_switch').hide(); @@ -158,7 +162,7 @@ openerp.base.ViewManager = openerp.base.Controller.extend({ if (!view.controller) { // Lazy loading of views var controllerclass = this.registry.get_object(view_type); - var controller = new controllerclass( this, this.element_id + "_view_" + view_type, + var controller = new controllerclass(this, this.element_id + '_view_' + view_type, this.dataset, view.view_id, view.options); if (view.embedded_view) { controller.set_embedded_view(view.embedded_view); @@ -275,7 +279,6 @@ openerp.base.NullViewManager = openerp.base.generate_null_object_class(openerp.b if(parent) this.session = parent.session; this.action = {flags: {}}; - this.sidebar = new openerp.base.NullSidebar(); } }); @@ -300,19 +303,10 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({ // Not elegant but allows to avoid flickering of SearchView#do_hide this.flags.search_view = this.flags.pager = this.flags.sidebar = this.flags.action_buttons = false; } - if (this.flags.sidebar) { - this.sidebar = new openerp.base.Sidebar(null, this); - } }, start: function() { var inital_view_loaded = this._super(); - // init sidebar - if (this.flags.sidebar) { - this.$element.find('.view-manager-main-sidebar').html(this.sidebar.render()); - this.sidebar.start(); - } - var search_defaults = {}; _.each(this.action.context, function (value, key) { var match = /^search_default_(.*)$/.exec(key); @@ -337,7 +331,6 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({ }, stop: function() { // should be replaced by automatic destruction implemented in BaseWidget - this.sidebar.stop(); this._super(); }, /** @@ -364,62 +357,88 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({ } }); -openerp.base.Sidebar = openerp.base.BaseWidget.extend({ - template: "ViewManager.sidebar", - init: function(parent, view_manager) { - this._super(parent, view_manager.session); - this.view_manager = view_manager; - this.sections = []; - }, - set_toolbar: function(toolbar) { - this.sections = []; - var self = this; - _.each([["print", "Reports"], ["action", "Actions"], ["relate", "Links"]], function(type) { - if (toolbar[type[0]].length == 0) - return; - var section = {elements:toolbar[type[0]], label:type[1]}; - self.sections.push(section); - }); - this.do_refresh(true); +openerp.base.Sidebar = openerp.base.Controller.extend({ + init: function(parent, element_id) { + this._super(parent, element_id); + this.items = {}; }, - do_refresh: function(new_view) { - var view = this.view_manager.active_view; - var the_condition = this.sections.length > 0 && _.detect(this.sections, - function(x) {return x.elements.length > 0;}) != undefined - && (!new_view || view != 'list'); - - this.$element.toggleClass('open-sidebar', the_condition) - .toggleClass('closed-sidebar', !the_condition); - - this.$element.html(QWeb.render("ViewManager.sidebar.internal", { sidebar: this, view: view })); - + start: function() { var self = this; + this._super(this, arguments); + this.$element.html(QWeb.render('Sidebar')); this.$element.find(".toggle-sidebar").click(function(e) { - self.$element.toggleClass('open-sidebar closed-sidebar'); - e.stopPropagation(); - e.preventDefault(); + self.do_toggle(); }); - - this.$element.find("a.oe_sidebar_action_a").click(function(e) { - var $this = jQuery(this); - var index = $this.attr("data-index").split('-'); - var action = self.sections[index[0]].elements[index[1]]; - action.flags = { - new_window : true - }; - self.session.action_manager.do_action(action); - e.stopPropagation(); - e.preventDefault(); + }, + add_toolbar: function(toolbar) { + var self = this; + _.each([['print', "Reports"], ['action', "Actions"], ['relate', "Links"]], function(type) { + var items = toolbar[type[0]]; + if (items.length) { + for (var i = 0; i < items.length; i++) { + items[i] = { + label: items[i]['name'], + action: items[i], + classname: 'oe_sidebar_' + type[0] + } + } + self.add_section(type[1], items); + } }); }, - start: function() { - this._super(); - this.do_refresh(false); + add_section: function(name, items) { + // For each section, we pass a name/label and optionally an array of items. + // If no items are passed, then the section will be created as a custom section + // returning back an element_id to be used by a custom controller. + // Else, the section is a standard section with items displayed as links. + // An item is a dictonary : { + // label: label to be displayed for the link, + // action: action to be launch when the link is clicked, + // callback: a function to be executed when the link is clicked, + // classname: optionnal dom class name for the line, + // } + // Note: The item should have one action or/and a callback + var self = this, + section_id = _.uniqueId(this.element_id + '_section_'); + if (items) { + for (var i = 0; i < items.length; i++) { + items[i].element_id = _.uniqueId(section_id + '_item_'); + this.items[items[i].element_id] = items[i]; + } + } + var $section = $(QWeb.render("Sidebar.section", { + section_id: section_id, + name: name, + items: items + })); + if (items) { + $section.find('a.oe_sidebar_action_a').click(function() { + var item = self.items[$(this).attr('id')]; + if (item.callback) { + item.callback(); + } + if (item.action) { + item.action.flags = item.action.flags || {}; + item.action.flags.new_window = true; + self.do_action(item.action); + } + return false; + }); + } + $section.appendTo(this.$element.find('div.sidebar-actions')); + return section_id; + }, + do_fold: function() { + this.$element.addClass('closed-sidebar').removeClass('open-sidebar'); + }, + do_unfold: function() { + this.$element.addClass('open-sidebar').removeClass('closed-sidebar'); + }, + do_toggle: function() { + this.$element.toggleClass('open-sidebar closed-sidebar'); } }); -openerp.base.NullSidebar = openerp.base.generate_null_object_class(openerp.base.Sidebar); - openerp.base.Export = openerp.base.Dialog.extend({ dialog_title: "Export", template: 'ExportDialog', @@ -440,6 +459,14 @@ openerp.base.Export = openerp.base.Dialog.extend({ }); openerp.base.View = openerp.base.Controller.extend({ + set_default_options: function(options) { + this.options = options || {}; + _.defaults(this.options, { + // All possible views options should be defaulted here + sidebar_id: null, + sidebar: true + }); + }, /** * Fetches and executes the action identified by ``action_data``. * diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index 0f7c3f3d51f..10d1539cde1 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -232,10 +232,32 @@
+ +
+ + + + + +

+
+ +
+
@@ -360,21 +382,20 @@ -

Attachments

- - + + + t-att-onclick="view.datarecord.id ? null : 'alert(\'No record selected ! You can only attach to existing record.\'); return false;'"/>
@@ -384,7 +405,7 @@
  • + + '&field=datas&fieldname=name&t=' + (new Date().getTime())"/> @@ -849,29 +870,6 @@ - - - - - - -
  • -- cgit v1.2.3 From 30bca6090729aec58e7076443cc751e09678d860 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Wed, 27 Jul 2011 10:03:19 +0200 Subject: [REM] Removed reference to view_manager.flags from views. The action flags are merged in View's options constructor argument so we shall not fetch them from view_manager anymore. bzr revid: fme@openerp.com-20110727080319-nztgq4txu2tt6odq --- addons/base/static/src/js/form.js | 1 - addons/base/static/src/js/list.js | 1 - 2 files changed, 2 deletions(-) (limited to 'addons/base/static/src') diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index e66a073643c..6cc208facda 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -32,7 +32,6 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormVi this.ready = false; this.show_invalid = true; this.touched = false; - this.flags = this.view_manager.flags || {}; this.default_focus_field = null; this.default_focus_button = null; this.registry = openerp.base.form.widgets; diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index a4e516721ca..0c595bed22d 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -111,7 +111,6 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi this.columns = []; this.options = _.extend({}, this.defaults, options || {}); - this.flags = this.view_manager.flags || {}; this.set_groups(new openerp.base.ListView.Groups(this)); -- cgit v1.2.3 From 87206f1fd59a65952435ebf4ccd80ced8151d204 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Wed, 27 Jul 2011 10:14:48 +0200 Subject: [FIX] Forgot some flags reference in previous commit bzr revid: fme@openerp.com-20110727081448-fbspxdyx1oefmus4 --- addons/base/static/src/xml/base.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'addons/base/static/src') diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index 10d1539cde1..e34c20dcb8a 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -261,11 +261,11 @@
    - +
    - -
    + + -
    +
    -
    +
    -- cgit v1.2.3 From 9d6085e99e6436a9b5b9edc96050eba46d896436 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Wed, 27 Jul 2011 11:28:01 +0200 Subject: [REM] Removed debug logging in dialog function bzr revid: fme@openerp.com-20110727092801-fg93veg1rcox72z7 --- addons/base/static/src/js/form.js | 1 - 1 file changed, 1 deletion(-) (limited to 'addons/base/static/src') diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index 5c14b953b70..c8d205b9492 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -1289,7 +1289,6 @@ openerp.base.form.dialog = function(content, options) { options.autoOpen = true; var dialog = new openerp.base.Dialog(null, options); dialog.$dialog = $(content).dialog(dialog.options); - console.log(dialog.options) return dialog.$dialog; } -- cgit v1.2.3 From 216ab84e5f27927ff1bf664ac8bdf38bbed57897 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Wed, 27 Jul 2011 12:25:19 +0200 Subject: [FIX] Fixed niv's mood bzr revid: fme@openerp.com-20110727102519-at3qxx4sxc3fqp44 --- addons/base/static/src/js/form.js | 56 ++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 25 deletions(-) (limited to 'addons/base/static/src') diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index c8d205b9492..d5a87a78309 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -31,7 +31,7 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormVi this.datarecord = {}; this.ready = false; this.show_invalid = true; - this.touched = false; + this.dirty = false; this.default_focus_field = null; this.default_focus_button = null; this.registry = openerp.base.form.widgets; @@ -133,22 +133,22 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormVi this.$form_header.find('.oe_form_on_update').show(); this.$form_header.find('button.oe_form_button_new').show(); } - this.touched = false; + this.dirty = false; this.datarecord = record; for (var f in this.fields) { var field = this.fields[f]; - field.touched = false; + field.dirty = false; field.set_value(this.datarecord[f] || false); field.validate(); } if (!record.id) { // New record: Second pass in order to trigger the onchanges - this.touched = true; + this.dirty = true; this.show_invalid = false; for (var f in record) { var field = this.fields[f]; if (field) { - field.touched = true; + field.dirty = true; this.do_onchange(field); } } @@ -267,7 +267,7 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormVi processed.push(field.name); if (field.get_value() != value) { field.set_value(value); - field.touched = true; + field.dirty = true; if (_.indexOf(processed, field.name) < 0) { this.do_onchange(field, processed); } @@ -315,28 +315,28 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormVi if (!this.ready) { return false; } - var dirty = false; - var invalid = false, + var form_dirty = false, + form_invalid = false, values = {}, first_invalid_field = null; for (var f in this.fields) { f = this.fields[f]; - if (f.invalid) { - invalid = true; + if (!f.is_valid()) { + form_invalid = true; f.update_dom(); if (!first_invalid_field) { first_invalid_field = f; } - } else if (f.touched) { - dirty = true; + } else if (f.is_dirty()) { + form_dirty = true; values[f.name] = f.get_value(); } } - if (invalid) { + if (form_invalid) { first_invalid_field.focus(); this.on_invalid(); return false; - } else if (dirty) { + } else if (form_dirty) { this.log("About to save", values); if (!this.datarecord.id) { return this.dataset.create(values, function(r) { @@ -362,7 +362,7 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormVi on_invalid: function() { var msg = "
      "; _.each(this.fields, function(f) { - if (f.invalid) { + if (!f.is_valid()) { msg += "
    • " + f.string + "
    • "; } }); @@ -729,7 +729,7 @@ openerp.base.form.WidgetButton = openerp.base.form.Widget.extend({ }, on_click: function(saved) { var self = this; - if (!this.node.attrs.special && this.view.touched && saved !== true) { + if (!this.node.attrs.special && this.view.dirty && saved !== true) { this.view.do_save(function() { self.on_click(true); }); @@ -809,7 +809,7 @@ openerp.base.form.Field = openerp.base.form.Widget.extend({ this.readonly = this.modifiers['readonly'] === true; this.required = this.modifiers['required'] === true; this.invalid = false; - this.touched = false; + this.dirty = false; }, set_value: function(value) { this.value = value; @@ -822,6 +822,12 @@ openerp.base.form.Field = openerp.base.form.Widget.extend({ get_value: function() { return this.value; }, + is_valid: function() { + return !this.invalid; + }, + is_dirty: function() { + return this.dirty; + }, get_on_change_value: function() { return this.get_value(); }, @@ -830,13 +836,13 @@ openerp.base.form.Field = openerp.base.form.Widget.extend({ this.$element.toggleClass('disabled', this.readonly); this.$element.toggleClass('required', this.required); if (this.view.show_invalid) { - this.$element.toggleClass('invalid', this.invalid); + this.$element.toggleClass('invalid', !this.is_valid()); } }, on_ui_change: function() { - this.touched = this.view.touched = true; + this.dirty = this.view.dirty = true; this.validate(); - if (!this.invalid) { + if (this.is_valid()) { this.set_value_from_ui(); this.view.do_onchange(this); this.view.on_form_changed(); @@ -934,7 +940,7 @@ openerp.base.form.FieldEmail = openerp.base.form.FieldChar.extend({ this.$element.find('button').click(this.on_button_clicked); }, on_button_clicked: function() { - if (!this.value || this.invalid) { + if (!this.value || !this.is_valid()) { this.notification.warn("E-mail error", "Can't send email to invalid e-mail address"); } else { location.href = 'mailto:' + this.value; @@ -975,7 +981,7 @@ openerp.base.form.FieldFloat = openerp.base.form.FieldChar.extend({ if (value === false || value === undefined) { // As in GTK client, floats default to 0 value = 0; - this.touched = true; + this.dirty = true; } var show_value = value.toFixed(2); this.$element.find('input').val(show_value); @@ -995,7 +1001,7 @@ openerp.base.form.FieldInteger = openerp.base.form.FieldFloat.extend({ if (value === false || value === undefined) { // TODO fme: check if GTK client default integers to 0 (like it does with floats) value = 0; - this.touched = true; + this.dirty = true; } var show_value = parseInt(value, 10); this.$element.find('input').val(show_value); @@ -1082,7 +1088,7 @@ openerp.base.form.FieldFloatTime = openerp.base.form.FieldChar.extend({ if (value === false || value === undefined) { // As in GTK client, floats default to 0 value = 0; - this.touched = true; + this.dirty = true; } var show_value = _.sprintf("%02d:%02d", Math.floor(value), Math.round((value % 1) * 60)); this.$element.find('input').val(show_value); @@ -1759,7 +1765,7 @@ openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({ } else if (self.viewmanager.active_view === "form") { for (var f in view.fields) { f = view.fields[f]; - if (f.invalid) { + if (!f.is_valid()) { this.invalid = true; return; } -- cgit v1.2.3