From bd2ffc1e061f1714ece6a1457478fe97b97065a8 Mon Sep 17 00:00:00 2001 From: "Kuldeep Joshi (OpenERP)" Date: Mon, 16 May 2011 15:05:00 +0530 Subject: [PATCH 01/20] [BUG/FIX] project : change the domian in Manger dashboard and remove unused context from report lp bug: https://launchpad.net/bugs/781724 fixed bzr revid: kjo@tinyerp.com-20110516093500-hv0vo6jdlyneedmz --- addons/project/board_project_manager_view.xml | 2 +- addons/project/report/project_report_view.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/project/board_project_manager_view.xml b/addons/project/board_project_manager_view.xml index 03dae91ee6d..c34b367a900 100644 --- a/addons/project/board_project_manager_view.xml +++ b/addons/project/board_project_manager_view.xml @@ -10,7 +10,7 @@ Board for project managers --> diff --git a/addons/project/report/project_report_view.xml b/addons/project/report/project_report_view.xml index 77dce617c7f..eaf0985faef 100644 --- a/addons/project/report/project_report_view.xml +++ b/addons/project/report/project_report_view.xml @@ -272,7 +272,7 @@ project.vs.hours form graph,tree - {'group_by':['project'],'group_by_no_leaf':1} + {} [('uid','=',uid),('state','=','open')] From 0910292059be449258fc251681f80334b55167db Mon Sep 17 00:00:00 2001 From: "DBR (OpenERP)" Date: Mon, 16 May 2011 17:05:55 +0530 Subject: [PATCH 02/20] [FIX] Fix the help for progression bar lp bug: https://launchpad.net/bugs/751401 fixed bzr revid: dbr@tinyerp.com-20110516113555-22pqezc5z7npxy9r --- addons/project/project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/project/project.py b/addons/project/project.py index 25dd687d803..6a262e16428 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -449,7 +449,7 @@ class task(osv.osv): 'project.task': (lambda self, cr, uid, ids, c={}: ids, ['work_ids', 'remaining_hours', 'planned_hours'], 10), 'project.task.work': (_get_task, ['hours'], 10), }), - 'progress': fields.function(_hours_get, method=True, string='Progress (%)', multi='hours', group_operator="avg", help="Computed as: Time Spent / Total Time.", + 'progress': fields.function(_hours_get, method=True, string='Progress (%)', multi='hours', group_operator="avg", help="If the task has a progress of 99.99% you should close the task if it's finished or reevaluate the time", store = { 'project.task': (lambda self, cr, uid, ids, c={}: ids, ['work_ids', 'remaining_hours', 'planned_hours','state'], 10), 'project.task.work': (_get_task, ['hours'], 10), From 50bea257acef7d4ce5a3f30110c02d74b013cd8f Mon Sep 17 00:00:00 2001 From: "Ashutosh Srivastava (Open ERP)" Date: Tue, 17 May 2011 11:26:46 +0530 Subject: [PATCH 03/20] [FIX] crm_claim : fix the claim history lp bug: https://launchpad.net/bugs/689577 fixed bzr revid: asr@tinyerp.com-20110517055646-a3ftqzj2w3rzumz8 --- addons/crm_claim/crm_claim.py | 8 ++++++++ addons/crm_claim/crm_claim_view.xml | 32 +++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/addons/crm_claim/crm_claim.py b/addons/crm_claim/crm_claim.py index b7ffe764a03..05634d564b8 100644 --- a/addons/crm_claim/crm_claim.py +++ b/addons/crm_claim/crm_claim.py @@ -32,6 +32,7 @@ CRM_CLAIM_PENDING_STATES = ( crm.AVAILABLE_STATES[4][0], # Pending ) + class crm_claim(crm.crm_case, osv.osv): """ Crm claim @@ -265,6 +266,13 @@ class crm_claim(crm.crm_case, osv.osv): crm_claim() +class res_partner(osv.osv): + + _inherit = 'res.partner' + _columns = { + 'claims_ids': fields.one2many('crm.claim', 'partner_id', 'Claims'), + } +res_partner() class crm_stage_claim(osv.osv): diff --git a/addons/crm_claim/crm_claim_view.xml b/addons/crm_claim/crm_claim_view.xml index 00d7128abcf..7972ccc4943 100644 --- a/addons/crm_claim/crm_claim_view.xml +++ b/addons/crm_claim/crm_claim_view.xml @@ -306,6 +306,38 @@ + + res.partner.crm.history.inherit1 + res.partner + form + + + + False + + + + + + res.partner.claim.info.form + res.partner + form + + 20 + + + + + + + + + + + + + + Date: Tue, 17 May 2011 14:18:53 +0530 Subject: [PATCH 04/20] [FIX] crm_claim : fix the claim history lp bug: https://launchpad.net/bugs/689577 fixed bzr revid: asr@tinyerp.com-20110517084853-hruy2sltxn9ope2o --- addons/crm_claim/crm_claim_view.xml | 52 ++++++++++++++--------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/addons/crm_claim/crm_claim_view.xml b/addons/crm_claim/crm_claim_view.xml index 7972ccc4943..ec842a2c791 100644 --- a/addons/crm_claim/crm_claim_view.xml +++ b/addons/crm_claim/crm_claim_view.xml @@ -306,37 +306,35 @@ - - res.partner.crm.history.inherit1 - res.partner - form - - - - False - - - - - - res.partner.claim.info.form - res.partner - form - + + res.partner.crm.history.inherit1 + res.partner + form + + + + False + + + + + res.partner.claim.info.form + res.partner + form + 20 - + - - - - + + + + - - + + - - - + + Date: Tue, 17 May 2011 14:00:27 +0200 Subject: [PATCH 05/20] [FIX] res_lang: when testing if there is some default value on res.partner, pass it as a list of strings, not as a string. bzr revid: vmt@openerp.com-20110517120027-cj3nfku07hx521al --- openerp/addons/base/res/res_lang.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/openerp/addons/base/res/res_lang.py b/openerp/addons/base/res/res_lang.py index 508da3c9064..600f31aead2 100644 --- a/openerp/addons/base/res/res_lang.py +++ b/openerp/addons/base/res/res_lang.py @@ -37,6 +37,15 @@ class lang(osv.osv): _disallowed_datetime_patterns.remove('%y') # this one is in fact allowed, just not good practice def install_lang(self, cr, uid, **args): + """ + + This method is called from openerp/addons/base/base_data.xml to load + some language and set it as the default for every partners. The + language is set via tools.config by the RPC 'create' method on the + 'db' object. This is a fragile solution and something else should be + found. + + """ lang = tools.config.get('lang') if not lang: return False @@ -44,7 +53,7 @@ class lang(osv.osv): ir_values_obj = self.pool.get('ir.values') if not lang_ids: lang_id = self.load_lang(cr, uid, lang) - default_value = ir_values_obj.get(cr, uid, 'default', False, 'res.partner') + default_value = ir_values_obj.get(cr, uid, 'default', False, ['res.partner']) if not default_value: ir_values_obj.set(cr, uid, 'default', False, 'lang', ['res.partner'], lang) return True From 6c7a14b61ab0acbe705f478376382643178b03de Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Tue, 17 May 2011 15:28:56 +0200 Subject: [PATCH 06/20] [FIX] Dataset#get does not honor context bzr revid: fme@openerp.com-20110517132856-9za8lqoaj959h3z7 --- addons/base/controllers/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py index 3a6405e5311..fd44f2d0448 100644 --- a/addons/base/controllers/main.py +++ b/addons/base/controllers/main.py @@ -385,7 +385,7 @@ class DataSet(openerpweb.Controller): :rtype: list """ Model = request.session.model(model) - records = Model.read(ids, fields) + records = Model.read(ids, fields, request.context) record_map = dict((record['id'], record) for record in records) From 0763b38c6e35af58eb1cf3a359f7030d80583be8 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Tue, 17 May 2011 17:59:53 +0200 Subject: [PATCH 07/20] [ADD] Add session property to openerpweb.HttpRequest bzr revid: fme@openerp.com-20110517155953-7e7a79a3nun3wzuf --- openerpweb/openerpweb.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openerpweb/openerpweb.py b/openerpweb/openerpweb.py index 19836497ef1..81a323f2b97 100644 --- a/openerpweb/openerpweb.py +++ b/openerpweb/openerpweb.py @@ -422,6 +422,8 @@ class HttpRequest(object): self.applicationsession = applicationsession self.httpsession_id = "cookieid" self.httpsession = cherrypy.session + self.context = kw.get('context', {}) + self.session = self.httpsession.setdefault(kw.get('session_id', None), OpenERPSession()) self.result = "" print "GET/POST --> %s.%s %s %r" % (controller.__class__.__name__, f.__name__, request, kw) r = f(controller, self, **kw) From e6e0d70f2b994f325137158e8d7f0d8bc6a7fc6b Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Tue, 17 May 2011 18:00:58 +0200 Subject: [PATCH 08/20] [ADD] Add binary field type image's placeholder bzr revid: fme@openerp.com-20110517160058-1ye2lma0bu20umzz --- addons/base/static/src/img/placeholder.png | Bin 0 -> 1362 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 addons/base/static/src/img/placeholder.png diff --git a/addons/base/static/src/img/placeholder.png b/addons/base/static/src/img/placeholder.png new file mode 100644 index 0000000000000000000000000000000000000000..25af75ee81514d49e225c877f3c7f726b588e44b GIT binary patch literal 1362 zcmV-Y1+DstP)v{x$HznTp(FF)lAVo?_`zJf&u|yFc7JFe=>HnuFzcrw%%RI~SvTpwa zpv?of%Y6eQOo+jR5a1YI+C2#95*s5}%l2o2**9cH?IVE9LKxmh z*mV3LjN>Tq9TU@MfJp8F8lS&<&ZX_zBCx;~fOV?dfZPD(F>y)3FgS_2eoaz?Zs4y0=z3z6{S9dxP+~%m01;hpRDE}g(D{^bUIJtg zIB){*=6aAb?1SQKKurS<7|6XxI3b9t;tJqm13LlL?=Hbb2DZ8xAOS3?`iBUOiH*^j z9MIBdG1zZL=s>OsIW<=`0Yspc!#>FbzP1yrk>Dc(on%03f(7$_M(Fy+J06_{$JW$g zwFCeQU|0Ma90vlN=dj(X+b=FJCKTd>UHS?Jk7G&%y%LA4np ztAE$vWkvuc%PcRd(^rkH2Ne$E8C)n(4F^yYTr%`srEd?XFwbES1V#Cc6ZFHlPXLZ9 zIG~UsQvi1Q51N~H1QKNVlRgK4=TXW5)FAN;uvh9pM1!3k6(fOs?DQFc zmY|#ipq%h>Gy#0gt1t+|&><`@^eNzkhWt_FxSjy^+84jBilS;PFvCE&06H5JmOl!Q z>x&!SMCR;u^%c7=dEY@^Fal(wNTw3={84yVifroopMU7uAW#lAAX`oSVGM-riM# zPUtM%n_xl%XA*$c$XVxclRy>VRag;$Nu;v4O5isRyBv7|5SObjUoH0tr|}}Z0BU-f z1P>A501#Q_48Wd(XS;g@hQE z!00w0rR#~*3d((AZBl}FBcQr7?S$p^(@wRqkzpVsS+fH)^03~Vw4&2qx%F5#Y%k6h zxr3;N&Q!yByB`tO?OV|-EbG{2%{mTd?5lyJa)*I|I6+#}P1`ngnT0MHp4!Fy{e_Vy zv+0aO=OoOACjJTjSqs)#8oIiSZb;a;MP-0sXVJJTV_zM)1|7LDW|J2-oNy&q*9XtG zNP?5+x}G1z#d>V~-m~*V@-NH}O^6S}Fya6J03~!qSaf7zbY(hYa%Ew3WdJfTF)=ML zF)cAUR4_9-H90ykFe@-IIxsM3TJq@t001R)MObuXVRU6WZEs|0W_bWIFflMKF)}SO zF;p=$Ix{djG&CzPF*-0XY)*Us0000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oe Ud2z{QJOBUy07*qoM6N<$f_D>3qyPW_ literal 0 HcmV?d00001 From f9592082325796c0b3490ce33ac9832e2157d8cc Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Tue, 17 May 2011 18:03:11 +0200 Subject: [PATCH 09/20] [FIX] Binary images are now fetched with regular http request bzr revid: fme@openerp.com-20110517160311-4bb5exoguxn3tx3a --- addons/base/controllers/main.py | 16 ++++++++++++++++ addons/base/static/src/js/chrome.js | 2 +- addons/base/static/src/js/form.js | 4 +++- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py index fd44f2d0448..62b3b6795ab 100644 --- a/addons/base/controllers/main.py +++ b/addons/base/controllers/main.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +import base64 import glob, os import pprint from xml.etree import ElementTree @@ -554,6 +555,21 @@ class FormView(View): fields_view = self.fields_view_get(req, model, view_id, 'form', toolbar=toolbar) return {'fields_view': fields_view} + @openerpweb.httprequest + def image(self, request, session_id, model, id, field): + cherrypy.response.headers['Content-Type'] = 'image/png' + Model = request.session.model(model) + try: + if not id: + res = Model.default_get([field], request.context).get(field, '') + else: + res = Model.read([id], [field], request.context)[0].get(field, '') + return base64.decodestring(res) + except: + return self.placeholder() + def placeholder(self): + return open(os.path.join(openerpweb.path_addons, 'base', 'static', 'src', 'img', 'placeholder.png'), 'rb').read() + class ListView(View): _cp_path = "/base/listview" diff --git a/addons/base/static/src/js/chrome.js b/addons/base/static/src/js/chrome.js index 2be3f28260f..b54e0fff92f 100644 --- a/addons/base/static/src/js/chrome.js +++ b/addons/base/static/src/js/chrome.js @@ -274,7 +274,7 @@ openerp.base.Session = openerp.base.BasicController.extend( /** @lends openerp.b this.session_id = false; this.module_list = []; this.module_loaded = {"base": true}; - this.context = {}; + this.context = { bin_size : true }; }, start: function() { this.session_restore(); diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index deed1c526d0..83bb4694b12 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -1188,7 +1188,9 @@ openerp.base.form.FieldImage = openerp.base.form.Field.extend({ }, set_value: function(value) { this._super.apply(this, arguments); - this.$element.find('img').show().attr('src', 'data:image/png;base64,' + this.value); + var url = '/base/formview/image?session_id=' + this.session.session_id + '&model=' + + this.view.dataset.model +'&id=' + this.view.datarecord.id + '&field=' + this.name + this.$element.find('img').show().attr('src', url); } }); From 28290faf6d2af77a62a19cd916c9a91ddcf55eaa Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Mon, 16 May 2011 12:39:56 +0530 Subject: [PATCH 10/20] [FIX] Fixed button image position, limit of list and show more every time. bzr revid: nicolas.vanhoren@openerp.com-20110516070956-63u36dkygncatr7c --- addons/base/static/src/css/base.css | 11 ++--- addons/base/static/src/js/m2o.js | 67 +++++++++++++---------------- addons/base/static/src/xml/base.xml | 4 +- 3 files changed, 38 insertions(+), 44 deletions(-) diff --git a/addons/base/static/src/css/base.css b/addons/base/static/src/css/base.css index 9b3ac6ef47c..26ea9e3df45 100644 --- a/addons/base/static/src/css/base.css +++ b/addons/base/static/src/css/base.css @@ -827,10 +827,11 @@ body.openerp { /* Many2one Autosearch */ .openerp .ui_combo { - height: 20px; - margin-right: 1px; - top: 4px; - width: 22px; + height: 19px; + top: 6px; + width: 20px; + position: relative; + margin-left: -26px; } -/* ------------- End autocomplete ------- */ +/*------------- End autocomplete ------- */ diff --git a/addons/base/static/src/js/m2o.js b/addons/base/static/src/js/m2o.js index b20eab0689e..d2e369eb8ac 100644 --- a/addons/base/static/src/js/m2o.js +++ b/addons/base/static/src/js/m2o.js @@ -7,12 +7,13 @@ openerp.base.m2o = function(openerp){ this.view_manager = view_manager this.session = session; this.element = element_id.find('input'); + this.button = element_id.find('div'); this.dataset = dataset; var cache = {}; var lastXhr; this.relation = model; - this.result_ids = [] - var self = this + this.result_ids = []; + var self = this; var $input = this.element.autocomplete({ @@ -24,10 +25,10 @@ openerp.base.m2o = function(openerp){ } //pass request to server lastXhr = self.dataset.name_search(search_val, function(obj, status, xhr){ - var result = obj.result + var result = obj.result; var values = []; if (!result.length) { - values.push({'value': 'Create...', id: 'create'}) + values.push({'value': 'Create...', id: 'create', orig_val: ''}); } $.each(result, function(i, val){ @@ -36,14 +37,13 @@ openerp.base.m2o = function(openerp){ id: val[0], orig_val: val[1] }); - self.result_ids.push(result[i][0]) + self.result_ids.push(result[i][0]); }); - if (values.length > 10) { - values = values.slice(0, 10); - values.push({'value': 'More...', id: 'more'}) + if (values.length > 7) { + values = values.slice(0, 7); } - //process response + values.push({'value': 'More...', id: 'more', orig_val:''}); cache[search_val] = values; response(values); }); @@ -51,19 +51,19 @@ openerp.base.m2o = function(openerp){ }, select: function(event, ui){ - ui.item.value = ui.item.orig_val? ui.item.orig_val : self.element.data( "autocomplete" ).term + ui.item.value = ui.item.orig_val? ui.item.orig_val : self.element.data( "autocomplete" ).term; if (ui.item.id == 'more') { self.dataset.ids = self.result_ids; self.dataset.count = self.dataset.ids.length; - self.dataset.domain = [] - self.element.val('') + self.dataset.domain = []; + self.element.val(''); var pop = new openerp.base.form.Many2XSelectPopup(null, self.session); pop.select_element(self.relation, self.dataset); return; } if (ui.item.id == 'create') { - var val = self.element.val() + var val = self.element.val(); self.dataset.create({'name': ui.item.value}, function(r){}, function(r){ var element_id = _.uniqueId("act_window_dialog"); @@ -73,7 +73,7 @@ openerp.base.m2o = function(openerp){ modal: true, minWidth: 800 }); - self.element.val('') + self.element.val(''); var event_form = new openerp.base.FormView(self.view_manager, self.session, element_id, self.dataset, false); event_form.start(); }); @@ -89,33 +89,26 @@ openerp.base.m2o = function(openerp){ if (ui.item.id == ('create')) { return true; } - ui.item.value = self.element.data("autocomplete").term.length ? self.element.val() + '[' + ui.item.orig_val.substring(self.element.data("autocomplete").term.length) + ']' : this.lastSearch + ui.item.value = self.element.data("autocomplete").term.length ? self.element.val() + '[' + ui.item.orig_val.substring(self.element.data("autocomplete").term.length) + ']' : this.lastSearch; }, }); - $("
 
