From 2ffcff8fa9bd58beee33170be5a11649ec282602 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 11 Sep 2014 08:38:08 +0200 Subject: [PATCH] [ADD] qweb: handling of t-att=mapping Changed render_att_att to return an iterable of pairs instead of a pair, and dispatched t-att on whether its result is a Mapping. Also changed qweb test runner so it uses ordereddict for JSON mapping in params, otherwise iteration order (and thus order of attributes in output) is unpredictable and results don't/can't match expectations (as both are strings). Note that this relies on JS implementation details wrt iteration order of mappings. Tests would probably be somewhat less brittle if rendering output was parsed to XML... if that's possible (?) --- addons/website/models/ir_qweb.py | 10 ++++++---- openerp/addons/base/ir/ir_qweb.py | 26 ++++++++++++++++---------- openerp/addons/base/tests/test_qweb.py | 5 ++++- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/addons/website/models/ir_qweb.py b/addons/website/models/ir_qweb.py index 40b85fda697..c598773c10b 100644 --- a/addons/website/models/ir_qweb.py +++ b/addons/website/models/ir_qweb.py @@ -56,11 +56,13 @@ class QWeb(orm.AbstractModel): super(QWeb, self).add_template(qcontext, name, node) def render_att_att(self, element, attribute_name, attribute_value, qwebcontext): - att, val = super(QWeb, self).render_att_att(element, attribute_name, attribute_value, qwebcontext) + URL_ATTRS = self.URL_ATTRS.get(element.tag) + is_website = request.website + for att, val in super(QWeb, self).render_att_att(element, attribute_name, attribute_value, qwebcontext): + if is_website and att == URL_ATTRS and isinstance(val, basestring): + val = qwebcontext.get('url_for')(val) + yield (att, val) - if request.website and att == self.URL_ATTRS.get(element.tag) and isinstance(val, basestring): - val = qwebcontext.get('url_for')(val) - return att, val def get_converter_for(self, field_type): return self.pool.get( diff --git a/openerp/addons/base/ir/ir_qweb.py b/openerp/addons/base/ir/ir_qweb.py index d91d4cd5d02..1508baff9d8 100644 --- a/openerp/addons/base/ir/ir_qweb.py +++ b/openerp/addons/base/ir/ir_qweb.py @@ -265,8 +265,12 @@ class QWeb(orm.AbstractModel): if attribute_name.startswith("t-"): for attribute in self._render_att: if attribute_name[2:].startswith(attribute): - att, val = self._render_att[attribute](self, element, attribute_name, attribute_value, qwebcontext) - if val: + attrs = self._render_att[attribute]( + self, element, attribute_name, attribute_value, qwebcontext) + for att, val in attrs: + if not val: continue + if not isinstance(val, str): + val = unicode(val).encode('utf-8') generated_attributes += self.render_attribute(element, att, val, qwebcontext) break else: @@ -336,14 +340,16 @@ class QWeb(orm.AbstractModel): # Attributes def render_att_att(self, element, attribute_name, attribute_value, qwebcontext): if attribute_name.startswith("t-attf-"): - att, val = attribute_name[7:], self.eval_format(attribute_value, qwebcontext) - elif attribute_name.startswith("t-att-"): - att, val = attribute_name[6:], self.eval(attribute_value, qwebcontext) - else: - att, val = self.eval_object(attribute_value, qwebcontext) - if val and not isinstance(val, str): - val = unicode(val).encode("utf8") - return att, val + return [(attribute_name[7:], self.eval_format(attribute_value, qwebcontext))] + + if attribute_name.startswith("t-att-"): + return [(attribute_name[6:], self.eval(attribute_value, qwebcontext))] + + result = self.eval_object(attribute_value, qwebcontext) + if isinstance(result, collections.Mapping): + return result.iteritems() + # assume tuple + return [result] # Tags def render_tag_raw(self, element, template_attributes, generated_attributes, qwebcontext): diff --git a/openerp/addons/base/tests/test_qweb.py b/openerp/addons/base/tests/test_qweb.py index a923a835402..9ac4388cbe2 100644 --- a/openerp/addons/base/tests/test_qweb.py +++ b/openerp/addons/base/tests/test_qweb.py @@ -4,6 +4,7 @@ import json import os.path import glob import re +import collections from lxml import etree import openerp.addons.base.ir.ir_qweb @@ -118,7 +119,9 @@ class TestQWeb(common.TransactionCase): for template in context.templates: if template.startswith('_'): continue param = doc.find('params[@id="{}"]'.format(template)) - params = {} if param is None else json.loads(param.text) + # OrderedDict to ensure JSON mappings are iterated in source order + # so output is predictable & repeatable + params = {} if param is None else json.loads(param.text, object_pairs_hook=collections.OrderedDict) ctx = context.copy() ctx.update(params)