From c5bb2d0838591740e0165d81186b0954abc439e1 Mon Sep 17 00:00:00 2001 From: Renaud Thiry Date: Wed, 1 Mar 2023 09:03:28 +0000 Subject: [PATCH] [FIX] web_editor: prevent editing of header The way the live HTML editor for html_field works means the header (and other nodes that should only appear once) are removed and the content inserted inside the body. This results in values being edited without the user being aware. For emails, this results in any email using 'style' in the header to break on GMail and other clients that do not support 'style' outside of the header. When an html_field is passed a value containing a header the html_field appears readonly and the user is able to toggle the code view. Which enables them to edit the 'raw' HTML and see changes while preventing the presentation view from affecting the database value task - 3035163 closes odoo/odoo#118920 Signed-off-by: Thibault Delavallee (tde) Signed-off-by: Thiry Renaud (reth) --- .../static/src/js/backend/html_field.js | 26 ++-- .../static/src/js/backend/html_field.xml | 12 +- .../static/tests/html_field_tests.js | 126 ++++++++++++++++++ 3 files changed, 149 insertions(+), 15 deletions(-) create mode 100644 addons/web_editor/static/tests/html_field_tests.js diff --git a/addons/web_editor/static/src/js/backend/html_field.js b/addons/web_editor/static/src/js/backend/html_field.js index bed37dc3565..676fc314321 100644 --- a/addons/web_editor/static/src/js/backend/html_field.js +++ b/addons/web_editor/static/src/js/backend/html_field.js @@ -74,6 +74,12 @@ export class HtmlFieldWysiwygAdapterComponent extends ComponentAdapter { export class HtmlField extends Component { setup() { + // readonly if nodes in as the head will be removed on insertion in the DOM + // this prevents the field from overwriting the value with invalid HTML when relevant + const domParser = new DOMParser(); + const parsedOriginal = domParser.parseFromString(this.props.record.data[this.props.name] || '', 'text/html'); + this.containsComplexHTML = !!parsedOriginal.head.innerHTML.trim(); + this.readonlyElementRef = useRef("readonlyElement"); this.codeViewRef = useRef("codeView"); this.iframeRef = useRef("iframe"); @@ -326,19 +332,21 @@ export class HtmlField extends Component { } /** * Toggle the code view and update the UI. - * - * @param {JQuery} $codeview */ toggleCodeView() { this.state.showCodeView = !this.state.showCodeView; - this.wysiwyg.odooEditor.observerUnactive('toggleCodeView'); - if (this.state.showCodeView) { - this.wysiwyg.odooEditor.toolbarHide(); - const value = this.wysiwyg.getValue(); - this.props.record.update({ [this.props.name]: value }); - } else { - this.wysiwyg.odooEditor.observerActive('toggleCodeView'); + if (this.wysiwyg) { + this.wysiwyg.odooEditor.observerUnactive('toggleCodeView'); + if (this.state.showCodeView) { + this.wysiwyg.odooEditor.toolbarHide(); + const value = this.wysiwyg.getValue(); + this.props.record.update({ [this.props.name]: value }); + } else { + this.wysiwyg.odooEditor.observerActive('toggleCodeView'); + } + } + if (!this.state.showCodeView) { const $codeview = $(this.codeViewRef.el); const value = $codeview.val(); this.props.record.update({ [this.props.name]: value }); diff --git a/addons/web_editor/static/src/js/backend/html_field.xml b/addons/web_editor/static/src/js/backend/html_field.xml index 59e79040520..1c287cd22d6 100644 --- a/addons/web_editor/static/src/js/backend/html_field.xml +++ b/addons/web_editor/static/src/js/backend/html_field.xml @@ -2,7 +2,7 @@ - + @@ -13,11 +13,6 @@