Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 51 additions & 10 deletions base_view_inheritance_extension/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,43 @@ conditional changes**
$domain_to_add
</attribute>

**Wrap loose text in an element for further processing**

.. code:: xml

<wraptext expr="//some/node" position="text" element="span" />
<wraptext expr="//some/node/other_node" position="tail" element="div" />

which transforms

.. code:: xml

<some>
<node>
plain text 1
<other_node />
plain text2
</node>
</some>

to

.. code:: xml

<some>
<node>
<span>plain text 1</span>
<other_node />
<div>plain text2</div>
</node>
</some>

making those texts accessible for further operations

Known issues / Roadmap
======================

- Support an ``eval`` attribute for our new node types.
- Support an ``eval`` attribute for our new node types.

Bug Tracker
===========
Expand All @@ -102,19 +135,19 @@ Authors
Contributors
------------

- Holger Brunn <[email protected]>
- Ronald Portier <[email protected]>
- `Tecnativa <https://www.tecnativa.com>`__:
- Holger Brunn <[email protected]>
- Ronald Portier <[email protected]>
- `Tecnativa <https://www.tecnativa.com>`__:

- Sergio Teruel
- Carlos Dauden
- Sergio Teruel
- Carlos Dauden

- `Trobz <https://www.trobz.com>`__:
- `Trobz <https://www.trobz.com>`__:

- Nhan Tran <[email protected]>
- Nhan Tran <[email protected]>

- Iván Todorovich <[email protected]>
- Frederic Grall <[email protected]>
- Iván Todorovich <[email protected]>
- Frederic Grall <[email protected]>

Maintainers
-----------
Expand All @@ -129,6 +162,14 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

.. |maintainer-hbrunn| image:: https://github.com/hbrunn.png?size=40px
:target: https://github.com/hbrunn
:alt: hbrunn

Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:

|maintainer-hbrunn|

This module is part of the `OCA/server-tools <https://github.com/OCA/server-tools/tree/19.0/base_view_inheritance_extension>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
1 change: 1 addition & 0 deletions base_view_inheritance_extension/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@
"website": "https://github.com/OCA/server-tools",
"depends": ["base"],
"demo": ["demo/ir_ui_view.xml"],
"maintainers": ["hbrunn"],
}
80 changes: 80 additions & 0 deletions base_view_inheritance_extension/models/ir_ui_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from lxml import etree

from odoo import api, models
from odoo.exceptions import ValidationError
from odoo.fields import Domain


Expand Down Expand Up @@ -83,6 +84,85 @@ def _get_inheritance_handler(self, node):
handler = getattr(self, f"inheritance_handler_{node.tag}")
return handler

@api.model
def inheritance_handler_wraptext(self, source, specs):
"""Implement wraptext inheritance spec

.. code-block:: xml

<wraptext expr="//some/node" position="text" element="span" />

Which transforms xml like

.. code-block:: xml

<some>
<node>
plain text
<other_node />
</node>
</some>

to

.. code-block:: xml

<some>
<node>
<span>plain text</span>
<other_node />
</node>
</some>

"""
if len(specs):
raise ValidationError(self.env._("wraptext elements cannot have children"))

expression = specs.attrib.get("expr")
found = source.xpath(specs.attrib["expr"])
if not found:
raise ValidationError(
self.env._("wraptext: nothing found for expression %r", expression)
)

found = found[0]
text_position = specs.attrib.get("position", "text")
if text_position not in ("text", "tail"):
raise ValidationError(
self.env._("wraptext: the only valid positions are 'text' or 'tail'")
)

wrapped = etree.Element(specs.attrib.get("element", "t"))
wrapped.text = getattr(found, text_position)
setattr(found, text_position, None)

if self.env.context.get("edit_translations") and not wrapped.text:
# translation might have wrapped the text already in a <span> element
# we wrap this element so that subsequent view manipulations find
# the wrapped element at the same position in the tree it would be at
# without translation
next_sibling = found.getnext()

if (
text_position == "text"
and len(found)
and found[0].attrib.get("data-oe-translation-state")
):
wrapped.append(found[0])
elif (
text_position == "tail"
and next_sibling is not None
and next_sibling.attrib.get("data-oe-translation-state")
):
wrapped.append(next_sibling)

if text_position == "text":
found.insert(0, wrapped)
elif text_position == "tail":
found.addnext(wrapped)

return source

@api.model
def _get_inheritance_handler_attributes(self, node):
handler = super().apply_inheritance_specs
Expand Down
2 changes: 1 addition & 1 deletion base_view_inheritance_extension/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
- Holger Brunn \<<[email protected]>\>
- Holger Brunn \<<[email protected]>\>
- Ronald Portier \<<[email protected]>\>
- [Tecnativa](https://www.tecnativa.com):
- Sergio Teruel
Expand Down
33 changes: 33 additions & 0 deletions base_view_inheritance_extension/readme/USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,36 @@ conditional changes**
$domain_to_add
</attribute>
```

**Wrap loose text in an element for further processing**

``` xml
<wraptext expr="//some/node" position="text" element="span" />
<wraptext expr="//some/node/other_node" position="tail" element="div" />
```

which transforms

``` xml
<some>
<node>
plain text 1
<other_node />
plain text2
</node>
</some>
```

to

``` xml
<some>
<node>
<span>plain text 1</span>
<other_node />
<div>plain text2</div>
</node>
</some>
```

