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 2ca099a70ef..93f4aadd5a2 100644 --- a/addons/web_editor/static/src/js/editor/snippets.editor.js +++ b/addons/web_editor/static/src/js/editor/snippets.editor.js @@ -2643,6 +2643,11 @@ var SnippetsMenu = Widget.extend({ * @return {Promise} */ async _scrollToSnippet($el, $scrollable) { + // Don't scroll if $el is added to a visible popup that does not fill + // the page (otherwise the page would scroll to a random location). + if ($el.closest('div.modal:not(.s_popup_overflow_page)').length) { + return; + } return dom.scrollTo($el[0], {extraOffset: 50, $scrollable: $scrollable}); }, /** diff --git a/addons/website/static/src/snippets/s_popup/000.js b/addons/website/static/src/snippets/s_popup/000.js index cb8b2fa3e9c..ba6194ed02d 100644 --- a/addons/website/static/src/snippets/s_popup/000.js +++ b/addons/website/static/src/snippets/s_popup/000.js @@ -117,22 +117,63 @@ const PopupWidget = publicWidget.Widget.extend({ publicWidget.registry.popup = PopupWidget; +// Try to update the scrollbar based on the current context (modal state) +// and only if the modal overflowing has changed + +function _updateScrollbar(ev) { + const context = ev.data; + const modalContent = context._element.querySelector('.modal-content'); + const currentOverflow = modalContent.offsetHeight >= window.innerHeight; + if (modalContent && context._isOverflowingWindow !== currentOverflow) { + context._isOverflowingWindow = currentOverflow; + context._checkScrollbar(); + context._setScrollbar(); + if (context._element.classList.contains('s_popup_overflow_page')) { + $(document.body).addClass('modal-open'); + } else { + $(document.body).removeClass('modal-open'); + context._resetScrollbar(); + } + } +} + // Prevent bootstrap to prevent scrolling and to add the strange body // padding-right they add if the popup does not use a backdrop (especially // important for default cookie bar). + +const _baseShowElement = $.fn.modal.Constructor.prototype._showElement; +$.fn.modal.Constructor.prototype._showElement = function () { + _baseShowElement.apply(this, arguments); + // Update the scrollbar if the content changes or if the window has been + // resized + $(this._element).on('content_changed.update_scrollbar', this, _updateScrollbar); + $(window).on('resize.update_scrollbar', this, _updateScrollbar); + _updateScrollbar({ data: this }); +}; + +const _baseHideModal = $.fn.modal.Constructor.prototype._hideModal; +$.fn.modal.Constructor.prototype._hideModal = function () { + _baseHideModal.apply(this, arguments); + $(this._element).off('content_changed.update_scrollbar'); + $(window).off('resize.update_scrollbar'); +}; + const _baseSetScrollbar = $.fn.modal.Constructor.prototype._setScrollbar; $.fn.modal.Constructor.prototype._setScrollbar = function () { - if (this._element.classList.contains('s_popup_no_backdrop')) { + if (this._element.classList.contains('s_popup_no_backdrop') && !this._isOverflowingWindow) { + this._element.classList.remove('s_popup_overflow_page'); return; } - return _baseSetScrollbar.apply(this, ...arguments); + this._element.classList.add('s_popup_overflow_page'); + return _baseSetScrollbar.apply(this, arguments); }; + const _baseGetScrollbarWidth = $.fn.modal.Constructor.prototype._getScrollbarWidth; $.fn.modal.Constructor.prototype._getScrollbarWidth = function () { - if (this._element.classList.contains('s_popup_no_backdrop')) { + if (this._element.classList.contains('s_popup_no_backdrop') && !this._isOverflowingWindow) { return 0; } - return _baseGetScrollbarWidth.apply(this, ...arguments); + return _baseGetScrollbarWidth.apply(this, arguments); }; return PopupWidget; diff --git a/addons/website/static/src/snippets/s_popup/001.scss b/addons/website/static/src/snippets/s_popup/001.scss index f8ae94ca632..a8200adf4e9 100644 --- a/addons/website/static/src/snippets/s_popup/001.scss +++ b/addons/website/static/src/snippets/s_popup/001.scss @@ -63,7 +63,12 @@ // No backdrop .s_popup_no_backdrop { - pointer-events: none; + // If the popup is taller than the page you should not be able to + // interact with the elements behind, otherwise you should (when there + // is no backdrop). + &:not(.s_popup_overflow_page) { + pointer-events: none; + } .modal-content { pointer-events: auto; diff --git a/addons/website/static/src/snippets/s_popup/options.js b/addons/website/static/src/snippets/s_popup/options.js index cf0dfca6041..722c3ada212 100644 --- a/addons/website/static/src/snippets/s_popup/options.js +++ b/addons/website/static/src/snippets/s_popup/options.js @@ -79,6 +79,12 @@ options.registry.SnippetPopup = options.Class.extend({ this.$target.modal('hide'); }); }, + /** + * @override + */ + cleanForSave: function () { + this.$target.removeClass("s_popup_overflow_page"); + }, //-------------------------------------------------------------------------- // Options