[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
This commit is contained in:
Antoine Guenet
2023-11-07 21:02:24 +00:00
committed by Sébastien Geelen (sge)
parent ef11e75b70
commit 2f1786c5d2
@@ -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,