diff --git a/addons/web_editor/static/src/js/editor/snippets.options.js b/addons/web_editor/static/src/js/editor/snippets.options.js index b3bca12b765..1244773ff3a 100644 --- a/addons/web_editor/static/src/js/editor/snippets.options.js +++ b/addons/web_editor/static/src/js/editor/snippets.options.js @@ -6757,7 +6757,7 @@ registry.BackgroundShape = SnippetOptionWidget.extend({ const shapeContainer = target.querySelector(':scope > .o_we_shape'); if (shapeContainer) { - shapeContainer.remove(); + this._removeShapeEl(shapeContainer); } if (newContainer) { const preShapeLayerElement = this._getLastPreShapeLayerElement(); @@ -6855,6 +6855,13 @@ registry.BackgroundShape = SnippetOptionWidget.extend({ this.prevShape = target.dataset.oeShapeData; } }, + /** + * @private + * @param {HTMLElement} shapeEl + */ + _removeShapeEl(shapeEl) { + shapeEl.remove(); + }, /** * Overwrites shape properties with the specified data. * diff --git a/addons/website/static/src/js/content/snippets.animation.js b/addons/website/static/src/js/content/snippets.animation.js index e2f0fc14569..1e1cde02534 100644 --- a/addons/website/static/src/js/content/snippets.animation.js +++ b/addons/website/static/src/js/content/snippets.animation.js @@ -1467,6 +1467,89 @@ registry.ImagesLazyLoading = publicWidget.Widget.extend({ }, }); +/** + * @todo while this solution mitigates the issue, it is not fixing it entirely + * but mainly, we should find a better solution than a JS solution as soon as + * one is available and ideally without having to make ugly patches to the SVGs. + * + * Due to a bug on Chrome when using browser zoom, there is sometimes a gap + * between sections with shapes. This gap is due to a rounding issue when + * positioning the SVG background images. This code reduces the rounding error + * by ensuring that shape elements always have a width value as close to an + * integer as possible. + * + * Note: a gap also appears between some shapes without zoom. This is likely + * due to error in the shapes themselves. Many things were done to try and fix + * this, but the remaining errors will likely be fixed with a review of the + * shapes in future Odoo versions. + * + * /!\ + * If a better solution for stable comes up, this widget behavior may be + * disabled, avoid depending on it if possible. + * /!\ + */ +registry.ZoomedBackgroundShape = publicWidget.Widget.extend({ + selector: '.o_we_shape', + disabledInEditableMode: false, + + /** + * @override + */ + start() { + this._onBackgroundShapeResize(); + this.throttledShapeResize = _.throttle(() => this._onBackgroundShapeResize(), 25); + window.addEventListener('resize', this.throttledShapeResize); + return this._super(...arguments); + }, + /** + * @override + */ + destroy() { + this._updateShapePosition(); + window.removeEventListener('resize', this.throttledShapeResize); + this._super(...arguments); + }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * Updates the left and right offset of the shape. + * + * @private + * @param {string} offset + */ + _updateShapePosition(offset = '') { + this.el.style.left = offset; + this.el.style.right = offset; + }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + /** + * @private + */ + _onBackgroundShapeResize() { + this._updateShapePosition(); + // Get the decimal part of the shape element width. + let decimalPart = this.el.getBoundingClientRect().width % 1; + // Round to two decimal places. + decimalPart = Math.round((decimalPart + Number.EPSILON) * 100) / 100; + // If there is a decimal part. (e.g. Chrome + browser zoom enabled) + if (decimalPart > 0) { + // Compensate for the gap by giving an integer width value to the + // shape by changing its "right" and "left" positions. + let offset = (decimalPart < 0.5 ? decimalPart : decimalPart - 1) / 2; + // This never causes the horizontal scrollbar to appear because it + // only appears if the overflow to the right exceeds 0.333px. + this._updateShapePosition(offset + 'px'); + } + }, +}); + return { Widget: publicWidget.Widget, Animation: Animation, diff --git a/addons/website/static/src/js/editor/snippets.options.js b/addons/website/static/src/js/editor/snippets.options.js index daba07839f5..b716fc2fb37 100644 --- a/addons/website/static/src/js/editor/snippets.options.js +++ b/addons/website/static/src/js/editor/snippets.options.js @@ -936,7 +936,16 @@ options.registry.BackgroundShape.include({ return el; } return _getLastPreFilterLayerElement(this.$target); - } + }, + /** + * @override + */ + _removeShapeEl(shapeEl) { + this.trigger_up('widgets_stop_request', { + $target: $(shapeEl), + }); + return this._super(...arguments); + }, }); options.registry.ReplaceMedia.include({