Merge PR #550 into 18.0

Signed-off-by pedrobaeza
This commit is contained in:
OCA-git-bot 2025-07-08 10:21:31 +00:00
commit 3b6e9e6a71
20 changed files with 1066 additions and 0 deletions

View File

@ -0,0 +1,92 @@
=======================
Document Page Reference
=======================
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:ead414b479ae1108c68fadb93a675584c882eb76c59617f82296e9f3570df6ab
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |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
: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
:target: https://github.com/OCA/knowledge/tree/18.0/document_page_reference
:alt: OCA/knowledge
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/knowledge-18-0/knowledge-18-0-document_page_reference
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/knowledge&target_branch=18.0
:alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5|
This module allows to add a reference name on documents and simplifies
the link between document pages.
**Table of contents**
.. contents::
:local:
Usage
=====
When editing a document page add elements like ${XXX} where XXX is the
reference of another page. Now, when viewing the document, it will link
directly to the page. Also, the name will be parsed as the display name.
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/knowledge/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
`feedback <https://github.com/OCA/knowledge/issues/new?body=module:%20document_page_reference%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
Credits
=======
Authors
-------
* Creu Blanca
Contributors
------------
- Enric Tobella <etobella@creublanca.es>
Maintainers
-----------
This module is maintained by the OCA.
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
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-etobella| image:: https://github.com/etobella.png?size=40px
:target: https://github.com/etobella
:alt: etobella
Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:
|maintainer-etobella|
This module is part of the `OCA/knowledge <https://github.com/OCA/knowledge/tree/18.0/document_page_reference>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

@ -0,0 +1 @@
from . import models

View File

@ -0,0 +1,23 @@
# Copyright 2019 Creu Blanca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
"name": "Document Page Reference",
"summary": """
Include references on document pages""",
"version": "18.0.1.0.0",
"license": "AGPL-3",
"author": "Creu Blanca,Odoo Community Association (OCA)",
"website": "https://github.com/OCA/knowledge",
"depends": ["document_page"],
"data": [
"views/document_page.xml",
"views/report_document_page.xml",
],
"assets": {
"web.assets_backend": [
"document_page_reference/static/src/js/editor.esm.js",
],
},
"maintainers": ["etobella"],
}

View File

@ -0,0 +1,53 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * document_page_reference
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: document_page_reference
#: model:ir.model.fields,field_description:document_page_reference.field_document_page__content_parsed
msgid "Content Parsed"
msgstr ""
#. module: document_page_reference
#: model:ir.model,name:document_page_reference.model_document_page
msgid "Document Page"
msgstr ""
#. module: document_page_reference
#: model:ir.model.fields,field_description:document_page_reference.field_document_page__reference
msgid "Reference"
msgstr ""
#. module: document_page_reference
#. odoo-python
#: code:addons/document_page_reference/models/document_page.py:0
#, python-format
msgid "Reference is not valid"
msgstr ""
#. module: document_page_reference
#. odoo-python
#: code:addons/document_page_reference/models/document_page.py:0
#, python-format
msgid "Reference must be unique"
msgstr ""
#. module: document_page_reference
#: model:ir.model.fields,help:document_page_reference.field_document_page__reference
msgid "Used to find the document, it can contain letters, numbers and _"
msgstr ""
#. module: document_page_reference
#: model_terms:ir.ui.view,arch_db:document_page_reference.document_page_form_view
msgid "internal_reference (autofilled if not value is provided)"
msgstr ""

View File

@ -0,0 +1,57 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * document_page_reference
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2023-09-05 22:41+0000\n"
"Last-Translator: Ivorra78 <informatica@totmaterial.es>\n"
"Language-Team: none\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.17\n"
#. module: document_page_reference
#: model:ir.model.fields,field_description:document_page_reference.field_document_page__content_parsed
msgid "Content Parsed"
msgstr "Contenido procesado"
#. module: document_page_reference
#: model:ir.model,name:document_page_reference.model_document_page
msgid "Document Page"
msgstr "Página de Documento"
#. module: document_page_reference
#: model:ir.model.fields,field_description:document_page_reference.field_document_page__reference
msgid "Reference"
msgstr "Referencia"
#. module: document_page_reference
#. odoo-python
#: code:addons/document_page_reference/models/document_page.py:0
#, python-format
msgid "Reference is not valid"
msgstr "La referencia no es válida"
#. module: document_page_reference
#. odoo-python
#: code:addons/document_page_reference/models/document_page.py:0
#, python-format
msgid "Reference must be unique"
msgstr "La referencia debe ser única"
#. module: document_page_reference
#: model:ir.model.fields,help:document_page_reference.field_document_page__reference
msgid "Used to find the document, it can contain letters, numbers and _"
msgstr ""
"Se utiliza para encontrar el documento, puede contener letras, números y _"
#. module: document_page_reference
#: model_terms:ir.ui.view,arch_db:document_page_reference.document_page_form_view
msgid "internal_reference (autofilled if not value is provided)"
msgstr "internal_reference (autocompletado si no se proporciona ningún valor)"

