diff --git a/addons/website/static/src/components/wysiwyg_adapter/wysiwyg_adapter.js b/addons/website/static/src/components/wysiwyg_adapter/wysiwyg_adapter.js index 20a86f16a35..8c7c0ee12ea 100644 --- a/addons/website/static/src/components/wysiwyg_adapter/wysiwyg_adapter.js +++ b/addons/website/static/src/components/wysiwyg_adapter/wysiwyg_adapter.js @@ -46,6 +46,25 @@ function toggleDropdown($toggles, show) { })).then(() => $toggles); } +/** + * Checks if the classes that changed during the mutation are all to be ignored. + * (The mutation can be discarded if it is the case, when filtering the mutation + * records). + * + * @param {Object} record the current mutation + * @param {Array} excludedClasses the classes to ignore + * @returns {Boolean} + */ +function checkForExcludedClasses(record, excludedClasses) { + const classBefore = (record.oldValue && record.oldValue.split(" ")) || []; + const classAfter = [...record.target.classList]; + const changedClasses = [ + ...classBefore.filter(c => c && !classAfter.includes(c)), + ...classAfter.filter(c => c && !classBefore.includes(c)), + ]; + return changedClasses.every(c => excludedClasses.includes(c)); +} + /** * This component adapts the Wysiwyg widget from @web_editor/wysiwyg.js. * It encapsulate it so that this legacy widget can work in an OWL framework. @@ -172,7 +191,6 @@ export class WysiwygAdapterComponent extends Wysiwyg { // Since bootstrap 5.1.3, removing bsToggle is not sufficient anymore. $dropdownMenuToggles.siblings(".dropdown-menu").addClass("o_wysiwyg_submenu"); $dropdownMenuToggles.on('click.wysiwyg_megamenu', ev => { - this.odooEditor.observerUnactive(); var $toggle = $(ev.currentTarget); // Each time we toggle a dropdown, we will destroy the dropdown @@ -189,10 +207,7 @@ export class WysiwygAdapterComponent extends Wysiwyg { if (!this.options.enableTranslation) { this._toggleMegaMenu($toggle[0]); } - }) - // FIXME this is not right, the observer should not be inactive - // for async periods of time. - .then(() => this.odooEditor.observerActive()); + }); }); // Ensure :blank oe_structure elements are in fact empty as ':blank' @@ -204,6 +219,66 @@ export class WysiwygAdapterComponent extends Wysiwyg { } await super.startEdition(); + // Overriding the `filterMutationRecords` function so it can be used to + // filter website-specific mutations. + const webEditorFilterMutationRecords = this.odooEditor.options.filterMutationRecords; + Object.assign(this.odooEditor.options, { + /** + * @override + */ + filterMutationRecords(records) { + const filteredRecords = webEditorFilterMutationRecords(records); + + // Dropdown attributes to ignore. + const dropdownClasses = ["show"]; + const dropdownToggleAttributes = ["aria-expanded"]; + const dropdownMenuAttributes = ["data-popper-placement", "style", "data-bs-popper"]; + // Offcanvas attributes to ignore. + const offcanvasClasses = ["show"]; + const offcanvasAttributes = ["aria-modal", "aria-hidden", "role", "style"]; + + return filteredRecords.filter(record => { + if (record.type === "attributes") { + if (record.target.closest("header#top")) { + // Do not record when showing/hiding a dropdown. + if (record.target.matches(".dropdown-toggle, .dropdown-menu") + && record.attributeName === "class") { + if (checkForExcludedClasses(record, dropdownClasses)) { + return false; + } + } else if (record.target.matches(".dropdown-menu") + && dropdownMenuAttributes.includes(record.attributeName)) { + return false; + } else if (record.target.matches(".dropdown-toggle") + && dropdownToggleAttributes.includes(record.attributeName)) { + return false; + } + + // Do not record when showing/hiding an offcanvas. + if (record.target.matches(".offcanvas, .offcanvas-backdrop") + && record.attributeName === "class") { + if (checkForExcludedClasses(record, offcanvasClasses)) { + return false; + } + } else if (record.target.matches(".offcanvas") + && offcanvasAttributes.includes(record.attributeName)) { + return false; + } + } + } else if (record.type === "childList") { + const addedOrRemovedNode = record.addedNodes[0] || record.removedNodes[0]; + // Do not record the addition/removal of the offcanvas + // backdrop. + if (addedOrRemovedNode.nodeType === Node.ELEMENT_NODE + && addedOrRemovedNode.matches(".offcanvas-backdrop")) { + return false; + } + } + return true; + }); + } + }); + // Disable OdooEditor observer's while setting up classes this.odooEditor.observerUnactive(); this._addEditorMessages(); @@ -979,7 +1054,9 @@ export class WysiwygAdapterComponent extends Wysiwyg { if (!megaMenuEl || !megaMenuEl.classList.contains('show')) { return this.snippetsMenu.activateSnippet(false); } + this.odooEditor.observerUnactive("toggleMegaMenu"); megaMenuEl.classList.add('o_no_parent_editor'); + this.odooEditor.observerActive("toggleMegaMenu"); return this.snippetsMenu.activateSnippet($(megaMenuEl)); } /** diff --git a/addons/website/static/src/js/content/auto_hide_menu.js b/addons/website/static/src/js/content/auto_hide_menu.js index cfffa333ca3..9419e80e58f 100644 --- a/addons/website/static/src/js/content/auto_hide_menu.js +++ b/addons/website/static/src/js/content/auto_hide_menu.js @@ -115,7 +115,9 @@ async function autoHideMenu(el, options) { const wysiwyg = window.$ && $('#wrapwrap').data('wysiwyg'); const odooEditor = wysiwyg && wysiwyg.odooEditor; if (odooEditor) { + odooEditor.observerUnactive("adapt"); odooEditor.withoutRollback(__adapt); + odooEditor.observerActive("adapt"); return; } __adapt(); diff --git a/addons/website/static/src/js/content/menu.js b/addons/website/static/src/js/content/menu.js index 3fc09d685a8..d6959ca9766 100644 --- a/addons/website/static/src/js/content/menu.js +++ b/addons/website/static/src/js/content/menu.js @@ -704,13 +704,17 @@ publicWidget.registry.HeaderGeneral = publicWidget.Widget.extend({ * @private */ _onCollapseShow() { + this.options.wysiwyg?.odooEditor.observerUnactive("addCollapseClass"); this.el.classList.add('o_top_menu_collapse_shown'); + this.options.wysiwyg?.odooEditor.observerActive("addCollapseClass"); }, /** * @private */ _onCollapseHidden() { + this.options.wysiwyg?.odooEditor.observerUnactive("removeCollapseClass"); this.el.classList.remove('o_top_menu_collapse_shown'); + this.options.wysiwyg?.odooEditor.observerActive("removeCollapseClass"); }, /** * @private