diff --git a/README.md b/README.md
index 61740589681..f3d98ec122c 100644
--- a/README.md
+++ b/README.md
@@ -23,14 +23,14 @@ addon | version | maintainers | summary
--- | --- | --- | ---
[attachment_zipped_download](attachment_zipped_download/) | 16.0.2.0.3 | | Attachment Zipped Download
[document_knowledge](document_knowledge/) | 16.0.1.1.0 | | Documents Knowledge
-[document_page](document_page/) | 16.0.1.6.2 | | Document Page
+[document_page](document_page/) | 16.0.2.0.1 | | Document Page
[document_page_access_group](document_page_access_group/) | 16.0.1.1.0 | | Choose groups to access document pages
[document_page_access_group_user_role](document_page_access_group_user_role/) | 16.0.1.1.0 |
| Document Page Access Group User Role
-[document_page_approval](document_page_approval/) | 16.0.1.2.0 | | Document Page Approval
+[document_page_approval](document_page_approval/) | 16.0.2.0.0 | | Document Page Approval
[document_page_group](document_page_group/) | 16.0.1.0.1 | | Define access groups on documents
[document_page_partner](document_page_partner/) | 16.0.1.0.0 | | Allows to link doucment pages to a partner
[document_page_project](document_page_project/) | 16.0.1.0.0 | | This module links document pages to projects
-[document_page_reference](document_page_reference/) | 16.0.1.0.1 |
| Include references on document pages
+[document_page_reference](document_page_reference/) | 16.0.2.0.0 |
| Include references on document pages
[document_page_tag](document_page_tag/) | 16.0.1.0.1 | | Allows you to assign tags or keywords to pages and search for them afterwards
[document_page_tag_print_control](document_page_tag_print_control/) | 16.0.1.0.0 | | Restricts document page printing based on assigned tags
[document_url](document_url/) | 16.0.1.0.4 | | URL attachment
diff --git a/document_page/README.rst b/document_page/README.rst
index c1136ab73e6..15bda3db522 100644
--- a/document_page/README.rst
+++ b/document_page/README.rst
@@ -11,7 +11,7 @@ Document Page
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- !! source digest: sha256:4e0718c27d5379fa95750128cae22c39c5f910b41101309b50a4010d363c92dd
+ !! source digest: sha256:ce46ed197a9f45f6a3a69b670cd72ee11e27f5e9ba0b196a2634f33b02f4af67
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
@@ -98,6 +98,10 @@ Trobz
* Ángel García de la Chica Herrera
+* `Dixmit `__:
+
+ * Enric Tobella
+
Other credits
~~~~~~~~~~~~~
diff --git a/document_page/__manifest__.py b/document_page/__manifest__.py
index e262e47cd24..466906b8f0c 100644
--- a/document_page/__manifest__.py
+++ b/document_page/__manifest__.py
@@ -4,7 +4,7 @@
{
"name": "Document Page",
- "version": "16.0.1.6.2",
+ "version": "16.0.2.0.1",
"category": "Knowledge Management",
"author": "OpenERP SA, Odoo Community Association (OCA)",
"images": [
@@ -17,7 +17,7 @@
],
"website": "https://github.com/OCA/knowledge",
"license": "AGPL-3",
- "depends": ["mail", "document_knowledge"],
+ "depends": ["mail", "document_knowledge", "web_editor"],
"data": [
"security/document_page_security.xml",
"security/ir.model.access.csv",
@@ -30,6 +30,9 @@
],
"demo": ["demo/document_page.xml"],
"assets": {
+ "web._assets_primary_variables": [
+ "document_page/static/src/**/document_page_variables.scss",
+ ],
"web.assets_backend": [
"document_page/static/src/scss/document_page.scss",
],
diff --git a/document_page/demo/document_page.xml b/document_page/demo/document_page.xml
index 450f7575bdc..b868bb93535 100644
--- a/document_page/demo/document_page.xml
+++ b/document_page/demo/document_page.xml
@@ -28,34 +28,23 @@ Additional ressources
1.0
Init
-
-
-
-The news is out, Odoo's latest version 15.0 is here. It's more
-user-friendly, even more business oriented and efficient to manage your company
-
-How to discover the latest version 15.0?
-
-Demo :
-Online:
-Download:
-
-We have also put together a functional demo that presents 15.0. Watch this video
-to learn directly from us what Odoo 15.0 can do for you. Share it in your
-company, with your clients and implement it now for your business.
-
-Watch on Youtube!
-
-]]>
@@ -63,41 +52,26 @@ company, with your clients and implement it now for your business.
1.0
Init
-
-
-You like Odoo, but feel like you want to personalise it more? You can customize your
-dashboard by adding new boards of any
-search view.
-
-How is it done?
-
-Step 1: access one search view
-
-Step 2: apply the filter you want to see at each connection to the application
-(eg. on sales, manufacturing, etc)
-
-Step 3: add it into the dashboard in the same space where you can save the filter
-
-Step 4: choose the application you want it visible on and the name of the array
-
-Look at this simple example below from Purchase, where I want to put on the
-application's dashboard "Purchases to Approve". After I access the search view
-and apply the filter for "Purchases to Approve", I can add it immediately to my
-Purchase dashboard.
-
-
-
-In less than a minute, the search view is visible on the dashboard
-
-
-
-Of course, you are free to delete what you don't need or like, but just in case
-you change your mind there is a reset button to return to the default view.
-
-
-]]>
-
+ You like Odoo, but feel like you want to personalise it more? You can customize your
+dashboard by adding new boards of any search view.
+How is it done?
+Step 1: access one search view
+Step 2: apply the filter you want to see at each connection to the application
+(eg. on sales, manufacturing, etc)
+Step 3: add it into the dashboard in the same space where you can save the filter
+Step 4: choose the application you want it visible on and the name of the array
+Look at this simple example below from Purchase, where I want to put on the
+application's dashboard "Purchases to Approve". After I access the search view
+and apply the filter for "Purchases to Approve", I can add it immediately to my
+Purchase dashboard.
+
+In less than a minute, the search view is visible on the dashboard
+
+Of course, you are free to delete what you don't need or like, but just in case
+you change your mind there is a reset button to return to the default view.
+]]>
@@ -105,38 +79,30 @@ you change your mind there is a reset button to return to the default view.
1.0
Init
-
-
-The Odoo touchscreen point of sale available with 15.0 allows you
-to manage your shop sales very easily. It's fully web based so that you don't
-have to install or deploy any software and all the sales shops can be easily
-consolidated. It works in connected and disconnected modes so that you can
-continue to sell if you lose your internet connection.
-
-
-
-Here's a summary of its main features and benefits:
-
-100% WEB based
-
-- available for any touchscreen device (ipod, ipad, any tablet)mobile (with portable devices)
- no installation required
- no synchronization needed, completely integrated
- continue working even when your connection is down if you close your browser, data won't be lost
- fully web based with a clean interface smart interface
-
-You have different options to select your products. You can do it through the
-barcode reader, just browse through the categories you have put in place (ie.
-drinks, snacks, meals, etc.), or text search in case neither of the other
-options work for you. If you need to use the POS for your restaurant, for
-example, your employees can record at the same time multiple tickets without
-having to wait to do one transaction at a time. Along, to facilitate payment,
-the application allows multiple payment methods.
-
-The POS application is so simple and accessible to use that your shop or
-restaurant will never need any other tool to manage orders. Due to its smart
-and user-friendly interface you don't need any training to learn how to use it.
-Think of it as an out-of-the-box solution to boost your business' productivity.
-
-]]>
-
+ The Odoo touchscreen point of sale available with 15.0 allows you
+to manage your shop sales very easily. It's fully web based so that you don't
+have to install or deploy any software and all the sales shops can be easily
+consolidated. It works in connected and disconnected modes so that you can
+continue to sell if you lose your internet connection.
+
+Here's a summary of its main features and benefits:
+100% WEB based
+- available for any touchscreen device (ipod, ipad, any tablet)mobile (with portable devices)
- no installation required
- no synchronization needed, completely integrated
- continue working even when your connection is down if you close your browser, data won't be lost
- fully web based with a clean interface smart interface
+You have different options to select your products. You can do it through the
+barcode reader, just browse through the categories you have put in place (ie.
+drinks, snacks, meals, etc.), or text search in case neither of the other
+options work for you. If you need to use the POS for your restaurant, for
+example, your employees can record at the same time multiple tickets without
+having to wait to do one transaction at a time. Along, to facilitate payment,
+the application allows multiple payment methods.
+
The POS application is so simple and accessible to use that your shop or
+restaurant will never need any other tool to manage orders. Due to its smart
+and user-friendly interface you don't need any training to learn how to use it.
+Think of it as an out-of-the-box solution to boost your business' productivity.
+
+]]>
diff --git a/document_page/i18n/document_page.pot b/document_page/i18n/document_page.pot
index a50d26b29bc..0802bdd9717 100644
--- a/document_page/i18n/document_page.pot
+++ b/document_page/i18n/document_page.pot
@@ -510,13 +510,6 @@ msgid ""
"category."
msgstr ""
-#. module: document_page
-#. odoo-python
-#: code:addons/document_page/models/document_page_history.py:0
-#, python-format
-msgid "There are no changes in revisions."
-msgstr ""
-
#. module: document_page
#: model:ir.model.fields,field_description:document_page.field_document_page__name
#: model_terms:ir.ui.view,arch_db:document_page.view_wiki_filter
diff --git a/document_page/models/diff_utils.py b/document_page/models/diff_utils.py
new file mode 100644
index 00000000000..8cb7772a1e1
--- /dev/null
+++ b/document_page/models/diff_utils.py
@@ -0,0 +1,242 @@
+# This code has been ported from Odoo 18.0 web_editor module.
+# License of this part should remain LGPL-3.0 or later following Odoo's licensing.
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+import re
+from difflib import SequenceMatcher
+
+# ------------------------------------------------------------
+# Patch and comparison functions
+# ------------------------------------------------------------
+
+
+OPERATION_SEPARATOR = "\n"
+LINE_SEPARATOR = "<"
+
+PATCH_OPERATION_LINE_AT = "@"
+PATCH_OPERATION_CONTENT = ":"
+
+PATCH_OPERATION_ADD = "+"
+PATCH_OPERATION_REMOVE = "-"
+PATCH_OPERATION_REPLACE = "R"
+
+PATCH_OPERATIONS = dict(
+ insert=PATCH_OPERATION_ADD,
+ delete=PATCH_OPERATION_REMOVE,
+ replace=PATCH_OPERATION_REPLACE,
+)
+
+HTML_ATTRIBUTES_TO_REMOVE = [
+ "data-last-history-steps",
+]
+
+
+HTML_TAG_ISOLATION_REGEX = r"^([^>]*>)(.*)$"
+ADDITION_COMPARISON_REGEX = r"\1\2"
+ADDITION_1ST_REPLACE_COMPARISON_REGEX = r"added>\2"
+DELETION_COMPARISON_REGEX = r"\1\2"
+EMPTY_OPERATION_TAG = r"<(added|removed)><\/(added|removed)>"
+SAME_TAG_REPLACE_FIXER = r"<\/added><(?:[^\/>]|(?:><))+>"
+UNNECESSARY_REPLACE_FIXER = (
+ r"([^<](?!<\/added>)*)<\/added>"
+ r"([^<](?!<\/removed>)*)<\/removed>"
+)
+
+
+def generate_comparison(new_content, old_content): # noqa: C901
+ """Compare a content to an older content
+ and generate a comparison html between both content.
+
+ :param string new_content: the current content
+ :param string old_content: the old content
+
+ :return: string: the comparison content
+ """
+ new_content = _remove_html_attribute(new_content, HTML_ATTRIBUTES_TO_REMOVE)
+ old_content = _remove_html_attribute(old_content, HTML_ATTRIBUTES_TO_REMOVE)
+
+ if new_content == old_content:
+ return new_content
+
+ patch = generate_patch(new_content, old_content)
+ comparison = new_content.split(LINE_SEPARATOR)
+ patch_operations = patch.split(OPERATION_SEPARATOR)
+ # We need to apply operation from last to the first
+ # to preserve the indexes integrity.
+ patch_operations.reverse()
+
+ for operation in patch_operations:
+ metadata, *patch_content_line = operation.split(LINE_SEPARATOR)
+
+ metadata_split = metadata.split(PATCH_OPERATION_LINE_AT)
+ operation_type = metadata_split[0]
+ lines_index_range = metadata_split[1] if len(metadata_split) > 1 else ""
+ lines_index_range = lines_index_range.split(PATCH_OPERATION_CONTENT)[0]
+ indexes = lines_index_range.split(",")
+ start_index = int(indexes[0])
+ end_index = int(indexes[1]) if len(indexes) > 1 else start_index
+
+ # If the operation is a replace, we need to flag the changes that
+ # will generate ghost opening tags if we don't ignore
+ # them.
+ # this can append when:
+ # * A change concerning only html parameters.
+ # a
=> a
+ # * An addition in a previously empty element opening tag
+ # => a
+ if operation_type == PATCH_OPERATION_REPLACE:
+ for i, line in enumerate(patch_content_line):
+ current_index = start_index + i
+ if current_index > end_index:
+ break
+
+ current_line = comparison[current_index]
+ current_line_tag = current_line.split(">")[0]
+ line_tag = line.split(">")[0]
+ if current_line[-1] == ">" and (
+ current_line_tag == line_tag
+ or current_line_tag.split(" ")[0] == line_tag.split(" ")[0]
+ ):
+ comparison[start_index + i] = "delete_me>"
+
+ # We need to insert lines from last to the first
+ # to preserve the indexes integrity.
+ patch_content_line.reverse()
+
+ for index in range(end_index, start_index - 1, -1):
+ if operation_type in [
+ PATCH_OPERATION_REMOVE,
+ PATCH_OPERATION_REPLACE,
+ ]:
+ deletion_flagged_comparison = re.sub(
+ HTML_TAG_ISOLATION_REGEX,
+ DELETION_COMPARISON_REGEX,
+ comparison[index],
+ )
+ # Only use this line if it doesn't generate an empty
+ # tag
+ if not re.search(EMPTY_OPERATION_TAG, deletion_flagged_comparison):
+ comparison[index] = deletion_flagged_comparison
+
+ if operation_type == PATCH_OPERATION_ADD:
+ for line in patch_content_line:
+ addition_flagged_line = re.sub(
+ HTML_TAG_ISOLATION_REGEX, ADDITION_COMPARISON_REGEX, line
+ )
+
+ if not re.search(EMPTY_OPERATION_TAG, addition_flagged_line):
+ comparison.insert(start_index + 1, addition_flagged_line)
+ else:
+ comparison.insert(start_index + 1, line)
+
+ if operation_type == PATCH_OPERATION_REPLACE:
+ for _i, line in enumerate(patch_content_line):
+ addition_flagged_line = re.sub(
+ HTML_TAG_ISOLATION_REGEX, ADDITION_COMPARISON_REGEX, line
+ )
+ if not re.search(EMPTY_OPERATION_TAG, addition_flagged_line):
+ comparison.insert(start_index, addition_flagged_line)
+ elif line.split(">")[0] != comparison[start_index].split(">")[0]:
+ comparison.insert(start_index, line)
+
+ final_comparison = LINE_SEPARATOR.join(comparison)
+ # We can remove all the opening tags which are located between the end of an
+ # added tag and the start of a removed tag, because this should never happen
+ # as the added and removed tags should always be near each other.
+ # This can happen when the new container tag had a parameter change.
+ final_comparison = re.sub(
+ SAME_TAG_REPLACE_FIXER, "", final_comparison
+ )
+
+ # Remove al the tags
+ final_comparison = final_comparison.replace(r"", "")
+
+ # This fix the issue of unnecessary replace tags.
+ # ex: abcabc -> abc
+ # This can occur when the new content is the same as the old content and
+ # their container tags are the same but the tags parameters are different
+ for match in re.finditer(UNNECESSARY_REPLACE_FIXER, final_comparison):
+ if match.group(1) == match.group(2):
+ final_comparison = final_comparison.replace(match.group(0), match.group(1))
+
+ return final_comparison
+
+
+def _format_line_index(start, end):
+ """Format the line index to be used in a patch operation.
+
+ :param start: the start index
+ :param end: the end index
+ :return: string
+ """
+ length = end - start
+ if not length:
+ start -= 1
+ if length <= 1:
+ return f"{PATCH_OPERATION_LINE_AT}{start}"
+ return f"{PATCH_OPERATION_LINE_AT}{start},{start + length - 1}"
+
+
+def _patch_generator(new_content, old_content):
+ """Generate a patch (multiple operations) between two contents.
+ Each operation is a string with the following format:
+ @[,][:*]
+ patch format example:
+ +@4:ab
cd
+ +@4,15:ef
gh
+ -@32
+ -@125,129
+ R@523:sdf
+
+ :param string new_content: the new content
+ :param string old_content: the old content
+
+ :return: string: the patch containing all the operations to reverse
+ the new content to the old content
+ """
+ # remove break line in contents to ensure they don't interfere with
+ # operations
+ new_content = new_content.replace("\n", "")
+ old_content = old_content.replace("\n", "")
+
+ new_content_lines = new_content.split(LINE_SEPARATOR)
+ old_content_lines = old_content.split(LINE_SEPARATOR)
+
+ for group in SequenceMatcher(
+ None, new_content_lines, old_content_lines, False
+ ).get_grouped_opcodes(0):
+ patch_content_line = []
+ first, last = group[0], group[-1]
+ patch_operation = _format_line_index(first[1], last[2])
+
+ if any(tag in {"replace", "delete"} for tag, _, _, _, _ in group):
+ for tag, _, _, _, _ in group:
+ if tag not in {"insert", "equal", "replace"}:
+ patch_operation = PATCH_OPERATIONS[tag] + patch_operation
+
+ if any(tag in {"replace", "insert"} for tag, _, _, _, _ in group):
+ for tag, _, _, j1, j2 in group:
+ if tag not in {"delete", "equal"}:
+ patch_operation = PATCH_OPERATIONS[tag] + patch_operation
+ for line in old_content_lines[j1:j2]:
+ patch_content_line.append(line)
+
+ if patch_content_line:
+ patch_content = LINE_SEPARATOR + LINE_SEPARATOR.join(patch_content_line)
+ yield str(patch_operation) + PATCH_OPERATION_CONTENT + patch_content
+ else:
+ yield str(patch_operation)
+
+
+def generate_patch(new_content, old_content):
+ new_content = _remove_html_attribute(new_content, HTML_ATTRIBUTES_TO_REMOVE)
+ old_content = _remove_html_attribute(old_content, HTML_ATTRIBUTES_TO_REMOVE)
+
+ return OPERATION_SEPARATOR.join(list(_patch_generator(new_content, old_content)))
+
+
+def _remove_html_attribute(html_content, attributes_to_remove):
+ for attribute in attributes_to_remove:
+ html_content = re.sub(rf' {attribute}="[^"]*"', "", html_content)
+
+ return html_content
diff --git a/document_page/models/document_page_history.py b/document_page/models/document_page_history.py
index 7b200e6abbb..45d8b077a2a 100644
--- a/document_page/models/document_page_history.py
+++ b/document_page/models/document_page_history.py
@@ -1,9 +1,12 @@
# Copyright (C) 2004-2010 Tiny SPRL ().
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-import difflib
-from odoo import _, api, fields, models
+from odoo import fields, models
+
+from .diff_utils import (
+ generate_comparison,
+)
class DocumentPageHistory(models.Model):
@@ -17,7 +20,7 @@ class DocumentPageHistory(models.Model):
name = fields.Char(index=True)
summary = fields.Char(index=True)
content = fields.Html(sanitize=False)
- diff = fields.Html(compute="_compute_diff")
+ diff = fields.Html(compute="_compute_diff", sanitize_tags=False)
company_id = fields.Many2one(
"res.company",
@@ -43,28 +46,10 @@ def _compute_diff(self):
)
rec.diff = self._get_diff(prev.id, rec.id)
- @api.model
def _get_diff(self, v1, v2):
- """Return the difference between two version of document version."""
text1 = v1 and self.browse(v1).content or ""
text2 = v2 and self.browse(v2).content or ""
- # Include line breaks to make it more readable
- # TODO: consider using a beautify library directly on the content
- text1 = text1.replace("", "
\r\n")
- text2 = text2.replace("
", "
\r\n")
- line1 = text1.splitlines(True)
- line2 = text2.splitlines(True)
- if line1 == line2:
- return _("There are no changes in revisions.")
- else:
- diff = difflib.HtmlDiff()
- return diff.make_table(
- line1,
- line2,
- f"Revision-{v1}",
- f"Revision-{v2}",
- context=True,
- )
+ return generate_comparison(text1, text2)
def name_get(self):
return [(rec.id, "%s #%i" % (rec.page_id.name, rec.id)) for rec in self]
diff --git a/document_page/readme/CONTRIBUTORS.rst b/document_page/readme/CONTRIBUTORS.rst
index a45e3a717c2..0aa38704d31 100644
--- a/document_page/readme/CONTRIBUTORS.rst
+++ b/document_page/readme/CONTRIBUTORS.rst
@@ -16,3 +16,7 @@ Trobz
* `Sygel `_:
* Ángel García de la Chica Herrera
+
+* `Dixmit `__:
+
+ * Enric Tobella
diff --git a/document_page/static/description/index.html b/document_page/static/description/index.html
index d652a43bbec..ef15c95f5a9 100644
--- a/document_page/static/description/index.html
+++ b/document_page/static/description/index.html
@@ -372,7 +372,7 @@ Document Page
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-!! source digest: sha256:4e0718c27d5379fa95750128cae22c39c5f910b41101309b50a4010d363c92dd
+!! source digest: sha256:ce46ed197a9f45f6a3a69b670cd72ee11e27f5e9ba0b196a2634f33b02f4af67
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

This module allows you to write web pages for internal documentation.
@@ -447,6 +447,10 @@
Ángel García de la Chica Herrera
+Dixmit:
+
diff --git a/document_page/static/src/scss/document_page.scss b/document_page/static/src/scss/document_page.scss
index 82cfbaaccc8..064d415a9dd 100644
--- a/document_page/static/src/scss/document_page.scss
+++ b/document_page/static/src/scss/document_page.scss
@@ -1,28 +1,40 @@
-table.diff {
- font-family: Courier;
- border: medium;
+.o_document_page_diff {
+ table.diff {
+ font-family: Courier;
+ border: medium;
- .diff_header {
- background-color: #e0e0e0;
- }
+ .diff_header {
+ background-color: $o_document_page_diff_header_background;
+ }
- td.diff_header {
- text-align: right;
- }
+ td.diff_header {
+ text-align: right;
+ }
- .diff_next {
- background-color: #c0c0c0;
- }
+ .diff_next {
+ background-color: $o_document_page_diff_next_background;
+ }
- .diff_add {
- background-color: #aaffaa;
- }
+ .diff_add {
+ background-color: $o_document_page_diff_add_background;
+ }
- .diff_chg {
- background-color: #ffff77;
- }
+ .diff_chg {
+ background-color: $o_document_page_diff_change_background;
+ }
- .diff_sub {
- background-color: #ffaaaa;
+ .diff_sub {
+ background-color: $o_document_page_diff_subtract_background;
+ }
+ }
+ removed {
+ display: inline;
+ text-decoration: line-through;
+ opacity: 0.5;
+ background-color: $o_document_page_diff_subtract_background;
+ }
+ added {
+ display: inline;
+ background-color: $o_document_page_diff_add_background;
}
}
diff --git a/document_page/static/src/scss/document_page_variables.scss b/document_page/static/src/scss/document_page_variables.scss
new file mode 100644
index 00000000000..0c4d02fedeb
--- /dev/null
+++ b/document_page/static/src/scss/document_page_variables.scss
@@ -0,0 +1,5 @@
+$o_document_page_diff_header_background: #e0e0e0;
+$o_document_page_diff_next_background: #c0c0c0;
+$o_document_page_diff_add_background: #aaffaa;
+$o_document_page_diff_change_background: #ffff77;
+$o_document_page_diff_subtract_background: #ffaaaa;
diff --git a/document_page/tests/test_document_page.py b/document_page/tests/test_document_page.py
index 22b03c2ae82..4ada5d71df4 100644
--- a/document_page/tests/test_document_page.py
+++ b/document_page/tests/test_document_page.py
@@ -31,12 +31,16 @@ def test_category_template(self):
self.assertEqual(page.content, self.category1.template)
def test_page_history_diff(self):
- page = self.page_obj.create({"name": "Test Page 3", "content": "Test content"})
- page.content = "New content"
+ page = self.page_obj.create(
+ {"name": "Test Page 3", "content": "
Test content
"}
+ )
+ page.content = "
New content
"
self.assertIsNotNone(page.history_ids[0].diff)
def test_page_link(self):
- page = self.page_obj.create({"name": "Test Page 3", "content": "Test content"})
+ page = self.page_obj.create(
+ {"name": "Test Page 3", "content": "
Test content
"}
+ )
self.assertEqual(
page.backend_url,
f"/web#id={page.id}&model=document.page&view_type=form",
@@ -51,7 +55,9 @@ def test_page_link(self):
)
def test_page_copy(self):
- page = self.page_obj.create({"name": "Test Page 3", "content": "Test content"})
+ page = self.page_obj.create(
+ {"name": "Test Page 3", "content": "
Test content
"}
+ )
page_copy = page.copy()
self.assertEqual(page_copy.name, page.name + " (copy)")
self.assertEqual(page_copy.content, page.content)
diff --git a/document_page/tests/test_document_page_history.py b/document_page/tests/test_document_page_history.py
index 856be77f783..dd09334191f 100644
--- a/document_page/tests/test_document_page_history.py
+++ b/document_page/tests/test_document_page_history.py
@@ -6,14 +6,15 @@ class TestDocumentPageHistory(common.TransactionCase):
def test_page_history_demo_page1(self):
"""Test page history demo page1."""
- page = self.env.ref("document_page.demo_page1")
- page.content = "Test content updated"
+ page = self.env["document.page"].create(
+ {
+ "name": "Test Page",
+ "content": "
Initial content
",
+ }
+ )
+ page.content = "
Test content updated
"
history_document = self.env["document.page.history"]
history_pages = history_document.search([("page_id", "=", page.id)])
active_ids = [i.id for i in history_pages]
-
result = history_document._get_diff(active_ids[0], active_ids[0])
- self.assertEqual(result, "There are no changes in revisions.")
-
- result = history_document._get_diff(active_ids[0], active_ids[1])
- self.assertNotEqual(result, "There are no changes in revisions.")
+ self.assertEqual(result, page.content)
diff --git a/document_page/tests/test_document_page_show_diff.py b/document_page/tests/test_document_page_show_diff.py
index 811c35e7cde..54f564ecc73 100644
--- a/document_page/tests/test_document_page_show_diff.py
+++ b/document_page/tests/test_document_page_show_diff.py
@@ -8,7 +8,12 @@ class TestDocumentPageShowDiff(common.TransactionCase):
def test_show_demo_page1_diff(self):
"""Show test page history difference."""
- page = self.env.ref("document_page.demo_page1")
+ page = self.env["document.page"].create(
+ {
+ "name": "Test Page",
+ "content": "
Initial content
",
+ }
+ )
show_diff_object = self.env["wizard.document.page.history.show_diff"]
@@ -21,8 +26,8 @@ def test_show_demo_page1_diff(self):
)._get_diff()
)
- page.write({"content": "Text content updated"})
- page.write({"content": "Text updated"})
+ page.write({"content": "
Text content updated
"})
+ page.write({"content": "
Text updated
"})
history_pages = history_document.search([("page_id", "=", page.id)])
diff --git a/document_page/views/document_page_history.xml b/document_page/views/document_page_history.xml
index 00107d75081..a01acfba7cf 100644
--- a/document_page/views/document_page_history.xml
+++ b/document_page/views/document_page_history.xml
@@ -70,6 +70,7 @@
diff --git a/document_page/wizard/document_page_show_diff.py b/document_page/wizard/document_page_show_diff.py
index 1557ff7b8d3..26f025421dc 100644
--- a/document_page/wizard/document_page_show_diff.py
+++ b/document_page/wizard/document_page_show_diff.py
@@ -27,4 +27,4 @@ def _get_diff(self):
raise UserError(_("Select one or maximum two history revisions!"))
return diff
- diff = fields.Html(readonly=True, default=_get_diff)
+ diff = fields.Html(readonly=True, default=_get_diff, sanitize_tags=False)
diff --git a/document_page_approval/README.rst b/document_page_approval/README.rst
index 921781b0705..066580d7f93 100644
--- a/document_page_approval/README.rst
+++ b/document_page_approval/README.rst
@@ -1,3 +1,7 @@
+.. image:: https://odoo-community.org/readme-banner-image
+ :target: https://odoo-community.org/get-involved?utm_source=readme
+ :alt: Odoo Community Association
+
======================
Document Page Approval
======================
@@ -7,13 +11,13 @@ Document Page Approval
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- !! source digest: sha256:0046d2f6babcbd4e392332b94640e27719d2cfa921e66c702dfdee86011883cb
+ !! source digest: sha256:020a774db178ba4c91e5a692b8b71f79c2b80fb63f864b8b658739cae0e6a76a
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
-.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
+.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fknowledge-lightgray.png?logo=github
diff --git a/document_page_approval/__manifest__.py b/document_page_approval/__manifest__.py
index 80fa265d007..d5ac1d2fd37 100644
--- a/document_page_approval/__manifest__.py
+++ b/document_page_approval/__manifest__.py
@@ -3,7 +3,7 @@
{
"name": "Document Page Approval",
- "version": "16.0.1.2.0",
+ "version": "16.0.2.0.0",
"author": "Savoir-faire Linux, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/knowledge",
"license": "AGPL-3",
diff --git a/document_page_approval/static/description/index.html b/document_page_approval/static/description/index.html
index fdfe00556a9..998d736bcc0 100644
--- a/document_page_approval/static/description/index.html
+++ b/document_page_approval/static/description/index.html
@@ -3,7 +3,7 @@
-
Document Page Approval
+
README.rst
-
-
Document Page Approval
+
+
+
+
+
+
+
Document Page Approval
-

+

This module adds a workflow to approve page modifications
and show the approved version by default.
Table of contents
@@ -387,7 +392,7 @@
Document Page Approval
-
+
To configure this module, you need to:
- Set a valid email address on the company settings.
@@ -397,7 +402,7 @@
-
+
To use this module, you need to:
- Go to Knowledge > Pages
@@ -409,7 +414,7 @@
-
+
Bugs are tracked on GitHub Issues.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
@@ -417,15 +422,15 @@
Do not contact contributors directly about support or help with technical issues.
+