View File

@ -0,0 +1,56 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * document_page_reference
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 15.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2023-06-23 10:10+0000\n"
"Last-Translator: mymage <stefano.consolaro@mymage.it>\n"
"Language-Team: none\n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.17\n"
#. module: document_page_reference
#: model:ir.model.fields,field_description:document_page_reference.field_document_page__content_parsed
msgid "Content Parsed"
msgstr "Contenuto analizzato"
#. module: document_page_reference
#: model:ir.model,name:document_page_reference.model_document_page
msgid "Document Page"
msgstr "Pagina documento"
#. module: document_page_reference
#: model:ir.model.fields,field_description:document_page_reference.field_document_page__reference
msgid "Reference"
msgstr "Riferimento"
#. module: document_page_reference
#. odoo-python
#: code:addons/document_page_reference/models/document_page.py:0
#, python-format
msgid "Reference is not valid"
msgstr "Il riferimento non è valido"
#. module: document_page_reference
#. odoo-python
#: code:addons/document_page_reference/models/document_page.py:0
#, python-format
msgid "Reference must be unique"
msgstr "Il riferimento deve essere unico"
#. module: document_page_reference
#: model:ir.model.fields,help:document_page_reference.field_document_page__reference
msgid "Used to find the document, it can contain letters, numbers and _"
msgstr "Utilizzato per trovare il documento, può contenere lettere, numeri e _"
#. module: document_page_reference
#: model_terms:ir.ui.view,arch_db:document_page_reference.document_page_form_view
msgid "internal_reference (autofilled if not value is provided)"
msgstr "internal_reference (auto compilato se non viene fornito un valore)"

View File

@ -0,0 +1,57 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * document_page_reference
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2024-02-28 21:33+0000\n"
"Last-Translator: Peter Romão <peterromao@yahoo.co.uk>\n"
"Language-Team: none\n"
"Language: pt\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Weblate 4.17\n"
#. module: document_page_reference
#: model:ir.model.fields,field_description:document_page_reference.field_document_page__content_parsed
msgid "Content Parsed"
msgstr "Conteúdo Analisado"
#. module: document_page_reference
#: model:ir.model,name:document_page_reference.model_document_page
msgid "Document Page"
msgstr "Página do documento"
#. module: document_page_reference
#: model:ir.model.fields,field_description:document_page_reference.field_document_page__reference
msgid "Reference"
msgstr "Referência"
#. module: document_page_reference
#. odoo-python
#: code:addons/document_page_reference/models/document_page.py:0
#, python-format
msgid "Reference is not valid"
msgstr "A referência não é válida"
#. module: document_page_reference
#. odoo-python
#: code:addons/document_page_reference/models/document_page.py:0
#, python-format
msgid "Reference must be unique"
msgstr "A referência deve ser única"
#. module: document_page_reference
#: model:ir.model.fields,help:document_page_reference.field_document_page__reference
msgid "Used to find the document, it can contain letters, numbers and _"
msgstr "Usado para encontrar o documento, pode conter letras, números e _"
#. module: document_page_reference
#: model_terms:ir.ui.view,arch_db:document_page_reference.document_page_form_view
msgid "internal_reference (autofilled if not value is provided)"
msgstr ""
"internal_reference (preenchimento automático se o valor não for fornecido)"

View File

@ -0,0 +1 @@
from . import document_page

View File

