diff --git a/addons/website/static/src/snippets/s_searchbar/000.js b/addons/website/static/src/snippets/s_searchbar/000.js index ee45d1c957f..b6a0a864e91 100644 --- a/addons/website/static/src/snippets/s_searchbar/000.js +++ b/addons/website/static/src/snippets/s_searchbar/000.js @@ -82,11 +82,29 @@ publicWidget.registry.searchBar = publicWidget.Widget.extend({ } return this._super.apply(this, arguments); }, + /** + * @override + */ + destroy() { + this._super(...arguments); + this._render(null); + }, //-------------------------------------------------------------------------- // Private //-------------------------------------------------------------------------- + /** + * @private + */ + _adaptToScrollingParent() { + const bcr = this.el.getBoundingClientRect(); + this.$menu[0].style.setProperty('position', 'fixed', 'important'); + this.$menu[0].style.setProperty('top', `${bcr.bottom}px`, 'important'); + this.$menu[0].style.setProperty('left', `${bcr.left}px`, 'important'); + this.$menu[0].style.setProperty('max-width', `${bcr.width}px`, 'important'); + this.$menu[0].style.setProperty('max-height', `${document.body.clientHeight - bcr.bottom - 16}px`, 'important'); + }, /** * @private */ @@ -123,6 +141,13 @@ publicWidget.registry.searchBar = publicWidget.Widget.extend({ * @private */ _render: function (res) { + if (this._scrollingParentEl) { + this._scrollingParentEl.removeEventListener('scroll', this._menuScrollAndResizeHandler); + window.removeEventListener('resize', this._menuScrollAndResizeHandler); + delete this._scrollingParentEl; + delete this._menuScrollAndResizeHandler; + } + const $prevMenu = this.$menu; this.$el.toggleClass('dropdown show', !!res); if (res && this.limit) { @@ -141,7 +166,29 @@ publicWidget.registry.searchBar = publicWidget.Widget.extend({ widget: this, })); this.$menu.css('min-width', this.autocompleteMinWidth); + + // Handle the case where the searchbar is in a mega menu by making + // it position:fixed and forcing its size. Note: this could be the + // default behavior or at least needed in more cases than the mega + // menu only (all scrolling parents). But as a stable fix, it was + // easier to fix that case only as a first step, especially since + // this cannot generically work on all scrolling parent. + const megaMenuEl = this.el.closest('.o_mega_menu'); + if (megaMenuEl) { + const navbarEl = this.el.closest('.navbar'); + const navbarTogglerEl = navbarEl ? navbarEl.querySelector('.navbar-toggler') : null; + if (navbarTogglerEl && navbarTogglerEl.clientWidth < 1) { + this._scrollingParentEl = megaMenuEl; + this._menuScrollAndResizeHandler = () => this._adaptToScrollingParent(); + this._scrollingParentEl.addEventListener('scroll', this._menuScrollAndResizeHandler); + window.addEventListener('resize', this._menuScrollAndResizeHandler); + + this._adaptToScrollingParent(); + } + } + this.$el.append(this.$menu); + this.$el.find('button.extra_link').on('click', function (event) { event.preventDefault(); window.location.href = event.currentTarget.dataset['target']; @@ -153,6 +200,7 @@ publicWidget.registry.searchBar = publicWidget.Widget.extend({ form.submit(); }); } + if ($prevMenu) { $prevMenu.remove(); }