making those texts accessible for further operations
30 changes: 29 additions & 1 deletion base_view_inheritance_extension/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,32 @@ <h2><a class="toc-backref" href="#toc-entry-1">Usage</a></h2>
</span>$domain_to_add<span class="w">
</span><span class="nt">&lt;/attribute&gt;</span>
</pre>
<p><strong>Wrap loose text in an element for further processing</strong></p>
<pre class="code xml literal-block">
<span class="nt">&lt;wraptext</span><span class="w"> </span><span class="na">expr=</span><span class="s">&quot;//some/node&quot;</span><span class="w"> </span><span class="na">position=</span><span class="s">&quot;text&quot;</span><span class="w"> </span><span class="na">element=</span><span class="s">&quot;span&quot;</span><span class="w"> </span><span class="nt">/&gt;</span><span class="w">
</span><span class="nt">&lt;wraptext</span><span class="w"> </span><span class="na">expr=</span><span class="s">&quot;//some/node/other_node&quot;</span><span class="w"> </span><span class="na">position=</span><span class="s">&quot;tail&quot;</span><span class="w"> </span><span class="na">element=</span><span class="s">&quot;div&quot;</span><span class="w"> </span><span class="nt">/&gt;</span>
</pre>
<p>which transforms</p>
<pre class="code xml literal-block">
<span class="nt">&lt;some&gt;</span><span class="w">
</span><span class="nt">&lt;node&gt;</span><span class="w">
</span>plain<span class="w"> </span>text<span class="w"> </span>1<span class="w">
</span><span class="nt">&lt;other_node</span><span class="w"> </span><span class="nt">/&gt;</span><span class="w">
</span>plain<span class="w"> </span>text2<span class="w">
</span><span class="nt">&lt;/node&gt;</span><span class="w">
</span><span class="nt">&lt;/some&gt;</span>
</pre>
<p>to</p>
<pre class="code xml literal-block">
<span class="nt">&lt;some&gt;</span><span class="w">
</span><span class="nt">&lt;node&gt;</span><span class="w">
</span><span class="nt">&lt;span&gt;</span>plain<span class="w"> </span>text<span class="w"> </span>1<span class="nt">&lt;/span&gt;</span><span class="w">
</span><span class="nt">&lt;other_node</span><span class="w"> </span><span class="nt">/&gt;</span><span class="w">
</span><span class="nt">&lt;div&gt;</span>plain<span class="w"> </span>text2<span class="nt">&lt;/div&gt;</span><span class="w">
</span><span class="nt">&lt;/node&gt;</span><span class="w">
</span><span class="nt">&lt;/some&gt;</span>
</pre>
<p>making those texts accessible for further operations</p>
</div>
<div class="section" id="known-issues-roadmap">
<h2><a class="toc-backref" href="#toc-entry-2">Known issues / Roadmap</a></h2>
Expand All @@ -445,7 +471,7 @@ <h3><a class="toc-backref" href="#toc-entry-5">Authors</a></h3>
<div class="section" id="contributors">
<h3><a class="toc-backref" href="#toc-entry-6">Contributors</a></h3>
<ul class="simple">
<li>Holger Brunn &lt;<a class="reference external" href="mailto:hbrunn&#64;therp.nl">hbrunn&#64;therp.nl</a>&gt;</li>
<li>Holger Brunn &lt;<a class="reference external" href="mailto:mail&#64;hunki-enterprises.com">mail&#64;hunki-enterprises.com</a>&gt;</li>
<li>Ronald Portier &lt;<a class="reference external" href="mailto:rportier&#64;therp.nl">rportier&#64;therp.nl</a>&gt;</li>
<li><a class="reference external" href="https://www.tecnativa.com">Tecnativa</a>:<ul>
<li>Sergio Teruel</li>
Expand All @@ -469,6 +495,8 @@ <h3><a class="toc-backref" href="#toc-entry-7">Maintainers</a></h3>
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.</p>
<p>Current <a class="reference external" href="https://odoo-community.org/page/maintainer-role">maintainer</a>:</p>
<p><a class="reference external image-reference" href="https://github.com/hbrunn"><img alt="hbrunn" src="https://github.com/hbrunn.png?size=40px" /></a></p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/server-tools/tree/19.0/base_view_inheritance_extension">OCA/server-tools</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from lxml import etree

from odoo.exceptions import ValidationError
from odoo.tests.common import TransactionCase


Expand Down Expand Up @@ -222,3 +223,47 @@ def test_update_source_not_a_dict(self):
)
with self.assertRaisesRegex(TypeError, "Attribute `domain` is not a dict"):
self.env["ir.ui.view"].apply_inheritance_specs(source, specs)

def test_wraptext(self):
"""Test textwrap transformations"""
base_view = self.env["ir.ui.view"].create(
{
"type": "qweb",
"arch": "<some>"
"<node>plain text 1<other_node />plain text2</node></some>",
}
)
inherited_view = self.env["ir.ui.view"].create(
{
"type": "qweb",
"inherit_id": base_view.id,
"arch": "<data>"
'<wraptext expr="//some/node" position="text" element="span" />'
'<wraptext expr="//some/node/other_node" position="tail" '
'element="div" />'
"</data>",
}
)
self.assertEqual(
base_view.with_context(load_all_views=True).get_combined_arch(),
"<some><node><span>plain text 1</span><other_node/>"
"<div>plain text2</div></node></some>",
)
translatable_arch = base_view.with_context(
load_all_views=True, edit_translations=True
)._get_combined_arch()
self.assertTrue(
translatable_arch.xpath("//some/node/span/span[@data-oe-translation-state]")
)
self.assertTrue(
translatable_arch.xpath("//some/node/div/span[@data-oe-translation-state]")
)

with self.assertRaisesRegex(ValidationError, "children"):
inherited_view.write({"arch": "<wraptext><node /></wraptext>"})
with self.assertRaisesRegex(ValidationError, "found"):
inherited_view.write({"arch": '<wraptext expr="//not/existing" />'})
with self.assertRaisesRegex(ValidationError, "positions"):
inherited_view.write(
{"arch": '<wraptext expr="//some/node" position="other" />'}
)