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)