") - .attr("tabIndex", -1) - .attr("title", "Show All Items") - .insertAfter($input) - .button({ - icons: { - primary: "ui-icon-triangle-1-s" - }, - text: false - }) - .removeClass("ui-corner-all") - .addClass("ui-corner-right ui-button-icon") - .click(function() { - // close if already visible - if ($input.autocomplete("widget").is(":visible")) { - $input.autocomplete( "close" ); - return; - } - $(this).blur(); - $input.autocomplete("search", "" ); - $input.focus(); - }); + this.button.button({ + icons: { + primary: "ui-icon-triangle-1-s"}, + text: false + }) + .click(function() { + // close if already visible + if ($input.autocomplete("widget").is(":visible")) { + $input.autocomplete( "close" ); + return; + } + $(this).blur(); + $input.autocomplete("search", "" ); + $input.focus(); + }); } }); } \ No newline at end of file diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index 856db3cedbd..141d8665d22 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -350,9 +350,9 @@ t-att-name="widget.name" t-att-id="widget.element_id + '_field'" t-att-class="'field_' + widget.type" - t-att-type="widget.type" + t-att-type="widget.type" style="width: 100%;"/> - +
From f39eea6a79179a780c058928083f1bd7a6d8fb93 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Mon, 16 May 2011 16:32:42 +0530 Subject: [PATCH 11/20] [FIX] Open popup with selected ids for more. bzr revid: nicolas.vanhoren@openerp.com-20110516110242-yxhdxhabobuid83u --- addons/base/static/src/js/form.js | 7 +++++-- addons/base/static/src/js/m2o.js | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index 83bb4694b12..05c642acd34 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -1086,8 +1086,9 @@ openerp.base.form.Many2ManyListView = openerp.base.ListView.extend({ openerp.base.form.Many2XSelectPopup = openerp.base.BaseWidget.extend({ identifier_prefix: "many2xselectpopup", template: "Many2XSelectPopup", - select_element: function(model) { + select_element: function(model, dataset) { this.model = model; + this.dataset = dataset var html = this.render(); jQuery(html).dialog({title: '', modal: true, @@ -1096,7 +1097,9 @@ openerp.base.form.Many2XSelectPopup = openerp.base.BaseWidget.extend({ }, start: function() { this._super(); - this.dataset = new openerp.base.DataSetSearch(this.session, this.model); + if (!this.dataset) { + this.dataset = new openerp.base.DataSetSearch(this.session, this.model); + } this.setup_search_view(); }, setup_search_view: function() { diff --git a/addons/base/static/src/js/m2o.js b/addons/base/static/src/js/m2o.js index d2e369eb8ac..84eb3ea2036 100644 --- a/addons/base/static/src/js/m2o.js +++ b/addons/base/static/src/js/m2o.js @@ -55,7 +55,7 @@ openerp.base.m2o = function(openerp){ if (ui.item.id == 'more') { self.dataset.ids = self.result_ids; self.dataset.count = self.dataset.ids.length; - self.dataset.domain = []; + self.dataset.domain = self.result_ids.length ? [["id", "in", self.dataset.ids]] : [] self.element.val(''); var pop = new openerp.base.form.Many2XSelectPopup(null, self.session); pop.select_element(self.relation, self.dataset); From fba3f1bfc7315bdd13eb105769b8ef0ecdd72518 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 17 May 2011 11:35:03 +0200 Subject: [PATCH 12/20] [IMP] better use underscore methods, don't subscript a 1-character string to get its first character (that's an identity function) bzr revid: xmo@openerp.com-20110517093503-9kb6newmr7q30z4f --- addons/base/static/src/js/form.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index dc631c1256a..deed1c526d0 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -321,7 +321,7 @@ openerp.base.form.compute_domain = function(expr, fields) { var ex = expr[i]; if (ex.length == 1) { var top = stack.pop(); - switch (ex[0]) { + switch (ex) { case '|': stack.push(stack.pop() || top); continue; @@ -332,7 +332,7 @@ openerp.base.form.compute_domain = function(expr, fields) { stack.push(!top); continue; default: - throw new Error('Unknown domain operator ' + ex[0]); + throw new Error('Unknown domain operator ' + ex); } } @@ -362,17 +362,17 @@ openerp.base.form.compute_domain = function(expr, fields) { stack.push(field >= val); break; case 'in': - stack.push(_.indexOf(val, field) > -1); + stack.push(_(val).contains(field)); break; case 'not in': - stack.push(_.indexOf(val, field) == -1); + stack.push(!_(val).contains(field)); break; default: this.log("Unsupported operator in attrs :", op); } } - return _.indexOf(stack, false) == -1; -} + return _.all(stack); +}; openerp.base.form.Widget = openerp.base.Controller.extend({ init: function(view, node) { From a6568345163fbcbd6f0e563952b976c47cc087a8 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 17 May 2011 11:59:23 +0200 Subject: [PATCH 13/20] [IMP] add ability to return a different object (than 'this') from Class.init, for factory-type scenarios bzr revid: xmo@openerp.com-20110517095923-8lr1pjelf94nwu44 --- addons/base/static/src/js/base.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/addons/base/static/src/js/base.js b/addons/base/static/src/js/base.js index 19d608e0260..7ee9c947d1e 100644 --- a/addons/base/static/src/js/base.js +++ b/addons/base/static/src/js/base.js @@ -44,8 +44,11 @@ // The dummy class constructor function Class() { // All construction is actually done in the init method - if ( !initializing && this.init ) - this.init.apply(this, arguments); + if ( !initializing && this.init ) { + var ret = this.init.apply(this, arguments); + if (ret) { return ret; } + } + return this; } // Populate our constructed prototype object From bdd3a72499ca6daf6cea4fda53c2ce301cc103fd Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Tue, 17 May 2011 12:46:28 +0200 Subject: [PATCH 14/20] [FIX] Fixed infinite loop under Internet Explorer 8 bzr revid: fme@openerp.com-20110517104628-xtjcqeb0n8y1fa43 --- addons/base/static/lib/qweb/qweb2.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/addons/base/static/lib/qweb/qweb2.js b/addons/base/static/lib/qweb/qweb2.js index b37a38e9c38..e113ddc7c80 100644 --- a/addons/base/static/lib/qweb/qweb2.js +++ b/addons/base/static/lib/qweb/qweb2.js @@ -1,4 +1,5 @@ // TODO: trim support +// TODO: line number -> https://bugzilla.mozilla.org/show_bug.cgi?id=618650 var QWeb2 = { expressions_cache: {}, reserved_words: 'true,false,NaN,null,undefined,debugger,in,instanceof,new,function,return,this,typeof,eval,Math,RegExp,Array,Object'.split(','), @@ -295,8 +296,7 @@ QWeb2.Engine = (function() { compile : function(node) { var e = new QWeb2.Element(this, node); var template = node.getAttribute(this.prefix + '-name'); - return "(function(dict) {\n" + - " /* 'this' refers to Qweb2.Engine instance */\n" + + return " /* 'this' refers to Qweb2.Engine instance */\n" + " var context = { engine : this, template : " + (this.tools.js_escape(template)) + " };\n" + " dict = dict || {};\n" + " dict['__template__'] = '" + template + "';\n" + @@ -306,8 +306,7 @@ QWeb2.Engine = (function() { " /* END OF TEMPLATE */ } catch(error) {\n" + " context.engine.tools.exception('Runtime Error: ' + error, context);\n" + " }\n" + - " return r.join('');\n" + - "});"; + " return r.join('');"; }, render : function(template, dict) { if (this.debug && window['console'] !== undefined) { @@ -332,12 +331,16 @@ QWeb2.Engine = (function() { } var code = this.compile(this.templates[template]), tcompiled; try { - // tcompiled = new Function(code); TODO: Check if could use this in order to avoid eval - tcompiled = eval(code); + tcompiled = new Function(['dict'], code); } catch (error) { - console.log(code); + if (this.debug && window.console) { + console.log(code); + } this.tools.exception("Error evaluating template: " + error, { template: name }); } + if (!tcompiled) { + this.tools.exception("Error evaluating template: (IE?)" + error, { template: name }); + } this.compiled_templates[template] = tcompiled; return this.render(template, dict); } else { From 368690174e9a87727083e6161a369d2e083cd291 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Tue, 17 May 2011 13:47:39 +0200 Subject: [PATCH 15/20] [FIX] some IE7 javascript bugs bzr revid: nicolas.vanhoren@openerp.com-20110517114739-jbxrpskqvkw8xrx8 --- addons/base/static/lib/json/json2.js | 480 +++++++++++++++++++++++++++ addons/base/static/src/base.html | 1 + addons/base/static/src/js/data.js | 2 +- addons/base/static/src/js/form.js | 2 +- addons/base/static/src/js/m2o.js | 4 +- 5 files changed, 485 insertions(+), 4 deletions(-) create mode 100755 addons/base/static/lib/json/json2.js diff --git a/addons/base/static/lib/json/json2.js b/addons/base/static/lib/json/json2.js new file mode 100755 index 00000000000..b4c02d3f08b --- /dev/null +++ b/addons/base/static/lib/json/json2.js @@ -0,0 +1,480 @@ +/* + http://www.JSON.org/json2.js + 2011-02-23 + + Public Domain. + + NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. + + See http://www.JSON.org/js.html + + + This code should be minified before deployment. + See http://javascript.crockford.com/jsmin.html + + USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO + NOT CONTROL. + + + This file creates a global JSON object containing two methods: stringify + and parse. + + JSON.stringify(value, replacer, space) + value any JavaScript value, usually an object or array. + + replacer an optional parameter that determines how object + values are stringified for objects. It can be a + function or an array of strings. + + space an optional parameter that specifies the indentation + of nested structures. If it is omitted, the text will + be packed without extra whitespace. If it is a number, + it will specify the number of spaces to indent at each + level. If it is a string (such as '\t' or ' '), + it contains the characters used to indent at each level. + + This method produces a JSON text from a JavaScript value. + + When an object value is found, if the object contains a toJSON + method, its toJSON method will be called and the result will be + stringified. A toJSON method does not serialize: it returns the + value represented by the name/value pair that should be serialized, + or undefined if nothing should be serialized. The toJSON method + will be passed the key associated with the value, and this will be + bound to the value + + For example, this would serialize Dates as ISO strings. + + Date.prototype.toJSON = function (key) { + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + return this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z'; + }; + + You can provide an optional replacer method. It will be passed the + key and value of each member, with this bound to the containing + object. The value that is returned from your method will be + serialized. If your method returns undefined, then the member will + be excluded from the serialization. + + If the replacer parameter is an array of strings, then it will be + used to select the members to be serialized. It filters the results + such that only members with keys listed in the replacer array are + stringified. + + Values that do not have JSON representations, such as undefined or + functions, will not be serialized. Such values in objects will be + dropped; in arrays they will be replaced with null. You can use + a replacer function to replace those with JSON values. + JSON.stringify(undefined) returns undefined. + + The optional space parameter produces a stringification of the + value that is filled with line breaks and indentation to make it + easier to read. + + If the space parameter is a non-empty string, then that string will + be used for indentation. If the space parameter is a number, then + the indentation will be that many spaces. + + Example: + + text = JSON.stringify(['e', {pluribus: 'unum'}]); + // text is '["e",{"pluribus":"unum"}]' + + + text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); + // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' + + text = JSON.stringify([new Date()], function (key, value) { + return this[key] instanceof Date ? + 'Date(' + this[key] + ')' : value; + }); + // text is '["Date(---current time---)"]' + + + JSON.parse(text, reviver) + This method parses a JSON text to produce an object or array. + It can throw a SyntaxError exception. + + The optional reviver parameter is a function that can filter and + transform the results. It receives each of the keys and values, + and its return value is used instead of the original value. + If it returns what it received, then the structure is not modified. + If it returns undefined then the member is deleted. + + Example: + + // Parse the text. Values that look like ISO date strings will + // be converted to Date objects. + + myData = JSON.parse(text, function (key, value) { + var a; + if (typeof value === 'string') { + a = +/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); + if (a) { + return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], + +a[5], +a[6])); + } + } + return value; + }); + + myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { + var d; + if (typeof value === 'string' && + value.slice(0, 5) === 'Date(' && + value.slice(-1) === ')') { + d = new Date(value.slice(5, -1)); + if (d) { + return d; + } + } + return value; + }); + + + This is a reference implementation. You are free to copy, modify, or + redistribute. +*/ + +/*jslint evil: true, strict: false, regexp: false */ + +/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, + call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, + getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, + lastIndex, length, parse, prototype, push, replace, slice, stringify, + test, toJSON, toString, valueOf +*/ + + +// Create a JSON object only if one does not already exist. We create the +// methods in a closure to avoid creating global variables. + +var JSON; +if (!JSON) { + JSON = {}; +} + +(function () { + "use strict"; + + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + if (typeof Date.prototype.toJSON !== 'function') { + + Date.prototype.toJSON = function (key) { + + return isFinite(this.valueOf()) ? + this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z' : null; + }; + + String.prototype.toJSON = + Number.prototype.toJSON = + Boolean.prototype.toJSON = function (key) { + return this.valueOf(); + }; + } + + var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + gap, + indent, + meta = { // table of character substitutions + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"' : '\\"', + '\\': '\\\\' + }, + rep; + + + function quote(string) { + +// If the string contains no control characters, no quote characters, and no +// backslash characters, then we can safely slap some quotes around it. +// Otherwise we must also replace the offending characters with safe escape +// sequences. + + escapable.lastIndex = 0; + return escapable.test(string) ? '"' + string.replace(escapable, function (a) { + var c = meta[a]; + return typeof c === 'string' ? c : + '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }) + '"' : '"' + string + '"'; + } + + + function str(key, holder) { + +// Produce a string from holder[key]. + + var i, // The loop counter. + k, // The member key. + v, // The member value. + length, + mind = gap, + partial, + value = holder[key]; + +// If the value has a toJSON method, call it to obtain a replacement value. + + if (value && typeof value === 'object' && + typeof value.toJSON === 'function') { + value = value.toJSON(key); + } + +// If we were called with a replacer function, then call the replacer to +// obtain a replacement value. + + if (typeof rep === 'function') { + value = rep.call(holder, key, value); + } + +// What happens next depends on the value's type. + + switch (typeof value) { + case 'string': + return quote(value); + + case 'number': + +// JSON numbers must be finite. Encode non-finite numbers as null. + + return isFinite(value) ? String(value) : 'null'; + + case 'boolean': + case 'null': + +// If the value is a boolean or null, convert it to a string. Note: +// typeof null does not produce 'null'. The case is included here in +// the remote chance that this gets fixed someday. + + return String(value); + +// If the type is 'object', we might be dealing with an object or an array or +// null. + + case 'object': + +// Due to a specification blunder in ECMAScript, typeof null is 'object', +// so watch out for that case. + + if (!value) { + return 'null'; + } + +// Make an array to hold the partial results of stringifying this object value. + + gap += indent; + partial = []; + +// Is the value an array? + + if (Object.prototype.toString.apply(value) === '[object Array]') { + +// The value is an array. Stringify every element. Use null as a placeholder +// for non-JSON values. + + length = value.length; + for (i = 0; i < length; i += 1) { + partial[i] = str(i, value) || 'null'; + } + +// Join all of the elements together, separated with commas, and wrap them in +// brackets. + + v = partial.length === 0 ? '[]' : gap ? + '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' : + '[' + partial.join(',') + ']'; + gap = mind; + return v; + } + +// If the replacer is an array, use it to select the members to be stringified. + + if (rep && typeof rep === 'object') { + length = rep.length; + for (i = 0; i < length; i += 1) { + if (typeof rep[i] === 'string') { + k = rep[i]; + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } else { + +// Otherwise, iterate through all of the keys in the object. + + for (k in value) { + if (Object.prototype.hasOwnProperty.call(value, k)) { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } + +// Join all of the member texts together, separated with commas, +// and wrap them in braces. + + v = partial.length === 0 ? '{}' : gap ? + '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' : + '{' + partial.join(',') + '}'; + gap = mind; + return v; + } + } + +// If the JSON object does not yet have a stringify method, give it one. + + if (typeof JSON.stringify !== 'function') { + JSON.stringify = function (value, replacer, space) { + +// The stringify method takes a value and an optional replacer, and an optional +// space parameter, and returns a JSON text. The replacer can be a function +// that can replace values, or an array of strings that will select the keys. +// A default replacer method can be provided. Use of the space parameter can +// produce text that is more easily readable. + + var i; + gap = ''; + indent = ''; + +// If the space parameter is a number, make an indent string containing that +// many spaces. + + if (typeof space === 'number') { + for (i = 0; i < space; i += 1) { + indent += ' '; + } + +// If the space parameter is a string, it will be used as the indent string. + + } else if (typeof space === 'string') { + indent = space; + } + +// If there is a replacer, it must be a function or an array. +// Otherwise, throw an error. + + rep = replacer; + if (replacer && typeof replacer !== 'function' && + (typeof replacer !== 'object' || + typeof replacer.length !== 'number')) { + throw new Error('JSON.stringify'); + } + +// Make a fake root object containing our value under the key of ''. +// Return the result of stringifying the value. + + return str('', {'': value}); + }; + } + + +// If the JSON object does not yet have a parse method, give it one. + + if (typeof JSON.parse !== 'function') { + JSON.parse = function (text, reviver) { + +// The parse method takes a text and an optional reviver function, and returns +// a JavaScript value if the text is a valid JSON text. + + var j; + + function walk(holder, key) { + +// The walk method is used to recursively walk the resulting structure so +// that modifications can be made. + + var k, v, value = holder[key]; + if (value && typeof value === 'object') { + for (k in value) { + if (Object.prototype.hasOwnProperty.call(value, k)) { + v = walk(value, k); + if (v !== undefined) { + value[k] = v; + } else { + delete value[k]; + } + } + } + } + return reviver.call(holder, key, value); + } + + +// Parsing happens in four stages. In the first stage, we replace certain +// Unicode characters with escape sequences. JavaScript handles many characters +// incorrectly, either silently deleting them, or treating them as line endings. + + text = String(text); + cx.lastIndex = 0; + if (cx.test(text)) { + text = text.replace(cx, function (a) { + return '\\u' + + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }); + } + +// In the second stage, we run the text against regular expressions that look +// for non-JSON patterns. We are especially concerned with '()' and 'new' +// because they can cause invocation, and '=' because it can cause mutation. +// But just to be safe, we want to reject all unexpected forms. + +// We split the second stage into 4 regexp operations in order to work around +// crippling inefficiencies in IE's and Safari's regexp engines. First we +// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we +// replace all simple value tokens with ']' characters. Third, we delete all +// open brackets that follow a colon or comma or that begin the text. Finally, +// we look to see that the remaining characters are only whitespace or ']' or +// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. + + if (/^[\],:{}\s]*$/ + .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@') + .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') + .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { + +// In the third stage we use the eval function to compile the text into a +// JavaScript structure. The '{' operator is subject to a syntactic ambiguity +// in JavaScript: it can begin a block or an object literal. We wrap the text +// in parens to eliminate the ambiguity. + + j = eval('(' + text + ')'); + +// In the optional fourth stage, we recursively walk the new structure, passing +// each name/value pair to a reviver function for possible transformation. + + return typeof reviver === 'function' ? + walk({'': j}, '') : j; + } + +// If the text is not JSON parseable, then a SyntaxError is thrown. + + throw new SyntaxError('JSON.parse'); + }; + } +}()); diff --git a/addons/base/static/src/base.html b/addons/base/static/src/base.html index 39909413397..c18860dcd15 100644 --- a/addons/base/static/src/base.html +++ b/addons/base/static/src/base.html @@ -20,6 +20,7 @@ + diff --git a/addons/base/static/src/js/data.js b/addons/base/static/src/js/data.js index 95c09ef483f..e41fb95308b 100644 --- a/addons/base/static/src/js/data.js +++ b/addons/base/static/src/js/data.js @@ -351,7 +351,7 @@ openerp.base.DataSetMany2Many = openerp.base.DataSetStatic.extend({ unlink: function(ids) { // just do nothing - }, + } }); }; diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index deed1c526d0..8172278b5b9 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -891,7 +891,7 @@ openerp.base.form.FieldMany2OneDatasSet = openerp.base.DataSetStatic.extend({ }, write: function (id, data, callback) { this._super(id, data, callback); - }, + } }); openerp.base.form.FieldMany2OneViewManager = openerp.base.ViewManager.extend({ diff --git a/addons/base/static/src/js/m2o.js b/addons/base/static/src/js/m2o.js index b20eab0689e..2dd311a02b6 100644 --- a/addons/base/static/src/js/m2o.js +++ b/addons/base/static/src/js/m2o.js @@ -90,7 +90,7 @@ openerp.base.m2o = function(openerp){ return true; } ui.item.value = self.element.data("autocomplete").term.length ? self.element.val() + '[' + ui.item.orig_val.substring(self.element.data("autocomplete").term.length) + ']' : this.lastSearch - }, + } }); @@ -118,4 +118,4 @@ openerp.base.m2o = function(openerp){ }); } }); -} \ No newline at end of file +} From 9255a66a8f9c11f56c0a464500d5c614bad0e917 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Tue, 17 May 2011 17:47:16 +0200 Subject: [PATCH 16/20] [FIX] Replaced ul/li in menu by table to support IE7. bzr revid: nicolas.vanhoren@openerp.com-20110517154716-xvvzi29o0ejvgj85 --- addons/base/static/src/css/base.css | 37 +++++++++-------------------- addons/base/static/src/xml/base.xml | 18 ++++++++------ 2 files changed, 22 insertions(+), 33 deletions(-) diff --git a/addons/base/static/src/css/base.css b/addons/base/static/src/css/base.css index 9b3ac6ef47c..b09c9d7a161 100644 --- a/addons/base/static/src/css/base.css +++ b/addons/base/static/src/css/base.css @@ -99,36 +99,21 @@ body.openerp { white-space: nowrap; background: url(../img/menu-bg.png) repeat-x; } -.openerp .menu ul { - margin: 0; - padding: 0; - list-style: none; - overflow: hidden; - position: absolute; - left: 0; - right: 0; - text-align: center; -} -.openerp .menu li { - display: -moz-inline-stack; - display: inline; /*IE7 */ - display: inline-block; - margin: 6px 1px; - text-align: center; - text-transform: uppercase; -} .openerp .menu a { display: block; - float: left; padding: 0 0 0 3px; background: url(../img/menu-item.png) no-repeat; color: #eee; text-shadow: #222 0 1px 0; text-decoration: none; + + text-align: center; + text-transform: uppercase; + margin: 3px 1px; + height: 23px; } .openerp .menu span { display: block; - float: left; min-width: 60px; height: 23px; padding: 0 9px 0 6px; @@ -137,15 +122,15 @@ body.openerp { font-weight: bold; font-size: 85%; } -.openerp .menu ul li a:hover, -.openerp .menu li a:focus, -.openerp .menu ul li a.active { +.openerp .menu a:hover, +.openerp .menu a:focus, +.openerp .menu a.active { background-position: 0 -23px; color: #fff; } -.openerp .menu ul li a:hover span, -.openerp .menu ul li a:focus span, -.openerp .menu ul li a.active span { +.openerp .menu a:hover span, +.openerp .menu a:focus span, +.openerp .menu a.active span { background-position: 100% -23px; } /* Secondary Menu */ diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index 856db3cedbd..0021f1f0db2 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -85,13 +85,17 @@
- + + + + + + +
+ + + +