diff --git a/addons/web_editor/static/src/js/editor/snippets.editor.js b/addons/web_editor/static/src/js/editor/snippets.editor.js index 9f093ae8751..482d94aa779 100644 --- a/addons/web_editor/static/src/js/editor/snippets.editor.js +++ b/addons/web_editor/static/src/js/editor/snippets.editor.js @@ -3051,9 +3051,6 @@ var SnippetsMenu = Widget.extend({ // Register the text nodes that needs to be auto-selected on click this._registerDefaultTexts(); - // Force non editable part to contentEditable=false - $html.find('.o_not_editable').attr('contentEditable', false); - // Add the computed template and make elements draggable this.$el.html($html); this.$el.append(this.customizePanel); diff --git a/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js b/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js index 351afe3e3d0..faeb082e6c9 100644 --- a/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js +++ b/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js @@ -109,7 +109,6 @@ const Wysiwyg = Widget.extend({ this._signalOnline = this._signalOnline.bind(this); this.tooltipTimeouts = []; Wysiwyg.activeWysiwygs.add(this); - this._oNotEditableObservers = new Map(); this._joinPeerToPeer = this._joinPeerToPeer.bind(this); }, /** @@ -178,7 +177,7 @@ const Wysiwyg = Widget.extend({ document: this.options.document, autohideToolbar: !!this.options.autohideToolbar, isRootEditable: this.options.isRootEditable, - onPostSanitize: this._setONotEditable.bind(this), + onPostSanitize: this._onPostSanitize.bind(this), placeholder: this.options.placeholder, powerboxFilters: this.options.powerboxFilters || [], showEmptyElementHint: this.options.showEmptyElementHint, @@ -409,12 +408,12 @@ const Wysiwyg = Widget.extend({ this.setCSSVariables(this.snippetsMenu ? this.snippetsMenu.el : this.toolbar.el); this.odooEditor.addEventListener('preObserverActive', () => { - // The setONotEditable will be called right after the + // The onPostSanitize will be called right after the // editor sanitization (to be right before the historyStep). // If any `.o_not_editable` is created while the observer is - // unactive, now is the time to call `setONotEditable` before the + // unactive, now is the time to call `onPostSanitize` before the // editor could register a mutation. - this._setONotEditable(this.odooEditor.editable); + this._onPostSanitize(this.odooEditor.editable); }); if (this.options.autohideToolbar) { @@ -716,9 +715,6 @@ const Wysiwyg = Widget.extend({ this.odooEditor.document.removeEventListener("keydown", this._signalOnline, true); this.odooEditor.document.removeEventListener("keyup", this._signalOnline, true); this.odooEditor.document.removeEventListener('selectionchange', this._onSelectionChange); - for (const observer of this._oNotEditableObservers.values()) { - observer.disconnect(); - } this.odooEditor.destroy(); } // If peer to peer is initializing, wait for properly closing it. @@ -2680,40 +2676,17 @@ const Wysiwyg = Widget.extend({ await this._peerToPeerLoading; }, /** - * Set contenteditable=false for all `.o_not_editable` found within node if - * node is an element. - * - * For all `.o_not_editable` element found, the attribute contenteditable - * will be removed if the class is removed. + * Set `contenteditable` according to `.o_not_editable` and `.o_editable`. * * @param {Node} node */ - _setONotEditable: function (node) { - const nodes = (node && node.querySelectorAll && node.querySelectorAll('.o_not_editable:not([contenteditable=false])')) || []; - for (const node of nodes) { - node.setAttribute('contenteditable', false); - let observer = this._oNotEditableObservers.get(node); - if (!observer) { - observer = new MutationObserver((records) => { - for (const record of records) { - if (record.type === 'attributes' && record.attributeName === 'class') { - // Remove contenteditable=false on nodes that were - // previsouly o_not_editable but are no longer - // o_not_editable. - if (!node.classList.contains('o_not_editable')) { - this.odooEditor.observerUnactive('_setONotEditable'); - node.removeAttribute('contenteditable'); - this.odooEditor.observerActive('_setONotEditable'); - observer.disconnect(); - this._oNotEditableObservers.delete(node); - } - } - } - }); - this._oNotEditableObservers.set(node, observer); - observer.observe(node, { - attributes: true, - }); + _onPostSanitize: function (node) { + if (node?.querySelectorAll) { + for (const element of node.querySelectorAll('.o_editable, .o_not_editable')) { + const editable = element.classList.contains('o_editable'); + if (element.isContentEditable !== editable) { + element.contentEditable = editable; + } } } }, diff --git a/addons/website/static/tests/tours/link_tools.js b/addons/website/static/tests/tours/link_tools.js index 211fab1ae4e..399c5172804 100644 --- a/addons/website/static/tests/tours/link_tools.js +++ b/addons/website/static/tests/tours/link_tools.js @@ -71,6 +71,7 @@ wTourUtils.registerWebsitePreviewTour('link_tools', { ...wTourUtils.clickOnSave(), // 3. Edit a link after saving the page. ...wTourUtils.clickOnEditAndWaitEditMode(), + clickOnImgStep, { content: "The new link content should be odoo website and url odoo.be", trigger: 'iframe .s_text_image a[href="http://odoo.be"]:contains("odoo website")',