[FIX] web_editor: paste odoo-editor html in iframe

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) <sge@odoo.com>
This commit is contained in:
Rodolpho Lima
2023-12-06 08:20:08 +00:00
parent 11a81bf88b
commit 37b7a0da7e
3 changed files with 34 additions and 3 deletions
@@ -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);
}
@@ -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;
@@ -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', '<p>text<b>bold text</b>more text</p>');
await triggerEvent(editor.editable, 'paste', { clipboardData });
// Clean-up
editor.clean();
editor.destroy();
iframe.remove();
// Assertion
window.chai.expect(editable.innerHTML).to.be.equal(
'<p>text<b>bold text</b>more text<br></p>',
'should paste content in the paragraph'
);
});
});
});