diff --git a/addons/html_builder/static/src/core/utils/update_on_img_changed.js b/addons/html_builder/static/src/core/utils/update_on_img_changed.js new file mode 100644 index 0000000000000..04606f19cf4e1 --- /dev/null +++ b/addons/html_builder/static/src/core/utils/update_on_img_changed.js @@ -0,0 +1,69 @@ +import { Component, onWillStart, xml } from "@odoo/owl"; +import { useDomState } from "../utils"; + +class LoadImgComponent extends Component { + static template = xml` + + `; + static props = { slots: { type: Object } }; + + setup() { + onWillStart(async () => { + const editingElements = this.env.getEditingElements(); + const promises = []; + for (const editingEl of editingElements) { + const imageEls = editingEl.matches("img") + ? [editingEl] + : editingEl.querySelectorAll("img"); + for (const imageEl of imageEls) { + if (!imageEl.complete) { + promises.push( + new Promise((resolve) => { + imageEl.addEventListener("load", () => resolve()); + }) + ); + } + } + } + await Promise.all(promises); + }); + } +} + +/** + * In Chrome, when replacing an image on the DOM, some image properties are not + * available even if the image has been loaded beforehand. This is a problem if + * an option is using one of those property at each DOM change (useDomState). + * To solve the problem, this component reloads the option (and waits for the + * images to be loaded) each time an image has been modified inside its editing + * element. + */ +export class UpdateOptionOnImgChanged extends Component { + // TODO: this is a hack until is + // fixed in OWL. + static template = xml` + + + `; + static props = { slots: { type: Object } }; + static components = { LoadImgComponent }; + + setup() { + let boolean = true; + this.state = useDomState((editingElement) => { + const imageEls = editingElement.matches("img") + ? [editingElement] + : editingElement.querySelectorAll("img"); + for (const imageEl of imageEls) { + if (!imageEl.complete) { + // Rerender the slot if an image is not loaded + boolean = !boolean; + break; + } + } + return { + bool: boolean, + }; + }); + } +} diff --git a/addons/html_builder/static/src/website_builder/plugins/options/card_option.js b/addons/html_builder/static/src/website_builder/plugins/options/card_option.js index 96c2329150b89..4525a667da4fc 100644 --- a/addons/html_builder/static/src/website_builder/plugins/options/card_option.js +++ b/addons/html_builder/static/src/website_builder/plugins/options/card_option.js @@ -3,6 +3,7 @@ import { WebsiteBackgroundOption } from "@html_builder/website_builder/plugins/o import { CardImageOption } from "./card_image_option"; import { BorderConfigurator } from "@html_builder/plugins/border_configurator_option"; import { ShadowOption } from "@html_builder/plugins/shadow_option"; +import { UpdateOptionOnImgChanged } from "@html_builder/core/utils/update_on_img_changed"; export class CardOption extends BaseOptionComponent { static template = "website.CardOption"; @@ -11,6 +12,7 @@ export class CardOption extends BaseOptionComponent { WebsiteBackgroundOption, BorderConfigurator, ShadowOption, + UpdateOptionOnImgChanged, }; static props = { disableWidth: { type: Boolean, optional: true }, diff --git a/addons/html_builder/static/src/website_builder/plugins/options/card_option.xml b/addons/html_builder/static/src/website_builder/plugins/options/card_option.xml index 4332aa361e8aa..37f702adb8b1e 100644 --- a/addons/html_builder/static/src/website_builder/plugins/options/card_option.xml +++ b/addons/html_builder/static/src/website_builder/plugins/options/card_option.xml @@ -11,7 +11,9 @@ - + + +