From 37b7a0da7e64d5b692f83c12ad0072a622e44f97 Mon Sep 17 00:00:00 2001 From: Rodolpho Lima Date: Fri, 24 Nov 2023 17:36:43 +0100 Subject: [PATCH] [FIX] web_editor: paste odoo-editor html in iframe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before this commit, pasting html content that had been copied from the the Editor failed to paste any content when inside an iframe. This happened because the DOMPurify library was not configured to use the iframe's window for Node prototypes, which led `instanceof` checks to fail, removing nodes a result. Additionally, commit [1] did not do the job completely: while the document for creating the document fragment became the one received as parameter, the DOMParser constructor remained the one from the window in which the JS code is executed, which might be different from the received document's window. This mismatch happens in particularly when the editable is inside an iframe. task-3575496 [1]: https://github.com/odoo/odoo/commit/c74d01279e49fadc5f509cfc3f6baf43d2b532d1 closes odoo/odoo#144744 Signed-off-by: Geelen Sébastien (sge) --- .../js/editor/odoo-editor/src/OdooEditor.js | 4 ++- .../js/editor/odoo-editor/src/utils/utils.js | 2 +- .../odoo-editor/test/spec/copyPaste.test.js | 31 ++++++++++++++++++- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js b/addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js index 08a75a216a0..ff1adb58410 100644 --- a/addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js +++ b/addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js @@ -4748,7 +4748,9 @@ export class OdooEditor extends EventTarget { } if (odooEditorHtml && targetSupportsHtmlContent) { const fragment = parseHTML(this.document, odooEditorHtml); - DOMPurify.sanitize(fragment, { IN_PLACE: true }); + // Instantiate DOMPurify with the correct window. + this.DOMPurify ??= DOMPurify(this.document.defaultView); + this.DOMPurify.sanitize(fragment, { IN_PLACE: true }); if (fragment.hasChildNodes()) { this._applyCommand('insert', fragment); } diff --git a/addons/web_editor/static/src/js/editor/odoo-editor/src/utils/utils.js b/addons/web_editor/static/src/js/editor/odoo-editor/src/utils/utils.js index b7e6a8c7c0c..5dfa633b2ff 100644 --- a/addons/web_editor/static/src/js/editor/odoo-editor/src/utils/utils.js +++ b/addons/web_editor/static/src/js/editor/odoo-editor/src/utils/utils.js @@ -2725,7 +2725,7 @@ export function rgbToHex(rgb = '', node = null) { export function parseHTML(document, html) { const fragment = document.createDocumentFragment(); - const parser = new DOMParser(); + const parser = new document.defaultView.DOMParser(); const parsedDocument = parser.parseFromString(html, 'text/html'); fragment.replaceChildren(...parsedDocument.body.childNodes); return fragment; diff --git a/addons/web_editor/static/src/js/editor/odoo-editor/test/spec/copyPaste.test.js b/addons/web_editor/static/src/js/editor/odoo-editor/test/spec/copyPaste.test.js index 9cf5a3b4974..0fa2d8a6315 100644 --- a/addons/web_editor/static/src/js/editor/odoo-editor/test/spec/copyPaste.test.js +++ b/addons/web_editor/static/src/js/editor/odoo-editor/test/spec/copyPaste.test.js @@ -12,7 +12,7 @@ import { pasteHtml, pasteOdooEditorHtml, } from "../utils.js"; -import {CLIPBOARD_WHITELISTS} from "../../src/OdooEditor.js"; +import { CLIPBOARD_WHITELISTS, setSelection } from "../../src/OdooEditor.js"; describe('Copy', () => { describe('range collapsed', async () => { @@ -2219,4 +2219,33 @@ describe('Paste', () => { }); }); }); + describe('editable in iframe', () => { + it('should paste odoo-editor html', async () => { + // Setup + const testContainer = document.querySelector('#editor-test-container'); + const iframe = document.createElement('iframe'); + testContainer.append(iframe); + const iframeDocument = iframe.contentDocument; + const editable = iframeDocument.createElement('div'); + iframeDocument.body.append(editable); + const editor = new BasicEditor(editable, { document: iframeDocument }); + + // Action: paste + setSelection(editable.querySelector('p'), 0); + const clipboardData = new DataTransfer(); + clipboardData.setData('text/odoo-editor', '

textbold textmore text

'); + await triggerEvent(editor.editable, 'paste', { clipboardData }); + + // Clean-up + editor.clean(); + editor.destroy(); + iframe.remove(); + + // Assertion + window.chai.expect(editable.innerHTML).to.be.equal( + '

textbold textmore text

', + 'should paste content in the paragraph' + ); + }); + }); });