diff --git a/base_view_inheritance_extension/README.rst b/base_view_inheritance_extension/README.rst index cc221b627e6..81f45a0c1ab 100644 --- a/base_view_inheritance_extension/README.rst +++ b/base_view_inheritance_extension/README.rst @@ -87,6 +87,39 @@ to refer to some xmlid, say ``%(xmlid)s``. $domain_to_add_to_attrs_key +**Wrap loose text in an element for further processing** + +.. code-block:: xml + + + + +which transforms + +.. code-block:: xml + + + + plain text 1 + + plain text2 + + + +to + +.. code-block:: xml + + + + plain text 1 + +
plain text2
+
+
+ +making those texts accessible for further operations + Known issues / Roadmap ====================== @@ -113,7 +146,7 @@ Authors Contributors ~~~~~~~~~~~~ -* Holger Brunn +* Holger Brunn * Ronald Portier * `Tecnativa `_: @@ -136,6 +169,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 `__: + +|maintainer-hbrunn| + This module is part of the `OCA/server-tools `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/base_view_inheritance_extension/__manifest__.py b/base_view_inheritance_extension/__manifest__.py index d43ebb21a79..818d6acb0a2 100644 --- a/base_view_inheritance_extension/__manifest__.py +++ b/base_view_inheritance_extension/__manifest__.py @@ -13,4 +13,5 @@ "depends": ["base"], "external_dependencies": {"python": ["astor"]}, "demo": ["demo/ir_ui_view.xml"], + "maintainers": ["hbrunn"], } diff --git a/base_view_inheritance_extension/models/ir_ui_view.py b/base_view_inheritance_extension/models/ir_ui_view.py index 21adc2e2562..6a5c3fb04b4 100644 --- a/base_view_inheritance_extension/models/ir_ui_view.py +++ b/base_view_inheritance_extension/models/ir_ui_view.py @@ -10,7 +10,8 @@ import astor from lxml import etree -from odoo import api, models +from odoo import _, api, models +from odoo.exceptions import ValidationError from odoo.osv import expression @@ -88,6 +89,85 @@ def _get_inheritance_handler(self, node): handler = getattr(self, "inheritance_handler_%s" % node.tag) return handler + @api.model + def inheritance_handler_wraptext(self, source, specs): + """Implement wraptext inheritance spec + + .. code-block:: xml + + + + Which transforms xml like + + .. code-block:: xml + + + + plain text + + + + + to + + .. code-block:: xml + + + + plain text + + + + + """ + if len(specs): + raise ValidationError(_("wraptext elements cannot have children")) + + expression = specs.attrib.get("expr") + found = source.xpath(specs.attrib["expr"]) + if not found: + raise ValidationError( + _("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( + _("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 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 diff --git a/base_view_inheritance_extension/readme/CONTRIBUTORS.rst b/base_view_inheritance_extension/readme/CONTRIBUTORS.rst index be310677228..b14edbc322c 100644 --- a/base_view_inheritance_extension/readme/CONTRIBUTORS.rst +++ b/base_view_inheritance_extension/readme/CONTRIBUTORS.rst @@ -1,4 +1,4 @@ -* Holger Brunn +* Holger Brunn * Ronald Portier * `Tecnativa `_: diff --git a/base_view_inheritance_extension/readme/USAGE.rst b/base_view_inheritance_extension/readme/USAGE.rst index f3661517a58..e96f19b3d47 100644 --- a/base_view_inheritance_extension/readme/USAGE.rst +++ b/base_view_inheritance_extension/readme/USAGE.rst @@ -40,3 +40,36 @@ to refer to some xmlid, say ``%(xmlid)s``. key="$attrs_key" join_operator="OR"> $domain_to_add_to_attrs_key + +**Wrap loose text in an element for further processing** + +.. code-block:: xml + + + + +which transforms + +.. code-block:: xml + + + + plain text 1 + + plain text2 + + + +to + +.. code-block:: xml + + + + plain text 1 + +
plain text2
+
+
+ +making those texts accessible for further operations diff --git a/base_view_inheritance_extension/static/description/index.html b/base_view_inheritance_extension/static/description/index.html index 932857a16d2..96069319c5d 100644 --- a/base_view_inheritance_extension/static/description/index.html +++ b/base_view_inheritance_extension/static/description/index.html @@ -425,6 +425,32 @@

Usage

$domain_to_add_to_attrs_key </attribute> +

Wrap loose text in an element for further processing

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

which transforms

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

to

+
+<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

@@ -451,7 +477,7 @@

Authors

Contributors

diff --git a/base_view_inheritance_extension/tests/test_base_view_inheritance_extension.py b/base_view_inheritance_extension/tests/test_base_view_inheritance_extension.py index 335ab67fb21..f2d4472b9ad 100644 --- a/base_view_inheritance_extension/tests/test_base_view_inheritance_extension.py +++ b/base_view_inheritance_extension/tests/test_base_view_inheritance_extension.py @@ -5,6 +5,7 @@ from lxml import etree +from odoo.exceptions import ValidationError from odoo.tests.common import TransactionCase @@ -307,3 +308,45 @@ def test_attrs_domain_add_no_attrs(self): res.xpath('//field[@name="ref"]')[0].attrib["attrs"], "{'required': [('state', '!=', 'draft')]}", ) + + def test_wraptext(self): + """Test textwrap transformations""" + base_view = self.env["ir.ui.view"].create( + { + "type": "qweb", + "arch": "plain text 1plain text2", + } + ) + inherited_view = self.env["ir.ui.view"].create( + { + "type": "qweb", + "inherit_id": base_view.id, + "arch": "" + '' + '' + "", + } + ) + self.assertEqual( + base_view.with_context(load_all_views=True).get_combined_arch(), + "plain text 1" + "
plain text2
", + ) + 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": ""}) + with self.assertRaisesRegex(ValidationError, "found"): + inherited_view.write({"arch": ''}) + with self.assertRaisesRegex(ValidationError, "positions"): + inherited_view.write( + {"arch": ''} + )