@ -0,0 +1,102 @@
# Copyright 2019 Creu Blanca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import logging
import re
from jinja2.sandbox import SandboxedEnvironment
from markupsafe import Markup
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
from odoo.tools import html_escape
_logger = logging.getLogger(__name__)
env = SandboxedEnvironment(autoescape=False)
class DocumentPage(models.Model):
_inherit = "document.page"
_description = "Document Page"
reference = fields.Char(
help="Used to find the document, it can contain letters, numbers and _"
)
content_parsed = fields.Html(
"Parsed Content", compute="_compute_content_parsed", sanitize=False, store=True
)
def get_formview_action(self, access_uid=None):
res = super().get_formview_action(access_uid)
view_id = self.env.ref("document_page.view_wiki_form").id
res["views"] = [(view_id, "form")]
return res
@api.depends("content")
def _compute_content_parsed(self):
for record in self:
try:
raw = record.content or ""
converted = re.sub(r"\$\{([\w_]+)\}", r"{{ resolve('\1') }}", raw)
template = env.from_string(converted)
rendered = template.render(resolve=record._resolve_reference)
record.content_parsed = rendered
except Exception as e:
_logger.info("Render failed for %s: %s", record.id, e)
record.content_parsed = record.content or ""
@api.constrains("reference")
def _check_reference_validity(self):
for rec in self:
if not rec.reference:
continue
regex = r"^[a-zA-Z_][a-zA-Z0-9_]*$"
if not re.match(regex, rec.reference):
raise ValidationError(_("Reference is not valid"))
domain = [("reference", "=", rec.reference), ("id", "!=", rec.id)]
if self.search(domain):
raise ValidationError(_("Reference must be unique"))
def _get_document(self, code):
return self.search([("reference", "=", code)], limit=1)
def get_content(self):
for record in self:
try:
raw = record.content or ""
converted = re.sub(r"\$\{([\w_]+)\}", r"{{ resolve('\1') }}", raw)
template = env.from_string(converted)
return template.render(resolve=record._resolve_reference)
except Exception:
_logger.error(
"Template from page with id = %s cannot be processed", record.id
)
return record.content
def _resolve_reference(self, code):
doc = self._get_document(code)
if self.env.context.get("raw_reference", False):
return html_escape(doc.display_name if doc else code)
sanitized_code = html_escape(code)
if not doc:
return (
f"<i><a href='#' class='oe_direct_line' "
f"data-oe-model='document.page' data-oe-id='' "
f"name='{sanitized_code}'>{sanitized_code}</a></i>"
)
return (
f"<a href='#' class='oe_direct_line' data-oe-model='{doc._name}' "
f"data-oe-id='{doc.id}' name='{sanitized_code}'>"
f"{html_escape(doc.display_name)}</a>"
)
def get_raw_content(self):
return Markup(self.with_context(raw_reference=True).get_content())
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if not vals.get("reference") and vals.get("name"):
reference = self.env["ir.http"]._slugify(vals["name"]).replace("-", "_")
vals["reference"] = reference
return super().create(vals_list)

View File

@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"

View File

@ -0,0 +1 @@
- Enric Tobella \<etobella@creublanca.es\>

View File

@ -0,0 +1,2 @@
This module allows to add a reference name on documents and simplifies
the link between document pages.

View File

@ -0,0 +1,3 @@
When editing a document page add elements like \${XXX} where XXX is the
reference of another page. Now, when viewing the document, it will link
directly to the page. Also, the name will be parsed as the display name.

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@ -0,0 +1,433 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>Document Page Reference</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
Despite the name, some widely supported CSS2 features are used.
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: gray; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic, pre.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="document-page-reference">
<h1 class="title">Document Page Reference</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:ead414b479ae1108c68fadb93a675584c882eb76c59617f82296e9f3570df6ab
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/knowledge/tree/18.0/document_page_reference"><img alt="OCA/knowledge" src="https://img.shields.io/badge/github-OCA%2Fknowledge-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/knowledge-18-0/knowledge-18-0-document_page_reference"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/knowledge&amp;target_branch=18.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This module allows to add a reference name on documents and simplifies
the link between document pages.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#usage" id="toc-entry-1">Usage</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-2">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-3">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-4">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-5">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-6">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#toc-entry-1">Usage</a></h1>
<p>When editing a document page add elements like ${XXX} where XXX is the
reference of another page. Now, when viewing the document, it will link
directly to the page. Also, the name will be parsed as the display name.</p>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-2">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/knowledge/issues">GitHub Issues</a>.
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
<a class="reference external" href="https://github.com/OCA/knowledge/issues/new?body=module:%20document_page_reference%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#toc-entry-3">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-4">Authors</a></h2>
<ul class="simple">
<li>Creu Blanca</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-5">Contributors</a></h2>
<ul class="simple">
<li>Enric Tobella &lt;<a class="reference external" href="mailto:etobella&#64;creublanca.es">etobella&#64;creublanca.es</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-6">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
</a>
<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/etobella"><img alt="etobella" src="https://github.com/etobella.png?size=40px" /></a></p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/knowledge/tree/18.0/document_page_reference">OCA/knowledge</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>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,32 @@
import {HtmlField, htmlField} from "@web/views/fields/html/html_field";
import {onMounted} from "@odoo/owl";
import {registry} from "@web/core/registry";
import {useService} from "@web/core/utils/hooks";
class DocumentPageReferenceField extends HtmlField {
setup() {
super.setup();
this.orm = useService("orm");
this.action = useService("action");
onMounted(() => {
// eslint-disable-next-line no-undef
const links = document.querySelectorAll(".oe_direct_line");
links.forEach((link) => {
link.addEventListener("click", (event) =>
this._onClickDirectLink(event)
);
});
});
}
_onClickDirectLink(event) {
const {oeModel: model, oeId} = event.target.dataset;
const id = parseInt(oeId, 10);
this.orm.call(model, "get_formview_action", [[id]], {}).then((action) => {
this.action.doAction(action);
});
}
}
registry.category("fields").add("document_page_reference", {
...htmlField,
component: DocumentPageReferenceField,
});

