From 3666ed98289408b1d2a4f914dbc7ef395ff27b19 Mon Sep 17 00:00:00 2001 From: Holger Brunn Date: Wed, 13 Jun 2012 11:02:22 +0200 Subject: [PATCH 001/116] [FIX] (safe_eval) opcode STORE_MAP belongs into _CONST_OPCODES otherwise, const_eval("{'hello':'world'}") won't work bzr revid: hbrunn@therp.nl-20120613090222-gt33zwz1aymcmxqo --- openerp/tools/safe_eval.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openerp/tools/safe_eval.py b/openerp/tools/safe_eval.py index 601fd95200a..1c3870004a7 100644 --- a/openerp/tools/safe_eval.py +++ b/openerp/tools/safe_eval.py @@ -46,7 +46,7 @@ _ALLOWED_MODULES = ['_strptime', 'time'] _CONST_OPCODES = set(opmap[x] for x in [ 'POP_TOP', 'ROT_TWO', 'ROT_THREE', 'ROT_FOUR', 'DUP_TOP', 'DUP_TOPX', 'POP_BLOCK','SETUP_LOOP', 'BUILD_LIST', 'BUILD_MAP', 'BUILD_TUPLE', - 'LOAD_CONST', 'RETURN_VALUE', 'STORE_SUBSCR'] if x in opmap) + 'LOAD_CONST', 'RETURN_VALUE', 'STORE_SUBSCR', 'STORE_MAP'] if x in opmap) _EXPR_OPCODES = _CONST_OPCODES.union(set(opmap[x] for x in [ 'UNARY_POSITIVE', 'UNARY_NEGATIVE', 'UNARY_NOT', @@ -61,7 +61,7 @@ _EXPR_OPCODES = _CONST_OPCODES.union(set(opmap[x] for x in [ ] if x in opmap)) _SAFE_OPCODES = _EXPR_OPCODES.union(set(opmap[x] for x in [ - 'STORE_MAP', 'LOAD_NAME', 'CALL_FUNCTION', 'COMPARE_OP', 'LOAD_ATTR', + 'LOAD_NAME', 'CALL_FUNCTION', 'COMPARE_OP', 'LOAD_ATTR', 'STORE_NAME', 'GET_ITER', 'FOR_ITER', 'LIST_APPEND', 'DELETE_NAME', 'JUMP_FORWARD', 'JUMP_IF_TRUE', 'JUMP_IF_FALSE', 'JUMP_ABSOLUTE', 'MAKE_FUNCTION', 'SLICE+0', 'SLICE+1', 'SLICE+2', 'SLICE+3', From ddb869f1804da7ad549dc9565653c861ab77ba0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20van=20der=20Essen?= Date: Fri, 5 Oct 2012 16:06:16 +0200 Subject: [PATCH 002/116] [FIX] fixing css errors as reported by firefox bzr revid: fva@openerp.com-20121005140616-w5tulvk6v6hesjmn --- addons/point_of_sale/static/src/css/pos.css | 2 +- addons/process/static/src/css/process.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/point_of_sale/static/src/css/pos.css b/addons/point_of_sale/static/src/css/pos.css index cbb625c02d7..81c6a1e1a6e 100644 --- a/addons/point_of_sale/static/src/css/pos.css +++ b/addons/point_of_sale/static/src/css/pos.css @@ -897,7 +897,7 @@ width: 100%; height: 100%; margin: 0; - margin-right: 18px + margin-right: 18px; font-family: "Inconsolata"; color: #6c6c6c; text-shadow: 0px 3px 3px rgba(0,0,0, 0.2); diff --git a/addons/process/static/src/css/process.css b/addons/process/static/src/css/process.css index 7442db9bc4a..5f438622653 100644 --- a/addons/process/static/src/css/process.css +++ b/addons/process/static/src/css/process.css @@ -44,7 +44,7 @@ a.cta-a strong { background-color:#FFF; } .process_canvas svg{ - height:500px;!important; + height:500px; padding:15px; } .oe_process { From f44f548f066e98d62b05ec762e46997d85a7a932 Mon Sep 17 00:00:00 2001 From: Vishmita Date: Tue, 9 Oct 2012 12:49:54 +0530 Subject: [PATCH 003/116] [IMP]replace callenabled for on_write bzr revid: vja@tinyerp.com-20121009071954-jojvmfs7cjuc0elg --- addons/web_diagram/static/src/js/diagram.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/web_diagram/static/src/js/diagram.js b/addons/web_diagram/static/src/js/diagram.js index 508aeb30563..35ce3277116 100644 --- a/addons/web_diagram/static/src/js/diagram.js +++ b/addons/web_diagram/static/src/js/diagram.js @@ -240,9 +240,9 @@ instance.web.DiagramView = instance.web.View.extend({ } ); - pop.on_write.add(function() { + pop.on('on_write_complete',self,function() { self.dataset.read_index(_.keys(self.fields_view.fields)).pipe(self.on_diagram_loaded); - }); + }); var form_fields = [self.parent_field]; var form_controller = pop.view_form; @@ -303,7 +303,7 @@ instance.web.DiagramView = instance.web.View.extend({ title: _t("Open: ") + title } ); - pop.on_write.add(function() { + pop.on('on_write_complete',self,function() { self.dataset.read_index(_.keys(self.fields_view.fields)).pipe(self.on_diagram_loaded); }); }, From 6454fd15904d430ea5c0038829f15b158f958b30 Mon Sep 17 00:00:00 2001 From: ggh-openerp Date: Wed, 10 Oct 2012 18:53:49 +0530 Subject: [PATCH 004/116] [IMP] Remove add_last in on_search method bzr revid: ggh@tinyerp.com-20121010132349-n3gdg0jhtyjfufma --- addons/web/static/src/js/search.js | 4 +--- addons/web/static/src/js/view_form.js | 2 +- addons/web/static/src/js/views.js | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js index a5e1aaeb3ae..b403dab95db 100644 --- a/addons/web/static/src/js/search.js +++ b/addons/web/static/src/js/search.js @@ -783,7 +783,7 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea this.on_invalid(search.errors); return; } - return this.on_search(search.domains, search.contexts, search.groupbys); + return this.trigger('data_search', search.domains, search.contexts, search.groupbys); }, /** * Triggered after the SearchView has collected all relevant domains and @@ -801,8 +801,6 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea * @param {Array} contexts an array of literal contexts or context refs * @param {Array} groupbys ordered contexts which may or may not have group_by keys */ - on_search: function (domains, contexts, groupbys) { - }, /** * Triggered after a validation error in the SearchView fields. * diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 9315ce15d1a..0ee753ccb52 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -4533,7 +4533,7 @@ instance.web.form.SelectCreatePopup = instance.web.form.AbstractFormPopup.extend } this.searchview = new instance.web.SearchView(this, this.dataset, false, search_defaults); - this.searchview.on_search.add(function(domains, contexts, groupbys) { + this.searchview.on('data_search', self, function(domains, contexts, groupbys) { if (self.initial_ids) { self.do_search(domains.concat([[["id", "in", self.initial_ids]], self.domain]), contexts, groupbys); diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index f985e5f6dc8..a49bf96441f 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -629,7 +629,7 @@ instance.web.ViewManager = instance.web.Widget.extend({ } this.searchview = new instance.web.SearchView(this, this.dataset, view_id, search_defaults, this.flags.search_view === false); - this.searchview.on_search.add(this.do_searchview_search); + this.searchview.on('data_search', self, this.do_searchview_search); return this.searchview.appendTo(this.$el.find(".oe_view_manager_view_search")); }, do_searchview_search: function(domains, contexts, groupbys) { From 1a476fed6919117c4f916a82b49b2162d7603338 Mon Sep 17 00:00:00 2001 From: ggh-openerp Date: Thu, 11 Oct 2012 11:09:07 +0530 Subject: [PATCH 005/116] [IMP] Remove add() in on_search method bzr revid: ggh@tinyerp.com-20121011053907-tykje6i145fmjrl3 --- addons/web/static/src/js/search.js | 16 ---------------- addons/web/static/test/search.js | 6 +++--- addons/web_hello/static/openerp/base_hello.js | 2 +- 3 files changed, 4 insertions(+), 20 deletions(-) diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js index b403dab95db..6810cfd35fa 100644 --- a/addons/web/static/src/js/search.js +++ b/addons/web/static/src/js/search.js @@ -785,22 +785,6 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea } return this.trigger('data_search', search.domains, search.contexts, search.groupbys); }, - /** - * Triggered after the SearchView has collected all relevant domains and - * contexts. - * - * It is provided with an Array of domains and an Array of contexts, which - * may or may not be evaluated (each item can be either a valid domain or - * context, or a string to evaluate in order in the sequence) - * - * It is also passed an array of contexts used for group_by (they are in - * the correct order for group_by evaluation, which contexts may not be) - * - * @event - * @param {Array} domains an array of literal domains or domain references - * @param {Array} contexts an array of literal contexts or context refs - * @param {Array} groupbys ordered contexts which may or may not have group_by keys - */ /** * Triggered after a validation error in the SearchView fields. * diff --git a/addons/web/static/test/search.js b/addons/web/static/test/search.js index 6dc37f31d08..7c6556da363 100644 --- a/addons/web/static/test/search.js +++ b/addons/web/static/test/search.js @@ -652,7 +652,7 @@ $(document).ready(function () { } }); var ds, cs, gs; - view.on_search.add(function (d, c, g) { + view.on('data_search', this, function (d, c, g) { ds = d, cs = c, gs = g; }); view.appendTo($fix) @@ -690,7 +690,7 @@ $(document).ready(function () { } }, {dummy: 42}); var ds, cs, gs; - view.on_search.add(function (d, c, g) { + view.on('data_search', this, function (d, c, g) { ds = d, cs = c, gs = g; }); view.appendTo($fix) @@ -718,7 +718,7 @@ $(document).ready(function () { } }, {dummy: 42}); var ds; - view.on_search.add(function (d) { ds = d; }); + view.on('data_search', this, function (d) { ds = d; }); view.appendTo($fix) .always(start) .fail(function (error) { ok(false, error.message); }) diff --git a/addons/web_hello/static/openerp/base_hello.js b/addons/web_hello/static/openerp/base_hello.js index a74b8ef8f2f..7bfbf7b78e8 100644 --- a/addons/web_hello/static/openerp/base_hello.js +++ b/addons/web_hello/static/openerp/base_hello.js @@ -7,7 +7,7 @@ openerp.web_hello = function(instance) { instance.web.SearchView = instance.web.SearchView.extend({ init:function() { this._super.apply(this,arguments); - this.on_search.add(function(){console.log('hello');}); + this.on('data_search', this, function(){console.log('hello');}); } }); From 4e33d693239fed16ae1b3b355b6c64c245f67f92 Mon Sep 17 00:00:00 2001 From: ggh-openerp Date: Thu, 11 Oct 2012 11:13:09 +0530 Subject: [PATCH 006/116] [IMP]Remove add() in on_search method bzr revid: ggh@tinyerp.com-20121011054309-1y2f54y735r6h9qh --- addons/mail/static/src/js/mail.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index e0c9ac9b7fc..e6a4ace66c7 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -1110,7 +1110,7 @@ openerp.mail = function(session) { var self = this; this.searchview = new session.web.SearchView(this, this.ds_msg, false, defaults || {}, hidden || false); return this.searchview.appendTo(this.$('.oe_view_manager_view_search')).then(function () { - self.searchview.on_search.add(self.do_searchview_search); + self.searchview.on('data_search', self, self.do_searchview_search); }); }, From 73c32663d6050563eb5fb18a2492a1f1d898d876 Mon Sep 17 00:00:00 2001 From: ggh-openerp Date: Thu, 11 Oct 2012 14:28:07 +0530 Subject: [PATCH 007/116] add on_search comment bzr revid: ggh@tinyerp.com-20121011085807-vmldw354xdbruj1s --- addons/web/static/src/js/search.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js index 6810cfd35fa..b403dab95db 100644 --- a/addons/web/static/src/js/search.js +++ b/addons/web/static/src/js/search.js @@ -785,6 +785,22 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea } return this.trigger('data_search', search.domains, search.contexts, search.groupbys); }, + /** + * Triggered after the SearchView has collected all relevant domains and + * contexts. + * + * It is provided with an Array of domains and an Array of contexts, which + * may or may not be evaluated (each item can be either a valid domain or + * context, or a string to evaluate in order in the sequence) + * + * It is also passed an array of contexts used for group_by (they are in + * the correct order for group_by evaluation, which contexts may not be) + * + * @event + * @param {Array} domains an array of literal domains or domain references + * @param {Array} contexts an array of literal contexts or context refs + * @param {Array} groupbys ordered contexts which may or may not have group_by keys + */ /** * Triggered after a validation error in the SearchView fields. * From a31de511b6d753e52a114f9c9b438c07c449e8c6 Mon Sep 17 00:00:00 2001 From: Vishmita Date: Thu, 11 Oct 2012 15:33:01 +0530 Subject: [PATCH 008/116] [FIX]change event name bzr revid: vja@tinyerp.com-20121011100301-nc4en7cn431zkgp6 --- addons/web_diagram/static/src/js/diagram.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/web_diagram/static/src/js/diagram.js b/addons/web_diagram/static/src/js/diagram.js index 1ee2e54cc3e..d5262604ef4 100644 --- a/addons/web_diagram/static/src/js/diagram.js +++ b/addons/web_diagram/static/src/js/diagram.js @@ -240,7 +240,7 @@ instance.web.DiagramView = instance.web.View.extend({ } ); - pop.on('on_write_complete', self, function() { + pop.on('write_completed', self, function() { self.dataset.read_index(_.keys(self.fields_view.fields)).pipe(self.on_diagram_loaded); }); @@ -304,7 +304,7 @@ instance.web.DiagramView = instance.web.View.extend({ title: _t("Open: ") + title } ); - pop.on('on_write_complete', self, function() { + pop.on('write_completed', self, function() { self.dataset.read_index(_.keys(self.fields_view.fields)).pipe(self.on_diagram_loaded); }); }, From 9ff1aa9f4a2f99df7154fef214231284946c33c3 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Thu, 11 Oct 2012 16:47:05 +0200 Subject: [PATCH 009/116] Removed lot of useless stuff and modified the form rendering engine to let the form view insert the fields. bzr revid: nicolas.vanhoren@openerp.com-20121011144705-cu4c2gzsghc2or2l --- addons/web/static/src/js/view_form.js | 90 +++++---------------------- 1 file changed, 17 insertions(+), 73 deletions(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 97ad0f220e6..7a0bad0a10c 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -118,7 +118,6 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM this.__clicked_inside = false; this.__blur_timeout = null; this.rendering_engine = new instance.web.form.FormRenderingEngine(this); - this.qweb = null; // A QWeb instance will be created if the view is a QWeb template self.set({actual_mode: self.options.initial_mode}); this.has_been_loaded.then(function() { self.on("change:actual_mode", self, self.check_actual_mode); @@ -157,11 +156,12 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM this.rendering_engine.set_fields_registry(this.fields_registry); this.rendering_engine.set_tags_registry(this.tags_registry); this.rendering_engine.set_widgets_registry(this.widgets_registry); - if (!this.extract_qweb_template(data)) { - this.rendering_engine.set_fields_view(data); - var $dest = this.$el.hasClass("oe_form_container") ? this.$el : this.$el.find('.oe_form_container'); - this.rendering_engine.render_to($dest); - } + this.rendering_engine.set_fields_view(data); + var $dest = this.$el.hasClass("oe_form_container") ? this.$el : this.$el.find('.oe_form_container'); + var rendering_result = this.rendering_engine.render_to($dest); + _.each(rendering_result.to_replace, function(el) { + el[0].replace(el[1]); + }); this.$el.on('mousedown.formBlur', function () { self.__clicked_inside = true; @@ -214,57 +214,6 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM return $.when(); }, - extract_qweb_template: function(fvg) { - for (var i=0, ii=fvg.arch.children.length; i < ii; i++) { - var child = fvg.arch.children[i]; - if (child.tag === "templates") { - this.qweb = new QWeb2.Engine(); - this.qweb.add_template(instance.web.json_node_to_xml(child)); - if (!this.qweb.has_template('form')) { - throw new Error("No QWeb template found for form view"); - } - return true; - } - } - this.qweb = null; - return false; - }, - get_fvg_from_qweb: function(record) { - var view = this.qweb.render('form', this.get_qweb_context(record)); - var fvg = _.clone(this.fields_view); - fvg.arch = instance.web.xml_to_json(instance.web.str_to_xml(view).firstChild); - return fvg; - }, - get_qweb_context: function(record) { - var self = this, - new_record = {}; - _.each(record, function(value_, name) { - var r = _.clone(self.fields_view.fields[name] || {}); - if ((r.type === 'date' || r.type === 'datetime') && value_) { - r.raw_value = instance.web.auto_str_to_date(value_); - } else { - r.raw_value = value_; - } - r.value = instance.web.format_value(value_, r); - new_record[name] = r; - }); - return { - record : new_record, - new_record : !record.id - }; - }, - kill_current_form: function() { - _.each(this.getChildren(), function(el) { - el.destroy(); - }); - this.fields = {}; - this.fields_order = []; - this.default_focus_field = null; - this.default_focus_button = null; - this.translatable_fields = []; - this.$el.find('.oe_form_container').empty(); - }, - widgetFocused: function() { // Clear click flag if used to focus a widget this.__clicked_inside = false; @@ -368,13 +317,6 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM this._actualize_mode(); this.set({ 'title' : record.id ? record.display_name : "New" }); - if (this.qweb) { - this.kill_current_form(); - this.rendering_engine.set_fields_view(this.get_fvg_from_qweb(record)); - var $dest = this.$el.hasClass("oe_form_container") ? this.$el : this.$el.find('.oe_form_container'); - this.rendering_engine.render_to($dest); - } - _(this.fields).each(function (field, f) { field._dirty_flag = false; field._inhibit_on_change_flag = true; @@ -1226,7 +1168,12 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt this.$form.appendTo(this.$target); - var ws = _.map(this.fields_to_init, function($elem) { + var res = { + target: $target, + to_replace: [], + }; + + _.each(this.fields_to_init, function($elem) { var name = $elem.attr("name"); if (!self.fvg.fields[name]) { throw new Error("Field '" + name + "' specified in view could not be found."); @@ -1242,24 +1189,21 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt } self.alter_field(w); self.view.register_field(w, $elem.attr("name")); - return [w, $elem]; - }); - _.each(ws, function(w) { - w[0].replace(w[1]); + res.to_replace.push([w, $elem]); }); _.each(this.tags_to_init, function($elem) { var tag_name = $elem[0].tagName.toLowerCase(); var obj = self.tags_registry.get_object(tag_name); var w = new (obj)(self.view, instance.web.xml_to_json($elem[0])); - w.replace($elem); + res.to_replace.push([w, $elem]); }); _.each(this.widgets_to_init, function($elem) { var widget_type = $elem.attr("type"); var obj = self.widgets_registry.get_object(widget_type); var w = new (obj)(self.view, instance.web.xml_to_json($elem[0])); - w.replace($elem); + res.to_replace.push([w, $elem]); }); - // TODO: return a deferred + return res; }, render_element: function(template /* dictionaries */) { var dicts = [].slice.call(arguments).slice(1); @@ -4991,7 +4935,7 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({ */ render_elements: function () { var self = this; - var content = instance.web.qweb.render("FieldStatus.content", {widget: this}); + var content = QWeb.render("FieldStatus.content", {widget: this}); this.$el.html(content); var colors = JSON.parse((this.node.attrs || {}).statusbar_colors || "{}"); var color = colors[this.selected_value]; From 3da22818fa25bd73d584f058af925c477908ac26 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Thu, 11 Oct 2012 16:51:48 +0200 Subject: [PATCH 010/116] Modified the way the fields are inserted a little bit more bzr revid: nicolas.vanhoren@openerp.com-20121011145148-ii0p0t704gdmmf24 --- addons/web/static/src/js/view_form.js | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 7a0bad0a10c..ea2e9fa289d 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -158,10 +158,8 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM this.rendering_engine.set_widgets_registry(this.widgets_registry); this.rendering_engine.set_fields_view(data); var $dest = this.$el.hasClass("oe_form_container") ? this.$el : this.$el.find('.oe_form_container'); - var rendering_result = this.rendering_engine.render_to($dest); - _.each(rendering_result.to_replace, function(el) { - el[0].replace(el[1]); - }); + this.rendering_engine.render_to($dest); + this.rendering_engine.init_fields(); this.$el.on('mousedown.formBlur', function () { self.__clicked_inside = true; @@ -1168,10 +1166,7 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt this.$form.appendTo(this.$target); - var res = { - target: $target, - to_replace: [], - }; + this.to_replace = []; _.each(this.fields_to_init, function($elem) { var name = $elem.attr("name"); @@ -1189,21 +1184,27 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt } self.alter_field(w); self.view.register_field(w, $elem.attr("name")); - res.to_replace.push([w, $elem]); + self.to_replace.push([w, $elem]); }); _.each(this.tags_to_init, function($elem) { var tag_name = $elem[0].tagName.toLowerCase(); var obj = self.tags_registry.get_object(tag_name); var w = new (obj)(self.view, instance.web.xml_to_json($elem[0])); - res.to_replace.push([w, $elem]); + self.to_replace.push([w, $elem]); }); _.each(this.widgets_to_init, function($elem) { var widget_type = $elem.attr("type"); var obj = self.widgets_registry.get_object(widget_type); var w = new (obj)(self.view, instance.web.xml_to_json($elem[0])); - res.to_replace.push([w, $elem]); + self.to_replace.push([w, $elem]); }); - return res; + }, + init_fields: function() { + var defs = []; + _.each(this.to_replace, function(el) { + defs.push(el[0].replace(el[1])); + }); + return $.when.apply($, defs); }, render_element: function(template /* dictionaries */) { var dicts = [].slice.call(arguments).slice(1); From 4757e5287e1ebca9508730413d94c63059531907 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Thu, 11 Oct 2012 17:21:40 +0200 Subject: [PATCH 011/116] Modified fields up to m2o bzr revid: nicolas.vanhoren@openerp.com-20121011152140-c4edgpmamqgiwx9s --- addons/web/static/src/js/view_form.js | 74 +++++++++++++-------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index ea2e9fa289d..6381cf5fe6c 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -159,7 +159,6 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM this.rendering_engine.set_fields_view(data); var $dest = this.$el.hasClass("oe_form_container") ? this.$el : this.$el.find('.oe_form_container'); this.rendering_engine.render_to($dest); - this.rendering_engine.init_fields(); this.$el.on('mousedown.formBlur', function () { self.__clicked_inside = true; @@ -335,6 +334,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM }); } self.on_form_changed(); + this.rendering_engine.init_fields(); self.is_initialized.resolve(); self.do_update_pager(record.id == null); if (self.sidebar) { @@ -1204,6 +1204,7 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt _.each(this.to_replace, function(el) { defs.push(el[0].replace(el[1])); }); + this.to_replace = []; return $.when.apply($, defs); }, render_element: function(template /* dictionaries */) { @@ -2066,6 +2067,14 @@ instance.web.form.AbstractField = instance.web.form.FormWidget.extend(instance.w this.field_manager.on("change:display_invalid_fields", this, this._check_css_flags); this._check_css_flags(); }, + start: function() { + var tmp = this._super(); + this.on("change:value", this, function() { + if (! this.no_rerender) + this.render(); + }); + this.render(); + }, /** * Private. Do not use. */ @@ -2078,6 +2087,20 @@ instance.web.form.AbstractField = instance.web.form.FormWidget.extend(instance.w get_value: function() { return this.get('value'); }, + /** + Utility method that all implementations should use to change the + value without triggering a re-rendering. + */ + internal_set_value: function(value_) { + var tmp = this.no_render; + this.no_rerender = true; + this.set({'value': value_}); + this.no_rerender = tmp; + }, + /** + This method is called each time the value is modified. + */ + render_value: function() {}, is_valid: function() { return this.is_syntax_valid() && !(this.get('required') && this.is_false()); }, @@ -2161,10 +2184,6 @@ instance.web.form.ReinitializeFieldMixin = _.extend({}, instance.web.form.Reini instance.web.form.ReinitializeWidgetMixin.reinitialize.call(this); this.render_value(); }, - /** - * Called to render the value. Should also be explicitly called at the end of a set_value(). - */ - render_value: function() {}, }); instance.web.form.FieldChar = instance.web.form.AbstractField.extend(instance.web.form.ReinitializeFieldMixin, { @@ -2178,14 +2197,10 @@ instance.web.form.FieldChar = instance.web.form.AbstractField.extend(instance.we var self = this; var $input = this.$el.find('input'); $input.change(function() { - self.set({'value': self.parse_value($input.val())}); + self.internal_set_value(self.parse_value($input.val())); }); this.setupFocus($input); }, - set_value: function(value_) { - this._super(value_); - this.render_value(); - }, render_value: function() { var show_value = this.format_value(this.get('value'), ''); if (!this.get("effective_readonly")) { @@ -2289,7 +2304,7 @@ instance.web.form.FieldFloat = instance.web.form.FieldChar.extend({ widget_class: 'oe_form_field_float', init: function (field_manager, node) { this._super(field_manager, node); - this.set({'value': 0}); + this.internal_set_value(0); if (this.node.attrs.digits) { this.digits = this.node.attrs.digits; } else { @@ -2415,16 +2430,12 @@ instance.web.form.FieldDatetime = instance.web.form.AbstractField.extend(instanc if (!this.get("effective_readonly")) { this.datewidget = this.build_widget(); this.datewidget.on_change.add_last(_.bind(function() { - this.set({'value': this.datewidget.get_value()}); + this.internal_set_value(this.datewidget.get_value()); }, this)); this.datewidget.appendTo(this.$el); this.setupFocus(this.datewidget.$input); } }, - set_value: function(value_) { - this._super(value_); - this.render_value(); - }, render_value: function() { if (!this.get("effective_readonly")) { this.datewidget.set_value(this.get('value')); @@ -2466,7 +2477,7 @@ instance.web.form.FieldText = instance.web.form.AbstractField.extend(instance.we this.default_height = this.$textarea.css('height'); if (!this.get("effective_readonly")) { this.$textarea.change(_.bind(function() { - self.set({'value': instance.web.parse_value(self.$textarea.val(), self)}); + self.internal_set_value(instance.web.parse_value(self.$textarea.val(), self)); }, this)); } else { this.$textarea.attr('disabled', 'disabled'); @@ -2478,12 +2489,8 @@ instance.web.form.FieldText = instance.web.form.AbstractField.extend(instance.we }); this.setupFocus(this.$textarea); }, - set_value: function(value_) { - this._super(value_); - this.render_value(); - $(window).resize(); - }, render_value: function() { + $(window).resize(); var show_value = instance.web.format_value(this.get('value'), this, ''); if (show_value === '') { this.$textarea.css('height', parseInt(this.default_height)+"px"); @@ -2543,15 +2550,11 @@ instance.web.form.FieldTextHtml = instance.web.form.AbstractField.extend(instanc this.$cleditor.change(function() { if (! self._updating_editor) { self.$cleditor.updateTextArea(); - self.set({'value': self.$textarea.val()}); + self.internal_set_value(self.$textarea.val()); } }); } }, - set_value: function(value_) { - this._super.apply(this, arguments); - this.render_value(); - }, render_value: function() { if (! this.get("effective_readonly")) { this.$textarea.val(this.get('value') || ''); @@ -2572,7 +2575,7 @@ instance.web.form.FieldBoolean = instance.web.form.AbstractField.extend({ this.$checkbox = $("input", this.$el); this.setupFocus(this.$checkbox); this.$el.click(_.bind(function() { - this.set({'value': this.$checkbox.is(':checked')}); + this.internal_set_value(this.$checkbox.is(':checked')); }, this)); var check_readonly = function() { self.$checkbox.prop('disabled', self.get("effective_readonly")); @@ -2580,10 +2583,9 @@ instance.web.form.FieldBoolean = instance.web.form.AbstractField.extend({ this.on("change:effective_readonly", this, check_readonly); check_readonly.call(this); }, - set_value: function(value_) { - this._super.apply(this, arguments); - this.$checkbox[0].checked = value_; - }, + render_value: function() { + this.$checkbox[0].checked = this.get('value'); + } focus: function() { this.$checkbox.focus(); } @@ -2598,9 +2600,8 @@ instance.web.form.FieldProgressBar = instance.web.form.AbstractField.extend({ disabled: this.get("effective_readonly") }); }, - set_value: function(value_) { - this._super.apply(this, arguments); - var show_value = Number(value_); + render_value: function() { + var show_value = Number(this.get('value')); if (isNaN(show_value)) { show_value = 0; } @@ -2638,7 +2639,7 @@ instance.web.form.FieldSelection = instance.web.form.AbstractField.extend(instan var ischanging = false; var $select = this.$el.find('select') .change(_.bind(function() { - this.set({'value': this.values[this.$el.find('select')[0].selectedIndex][0]}); + this.internal_set_value(this.values[this.$el.find('select')[0].selectedIndex][0]); }, this)) .change(function () { ischanging = true; }) .click(function () { ischanging = false; }) @@ -2653,7 +2654,6 @@ instance.web.form.FieldSelection = instance.web.form.AbstractField.extend(instan value_ = value_ === null ? false : value_; value_ = value_ instanceof Array ? value_[0] : value_; this._super(value_); - this.render_value(); }, render_value: function() { if (!this.get("effective_readonly")) { From 7cd873f86fb38996bab4ec3b9b8640669171095f Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Thu, 11 Oct 2012 17:23:08 +0200 Subject: [PATCH 012/116] fix typo bzr revid: nicolas.vanhoren@openerp.com-20121011152308-exmq8zruqba7u4fw --- addons/web/static/src/js/view_form.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 6381cf5fe6c..e599256de00 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -2585,7 +2585,7 @@ instance.web.form.FieldBoolean = instance.web.form.AbstractField.extend({ }, render_value: function() { this.$checkbox[0].checked = this.get('value'); - } + }, focus: function() { this.$checkbox.focus(); } From 2fadf797e56a15e7b3a6b19422876e1ce3752d03 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Thu, 11 Oct 2012 17:35:06 +0200 Subject: [PATCH 013/116] Ported the m2o bzr revid: nicolas.vanhoren@openerp.com-20121011153506-b91c4xm2jsf6a6t7 --- addons/web/static/src/js/view_form.js | 29 +++++++++++++-------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index e599256de00..dad787374a1 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -2873,26 +2873,28 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc this.display_value = {}; this.last_search = []; this.floating = false; - this.inhibit_on_change = false; this.current_display = null; + this.is_started = false; }, start: function() { this._super(); instance.web.form.ReinitializeFieldMixin.start.call(this); - this.on("change:value", this, function() { - this.floating = false; - this.render_value(); - }); + this.is_started = true; instance.web.bus.on('click', this, function() { if (!this.get("effective_readonly") && this.$input && this.$input.autocomplete('widget').is(':visible')) { this.$input.autocomplete("close"); } }); }, + reinit_value: function(val) { + this.internal_set_value(val); + this.floating = false; + if (this.is_started) + this.render_value(); + }, initialize_content: function() { if (!this.get("effective_readonly")) this.render_editable(); - this.render_value(); }, init_error_displayer: function() { // nothing @@ -2943,7 +2945,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc if (self.current_display !== self.$input.val()) { self.current_display = self.$input.val(); if (self.$input.val() === "") { - self.set({value: false}); + self.internal_set_value(false); self.floating = false; } else { self.floating = true; @@ -2975,15 +2977,14 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc if (self.last_search[0][0] != self.get("value")) { self.display_value = {}; self.display_value["" + self.last_search[0][0]] = self.last_search[0][1]; - self.set({value: self.last_search[0][0]}); + self.reinit_value(self.last_search[0][0]); } else { used = true; self.render_value(); } } else { used = true; - self.set({value: false}); - self.render_value(); + self.reinit_value(false); } self.floating = false; } @@ -3038,7 +3039,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc if (item.id) { self.display_value = {}; self.display_value["" + item.id] = item.name; - self.set({value: item.id}); + self.reinit_value(item.id); } else if (item.action) { item.action(); // Cancel widget blurring, to avoid form blur event @@ -3129,16 +3130,14 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc value_ = value_[0]; } value_ = value_ || false; - this.inhibit_on_change = true; - this._super(value_); - this.inhibit_on_change = false; + this.reinit_value(value_); }, get_displayed: function() { return this.display_value["" + this.get("value")]; }, add_id: function(id) { this.display_value = {}; - this.set({value: id}); + this.reinit_value(id); }, is_false: function() { return ! this.get("value"); From b164a96535e66313ed6502e17d1f8bee45a9a9c6 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Thu, 11 Oct 2012 17:47:00 +0200 Subject: [PATCH 014/116] Ported m2mtags, reference and binary, still need to port o2m & m2m bzr revid: nicolas.vanhoren@openerp.com-20121011154700-nm1j0nibq3xazaix --- addons/web/static/src/js/view_form.js | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index dad787374a1..add396df790 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -3830,7 +3830,6 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(in start: function() { this._super(); instance.web.form.ReinitializeFieldMixin.start.call(this); - this.on("change:value", this, this.render_value); }, initialize_content: function() { if (this.get("effective_readonly")) @@ -4624,10 +4623,6 @@ instance.web.form.FieldReference = instance.web.form.AbstractField.extend(instan is_false: function() { return typeof(this.get_value()) !== 'string'; }, - set_value: function(value_) { - this._super(value_); - this.render_value(); - }, render_value: function() { this.reference_ready = false; var vals = [], sel_val, m2o_val; @@ -4647,9 +4642,9 @@ instance.web.form.FieldReference = instance.web.form.AbstractField.extend(instan var model = this.selection.get_value(), id = this.m2o.get_value(); if (typeof(model) === 'string' && typeof(id) === 'number') { - this.set({'value': model + ',' + id}); + this.internal_set_value(model + ',' + id); } else { - this.set({'value': false}); + this.internal_set_value(false); } }, }); @@ -4748,7 +4743,7 @@ instance.web.form.FieldBinary = instance.web.form.AbstractField.extend(instance. on_clear: function() { if (this.get('value') !== false) { this.binary_value = false; - this.set({'value': false}); + this.internal_set_value(false); } return false; } @@ -4768,10 +4763,6 @@ instance.web.form.FieldBinaryFile = instance.web.form.FieldBinary.extend({ }); } }, - set_value: function(value_) { - this._super.apply(this, arguments); - this.render_value(); - }, render_value: function() { if (!this.get("effective_readonly")) { var show_value; @@ -4793,7 +4784,7 @@ instance.web.form.FieldBinaryFile = instance.web.form.FieldBinary.extend({ }, on_file_uploaded_and_valid: function(size, name, content_type, file_base64) { this.binary_value = true; - this.set({'value': file_base64}); + this.internal_set_value(file_base64); var show_value = name + " (" + this.human_filesize(size) + ")"; this.$el.find('input').eq(0).val(show_value); this.set_filename(name); @@ -4807,10 +4798,6 @@ instance.web.form.FieldBinaryFile = instance.web.form.FieldBinary.extend({ instance.web.form.FieldBinaryImage = instance.web.form.FieldBinary.extend({ template: 'FieldBinaryImage', - set_value: function(value_) { - this._super.apply(this, arguments); - this.render_value(); - }, render_value: function() { var self = this; var url; @@ -4843,7 +4830,7 @@ instance.web.form.FieldBinaryImage = instance.web.form.FieldBinary.extend({ this._super.apply(this, arguments); }, on_file_uploaded_and_valid: function(size, name, content_type, file_base64) { - this.set({'value': file_base64}); + this.internal_set_value(file_base64); this.binary_value = true; this.render_value(); this.set_filename(name); From f5b1729758010c319aba4381c5231203f486f828 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Thu, 11 Oct 2012 18:09:02 +0200 Subject: [PATCH 015/116] Fixed lot of stuff and rewritten partially field status bzr revid: nicolas.vanhoren@openerp.com-20121011160902-llwsclos30nju80s --- addons/web/static/src/js/view_form.js | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index add396df790..3d8f4a96ae1 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -334,7 +334,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM }); } self.on_form_changed(); - this.rendering_engine.init_fields(); + self.rendering_engine.init_fields(); self.is_initialized.resolve(); self.do_update_pager(record.id == null); if (self.sidebar) { @@ -2071,9 +2071,9 @@ instance.web.form.AbstractField = instance.web.form.FormWidget.extend(instance.w var tmp = this._super(); this.on("change:value", this, function() { if (! this.no_rerender) - this.render(); + this.render_value(); }); - this.render(); + this.render_value(); }, /** * Private. Do not use. @@ -2148,8 +2148,8 @@ instance.web.form.ReinitializeWidgetMixin = { * Default implementation of start(), use it or call explicitly initialize_field(). */ start: function() { - this._super(); this.initialize_field(); + this._super(); }, initialize_field: function() { this.on("change:effective_readonly", this, this.reinitialize); @@ -2571,7 +2571,6 @@ instance.web.form.FieldBoolean = instance.web.form.AbstractField.extend({ template: 'FieldBoolean', start: function() { var self = this; - this._super.apply(this, arguments); this.$checkbox = $("input", this.$el); this.setupFocus(this.$checkbox); this.$el.click(_.bind(function() { @@ -2582,6 +2581,7 @@ instance.web.form.FieldBoolean = instance.web.form.AbstractField.extend({ }; this.on("change:effective_readonly", this, check_readonly); check_readonly.call(this); + this._super.apply(this, arguments); }, render_value: function() { this.$checkbox[0].checked = this.get('value'); @@ -4851,7 +4851,6 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({ this.selected_value = null; }, start: function() { - this._super(); // backward compatibility this.loaded = new $.Deferred(); if (this.options.clickable) { @@ -4861,18 +4860,13 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({ if (this.$el.parent().is('header')) { this.$el.after('
'); } + this._super(); }, set_value: function(value_) { - var self = this; - this._super(value_); - // find selected value: - // - many2one: [2, "New"] -> 2 - // - selection: new -> new - if (this.field.type == "many2one") { - this.selected_value = value_[0]; - } else { - this.selected_value = value_; + if (value_ instanceof Array) { + value_ = value_[0]; } + this._super(value_); // trick to be sure all values are loaded in the form, therefore // enabling the evaluation of dynamic domains self.selection = []; @@ -4881,6 +4875,9 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({ }); return this.loaded; }, + render_value: function() { + this.get_selection(); + }, /** Get the selection and render it * selection: [[identifier, value_to_display], ...] * For selection fields: this is directly given by this.field.selection From fb944a77faff92a79d25957a89af47212e005afb Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Thu, 11 Oct 2012 18:18:16 +0200 Subject: [PATCH 016/116] Ported field status bzr revid: nicolas.vanhoren@openerp.com-20121011161816-lnz7prb3ag6nrbi3 --- addons/web/static/src/js/view_form.js | 53 +++++++++------------------ 1 file changed, 18 insertions(+), 35 deletions(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 3d8f4a96ae1..c708d56a7ef 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -4848,15 +4848,12 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({ this._super(field_manager, node); this.options.clickable = this.options.clickable || (this.node.attrs || {}).clickable || false; this.options.visible = this.options.visible || (this.node.attrs || {}).statusbar_visible || false; - this.selected_value = null; + this.set({value: false}); }, start: function() { - // backward compatibility - this.loaded = new $.Deferred(); if (this.options.clickable) { this.$el.on('click','li',this.on_click_stage); } - // TODO move the following into css :after if (this.$el.parent().is('header')) { this.$el.after('
'); } @@ -4867,16 +4864,18 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({ value_ = value_[0]; } this._super(value_); - // trick to be sure all values are loaded in the form, therefore - // enabling the evaluation of dynamic domains - self.selection = []; - $.async_when().then(function() { - self.get_selection(); - }); - return this.loaded; }, render_value: function() { - this.get_selection(); + var self = this; + self.get_selection().then(function() { + var content = QWeb.render("FieldStatus.content", {widget: self}); + self.$el.html(content); + var colors = JSON.parse((self.node.attrs || {}).statusbar_colors || "{}"); + var color = colors[self.get('value')]; + if (color) { + self.$("oe_active").css("color", color); + } + }); }, /** Get the selection and render it * selection: [[identifier, value_to_display], ...] @@ -4885,53 +4884,37 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({ */ get_selection: function() { var self = this; + self.selection = []; if (this.field.type == "many2one") { var domain = []; if(!_.isEmpty(this.field.domain) || !_.isEmpty(this.node.attrs.domain)) { - domain = new instance.web.CompoundDomain(['|'], self.build_domain(), [['id', '=', self.selected_value]]); + domain = new instance.web.CompoundDomain(['|'], self.build_domain(), [['id', '=', self.get('value')]]); } var ds = new instance.web.DataSetSearch(this, this.field.relation, self.build_context(), domain); - ds.read_slice(['name'], {}).done( function (records) { + return ds.read_slice(['name'], {}).pipe(function (records) { for(var i = 0; i < records.length; i++) { self.selection.push([records[i].id, records[i].name]); } - self.render_elements(); - self.loaded.resolve(); }); } else { - this.loaded.resolve(); // For field type selection filter values according to // statusbar_visible attribute of the field. For example: // statusbar_visible="draft,open". var selection = this.field.selection; - for(var i=0; i< selection.length; i++) { + for(var i=0; i < selection.length; i++) { var key = selection[i][0]; - if(key == this.selected_value || !this.options.visible || this.options.visible.indexOf(key) != -1) { + if(key == this.get('value') || !this.options.visible || this.options.visible.indexOf(key) != -1) { this.selection.push(selection[i]); } } - this.render_elements(); - } - }, - /** Renders the widget. This function also checks for statusbar_colors='{"pending": "blue"}' - * attribute in the widget. This allows to set a given color to a given - * state (given by the key of (key, label)). - */ - render_elements: function () { - var self = this; - var content = QWeb.render("FieldStatus.content", {widget: this}); - this.$el.html(content); - var colors = JSON.parse((this.node.attrs || {}).statusbar_colors || "{}"); - var color = colors[this.selected_value]; - if (color) { - this.$("oe_active").css("color", color); + return $.when(); } }, on_click_stage: function (ev) { var self = this; var $li = $(ev.currentTarget); var val = parseInt($li.data("id")); - if (val != self.selected_value) { + if (val != self.get('value')) { this.view.recursive_save().then(function() { var change = {}; change[self.name] = val; From 55a5f51aebe7fd4dc08759654d3649952ce8cb0e Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Thu, 11 Oct 2012 18:29:18 +0200 Subject: [PATCH 017/116] Ported o2m bzr revid: nicolas.vanhoren@openerp.com-20121011162918-d15ip9ci4o24axzy --- addons/web/static/src/js/view_form.js | 28 +++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index c708d56a7ef..3905501e6cd 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -2877,7 +2877,6 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc this.is_started = false; }, start: function() { - this._super(); instance.web.form.ReinitializeFieldMixin.start.call(this); this.is_started = true; instance.web.bus.on('click', this, function() { @@ -2885,6 +2884,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc this.$input.autocomplete("close"); } }); + this._super(); }, reinit_value: function(val) { this.internal_set_value(val); @@ -3213,6 +3213,16 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({ this.is_setted = $.Deferred(); this.form_last_update = $.Deferred(); this.init_form_last_update = this.form_last_update; + this.is_started = false; + this.dataset = new instance.web.form.One2ManyDataSet(this, this.field.relation); + this.dataset.o2m = this; + this.dataset.parent_view = this.view; + this.dataset.child_name = this.name; + var self = this; + this.dataset.on_change.add_last(function() { + self.trigger_on_change(); + }); + this.set_value([]); }, start: function() { this._super.apply(this, arguments); @@ -3220,14 +3230,6 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({ var self = this; - this.dataset = new instance.web.form.One2ManyDataSet(this, this.field.relation); - this.dataset.o2m = this; - this.dataset.parent_view = this.view; - this.dataset.child_name = this.name; - this.dataset.on_change.add_last(function() { - self.trigger_on_change(); - }); - this.is_setted.then(function() { self.load_views(); }); @@ -3241,6 +3243,8 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({ }); }); }); + this.is_started = true; + this.reload_current_view(); }, trigger_on_change: function() { var tmp = this.doing_on_change; @@ -3429,7 +3433,11 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({ } self.is_setted.resolve(); this.trigger_on_change(); - return self.reload_current_view(); + if (this.is_started) { + return self.reload_current_view(); + } else { + return $.when(); + } }, get_value: function() { var self = this; From 7314375acacbd6561a3baaf045fb86974a4a165d Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Fri, 12 Oct 2012 10:43:37 +0200 Subject: [PATCH 018/116] Ported m2m, still has to port m2mtags bzr revid: nicolas.vanhoren@openerp.com-20121012084337-7etwh54ugl4k01mu --- addons/web/static/src/js/view_form.js | 47 ++++++++++----------------- 1 file changed, 17 insertions(+), 30 deletions(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 3905501e6cd..eda2c8a64f4 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -3210,7 +3210,6 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({ lazy_build_o2m_kanban_view(); this.is_loaded = $.Deferred(); this.initial_is_loaded = this.is_loaded; - this.is_setted = $.Deferred(); this.form_last_update = $.Deferred(); this.init_form_last_update = this.form_last_update; this.is_started = false; @@ -3230,9 +3229,7 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({ var self = this; - this.is_setted.then(function() { - self.load_views(); - }); + self.load_views(); this.is_loaded.then(function() { self.on("change:effective_readonly", self, function() { self.is_loaded = self.is_loaded.pipe(function() { @@ -3348,10 +3345,8 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({ } }); }); - this.is_setted.then(function() { - $.async_when().then(function () { - self.viewmanager.appendTo(self.$el); - }); + $.async_when().then(function () { + self.viewmanager.appendTo(self.$el); }); return def; }, @@ -3431,7 +3426,6 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({ if (this.dataset.index === null && this.dataset.ids.length > 0) { this.dataset.index = 0; } - self.is_setted.resolve(); this.trigger_on_change(); if (this.is_started) { return self.reload_current_view(); @@ -3960,36 +3954,33 @@ instance.web.form.FieldMany2Many = instance.web.form.AbstractField.extend({ disable_utility_classes: true, init: function(field_manager, node) { this._super(field_manager, node); - this.set({"value": []}); this.is_loaded = $.Deferred(); this.initial_is_loaded = this.is_loaded; - this.is_setted = $.Deferred(); + this.dataset = new instance.web.form.Many2ManyDataSet(this, this.field.relation); + this.dataset.m2m = this; + var self = this; + this.dataset.on('unlink', self, function(ids) { + self.dataset_changed(); + }); + this.set_value([]); }, start: function() { - this._super.apply(this, arguments); this.$el.addClass('oe_form_field oe_form_field_many2many'); var self = this; - this.dataset = new instance.web.form.Many2ManyDataSet(this, this.field.relation); - this.dataset.m2m = this; - this.dataset.on('unlink', self, function(ids) { - self.dataset_changed(); - }); - - this.is_setted.then(function() { - self.load_view(); - }); + self.load_view(); this.is_loaded.then(function() { self.on("change:effective_readonly", self, function() { self.is_loaded = self.is_loaded.pipe(function() { self.list_view.destroy(); return $.when(self.load_view()).then(function() { - self.reload_content(); + self.render_value(); }); }); }); }); + this._super.apply(this, arguments); }, set_value: function(value_) { value_ = value_ || []; @@ -3997,17 +3988,12 @@ instance.web.form.FieldMany2Many = instance.web.form.AbstractField.extend({ value_ = value_[0][2]; } this._super(value_); - this.dataset.set_ids(value_); - var self = this; - self.reload_content(); - this.is_setted.resolve(); }, get_value: function() { return [commands.replace_with(this.get('value'))]; }, - is_false: function () { - return _(this.dataset.ids).isEmpty(); + return _(this.get("value")).isEmpty(); }, load_view: function() { var self = this; @@ -4034,14 +4020,15 @@ instance.web.form.FieldMany2Many = instance.web.form.AbstractField.extend({ }); return loaded; }, - reload_content: function() { + render_value: function() { var self = this; + this.dataset.set_ids(this.get("value")); this.is_loaded = this.is_loaded.pipe(function() { return self.list_view.reload_content(); }); }, dataset_changed: function() { - this.set({'value': this.dataset.ids}); + this.internal_set_value(this.dataset.ids); }, }); From dbe370f5851182427fcafb0484354a5672a89189 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Fri, 12 Oct 2012 11:18:20 +0200 Subject: [PATCH 019/116] Ported m2mkanban and corrected bug in selection bzr revid: nicolas.vanhoren@openerp.com-20121012091820-u712bie1h2a84l8a --- addons/web/static/src/js/view_form.js | 38 +++++++++------------------ 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index a3a61168f17..69cb549203b 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -2671,13 +2671,6 @@ instance.web.form.FieldSelection = instance.web.form.AbstractField.extend(instan this.$el.text(option ? option[1] : this.values[0][1]); } }, - is_syntax_valid: function() { - if (this.get("effective_readonly")) { - return true; - } - var value_ = this.values[this.$el.find('select')[0].selectedIndex]; - return !! value_; - }, focus: function() { this.$el.find('select:first').focus(); } @@ -4086,28 +4079,26 @@ instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend( m2m_kanban_lazy_init(); this.is_loaded = $.Deferred(); this.initial_is_loaded = this.is_loaded; - this.is_setted = $.Deferred(); + + var self = this; + this.dataset = new instance.web.form.Many2ManyDataSet(this, this.field.relation); + this.dataset.m2m = this; + this.dataset.on('unlink', self, function(ids) { + self.dataset_changed(); + }); }, start: function() { this._super.apply(this, arguments); var self = this; - this.dataset = new instance.web.form.Many2ManyDataSet(this, this.field.relation); - this.dataset.m2m = this; - this.dataset.on('unlink', self, function(ids) { - self.dataset_changed(); - }); - - this.is_setted.then(function() { - self.load_view(); - }); + self.load_view(); this.is_loaded.then(function() { self.on("change:effective_readonly", self, function() { self.is_loaded = self.is_loaded.pipe(function() { self.kanban_view.destroy(); return $.when(self.load_view()).then(function() { - self.reload_content(); + self.render_value(); }); }); }); @@ -4119,10 +4110,6 @@ instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend( value_ = value_[0][2]; } this._super(value_); - this.dataset.set_ids(value_); - var self = this; - self.reload_content(); - this.is_setted.resolve(); }, load_view: function() { var self = this; @@ -4149,8 +4136,9 @@ instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend( }); return loaded; }, - reload_content: function() { + render_value: function() { var self = this; + this.dataset.set_ids(this.get("value")); this.is_loaded = this.is_loaded.pipe(function() { return self.kanban_view.do_search(self.build_domain(), self.dataset.get_context(), []); }); @@ -4177,7 +4165,7 @@ instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend( if(! _.detect(self.dataset.ids, function(x) {return x == one_id;})) { self.dataset.set_ids([].concat(self.dataset.ids, [one_id])); self.dataset_changed(); - self.reload_content(); + self.render_value(); } }); }); @@ -4188,7 +4176,7 @@ instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend( title: _t("Open: ") + self.string, write_function: function(id, data, options) { return self.dataset.write(id, data, {}).then(function() { - self.reload_content(); + self.render_value(); }); }, alternative_form_view: self.field.views ? self.field.views["form"] : undefined, From c82642a2dfda36a78677b23b296449782c713fdb Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Fri, 12 Oct 2012 13:09:43 +0200 Subject: [PATCH 020/116] fixed problem with mail bzr revid: nicolas.vanhoren@openerp.com-20121012110943-b1fhnutsokyazh22 --- addons/mail/static/src/js/mail.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index e0c9ac9b7fc..25d32f2a32e 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -1017,9 +1017,7 @@ openerp.mail = function(session) { this.$el.toggle(this.view.get("actual_mode") !== "create"); }, - set_value: function() { - var self = this; - this._super.apply(this, arguments); + render_value: function() { if (! this.view.datarecord.id || session.web.BufferedDataSet.virtual_id_regex.test(this.view.datarecord.id)) { this.$('oe_mail_thread').hide(); return; From 36fa302c351846b09cd530a7e7674e489346f2d3 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Fri, 12 Oct 2012 13:14:40 +0200 Subject: [PATCH 021/116] Fixed bug in m2m tags bzr revid: nicolas.vanhoren@openerp.com-20121012111440-2y1q0745nv7nouiy --- addons/web/static/src/js/view_form.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 69cb549203b..3297b60e60d 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -3825,8 +3825,8 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(in this._drop_shown = false; }, start: function() { - this._super(); instance.web.form.ReinitializeFieldMixin.start.call(this); + this._super(); }, initialize_content: function() { if (this.get("effective_readonly")) From 15974eb2e095238cb1016d832e97110fb7a6794d Mon Sep 17 00:00:00 2001 From: Vishmita Date: Fri, 12 Oct 2012 17:15:34 +0530 Subject: [PATCH 022/116] [IMP]replace callenabled for on_loaded bzr revid: vja@tinyerp.com-20121012114534-qx7y6dzmqkw7t7px --- addons/web/static/src/js/search.js | 2 +- addons/web/static/src/js/view_form.js | 12 ++++++------ addons/web/static/src/js/view_list.js | 1 + addons/web/static/src/js/views.js | 1 + 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js index a5e1aaeb3ae..400411937c4 100644 --- a/addons/web/static/src/js/search.js +++ b/addons/web/static/src/js/search.js @@ -671,7 +671,7 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea 'facet_for_defaults', this.defaults)).then(function () { self.query.reset(_(arguments).compact(), {preventSearch: true}); }); - + self.trigger("search_view_load"); return $.when(drawer_started, defaults_fetched) .then(function () { self.ready.resolve(); }) }, diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index afb5e258c0b..d21c2320783 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -211,7 +211,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM e.stopPropagation(); } }); - + this._super.apply(this, arguments); return $.when(); }, extract_qweb_template: function(fvg) { @@ -4078,7 +4078,7 @@ instance.web.form.FieldMany2Many = instance.web.form.AbstractField.extend({ } this.list_view.m2m_field = this; var loaded = $.Deferred(); - this.list_view.on_loaded.add_last(function() { + this.list_view.on("view_loaded",self,function() { self.initial_is_loaded.resolve(); loaded.resolve(); }); @@ -4203,7 +4203,7 @@ instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend( } this.kanban_view.m2m = this; var loaded = $.Deferred(); - this.kanban_view.on_loaded.add_last(function() { + this.kanban_view.on("view_loaded",self,function() { self.initial_is_loaded.resolve(); loaded.resolve(); }); @@ -4427,7 +4427,7 @@ instance.web.form.AbstractFormPopup = instance.web.Widget.extend({ this.view_form.set_embedded_view(this.options.alternative_form_view); } this.view_form.appendTo(this.$el.find(".oe_popup_form")); - this.view_form.on_loaded.add_last(function() { + this.view_form.on("view_loaded",self,function() { var multi_select = self.row_id === null && ! self.options.disable_multiple_selection; self.$buttonpane.html(QWeb.render("AbstractFormPopup.buttons", { multi_select: multi_select, @@ -4546,7 +4546,7 @@ instance.web.form.SelectCreatePopup = instance.web.form.AbstractFormPopup.extend self.do_search(domains.concat([self.domain]), contexts.concat(self.context), groupbys); } }); - this.searchview.on_loaded.add_last(function () { + this.searchview.on("search_view_load",self,function () { self.view_list = new instance.web.form.SelectCreateListView(self, self.dataset, false, _.extend({'deletable': false, @@ -4563,7 +4563,7 @@ instance.web.form.SelectCreatePopup = instance.web.form.AbstractFormPopup.extend }).pipe(function() { self.searchview.do_search(); }); - self.view_list.on_loaded.add_last(function() { + self.view_list.on("view_loaded",self,function() { self.$buttonpane.html(QWeb.render("SelectCreatePopup.search.buttons", {widget:self})); var $cbutton = self.$buttonpane.find(".oe_selectcreatepopup-search-close"); $cbutton.click(function() { diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js index 7457ca5ef67..08e7662c630 100644 --- a/addons/web/static/src/js/view_list.js +++ b/addons/web/static/src/js/view_list.js @@ -358,6 +358,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi this.sidebar.add_toolbar(this.fields_view.toolbar); this.sidebar.$el.hide(); } + this._super.apply(this, arguments); }, /** * Configures the ListView pager based on the provided dataset's information diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index f985e5f6dc8..1d99ab31727 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -1146,6 +1146,7 @@ instance.web.View = instance.web.Widget.extend({ * Must return a promise. */ on_loaded: function(fields_view_get) { + this.trigger("view_loaded"); }, set_default_options: function(options) { this.options = options || {}; From 802eda5ad7169aa927029574007b1f868b72fae1 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Fri, 12 Oct 2012 14:11:26 +0200 Subject: [PATCH 023/116] Ported field pad bzr revid: nicolas.vanhoren@openerp.com-20121012121126-atu1vf14rc4fxu0g --- addons/pad/static/src/js/pad.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/addons/pad/static/src/js/pad.js b/addons/pad/static/src/js/pad.js index 1e45b535867..cba2086b772 100644 --- a/addons/pad/static/src/js/pad.js +++ b/addons/pad/static/src/js/pad.js @@ -4,16 +4,13 @@ openerp.pad = function(instance) { template: 'FieldPad', configured: false, content: "", - set_value: function(val) { + render_value: function() { var self = this; - var _super = self._super; - _super.apply(self,[val]); - - if (val === false || val === "") { - self.field_manager.dataset.call('pad_generate_url',{context:{ - model: self.field_manager.model, + if (this.get("value") === false || this.get("value") === "") { + self.view.dataset.call('pad_generate_url',{context:{ + model: self.view.model, field_name: self.name, - object_id: self.field_manager.datarecord.id + object_id: self.view.datarecord.id }}).then(function(data) { if(data&&data.url){ _super.apply(self,[data.url]); From e4e1803fb30bf09ee8cbcb6bf80905fa7261ad6d Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Fri, 12 Oct 2012 14:18:03 +0200 Subject: [PATCH 024/116] Ported field mail followers bzr revid: nicolas.vanhoren@openerp.com-20121012121803-imyqenc1jxipdra5 --- addons/mail/static/src/js/mail_followers.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/mail/static/src/js/mail_followers.js b/addons/mail/static/src/js/mail_followers.js index 6c016c6c679..dd1db686efc 100644 --- a/addons/mail/static/src/js/mail_followers.js +++ b/addons/mail/static/src/js/mail_followers.js @@ -103,9 +103,9 @@ openerp_mail_followers = function(session, mail) { }); }, - set_value: function(value_) { + render_value: function() { this.reinit(); - return this.fetch_followers(value_ || this.get_value()); + return this.fetch_followers(this.get("value")); }, set_is_follower: function(value_) { From ccfa2e83d4784b4ea165ae12b5befbdae3ef1a67 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Fri, 12 Oct 2012 14:37:13 +0200 Subject: [PATCH 025/116] Modified documentation. bzr revid: nicolas.vanhoren@openerp.com-20121012123713-6cmnayk7pr3mgs4p --- addons/web/static/src/js/view_form.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 3297b60e60d..20c796a1d8b 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -1954,12 +1954,9 @@ instance.web.form.FieldInterface = { /** * Called by the form view to indicate the value of the field. * - * set_value() may return an object that can be passed to $.when() that represents the moment when - * the field has finished all operations necessary before the user can effectively use the widget. - * * Multiple calls to set_value() can occur at any time and must be handled correctly by the implementation, - * regardless of any asynchronous operation currently running and the status of any promise that a - * previous call to set_value() could have returned. + * regardless of any asynchronous operation currently running. Calls to set_value() can and will also occur + * before the widget is inserted into the DOM. * * set_value() must be able, at any moment, to handle the syntax returned by the "read" method of the * osv class in the OpenERP server as well as the syntax used by the set_value() (see below). It must From 5f4e81d2bb84c9986ac9bd9959806affba7e11e3 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Fri, 12 Oct 2012 14:56:20 +0200 Subject: [PATCH 026/116] Corrected multiple rendering problem in m2o bzr revid: nicolas.vanhoren@openerp.com-20121012125620-h2pgav1nyj5tpq2z --- addons/web/static/src/js/view_form.js | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 20c796a1d8b..c37264c258f 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -2144,7 +2144,7 @@ instance.web.form.AbstractField = instance.web.form.FormWidget.extend(instance.w */ instance.web.form.ReinitializeWidgetMixin = { /** - * Default implementation of start(), use it or call explicitly initialize_field(). + * Default implementation of, you should not override it, use initialize_field() instead. */ start: function() { this.initialize_field(); @@ -2175,10 +2175,6 @@ instance.web.form.ReinitializeWidgetMixin = { * switch. */ instance.web.form.ReinitializeFieldMixin = _.extend({}, instance.web.form.ReinitializeWidgetMixin, { - initialize_field: function() { - instance.web.form.ReinitializeWidgetMixin.initialize_field.call(this); - this.render_value(); - }, reinitialize: function() { instance.web.form.ReinitializeWidgetMixin.reinitialize.call(this); this.render_value(); @@ -2868,21 +2864,20 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc this.current_display = null; this.is_started = false; }, - start: function() { - instance.web.form.ReinitializeFieldMixin.start.call(this); + reinit_value: function(val) { + this.internal_set_value(val); + this.floating = false; + if (this.is_started) + this.render_value(); + }, + initialize_field: function() { this.is_started = true; instance.web.bus.on('click', this, function() { if (!this.get("effective_readonly") && this.$input && this.$input.autocomplete('widget').is(':visible')) { this.$input.autocomplete("close"); } }); - this._super(); - }, - reinit_value: function(val) { - this.internal_set_value(val); - this.floating = false; - if (this.is_started) - this.render_value(); + instance.web.form.ReinitializeFieldMixin.initialize_field.call(this); }, initialize_content: function() { if (!this.get("effective_readonly")) @@ -3821,10 +3816,6 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(in this._display_orderer = new instance.web.DropMisordered(); this._drop_shown = false; }, - start: function() { - instance.web.form.ReinitializeFieldMixin.start.call(this); - this._super(); - }, initialize_content: function() { if (this.get("effective_readonly")) return; From e3b7890ac30c4524b9ff919b91073b703a9d2e7e Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Fri, 12 Oct 2012 16:40:37 +0200 Subject: [PATCH 027/116] fixed bug with datetimes bzr revid: nicolas.vanhoren@openerp.com-20121012144037-u29a479c1oa4b3bw --- addons/web/static/src/js/view_form.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 259f1aee44c..63ef5ee21d0 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -2445,7 +2445,7 @@ instance.web.form.FieldDatetime = instance.web.form.AbstractField.extend(instanc } }, is_syntax_valid: function() { - if (!this.get("effective_readonly")) { + if (!this.get("effective_readonly") && this.datewidget) { return this.datewidget.is_valid_(); } return true; From 0bd69bd176c69abb9ec4d6bd98123296aad2d62b Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Fri, 12 Oct 2012 16:43:52 +0200 Subject: [PATCH 028/116] Corrected some more problems with is_syntax_valid() bzr revid: nicolas.vanhoren@openerp.com-20121012144352-jejnnpu18otgrnvp --- addons/web/static/src/js/view_form.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 63ef5ee21d0..9c25e11d748 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -2210,7 +2210,7 @@ instance.web.form.FieldChar = instance.web.form.AbstractField.extend(instance.we } }, is_syntax_valid: function() { - if (!this.get("effective_readonly")) { + if (!this.get("effective_readonly") && this.$("input").size() > 0) { try { var value_ = this.parse_value(this.$el.find('input').val(), ''); return true; @@ -2500,7 +2500,7 @@ instance.web.form.FieldText = instance.web.form.AbstractField.extend(instance.we this.$textarea.autosize(); }, is_syntax_valid: function() { - if (!this.get("effective_readonly")) { + if (!this.get("effective_readonly") && this.$textarea) { try { var value_ = instance.web.parse_value(this.$textarea.val(), this, ''); return true; From 0c1b8b5a4cf0987af967dd206d451d9a95639430 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Fri, 12 Oct 2012 16:51:43 +0200 Subject: [PATCH 029/116] Fix problem with focus called before the field is started bzr revid: nicolas.vanhoren@openerp.com-20121012145143-oooxbdovspsjcxfk --- addons/web/static/src/js/view_form.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 9c25e11d748..f16773829ab 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -678,7 +678,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM } for (var i = 0; i < fields_order.length; i += 1) { var field = this.fields[fields_order[i]]; - if (!field.get('effective_invisible') && !field.get('effective_readonly')) { + if (!field.get('effective_invisible') && !field.get('effective_readonly') && field.$label) { if (field.focus() !== false) { break; } From 11051f32e0ff2cc65a65311f76415996242fac67 Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Mon, 15 Oct 2012 12:01:48 +0200 Subject: [PATCH 030/116] [FIX] res_users.login: fix query parameters in cr.execute bzr revid: rco@openerp.com-20121015100148-pkanx35vr6fqojuj --- openerp/addons/base/res/res_users.py | 4 ++-- openerp/sql_db.py | 3 +++ openerp/tests/test_db_cursor.py | 36 ++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 openerp/tests/test_db_cursor.py diff --git a/openerp/addons/base/res/res_users.py b/openerp/addons/base/res/res_users.py index a1c06a52494..14673ce118f 100644 --- a/openerp/addons/base/res/res_users.py +++ b/openerp/addons/base/res/res_users.py @@ -409,8 +409,8 @@ class res_users(osv.osv): # prevent/delay login in that case. It will also have been logged # as a SQL error, if anyone cares. try: - cr.execute("SELECT id FROM res_users WHERE id=%s FOR UPDATE NOWAIT", str(user_id)) - cr.execute("UPDATE res_users SET login_date = now() AT TIME ZONE 'UTC' WHERE id=%s", str(user_id)) + cr.execute("SELECT id FROM res_users WHERE id=%s FOR UPDATE NOWAIT", (user_id,)) + cr.execute("UPDATE res_users SET login_date = now() AT TIME ZONE 'UTC' WHERE id=%s", (user_id,)) except Exception, e: _logger.exception("Failed to update last_login for db:%s login:%s", db, login) except openerp.exceptions.AccessDenied: diff --git a/openerp/sql_db.py b/openerp/sql_db.py index a6ebcd0300f..f18414bdff8 100644 --- a/openerp/sql_db.py +++ b/openerp/sql_db.py @@ -215,6 +215,9 @@ class Cursor(object): _logger.warning(query) _logger.warning("SQL queries cannot contain %d or %f anymore. " "Use only %s") + if params and not isinstance(params, (tuple, list, dict)): + _logger.error("SQL query parameters should be a tuple, list or dict; got %r", params) + raise ValueError("SQL query parameters should be a tuple, list or dict; got %r" % (params,)) if self.sql_log: now = mdt.now() diff --git a/openerp/tests/test_db_cursor.py b/openerp/tests/test_db_cursor.py new file mode 100644 index 00000000000..97e3225d0aa --- /dev/null +++ b/openerp/tests/test_db_cursor.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Run with one of these commands: +# > OPENERP_ADDONS_PATH='../../addons/trunk' OPENERP_PORT=8069 \ +# OPENERP_DATABASE=yy PYTHONPATH=. python tests/test_ir_sequence.py +# > OPENERP_ADDONS_PATH='../../addons/trunk' OPENERP_PORT=8069 \ +# OPENERP_DATABASE=yy nosetests tests/test_ir_sequence.py +# > OPENERP_ADDONS_PATH='../../../addons/trunk' OPENERP_PORT=8069 \ +# OPENERP_DATABASE=yy PYTHONPATH=../:. unit2 test_ir_sequence +# This assume an existing database. + +import unittest2 + +import openerp +import common + +DB = common.DB +ADMIN_USER_ID = common.ADMIN_USER_ID + +def cursor(): + return openerp.modules.registry.RegistryManager.get(DB).db.cursor() + + +class test_ir_sequence_standard(unittest2.TestCase): + """ Try cr.execute with wrong parameters """ + + def test_execute_bad_params(self): + """ Try to use non-iterable in query parameters. """ + cr = cursor() + with self.assertRaises(ValueError): + cr.execute("SELECT id FROM res_users WHERE login=%s", 'admin') + with self.assertRaises(ValueError): + cr.execute("SELECT id FROM res_users WHERE id=%s", 1) + with self.assertRaises(ValueError): + cr.execute("SELECT id FROM res_users WHERE id=%s", '1') + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From ae0a437aa67de4ff56247c813633d6469c873b76 Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Mon, 15 Oct 2012 12:18:49 +0200 Subject: [PATCH 031/116] [FIX] tests: add missing test bzr revid: rco@openerp.com-20121015101849-hf7pyxjzkbxd4tgf --- openerp/tests/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openerp/tests/__init__.py b/openerp/tests/__init__.py index aa3055f471c..3427743263c 100644 --- a/openerp/tests/__init__.py +++ b/openerp/tests/__init__.py @@ -9,7 +9,7 @@ See the :ref:`test-framework` section in the :ref:`features` list. """ from . import test_expression, test_html_sanitize, test_ir_sequence, test_orm,\ - test_view_validation, test_uninstall, test_misc + test_view_validation, test_uninstall, test_misc, test_db_cursor fast_suite = [ test_ir_sequence, @@ -18,6 +18,7 @@ fast_suite = [ checks = [ test_expression, test_html_sanitize, + test_db_cursor, test_orm, test_view_validation, test_misc, From faf49e3fcbdac0091ee141b7bbe080738f92666d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 15 Oct 2012 12:21:35 +0200 Subject: [PATCH 032/116] [FIX] Action counter: renamed filter automatically added when clicking on the counter, from needaction_pending to message_unread. bzr revid: tde@openerp.com-20121015102135-hnnd57fi187m0j0a --- addons/web/static/src/js/chrome.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index c993f3e3ad1..9fe1940d85f 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -1116,7 +1116,7 @@ instance.web.WebClient = instance.web.Client.extend({ .pipe(function (result) { var action = result; if (options.needaction) { - action.context.search_default_needaction_pending = true; + action.context.search_default_message_unread = true; } return $.when(self.action_manager.do_action(action, null, true)).fail(function() { self.menu.open_menu(options.previous_menu_id); From d09f14df7e26dbd70d63600305b5a9231e4749fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 15 Oct 2012 13:12:24 +0200 Subject: [PATCH 033/116] [REV] Reverted commenting mail tests... seems weird to comment tests. bzr revid: tde@openerp.com-20121015111224-7vzt4zthbzs96bb2 --- addons/mail/tests/test_mail_access_rights.py | 92 ++++++++++---------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/addons/mail/tests/test_mail_access_rights.py b/addons/mail/tests/test_mail_access_rights.py index 4d40c66fc81..104d7f28ffe 100644 --- a/addons/mail/tests/test_mail_access_rights.py +++ b/addons/mail/tests/test_mail_access_rights.py @@ -102,53 +102,53 @@ class test_mail_access_rights(test_mail.TestMailMockups): """ Test mail_message search override about access rights. """ self.assertTrue(1 == 1, 'Test not implemented, do not replace by return True') - # def test_10_mail_flow_access_rights(self): - # """ Test a Chatter-looks alike flow. """ - # cr, uid = self.cr, self.uid - # partner_bert_id, partner_raoul_id = self.partner_bert_id, self.partner_raoul_id - # user_bert_id, user_raoul_id = self.user_bert_id, self.user_raoul_id + def test_10_mail_flow_access_rights(self): + """ Test a Chatter-looks alike flow. """ + cr, uid = self.cr, self.uid + partner_bert_id, partner_raoul_id = self.partner_bert_id, self.partner_raoul_id + user_bert_id, user_raoul_id = self.user_bert_id, self.user_raoul_id - # # Prepare groups: Pigs (employee), Jobs (public) - # self.mail_group.message_post(cr, uid, self.group_pigs_id, body='Message') - # self.group_jobs_id = self.mail_group.create(cr, uid, {'name': 'Jobs', 'public': 'public'}) + # Prepare groups: Pigs (employee), Jobs (public) + self.mail_group.message_post(cr, uid, self.group_pigs_id, body='Message') + self.group_jobs_id = self.mail_group.create(cr, uid, {'name': 'Jobs', 'public': 'public'}) - # # ---------------------------------------- - # # CASE1: Bert, without groups - # # ---------------------------------------- - # # Do: Bert creates a group, should crash because perm_create only for employees - # self.assertRaises(except_orm, - # self.mail_group.create, - # cr, user_bert_id, {'name': 'Bert\'s Group'}) - # # Do: Bert reads Jobs basic fields, ok because public = read access on the group - # self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['name', 'description']) - # # Do: Bert browse Pigs, ok (no direct browse of partners) - # self.mail_group.browse(cr, user_bert_id, self.group_jobs_id) - # # Do: Bert reads Jobs messages, ok because read access on the group => read access on its messages - # jobs_message_ids = self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['message_ids'])['message_ids'] - # self.mail_message.read(cr, user_bert_id, jobs_message_ids) - # # Do: Bert reads Jobs followers, ko because partner are accessible to employees or partner manager - # jobs_followers_ids = self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['message_follower_ids'])['message_follower_ids'] - # self.assertRaises(except_orm, - # self.res_partner.read, - # cr, user_bert_id, jobs_followers_ids) - # # Do: Bert comments Jobs, ko because no write access on the group and not in the followers - # self.assertRaises(except_orm, - # self.mail_group.message_post, - # cr, user_bert_id, self.group_jobs_id, body='I love Pigs') - # # Do: add Bert to jobs followers - # self.mail_group.message_subscribe(cr, uid, [self.group_jobs_id], [partner_bert_id]) - # # Do: Bert comments Jobs, ok because he is now in the followers - # self.mail_group.message_post(cr, user_bert_id, self.group_jobs_id, body='I love Pigs') + # ---------------------------------------- + # CASE1: Bert, without groups + # ---------------------------------------- + # Do: Bert creates a group, should crash because perm_create only for employees + self.assertRaises(except_orm, + self.mail_group.create, + cr, user_bert_id, {'name': 'Bert\'s Group'}) + # Do: Bert reads Jobs basic fields, ok because public = read access on the group + self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['name', 'description']) + # Do: Bert browse Pigs, ok (no direct browse of partners) + self.mail_group.browse(cr, user_bert_id, self.group_jobs_id) + # Do: Bert reads Jobs messages, ok because read access on the group => read access on its messages + jobs_message_ids = self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['message_ids'])['message_ids'] + self.mail_message.read(cr, user_bert_id, jobs_message_ids) + # Do: Bert reads Jobs followers, ko because partner are accessible to employees or partner manager + jobs_followers_ids = self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['message_follower_ids'])['message_follower_ids'] + self.assertRaises(except_orm, + self.res_partner.read, + cr, user_bert_id, jobs_followers_ids) + # Do: Bert comments Jobs, ko because no write access on the group and not in the followers + self.assertRaises(except_orm, + self.mail_group.message_post, + cr, user_bert_id, self.group_jobs_id, body='I love Pigs') + # Do: add Bert to jobs followers + self.mail_group.message_subscribe(cr, uid, [self.group_jobs_id], [partner_bert_id]) + # Do: Bert comments Jobs, ok because he is now in the followers + self.mail_group.message_post(cr, user_bert_id, self.group_jobs_id, body='I love Pigs') - # # Do: Bert reads Pigs, should crash because mail.group security=groups only for employee group - # self.assertRaises(except_orm, - # self.mail_group.read, - # cr, user_bert_id, self.group_pigs_id) + # Do: Bert reads Pigs, should crash because mail.group security=groups only for employee group + self.assertRaises(except_orm, + self.mail_group.read, + cr, user_bert_id, self.group_pigs_id) - # # ---------------------------------------- - # # CASE1: Raoul, employee - # # ---------------------------------------- - # # Do: Bert read Pigs, ok because public - # self.mail_group.read(cr, user_raoul_id, self.group_pigs_id) - # # Do: Bert read Jobs, ok because group_public_id = employee - # self.mail_group.read(cr, user_raoul_id, self.group_jobs_id) + # ---------------------------------------- + # CASE1: Raoul, employee + # ---------------------------------------- + # Do: Bert read Pigs, ok because public + self.mail_group.read(cr, user_raoul_id, self.group_pigs_id) + # Do: Bert read Jobs, ok because group_public_id = employee + self.mail_group.read(cr, user_raoul_id, self.group_jobs_id) From d7a38755166bba022ec8a913e9dd733cb8776a5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 15 Oct 2012 14:03:31 +0200 Subject: [PATCH 034/116] [CLEAN] [FIX] mail_followers widget: small cleanup of code, fixed wrong display of follower button when having more than one follower. bzr revid: tde@openerp.com-20121015120331-uiv40j3d9fxqhopt --- addons/mail/static/src/css/mail.css | 8 ++-- addons/mail/static/src/js/mail_followers.js | 40 +++++++++---------- addons/mail/static/src/xml/mail_followers.xml | 10 ++--- 3 files changed, 26 insertions(+), 32 deletions(-) diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css index 1592d79e18d..0f1f90d04fb 100644 --- a/addons/mail/static/src/css/mail.css +++ b/addons/mail/static/src/css/mail.css @@ -143,12 +143,12 @@ /* subtypes /* ------------------------------------------------------------ */ -.openerp .oe_mouse_subtypes { +.openerp .oe_mail_subtypes { display:inline-block; position: relative; z-index: 5; } -.openerp .oe_mouse_subtypes .oe_recthread_subtypes { +.openerp .oe_mail_subtypes .oe_recthread_subtypes { background: #fff; padding: 2px; border: 1px solid #aaaaaa; @@ -156,10 +156,10 @@ position: absolute; z-index: 2; } -.openerp .oe_mouse_subtypes.oe_mouseout .oe_recthread_subtypes { +.openerp .oe_mail_subtypes.oe_mouseout .oe_recthread_subtypes { display: none; } -.openerp .oe_mouse_subtypes.oe_mouseover .oe_recthread_subtypes { +.openerp .oe_mail_subtypes.oe_mouseover .oe_recthread_subtypes { display: block; } diff --git a/addons/mail/static/src/js/mail_followers.js b/addons/mail/static/src/js/mail_followers.js index 236e3081136..0dd3aef5571 100644 --- a/addons/mail/static/src/js/mail_followers.js +++ b/addons/mail/static/src/js/mail_followers.js @@ -26,7 +26,6 @@ openerp_mail_followers = function(session, mail) { this._super.apply(this, arguments); this.options.image = this.node.attrs.image || 'image_small'; this.options.title = this.node.attrs.title || 'Followers'; - this.options.context = this.node.attrs.context; this.options.comment = this.node.attrs.help || false; this.ds_model = new session.web.DataSetSearch(this, this.view.model); this.sub_model = new session.web.DataSetSearch(this,'mail.message.subtype'); @@ -55,16 +54,14 @@ openerp_mail_followers = function(session, mail) { bind_events: function() { var self = this; this.$('button.oe_follower') - .on('click', function () { + .on('click', function (event) { if($(this).hasClass('oe_notfollow')) self.do_follow(); else self.do_unfollow(); }); - - this.$el.on('click', 'ul.oe_subtypes input', self.do_update_subscription ); - - this.$el.on('click', 'button.oe_invite', function(event) { + this.$('ul.oe_subtypes input').on('click', self.do_update_subscription); + this.$('button.oe_invite').on('click', function (event) { action = { type: 'ir.actions.act_window', res_model: 'mail.wizard.invite', @@ -93,23 +90,13 @@ openerp_mail_followers = function(session, mail) { return this.fetch_followers(value_ || this.get_value()); }, - set_is_follower: function(value_) { - for(var i in value_){ - if(value_[i]['user_ids'][0]==this.session.uid) - this.message_is_follower=true; - this.display_buttons(); - return true; - } - this.message_is_follower=false; - this.display_buttons(); - return false; - }, - fetch_followers: function (value_) { this.value = value_ || {}; this.message_is_follower = (this.getParent().fields.message_is_follower && this.getParent().fields.message_is_follower.get_value()); if(value_) - return this.ds_follow.call('read', [this.value, ['name', 'user_ids']]).pipe(this.proxy('display_followers'), this.proxy('display_generic')); + return this.ds_follow.call('read', [this.value, ['name', 'user_ids']]) + .pipe(this.proxy('display_followers'), this.proxy('display_generic')) + .pipe(this.proxy('display_buttons')); }, /* Display generic info about follower, for people not having access to res_partner */ @@ -125,8 +112,6 @@ openerp_mail_followers = function(session, mail) { content += ' (' + this.value.length + ')' } this.$('div.oe_mail_recthread_followers h4').html(content); - this.display_buttons(); - return $.when(); }, /** Display the followers, evaluate is_follower directly */ @@ -142,6 +127,17 @@ openerp_mail_followers = function(session, mail) { self.set_is_follower(records); }, + /** Computes whether the current user is in the followers */ + set_is_follower: function(value_) { + this.message_is_follower = false; + for(var i in value_) { + if (value_[i]['user_ids'][0] == this.session.uid) { + this.message_is_follower = true; + return true; + } + } + }, + display_buttons: function () { if (this.message_is_follower) { this.$('button.oe_follower').removeClass('oe_notfollow').addClass('oe_following'); @@ -149,7 +145,7 @@ openerp_mail_followers = function(session, mail) { else { this.$('button.oe_follower').removeClass('oe_following').addClass('oe_notfollow'); } - + if (this.view.is_action_enabled('edit')) this.$('span.oe_mail_invite_wrapper').hide(); else diff --git a/addons/mail/static/src/xml/mail_followers.xml b/addons/mail/static/src/xml/mail_followers.xml index f78c91c6305..87b49579100 100644 --- a/addons/mail/static/src/xml/mail_followers.xml +++ b/addons/mail/static/src/xml/mail_followers.xml @@ -7,7 +7,7 @@ -->
-
+
-
- -
-
-
+ +
+
From ad54dfbbf6d73e5e5509ccaa11e15762858fc1bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 15 Oct 2012 15:23:13 +0200 Subject: [PATCH 035/116] [FIX] [CLEAN] mail_thrad: fixed subtypes (not comment by default, but Chatter explicitely set the new message as a comment); some code cleaning. bzr revid: tde@openerp.com-20121015132313-zmip3v7sv4y90lzr --- addons/mail/mail_group.py | 2 +- addons/mail/mail_thread.py | 106 +++++++++++++++--------------- addons/mail/res_partner.py | 2 +- addons/mail/static/src/js/mail.js | 2 +- 4 files changed, 56 insertions(+), 56 deletions(-) diff --git a/addons/mail/mail_group.py b/addons/mail/mail_group.py index 3febe34be51..644718fdfb9 100644 --- a/addons/mail/mail_group.py +++ b/addons/mail/mail_group.py @@ -30,7 +30,7 @@ class mail_group(osv.Model): group. The group mechanics are based on the followers. """ _description = 'Discussion group' _name = 'mail.group' - _mail_autothread = False + _mail_flat_thread = False _inherit = ['mail.thread'] _inherits = {'mail.alias': 'alias_id', 'ir.ui.menu': 'menu_id'} diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index e5b93ac4000..6388ad76457 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -57,10 +57,16 @@ class mail_thread(osv.AbstractModel): to override at least the ``message_new`` and ``message_update`` methods (calling ``super``) to add model-specific behavior at creation and update of a thread when processing incoming emails. + + Options: + - _mail_flat_thread: if set to True, all messages without parent_id + are automatically attached to the first message posted on the + ressource. If set to False, the display of Chatter is done using + threads, and no parent_id is automatically set. ''' _name = 'mail.thread' _description = 'Email Thread' - _mail_autothread = True + _mail_flat_thread = True def _get_message_data(self, cr, uid, ids, name, args, context=None): """ Computes: @@ -84,7 +90,7 @@ class mail_thread(osv.AbstractModel): res[thread.id]['message_summary'] = "9 %d + %d" % (cls, len(thread.message_comment_ids), len(thread.message_follower_ids)) return res - + def _get_subscription_data(self, cr, uid, ids, name, args, context=None): """ Computes: - message_is_follower: is uid in the document followers @@ -113,7 +119,7 @@ class mail_thread(osv.AbstractModel): for subtype in fol.subtype_ids: thread_subtype_dict[subtype.name]['followed'] = True res[fol.res_id]['message_subtype_data'] = thread_subtype_dict - + return res def _search_unread(self, cr, uid, obj=None, name=None, domain=None, context=None): @@ -633,8 +639,10 @@ class mail_thread(osv.AbstractModel): (isinstance(thread_id, (list, tuple)) and len(thread_id) == 1), "Invalid thread_id" if isinstance(thread_id, (list, tuple)): thread_id = thread_id and thread_id[0] + mail_message = self.pool.get('mail.message') + model = context.get('thread_model', self._name) if thread_id else False - attachment_ids=[] + attachment_ids = [] for name, content in attachments: if isinstance(content, unicode): content = content.encode('utf-8') @@ -648,24 +656,20 @@ class mail_thread(osv.AbstractModel): } attachment_ids.append((0, 0, data_attach)) - # get subtype - if not subtype: - subtype = 'mail.mt_comment' - s = subtype.split('.') - if len(s)==1: - s = ('mail', s[0]) - ref = self.pool.get('ir.model.data').get_object_reference(cr, uid, s[0], s[1]) - subtype_id = ref and ref[1] or False - - model = context.get('thread_model', self._name) if thread_id else False - messages = self.pool.get('mail.message') - - #auto link messages for same id and object - if self._mail_autothread and thread_id: - message_ids = messages.search(cr, uid, ['&',('res_id', '=', thread_id),('model','=',model)], context=context) - if len(message_ids): - parent_id = min(message_ids) + # fetch subtype + if subtype: + s_data = subtype.split('.') + if len(s_data) == 1: + s_data = ('mail', s_data[0]) + ref = self.pool.get('ir.model.data').get_object_reference(cr, uid, s_data[0], s_data[1]) + subtype_id = ref and ref[1] or False + else: + subtype_id = False + # _mail_flat_thread: automatically set free messages to the first posted message + if self._mail_flat_thread and not parent_id and thread_id: + message_ids = mail_message.search(cr, uid, ['&', ('res_id', '=', thread_id), ('model', '=', model)], context=context, order="id ASC", limit=1) + parent_id = message_ids and message_ids[0] or False values = kwargs values.update({ @@ -681,51 +685,47 @@ class mail_thread(osv.AbstractModel): # if the parent is private, the message must be private if parent_id: - msg = messages.browse(cr, uid, parent_id, context=context) - if msg.is_private: - values["is_private"] = msg.is_private + parent_message = mail_message.browse(cr, uid, parent_id, context=context) + if parent_message.is_private: + values["is_private"] = parent_message.is_private # Avoid warnings about non-existing fields for x in ('from', 'to', 'cc'): values.pop(x, None) - return messages.create(cr, uid, values, context=context) + return mail_message.create(cr, uid, values, context=context) + + def message_post_api(self, cr, uid, thread_id, body='', subject=False, type='notification', + subtype=None, parent_id=False, attachments=None, context=None, **kwargs): + # when writing on res.partner, without specific thread_id -> redirect to the user's partner + if self._name == 'res.partner' and not thread_id: + thread_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] + new_message_id = self.message_post(cr, uid, thread_id=thread_id, body=body, subject=subject, type=type, + subtype=subtype, parent_id=parent_id, context=context) + # Chatter: attachments linked to the document (not done JS-side), load the message + if attachments: + ir_attachment = self.pool.get('ir.attachment') + mail_message = self.pool.get('mail.message') + attachment_ids = ir_attachment.search(cr, SUPERUSER_ID, [('res_model', '=', False), ('res_id', '=', False), ('user_id', '=', uid), ('id', 'in', attachments)], context=context) + if attachment_ids: + ir_attachment.write(cr, SUPERUSER_ID, attachment_ids, {'res_model': self._name, 'res_id': thread_id}, context=context) + mail_message.write(cr, SUPERUSER_ID, [new_message_id], {'attachment_ids': [(6, 0, [pid for pid in attachment_ids])]}) + new_message = self.pool.get('mail.message').message_read(cr, uid, [new_message_id]) + return new_message #------------------------------------------------------ # Followers API #------------------------------------------------------ - def message_post_api(self, cr, uid, thread_id, body='', subject=False, type='notification', - subtype=None, parent_id=False, attachments=None, context=None, **kwargs): - # if the user write on his wall - if self._name=='res.partner' and not thread_id: - user = self.pool.get('res.users').browse(cr, uid, uid, context=context) - thread_id = user.partner_id.id - - added_message_id = self.message_post(cr, uid, thread_id=thread_id, body=body, subject=subject, type=type, - subtype=subtype, parent_id=parent_id, context=context) - - attachment_ids=[] - if attachments: - ir_attachment = self.pool.get('ir.attachment') - attachment_ids = ir_attachment.search(cr, 1, [('res_model', '=', ""), ('res_id', '=', ""), ('user_id', '=', uid), ('id', 'in', attachments)], context=context) - if attachment_ids: - self.pool.get('ir.attachment').write(cr, 1, attachment_ids, { 'res_model': self._name, 'res_id': thread_id }, context=context) - self.pool.get('mail.message').write(cr, 1, [added_message_id], {'attachment_ids': [(6, 0, [pid for pid in attachment_ids])]} ) - - added_message = self.pool.get('mail.message').message_read(cr, uid, [added_message_id]) - return added_message - def get_message_subtypes(self, cr, uid, ids, context=None): - """ message_subtype_data: data about document subtypes: which are - available, which are followed if any """ + """ Wrapper to get subtypes. """ return self._get_subscription_data(cr, uid, ids, None, None, context=context) def message_subscribe_users(self, cr, uid, ids, user_ids=None, subtype_ids=None, context=None): """ Wrapper on message_subscribe, using users. If user_ids is not provided, subscribe uid instead. """ - if not user_ids: - return False + if user_ids is None: + user_ids = [uid] partner_ids = [user.partner_id.id for user in self.pool.get('res.users').browse(cr, uid, user_ids, context=context)] return self.message_subscribe(cr, uid, ids, partner_ids, subtype_ids=subtype_ids, context=context) @@ -738,14 +738,14 @@ class mail_thread(osv.AbstractModel): subtype_ids = subtype_obj.search(cr, uid, [('default', '=', True), '|', ('res_model', '=', self._name), ('res_model', '=', False)], context=context) # update the subscriptions fol_obj = self.pool.get('mail.followers') - fol_ids = fol_obj.search(cr, 1, [('res_model', '=', self._name), ('res_id', 'in', ids), ('partner_id', 'in', partner_ids)], context=context) - fol_obj.write(cr, 1, fol_ids, {'subtype_ids': [(6, 0, subtype_ids)]}, context=context) + fol_ids = fol_obj.search(cr, SUPERUSER_ID, [('res_model', '=', self._name), ('res_id', 'in', ids), ('partner_id', 'in', partner_ids)], context=context) + fol_obj.write(cr, SUPERUSER_ID, fol_ids, {'subtype_ids': [(6, 0, subtype_ids)]}, context=context) return True def message_unsubscribe_users(self, cr, uid, ids, user_ids=None, context=None): """ Wrapper on message_subscribe, using users. If user_ids is not provided, unsubscribe uid instead. """ - if not user_ids: + if user_ids is None: user_ids = [uid] partner_ids = [user.partner_id.id for user in self.pool.get('res.users').browse(cr, uid, user_ids, context=context)] return self.message_unsubscribe(cr, uid, ids, partner_ids, context=context) diff --git a/addons/mail/res_partner.py b/addons/mail/res_partner.py index 363ea74d16c..6b13fe6ad20 100644 --- a/addons/mail/res_partner.py +++ b/addons/mail/res_partner.py @@ -25,7 +25,7 @@ class res_partner_mail(osv.Model): """ Update partner to add a field about notification preferences """ _name = "res.partner" _inherit = ['res.partner', 'mail.thread'] - _mail_autothread = False + _mail_flat_thread = False _columns = { 'notification_email_send': fields.selection([ diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index 15a81be4c54..7aa8a11f62a 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -387,7 +387,7 @@ openerp.mail = function(session) { mail.ChatterUtils.get_text2html(body), false, 'comment', - false, + 'mail.mt_comment',, this.context.default_parent_id, attachments] ).then(this.parent_thread.proxy('switch_new_message')); From 55700ac6616b2fdc77caed5d0953df0a48fba4c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 15 Oct 2012 15:34:38 +0200 Subject: [PATCH 036/116] [CLEAN] get_message_subtypes -> message_get_subscription_data bzr revid: tde@openerp.com-20121015133438-oqbe24v80y0ayimn --- addons/mail/mail_thread.py | 12 +++++++++--- addons/mail/static/src/js/mail_followers.js | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 6388ad76457..cfc2992ecde 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -36,6 +36,7 @@ from tools.safe_eval import safe_eval as eval _logger = logging.getLogger(__name__) + def decode_header(message, header, separator=' '): return separator.join(map(decode, message.get_all(header, []))) @@ -404,7 +405,8 @@ class mail_thread(osv.AbstractModel): overrides the automatic detection based on the message headers. """ - if context is None: context = {} + if context is None: + context = {} # extract message bytes - we are forced to pass the message as binary because # we don't know its encoding until we parse its headers and hence can't @@ -420,7 +422,8 @@ class mail_thread(osv.AbstractModel): thread_id, custom_values, context=context) msg = self.message_parse(cr, uid, msg_txt, save_original=save_original, context=context) - if strip_attachments: msg.pop('attachments', None) + if strip_attachments: + msg.pop('attachments', None) thread_id = False for model, thread_id, custom_values, user_id in routes: if self._name != model: @@ -700,8 +703,10 @@ class mail_thread(osv.AbstractModel): # when writing on res.partner, without specific thread_id -> redirect to the user's partner if self._name == 'res.partner' and not thread_id: thread_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] + new_message_id = self.message_post(cr, uid, thread_id=thread_id, body=body, subject=subject, type=type, subtype=subtype, parent_id=parent_id, context=context) + # Chatter: attachments linked to the document (not done JS-side), load the message if attachments: ir_attachment = self.pool.get('ir.attachment') @@ -711,13 +716,14 @@ class mail_thread(osv.AbstractModel): ir_attachment.write(cr, SUPERUSER_ID, attachment_ids, {'res_model': self._name, 'res_id': thread_id}, context=context) mail_message.write(cr, SUPERUSER_ID, [new_message_id], {'attachment_ids': [(6, 0, [pid for pid in attachment_ids])]}) new_message = self.pool.get('mail.message').message_read(cr, uid, [new_message_id]) + return new_message #------------------------------------------------------ # Followers API #------------------------------------------------------ - def get_message_subtypes(self, cr, uid, ids, context=None): + def message_get_subscription_data(self, cr, uid, ids, context=None): """ Wrapper to get subtypes. """ return self._get_subscription_data(cr, uid, ids, None, None, context=context) diff --git a/addons/mail/static/src/js/mail_followers.js b/addons/mail/static/src/js/mail_followers.js index 0dd3aef5571..eff3f904b71 100644 --- a/addons/mail/static/src/js/mail_followers.js +++ b/addons/mail/static/src/js/mail_followers.js @@ -171,7 +171,7 @@ openerp_mail_followers = function(session, mail) { if(subtype_list_ul.is(":empty")) { var context = new session.web.CompoundContext(this.build_context(), {}); - this.ds_model.call('get_message_subtypes',[[self.view.datarecord.id], context]).pipe(this.proxy('set_subtypes')); + this.ds_model.call('message_get_subscription_data',[[self.view.datarecord.id], context]).pipe(this.proxy('set_subtypes')); } }, From 4525b411e91b7fed75ba3809355e65c965765d0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 15 Oct 2012 17:11:27 +0200 Subject: [PATCH 037/116] [IMP] mail.followers: users can now read their own subscriptions. bzr revid: tde@openerp.com-20121015151127-5abtwg8uraj0du0u --- addons/mail/security/ir.model.access.csv | 2 +- addons/mail/security/mail_security.xml | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/addons/mail/security/ir.model.access.csv b/addons/mail/security/ir.model.access.csv index b68a9ab7443..c609667c26e 100644 --- a/addons/mail/security/ir.model.access.csv +++ b/addons/mail/security/ir.model.access.csv @@ -3,7 +3,7 @@ access_mail_message_all,mail.message.all,model_mail_message,,1,0,1,0 access_mail_message_group_user,mail.message.group.user,model_mail_message,base.group_user,1,1,1,1 access_mail_mail_all,mail.mail.all,model_mail_mail,,0,0,1,0 access_mail_mail_system,mail.mail.system,model_mail_mail,base.group_system,1,1,1,1 -access_mail_followers_all,mail.followers.all,model_mail_followers,,0,0,0,0 +access_mail_followers_all,mail.followers.all,model_mail_followers,,1,0,0,0 access_mail_followers_system,mail.followers.system,model_mail_followers,base.group_system,1,1,1,1 access_mail_notification_all,mail.notification.all,model_mail_notification,,1,0,0,0 access_mail_notification_aystem,mail.notification.system,model_mail_notification,base.group_system,1,1,1,1 diff --git a/addons/mail/security/mail_security.xml b/addons/mail/security/mail_security.xml index be3bb667628..c8d37f333c7 100644 --- a/addons/mail/security/mail_security.xml +++ b/addons/mail/security/mail_security.xml @@ -3,13 +3,22 @@ - + Mail.group: access only public and joined groups ['|', '|', ('public', '=', 'public'), ('message_follower_ids', 'in', [user.partner_id.id]), '&', ('public','=','groups'), ('group_public_id','in', [g.id for g in user.groups_id])] + + mail.followers: read its own entries + + + [('partner_id', '=', user.partner_id.id)] + + + + From 5a6158bb5ff58ef9d2ea9540ea348fec466c1a7e Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Tue, 16 Oct 2012 11:38:34 +0200 Subject: [PATCH 040/116] [FIX] Broken Dataset#unlink bzr revid: fme@openerp.com-20121016093834-ulhdzbhvasw9msp5 --- addons/web/static/src/js/data.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index fe7632d0612..76c2eb41ec1 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -774,11 +774,11 @@ instance.web.DataSetSearch = instance.web.DataSet.extend({ if (self._length) { self._length -= 1; } - if (this.index !== null) { + if (self.index !== null) { self.index = self.index <= self.ids.length - 1 ? self.index : (self.ids.length > 0 ? self.ids.length -1 : 0); } - this.trigger("dataset_changed", ids, callback, error_callback); + self.trigger("dataset_changed", ids, callback, error_callback); }); }, size: function () { From 97cb5f4dc417f60e8f2598ea82a1fa3cc5a80383 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Tue, 16 Oct 2012 11:58:24 +0200 Subject: [PATCH 041/116] [FIX] small problems in dialog actions bzr revid: nicolas.vanhoren@openerp.com-20121016095824-woasfpauu7unye5n --- addons/web/static/src/js/chrome.js | 4 +++- addons/web/static/src/js/views.js | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index a281745faa0..54d26c5ec5b 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -70,7 +70,9 @@ instance.web.Dialog = instance.web.Widget.extend({ autoOpen: false, position: [false, 40], buttons: {}, - beforeClose: function () { self.trigger("closing") }, + beforeClose: function () { + self.trigger("closing"); + }, resizeStop: this.on_resized }; for (var f in this) { diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index 1554d347552..7cbc346b59f 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -290,13 +290,13 @@ instance.web.ActionManager = instance.web.Widget.extend({ } var widget = executor.widget(); if (executor.action.target === 'new') { - if (this.dialog === null) { + if (this.dialog === null || this.dialog.isDestroyed()) { // These buttons will be overwrited by