From 2f1786c5d234fcc2f418cafd285d8cf4ecdc5020 Mon Sep 17 00:00:00 2001 From: Antoine Guenet Date: Tue, 24 Oct 2023 11:23:25 +0200 Subject: [PATCH] [FIX] web_editor: ensure observer is always disabled for link zws To prevent history steps that include the link zws, we need to ensure that the observer is always disabled when the link zws is inserted or removed. Due to these changes, we need to initialize `_currentStep` before setting the original link zws, so that `observerApply` can access it in the process of pausing the mutations observer. Part-of: odoo/odoo#141303 --- .../js/editor/odoo-editor/src/OdooEditor.js | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 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 51599ec18ad..812487a8729 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 @@ -340,6 +340,11 @@ export class OdooEditor extends EventTarget { // Set contenteditable before clone as FF updates the content at this point. this._activateContenteditable(); + this._currentStep = { + selection: {}, + mutations: [], + }; + this._setLinkZws(); this._collabClientId = this.options.collaborationClientId; @@ -1279,7 +1284,7 @@ export class OdooEditor extends EventTarget { if (!this._historyStepsActive) { return; } - this._setLinkZws(); + this._resetLinkZws(); this.sanitize(); // check that not two unBreakables modified if (this._toRollback) { @@ -1302,6 +1307,7 @@ export class OdooEditor extends EventTarget { if (this.options.onHistoryStep) { this.options.onHistoryStep(currentStep); } + this._setLinkZws(); this._currentStep = { selection: {}, mutations: [], @@ -2020,15 +2026,14 @@ export class OdooEditor extends EventTarget { link.firstElementChild.nodeName === 'IMG' ) ) { - link.prepend(this._createLinkZws('start')); + this._insertLinkZws('start', link); // Only add the ZWS at the end if the link is in selection. if (link === linkInSelection) { - link.append(this._createLinkZws('end')); + this._insertLinkZws('end', link); link.classList.add('o_link_in_selection'); didAddZwsInLinkInSelection = true; } - const zwsAfter = this._createLinkZws('after'); - link.after(zwsAfter); + const zwsAfter = this._insertLinkZws('after', link); if (!zwsAfter.parentElement || !zwsAfter.parentElement.isContentEditable) { zwsAfter.remove(); } @@ -2521,8 +2526,10 @@ export class OdooEditor extends EventTarget { } } _resetLinkZws(element = this.editable) { + this.observerUnactive('_resetLinkZws'); element.querySelectorAll('[data-o-link-zws]').forEach(zws => zws.remove()); element.querySelectorAll('.o_link_in_selection').forEach(link => link.classList.remove('o_link_in_selection')); + this.observerActive('_resetLinkZws'); } _activateContenteditable() { this.observerUnactive('_activateContenteditable'); @@ -3489,13 +3496,22 @@ export class OdooEditor extends EventTarget { } this.observer.takeRecords(); } - _createLinkZws(side) { + _insertLinkZws(side, link) { + this.observerUnactive('_insertLinkZws'); const span = document.createElement('span'); span.setAttribute('data-o-link-zws', side); if (side !== 'end') { span.setAttribute('contenteditable', 'false'); } span.textContent = '\u200B'; + if (side === 'start') { + link.prepend(span); + } else if (side === 'end') { + link.append(span); + } else if (side === 'after') { + link.after(span); + } + this.observerActive('_insertLinkZws'); return span; } @@ -4045,8 +4061,7 @@ export class OdooEditor extends EventTarget { if (isAtEndOfLink) { let afterZws = link.nextElementSibling; if (!afterZws) { - afterZws = this._createLinkZws('after'); - link.after(afterZws); + afterZws = this._insertLinkZws('after', link); } setSelection( afterZws.nextSibling || afterZws.parentElement,