View File

@ -0,0 +1 @@
from . import test_document_reference

View File

@ -0,0 +1,65 @@
# Copyright 2019 Creu Blanca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo.exceptions import ValidationError
from odoo.tests.common import TransactionCase
class TestDocumentReference(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.page_obj = cls.env["document.page"]
cls.history_obj = cls.env["document.page.history"]
cls.page1 = cls.page_obj.create(
{"name": "Test Page 1", "content": "${r2}", "reference": "R1"}
)
cls.page2 = cls.page_obj.create(
{"name": "Test Page 1", "content": "${r1}", "reference": "r2"}
)
def test_constraints_duplicate_reference(self):
"""Should raise if reference is not unique (same as another)."""
with self.assertRaises(ValidationError):
self.page2.write({"reference": self.page1.reference})
def test_constraints_invalid_reference(self):
"""Should raise if reference does not match the required pattern."""
with self.assertRaises(ValidationError):
self.page2.write({"reference": self.page2.reference + "-02"})
def test_auto_reference(self):
"""Test if reference is proposed when saving a page without one."""
self.assertEqual(self.page1.reference, "R1")
new_page = self.page_obj.create(
{"name": "Test Page with no reference", "content": "some content"}
)
self.assertEqual(new_page.reference, "test_page_with_no_reference")
with self.assertRaises(ValidationError):
new_page_duplicated_name = self.page_obj.create(
{
"name": "test page with no reference",
"content": "this should have an empty reference "
"because reference must be unique",
}
)
self.assertFalse(new_page_duplicated_name.reference)
def test_get_formview_action(self):
res = self.page1.get_formview_action()
view_id = self.env.ref("document_page.view_wiki_form").id
expected_keys = {
"type": "ir.actions.act_window",
"res_model": "document.page",
"res_id": self.page1.id,
"context": {},
"target": "current",
"views": [(view_id, "form")],
}
for key, expected_value in expected_keys.items():
self.assertEqual(res.get(key), expected_value, f"Mismatch in key: {key}")
def test_compute_content_parsed(self):
self.page1.content = "<p></p>"
self.page1._compute_content_parsed()
self.assertEqual(str(self.page1.content_parsed), "<p></p>")

View File

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2019 Creu Blanca
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<record model="ir.ui.view" id="document_page_form_view">
<field name="name">document.page.form (in knowledge_reference)</field>
<field name="model">document.page</field>
<field name="inherit_id" ref="document_page.view_wiki_form" />
<field name="arch" type="xml">
<xpath expr="//h1" position="before">
<h2>
<field
name="reference"
placeholder="internal_reference (autofilled if not value is provided)"
/>
</h2>
</xpath>
<field name="content" position="attributes">
<attribute name="class">oe_edit_only</attribute>
</field>
<field name="content" position="before">
<field
name="content_parsed"
class="oe_read_only"
widget="document_page_reference"
/>
</field>
</field>
</record>
<record id="view_wiki_menu_form" model="ir.ui.view">
<field name="name">document.page.menu.form</field>
<field name="model">document.page</field>
<field name="inherit_id" ref="document_page.view_wiki_menu_form" />
<field name="arch" type="xml">
<field name="content" position="attributes">
<attribute name="class">oe_edit_only</attribute>
</field>
<field name="content" position="before">
<field
name="content_parsed"
class="oe_read_only"
widget="document_page_reference"
/>
</field>
</field>
</record>
<record model="ir.ui.view" id="document_page_search_view">
<field name="name">document.page.search (in knowledge_reference)</field>
<field name="model">document.page</field>
<field name="inherit_id" ref="document_page.view_wiki_filter" />
<field name="arch" type="xml">
<field name="parent_id" position="before">
<field name="reference" />
</field>
</field>
</record>
<record model="ir.ui.view" id="document_page_tree_view">
<field name="name">document.page.tree (in knowledge_reference)</field>
<field name="model">document.page</field>
<field name="inherit_id" ref="document_page.view_wiki_tree" />
<field name="arch" type="xml">
<field name="name" position="after">
<field name="reference" optional="hidden" />
</field>
</field>
</record>
</odoo>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<template
id="report_documentpage_doc"
inherit_id="document_page.report_documentpage_doc"
>
<xpath expr="//div[@t-raw='doc.content']" position="attributes">
<attribute name="t-if">1==0</attribute>
</xpath>
<xpath expr="//div[@t-raw='doc.content']" position="after">
<t t-out="doc.get_raw_content()" />
</xpath>
</template>
</odoo>