From e8cb9c0e45962fc11a91fc9bc9bc5c1892525fd2 Mon Sep 17 00:00:00 2001 From: Nicolas Lempereur Date: Tue, 12 Feb 2019 15:21:48 +0000 Subject: [PATCH] [FIX] base: better branding with view inheritance To edit a view on the website, we use the branding mechanism. This mechanism adds informations to node which can be edited about how or where the change should be saved, for example: ``` ``` might be rendered to someone that can edit it: `
hello
` when something is changed: we will send the modified content, the view id (eg. 5 for view `a`) and the xpath in this view of what is replaced. If a view is overridden, there is mechanism to distribute the branding to children, for example: ``` ``` The branding can't be on the parent div that will contain other content, because the other content is in another template and should not be saved in template `b`, so this would be rendered like this: `
hello world
` This changeset fixes two issues: - if we have a primary inheriting view: the xpath are wrong in the primary inheriting view part, they are computed on the view applied on its inherit_id; the part of the inherit_id view have the primary inheriting view ID instead of inherit_id view id. - if we have `
` in a view, the branding of view should be distributed to children and not affect t-call part: this was done for `` but not for ``. The added test failed on all assertions before the change: - "test_branding_primary_inherit" would not distributed - "test_call_no_branding" would distribute branding on `t-call` opw-1937757 closes #31039 --- odoo/addons/base/models/ir_ui_view.py | 16 +++---- odoo/addons/base/tests/test_views.py | 60 +++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 7 deletions(-) diff --git a/odoo/addons/base/models/ir_ui_view.py b/odoo/addons/base/models/ir_ui_view.py index 391244cce86..b1a00d904b6 100644 --- a/odoo/addons/base/models/ir_ui_view.py +++ b/odoo/addons/base/models/ir_ui_view.py @@ -766,19 +766,20 @@ actual arch. [view_data] = root.read(fields=fields) view_arch = etree.fromstring(view_data['arch'].encode('utf-8')) if not root.inherit_id: + if self._context.get('inherit_branding'): + view_arch.attrib.update({ + 'data-oe-model': 'ir.ui.view', + 'data-oe-id': str(root.id), + 'data-oe-field': 'arch', + }) arch_tree = view_arch else: + if self._context.get('inherit_branding'): + self.inherit_branding(view_arch, root.id, root.id) parent_view = root.inherit_id.read_combined(fields=fields) arch_tree = etree.fromstring(parent_view['arch']) arch_tree = self.apply_inheritance_specs(arch_tree, view_arch, parent_view['id']) - if self._context.get('inherit_branding'): - arch_tree.attrib.update({ - 'data-oe-model': 'ir.ui.view', - 'data-oe-id': str(root.id), - 'data-oe-field': 'arch', - }) - # and apply inheritance arch = self.apply_view_inheritance(arch_tree, root.id, self.model) @@ -1196,6 +1197,7 @@ actual arch. def _contains_branded(self, node): return node.tag == 't'\ or 't-raw' in node.attrib\ + or 't-call' in node.attrib\ or any(self.is_node_branded(child) for child in node.iterdescendants()) def _pop_view_branding(self, element): diff --git a/odoo/addons/base/tests/test_views.py b/odoo/addons/base/tests/test_views.py index 461fe6277c3..7b8deb8ea33 100644 --- a/odoo/addons/base/tests/test_views.py +++ b/odoo/addons/base/tests/test_views.py @@ -674,6 +674,51 @@ class TestTemplating(ViewCase): second.get('data-oe-id'), "second should come from the extension view") + def test_branding_primary_inherit(self): + view1 = self.View.create({ + 'name': "Base view", + 'type': 'qweb', + 'arch': """ + + + """ + }) + view2 = self.View.create({ + 'name': "Extension", + 'type': 'qweb', + 'mode': 'primary', + 'inherit_id': view1.id, + 'arch': """ + + + """ + }) + + arch_string = view2.with_context(inherit_branding=True).read_combined(['arch'])['arch'] + + arch = etree.fromstring(arch_string) + self.View.distribute_branding(arch) + + [initial] = arch.xpath('//item[@order=1]') + self.assertEqual( + initial.get('data-oe-id'), + str(view1.id), + "initial should come from the root view") + self.assertEqual( + initial.get('data-oe-xpath'), + '/root[1]/item[1]', + "initial's xpath should be within the inherited view only") + + [second] = arch.xpath('//item[@order=2]') + self.assertEqual( + second.get('data-oe-id'), + str(view2.id), + "second should come from the extension view") + self.assertEqual( + second.get('data-oe-xpath'), + '/xpath/item', + "second xpath should be on the inheriting view only") + def test_branding_distribute_inner(self): """ Checks that the branding is correctly distributed within a view extension @@ -724,6 +769,21 @@ class TestTemplating(ViewCase): ) ) + def test_call_no_branding(self): + view = self.View.create({ + 'name': "Base View", + 'type': 'qweb', + 'arch': """ + + """, + }) + + arch_string = view.with_context(inherit_branding=True).read_combined(['arch'])['arch'] + arch = etree.fromstring(arch_string) + self.View.distribute_branding(arch) + + self.assertEqual(arch, E.root(E.item(E.span({'t-call': "foo"})))) + def test_esc_no_branding(self): view = self.View.create({ 'name': "Base View",