diff --git a/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js b/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js index b36f2b5e70b..63853bb2f28 100644 --- a/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js +++ b/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js @@ -273,6 +273,7 @@ export class Wysiwyg extends Component { this.colorpickers = {}; this._onDocumentMousedown = this._onDocumentMousedown.bind(this); this._onBlur = this._onBlur.bind(this); + this._onScroll = this._onScroll.bind(this); this.customizableLinksSelector = 'a' + ':not([data-bs-toggle="tab"])' + ':not([data-bs-toggle="collapse"])' @@ -947,6 +948,7 @@ export class Wysiwyg extends Component { for (const timeout of this.tooltipTimeouts) { clearTimeout(timeout); } + document.removeEventListener('scroll', this._onScroll, true); } /** * @override @@ -1919,18 +1921,10 @@ export class Wysiwyg extends Component { } this._updateFaResizeButtons(); }); - // we need the Timeout to be sure the editable content is loaded - // before calculating the scrollParent() element. - setTimeout(() => { - const scrollableContainer = this.$el.scrollParent(); - if (!options.snippets && scrollableContainer.length) { - this.odooEditor.addDomListener( - scrollableContainer[0], - 'scroll', - this.odooEditor.updateToolbarPosition.bind(this.odooEditor), - ); - } - }, 0); + if (!options.snippets) { + // Scroll event does not bubble. + document.addEventListener('scroll', this._onScroll, true); + } } /** * @private @@ -2764,6 +2758,11 @@ export class Wysiwyg extends Component { this.options.onWysiwygBlur && this.options.onWysiwygBlur(); } } + _onScroll(ev) { + if (ev.target.contains(this.$editable[0])) { + this.odooEditor.updateToolbarPosition(); + } + } _signalOffline() { if (!this._isOnline) { return; diff --git a/addons/web_editor/static/src/js/wysiwyg/wysiwyg_iframe.js b/addons/web_editor/static/src/js/wysiwyg/wysiwyg_iframe.js index 0bb692ac1c1..f6eef88e415 100644 --- a/addons/web_editor/static/src/js/wysiwyg/wysiwyg_iframe.js +++ b/addons/web_editor/static/src/js/wysiwyg/wysiwyg_iframe.js @@ -38,6 +38,16 @@ patch(Wysiwyg.prototype, { } }, + /** + * @override + **/ + destroy() { + if (this.options.inIframe) { + this.$iframe?.[0].contentDocument.removeEventListener('scroll', this._onScroll, true); + } + super.destroy(); + }, + //-------------------------------------------------------------------------- // Private //-------------------------------------------------------------------------- @@ -180,6 +190,37 @@ patch(Wysiwyg.prototype, { this.$iframe[0].contentWindow.addEventListener('blur', this._onBlur); } }, + + /** + * When the editable is inside an iframe, we want to update the toolbar + * position in 2 scenarios: + * 1. scroll event in the top document, if the iframe is a descendant of + * the scroll container. + * 2. scroll event in the iframe's document. + * + * @override + */ + _onScroll(ev) { + if (this.options.inIframe) { + const iframeDocument = this.$iframe[0].contentDocument; + const scrollInIframe = ev.target === iframeDocument || ev.target.ownerDocument === iframeDocument; + if (ev.target.contains(this.$iframe[0]) || scrollInIframe) { + this.odooEditor.updateToolbarPosition(); + } + } else { + return super._onScroll(...arguments); + } + }, + + /** + * @override + */ + _configureToolbar(options) { + super._configureToolbar(...arguments); + if (this.options.inIframe && !options.snippets) { + this.$iframe[0].contentDocument.addEventListener('scroll', this._onScroll, true); + } + }, }); function getWysiwygIframeContent(params) {