Skip to content

Commit

Permalink
[FIX] base: correct branding for replaced node
Browse files Browse the repository at this point in the history
Have an inherited view replacing a node in its parent
namely:

```
<view name="1">
<world/>
<world/>
<world/>
</view>
```

Inherited by
```
<view name="2" inherit_id="1">
<xpath expr="//world[1]" position="replace">
<world/>
</xpath>
</view>
```

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) <lpe@odoo.com>
  • Loading branch information
kebeclibre committed Aug 1, 2019
1 parent 7b1a894 commit c077ef0
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 0 deletions.
15 changes: 15 additions & 0 deletions odoo/addons/base/models/ir_ui_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -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':
Expand Down Expand Up @@ -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
Expand Down
109 changes: 109 additions & 0 deletions odoo/addons/base/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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': """<hello>
<world></world>
<world><t t-esc="hello"/></world>
<world></world>
</hello>
"""
})
self.View.create({
'name': "Extension",
'type': 'qweb',
'inherit_id': view1.id,
'arch': """<xpath expr="/hello/world[1]" position="replace">
<world>Is a ghetto</world>
<world>Wonder when I'll find paradise</world>
</xpath>
"""
})

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': """<hello>
<world></world>
<world><t t-esc="hello"/></world>
<world></world>
</hello>
"""
})
self.View.create({
'name': "Extension",
'type': 'qweb',
'inherit_id': view1.id,
'arch': """<xpath expr="/hello/world[1]" position="replace">
<war>Is a ghetto</war>
<world>Wonder when I'll find paradise</world>
</xpath>
"""
})

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",
Expand Down

0 comments on commit c077ef0

Please sign in to comment.