From 57bf5720eb02731431c5c86630652c50b2bea50f Mon Sep 17 00:00:00 2001 From: Benoit Socias Date: Wed, 19 Feb 2025 09:02:24 +0000 Subject: [PATCH 1/2] cherry pick [FIX] web_editor: fix recognition of SVG mimetype At some point, servers started to return `image/svg+xml; charset=utf-8` instead of `image/svg+xml` in the `content-type` header of SVG images. Because of this, dynamic SVGs were not properly handled anymore. This commit adapts the mimetype comparisons to cope for this extra `charset` info inside the mimetype. Steps to reproduce: - Drop an image block inside a website page. - Replace the image. - Search for e.g. "city". - Pick an undraw illustration. => The image was lost because its `src` became `false`. closes odoo/odoo#199112 X-original-commit: e255894abdad53691da107f79e8af10140d3b594 Signed-off-by: Benoit Socias (bso) --- addons/html_editor/models/ir_attachment.py | 2 +- .../static/src/components/media_dialog/image_selector.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/addons/html_editor/models/ir_attachment.py b/addons/html_editor/models/ir_attachment.py index 4f504d2a15055..be9aacf0cb02f 100644 --- a/addons/html_editor/models/ir_attachment.py +++ b/addons/html_editor/models/ir_attachment.py @@ -37,7 +37,7 @@ def _compute_local_url(self): def _compute_image_src(self): for attachment in self: # Only add a src for supported images - if attachment.mimetype not in SUPPORTED_IMAGE_MIMETYPES: + if not attachment.mimetype or attachment.mimetype.split(';')[0] not in SUPPORTED_IMAGE_MIMETYPES: attachment.image_src = False continue diff --git a/addons/web_editor/static/src/components/media_dialog/image_selector.js b/addons/web_editor/static/src/components/media_dialog/image_selector.js index d58c57f534bde..10571cef8f5ca 100644 --- a/addons/web_editor/static/src/components/media_dialog/image_selector.js +++ b/addons/web_editor/static/src/components/media_dialog/image_selector.js @@ -428,7 +428,8 @@ export class ImageSelector extends FileSelector { const mediaUrl = imgEl.src; try { const response = await fetch(mediaUrl); - if (response.headers.get('content-type') === 'image/svg+xml') { + const contentType = response.headers.get("content-type"); + if (contentType && contentType.startsWith("image/svg+xml")) { let svg = await response.text(); const dynamicColors = {}; const combinedColorsRegex = new RegExp(Object.values(weUtils.DEFAULT_PALETTE).join('|'), 'gi'); From 302e3a7a7b2fb83086bf530b848c1c3cbc80e555 Mon Sep 17 00:00:00 2001 From: Benoit Socias Date: Fri, 31 Jan 2025 18:08:09 +0100 Subject: [PATCH 2/2] dynamic svg option + withGradient in color picker --- .../building_blocks/builder_colorpicker.js | 3 ++ .../static/src/plugins/dynamic_svg_option.js | 25 +++++++++ .../static/src/plugins/dynamic_svg_option.xml | 12 +++++ .../src/plugins/dynamic_svg_option_plugin.js | 51 +++++++++++++++++++ .../src/core/color_picker/color_picker.js | 2 + .../src/core/color_picker/color_picker.xml | 3 +- 6 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 addons/html_builder/static/src/plugins/dynamic_svg_option.js create mode 100644 addons/html_builder/static/src/plugins/dynamic_svg_option.xml create mode 100644 addons/html_builder/static/src/plugins/dynamic_svg_option_plugin.js diff --git a/addons/html_builder/static/src/core/building_blocks/builder_colorpicker.js b/addons/html_builder/static/src/core/building_blocks/builder_colorpicker.js index fa2cf871efb4d..1adb4480da43e 100644 --- a/addons/html_builder/static/src/core/building_blocks/builder_colorpicker.js +++ b/addons/html_builder/static/src/core/building_blocks/builder_colorpicker.js @@ -78,12 +78,14 @@ export class BuilderColorPicker extends Component { static props = { ...basicContainerBuilderComponentProps, noTransparency: { type: Boolean, optional: true }, + withGradient: { type: Boolean, optional: true }, unit: { type: String, optional: true }, title: { type: String, optional: true }, getUsedCustomColors: { type: Function, optional: true }, }; static defaultProps = { getUsedCustomColors: () => [], + withGradient: true, }; static components = { ColorSelector: ColorSelector, @@ -105,6 +107,7 @@ export class BuilderColorPicker extends Component { getUsedCustomColors: this.props.getUsedCustomColors, colorPrefix: "color-prefix-", noTransparency: this.props.noTransparency, + withGradient: this.props.withGradient, }, { onClose: onPreviewRevert, diff --git a/addons/html_builder/static/src/plugins/dynamic_svg_option.js b/addons/html_builder/static/src/plugins/dynamic_svg_option.js new file mode 100644 index 0000000000000..706b7a6db822f --- /dev/null +++ b/addons/html_builder/static/src/plugins/dynamic_svg_option.js @@ -0,0 +1,25 @@ +import { Component } from "@odoo/owl"; +import { defaultBuilderComponents } from "../core/default_builder_components"; +import { useDomState } from "@html_builder/core/building_blocks/utils"; + +export class DynamicSvgOption extends Component { + static template = "html_builder.DynamicSvgOption"; + static components = { ...defaultBuilderComponents }; + static props = {}; + + setup() { + this.domState = useDomState((imgEl) => { + const colors = {}; + const searchParams = new URL(imgEl.src, window.location.origin).searchParams; + for (const colorName of ["c1", "c2", "c3", "c4", "c5"]) { + const color = searchParams.get(colorName); + if (color) { + colors[colorName] = color; + } + } + return { + colors: colors, + }; + }); + } +} diff --git a/addons/html_builder/static/src/plugins/dynamic_svg_option.xml b/addons/html_builder/static/src/plugins/dynamic_svg_option.xml new file mode 100644 index 0000000000000..fdd9f6bd8d708 --- /dev/null +++ b/addons/html_builder/static/src/plugins/dynamic_svg_option.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/addons/html_builder/static/src/plugins/dynamic_svg_option_plugin.js b/addons/html_builder/static/src/plugins/dynamic_svg_option_plugin.js new file mode 100644 index 0000000000000..7964333f3b800 --- /dev/null +++ b/addons/html_builder/static/src/plugins/dynamic_svg_option_plugin.js @@ -0,0 +1,51 @@ +import { registry } from "@web/core/registry"; +import { Plugin } from "@html_editor/plugin"; +import { DynamicSvgOption } from "./dynamic_svg_option"; +import { normalizeCSSColor } from "@web/core/utils/colors"; +import { loadImage } from "@html_editor/utils/image_processing"; + +class DynamicSvgOptionPlugin extends Plugin { + static id = "DynamicSvgOption"; + resources = { + builder_options: [ + { + OptionComponent: DynamicSvgOption, + props: {}, + selector: "img[src^='/html_editor/shape/'], img[src^='/web_editor/shape/']", + }, + ], + builder_actions: this.getActions(), + }; + + getActions() { + return { + svgColor: { + getValue: ({ editingElement: imgEl, param: { mainParam: colorName } }) => { + const searchParams = new URL(imgEl.src, window.location.origin).searchParams; + return searchParams.get(colorName); + }, + load: async ({ + editingElement: imgEl, + param: { mainParam: colorName }, + value: color, + }) => { + const newURL = new URL(imgEl.src, window.location.origin); + newURL.searchParams.set(colorName, normalizeCSSColor(color)); + const src = newURL.pathname + newURL.search; + await loadImage(src); + return src; + }, + apply: ({ + editingElement: imgEl, + param: { mainParam: colorName }, + value: color, + loadResult: newSrc, + }) => { + imgEl.setAttribute("src", newSrc); + }, + }, + }; + } +} + +registry.category("website-plugins").add(DynamicSvgOptionPlugin.id, DynamicSvgOptionPlugin); diff --git a/addons/web/static/src/core/color_picker/color_picker.js b/addons/web/static/src/core/color_picker/color_picker.js index 063dc5fead687..ab4fbf2c08fd6 100644 --- a/addons/web/static/src/core/color_picker/color_picker.js +++ b/addons/web/static/src/core/color_picker/color_picker.js @@ -43,10 +43,12 @@ export class ColorPicker extends Component { applyColorResetPreview: Function, colorPrefix: { type: String }, noTransparency: { type: Boolean, optional: true }, + withGradient: { type: Boolean, optional: true }, close: { type: Function, optional: true }, }; static defaultProps = { close: () => {}, + withGradient: true, }; setup() { diff --git a/addons/web/static/src/core/color_picker/color_picker.xml b/addons/web/static/src/core/color_picker/color_picker.xml index 28fd4b86caddb..ed8a56add9db3 100644 --- a/addons/web/static/src/core/color_picker/color_picker.xml +++ b/addons/web/static/src/core/color_picker/color_picker.xml @@ -13,6 +13,7 @@ Custom