[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:
```
<template id="a">
<div><b>hello</b></div>
</template>
```
might be rendered to someone that can edit it:
`<div data-oe-model="ir.ui.view" data-oe-id="5" data-oe-field="arch"
data-oe-xpath="/div[1]"><b>hello</b></div>`
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:
```
<template id="b">
<div>
<b>hello</b>
<div>
</template>
<template inherit_id="b">
<div position="inside">
<b>world</b>
</div>
</template>
```
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:
`<div><b data-oe-model="ir.ui.view" data-oe-id="6" data-oe-field="arch"
data-oe-xpath="/div[1]/b[1]">hello</b><b data-oe-model="ir.ui.view"
data-oe-id="7" data-oe-field="arch" data-oe-xpath="/div[1]/b[1]"><b>
world</b></div>`
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 `<div t-call="..."/>` in a view, the branding of view
should be distributed to children and not affect t-call part: this was
done for `<t t-call="..."/>` but not for `<anyothertag t-call/>`.
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
This commit is contained in:
@@ -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):
|
||||
|
||||
@@ -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': """<root>
|
||||
<item order="1"/>
|
||||
</root>
|
||||
"""
|
||||
})
|
||||
view2 = self.View.create({
|
||||
'name': "Extension",
|
||||
'type': 'qweb',
|
||||
'mode': 'primary',
|
||||
'inherit_id': view1.id,
|
||||
'arch': """<xpath expr="//item" position="after">
|
||||
<item order="2"/>
|
||||
</xpath>
|
||||
"""
|
||||
})
|
||||
|
||||
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': """<root>
|
||||
<item><span t-call="foo"/></item>
|
||||
</root>""",
|
||||
})
|
||||
|
||||
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",
|
||||
|
||||
Reference in New Issue
Block a user