From c077ef05575d9677bce284195683f96c68386788 Mon Sep 17 00:00:00 2001 From: "Lucas Perais (lpe)" Date: Wed, 24 Jul 2019 09:31:10 +0000 Subject: [PATCH] [FIX] base: correct branding for replaced node Have an inherited view replacing a node in its parent namely: ``` ``` Inherited by ``` ``` Before this commit, the resulting xpath branding of the nodes (useful for web_editor, to know where it is supposed to anchor new elements) was incorrect. Note that there is the branding attr data-oe-view_id which specifies in which view they are The 2nd and 3rd world in view #1 were numbered respectively world[1] and world[2] which is incorrect since we *know* those should be world[2] and world[3] (in their own view, i.e. in view #1) This was because when replacing the node, the code lost track of what it replaced and that it attributed the inheriting branding to the replacing nodes After this commit, the 2nd and 3rd world nodes are numbered world[2] and world[3] respectively OPW 2007312 closes odoo/odoo#35134 Signed-off-by: Lucas Perais (lpe) --- odoo/addons/base/models/ir_ui_view.py | 15 ++++ odoo/addons/base/tests/test_views.py | 109 ++++++++++++++++++++++++++ 2 files changed, 124 insertions(+) diff --git a/odoo/addons/base/models/ir_ui_view.py b/odoo/addons/base/models/ir_ui_view.py index b1a00d904b6f..6c2570792b24 100644 --- a/odoo/addons/base/models/ir_ui_view.py +++ b/odoo/addons/base/models/ir_ui_view.py @@ -646,9 +646,19 @@ def extract(spec): if node.getparent() is None: source = copy.deepcopy(spec[0]) else: + replaced_node_tag = None for child in spec: if child.get('position') == 'move': child = extract(child) + + if self._context.get('inherit_branding') and not replaced_node_tag and child.tag is not etree.Comment: + # To make a correct branding, we need to + # - know exactly which node has been replaced + # - store it before anything else has altered the Tree + # Do it exactly here :D + child.set('meta-oe-xpath-replacing', node.tag) + replaced_node_tag = node.tag # We just store the replaced node tag on the first child of the xpath replacing it + node.addprevious(child) node.getparent().remove(node) elif pos == 'attributes': @@ -1246,6 +1256,11 @@ def distribute_branding(self, e, branding=None, parent_xpath='', if child.get('data-oe-xpath'): # injected by view inheritance, skip otherwise # generated xpath is incorrect + # Also, if a node is known to have been replaced during applying xpath + # increment its index to compute an accurate xpath for susequent nodes + replaced_node_tag = child.attrib.pop('meta-oe-xpath-replacing', None) + if replaced_node_tag: + indexes[replaced_node_tag] += 1 self.distribute_branding(child) else: indexes[child.tag] += 1 diff --git a/odoo/addons/base/tests/test_views.py b/odoo/addons/base/tests/test_views.py index 7b8deb8ea33a..403e7f9260d4 100644 --- a/odoo/addons/base/tests/test_views.py +++ b/odoo/addons/base/tests/test_views.py @@ -674,6 +674,115 @@ def test_branding_inherit(self): second.get('data-oe-id'), "second should come from the extension view") + def test_branding_inherit_replace_node(self): + view1 = self.View.create({ + 'name': "Base view", + 'type': 'qweb', + 'arch': """ + + + + + """ + }) + self.View.create({ + 'name': "Extension", + 'type': 'qweb', + 'inherit_id': view1.id, + 'arch': """ + Is a ghetto + Wonder when I'll find paradise + + """ + }) + + arch_string = view1.with_context(inherit_branding=True).read_combined(['arch'])['arch'] + + arch = etree.fromstring(arch_string) + self.View.distribute_branding(arch) + + # First world - has been replaced by inheritance + [initial] = arch.xpath('/hello[1]/world[1]') + self.assertEqual( + '/xpath/world[1]', + initial.get('data-oe-xpath'), + 'Inherited nodes have correct xpath') + + # Second world added by inheritance + [initial] = arch.xpath('/hello[1]/world[2]') + self.assertEqual( + '/xpath/world[2]', + initial.get('data-oe-xpath'), + 'Inherited nodes have correct xpath') + + # Third world - is not editable + [initial] = arch.xpath('/hello[1]/world[3]') + self.assertFalse( + initial.get('data-oe-xpath'), + 'node containing t-esc is not branded') + + # The most important assert + # Fourth world - should have a correct oe-xpath, which is 3rd in main view + [initial] = arch.xpath('/hello[1]/world[4]') + self.assertEqual( + '/hello[1]/world[3]', + initial.get('data-oe-xpath'), + "The node's xpath position should be correct") + + def test_branding_inherit_replace_node2(self): + view1 = self.View.create({ + 'name': "Base view", + 'type': 'qweb', + 'arch': """ + + + + + """ + }) + self.View.create({ + 'name': "Extension", + 'type': 'qweb', + 'inherit_id': view1.id, + 'arch': """ + Is a ghetto + Wonder when I'll find paradise + + """ + }) + + arch_string = view1.with_context(inherit_branding=True).read_combined(['arch'])['arch'] + + arch = etree.fromstring(arch_string) + self.View.distribute_branding(arch) + + [initial] = arch.xpath('/hello[1]/war[1]') + self.assertEqual( + '/xpath/war', + initial.get('data-oe-xpath'), + 'Inherited nodes have correct xpath') + + # First world: from inheritance + [initial] = arch.xpath('/hello[1]/world[1]') + self.assertEqual( + '/xpath/world', + initial.get('data-oe-xpath'), + 'Inherited nodes have correct xpath') + + # Second world - is not editable + [initial] = arch.xpath('/hello[1]/world[2]') + self.assertFalse( + initial.get('data-oe-xpath'), + 'node containing t-esc is not branded') + + # The most important assert + # Third world - should have a correct oe-xpath, which is 3rd in main view + [initial] = arch.xpath('/hello[1]/world[3]') + self.assertEqual( + '/hello[1]/world[3]', + initial.get('data-oe-xpath'), + "The node's xpath position should be correct") + def test_branding_primary_inherit(self): view1 = self.View.create({ 'name': "Base view",