diff --git a/addons/website/static/src/js/editor/snippets.options.js b/addons/website/static/src/js/editor/snippets.options.js
index f5637bf2c86..87bb3b387ef 100644
--- a/addons/website/static/src/js/editor/snippets.options.js
+++ b/addons/website/static/src/js/editor/snippets.options.js
@@ -810,6 +810,8 @@ options.registry.BackgroundVideo = options.Class.extend({
});
options.registry.OptionsTab = options.Class.extend({
+ GRAY_PARAMS: {EXTRA_SATURATION: "gray-extra-saturation", HUE: "gray-hue"},
+
/**
* @override
*/
@@ -827,14 +829,63 @@ options.registry.OptionsTab = options.Class.extend({
* @override
*/
async updateUI() {
- await this._super(...arguments);
-
// The bg-XXX classes have been updated (and could be updated by another
// option like changing color palette) -> remove the inline style that
// was added for gray previews.
this.$el.find(".o_we_gray_preview").each((_, e) => {
e.style.removeProperty("background-color");
});
+
+ // If the gray palette has been generated by Odoo standard option,
+ // the hue of all gray is the same and the saturation has been
+ // increased/decreased by the same amount for all grays in
+ // comparaison with BS grays. However the system supports any
+ // gray palette.
+
+ const hues = [];
+ const saturationDiffs = [];
+ let oneHasNoSaturation = false;
+ for (let id = 100; id <= 900; id += 100) {
+ const gray = weUtils.getCSSVariableValue(`${id}`);
+ const grayRGB = ColorpickerWidget.convertCSSColorToRgba(gray);
+ const grayHSL = ColorpickerWidget.convertRgbToHsl(grayRGB.red, grayRGB.green, grayRGB.blue);
+
+ const baseGray = weUtils.getCSSVariableValue(`base-${id}`);
+ const baseGrayRGB = ColorpickerWidget.convertCSSColorToRgba(baseGray);
+ const baseGrayHSL = ColorpickerWidget.convertRgbToHsl(baseGrayRGB.red, baseGrayRGB.green, baseGrayRGB.blue);
+
+ if (grayHSL.saturation > 0.01) {
+ if (grayHSL.lightness > 0.01 && grayHSL.lightness < 99.99) {
+ hues.push(grayHSL.hue);
+ }
+ if (grayHSL.saturation < 99.99) {
+ saturationDiffs.push(grayHSL.saturation - baseGrayHSL.saturation);
+ }
+ } else {
+ oneHasNoSaturation = true;
+ }
+ }
+ this.grayHueIsDefined = !!hues.length;
+
+ // Average of angles: we need to take the average of found hues
+ // because even if grays are supposed to be set to the exact
+ // same hue by the Odoo editor, there might be rounding errors
+ // during the conversion from RGB to HSL as the HSL system
+ // allows to represent more colors that the RGB hexadecimal
+ // notation (also: hue 360 = hue 0 and should not be averaged to 180).
+ // This also better support random gray palettes.
+ this.grayParams[this.GRAY_PARAMS.HUE] = (!hues.length) ? 0 : Math.round((Math.atan2(
+ hues.map(hue => Math.sin(hue * Math.PI / 180)).reduce((memo, value) => memo + value, 0) / hues.length,
+ hues.map(hue => Math.cos(hue * Math.PI / 180)).reduce((memo, value) => memo + value, 0) / hues.length
+ ) * 180 / Math.PI) + 360) % 360;
+
+ // Average of found saturation diffs, or all grays have no
+ // saturation, or all grays are fully saturated.
+ this.grayParams[this.GRAY_PARAMS.EXTRA_SATURATION] = saturationDiffs.length
+ ? saturationDiffs.reduce((memo, value) => memo + value, 0) / saturationDiffs.length
+ : (oneHasNoSaturation ? -100 : 100);
+
+ await this._super(...arguments);
},
//--------------------------------------------------------------------------
@@ -1012,11 +1063,35 @@ options.registry.OptionsTab = options.Class.extend({
const gray = weUtils.getCSSVariableValue(`base-${id}`);
const grayRGB = ColorpickerWidget.convertCSSColorToRgba(gray);
const hsl = ColorpickerWidget.convertRgbToHsl(grayRGB.red, grayRGB.green, grayRGB.blue);
- const adjustedGrayRGB = ColorpickerWidget.convertHslToRgb(this.grayParams['gray-hue'],
- Math.min(Math.max(hsl.saturation + this.grayParams['gray-extra-saturation'], 0), 100),
+ const adjustedGrayRGB = ColorpickerWidget.convertHslToRgb(this.grayParams[this.GRAY_PARAMS.HUE],
+ Math.min(Math.max(hsl.saturation + this.grayParams[this.GRAY_PARAMS.EXTRA_SATURATION], 0), 100),
hsl.lightness);
return ColorpickerWidget.convertRgbaToCSSColor(adjustedGrayRGB.red, adjustedGrayRGB.green, adjustedGrayRGB.blue);
},
+ /**
+ * @override
+ */
+ async _renderCustomXML(uiFragment) {
+ await this._super(...arguments);
+ const extraSaturationRangeEl = uiFragment.querySelector(`we-range[data-param=${this.GRAY_PARAMS.EXTRA_SATURATION}]`);
+ if (extraSaturationRangeEl) {
+ const baseGrays = _.range(100, 1000, 100).map(id => {
+ const gray = weUtils.getCSSVariableValue(`base-${id}`);
+ const grayRGB = ColorpickerWidget.convertCSSColorToRgba(gray);
+ const hsl = ColorpickerWidget.convertRgbToHsl(grayRGB.red, grayRGB.green, grayRGB.blue);
+ return {id: id, hsl: hsl};
+ });
+ const first = baseGrays[0];
+ const maxValue = baseGrays.reduce((gray, value) => {
+ return gray.hsl.saturation > value.hsl.saturation ? gray : value;
+ }, first);
+ const minValue = baseGrays.reduce((gray, value) => {
+ return gray.hsl.saturation < value.hsl.saturation ? gray : value;
+ }, first);
+ extraSaturationRangeEl.dataset.max = 100 - minValue.hsl.saturation;
+ extraSaturationRangeEl.dataset.min = -maxValue.hsl.saturation;
+ }
+ },
/**
* @override
*/
@@ -1048,22 +1123,7 @@ options.registry.OptionsTab = options.Class.extend({
return weUtils.getCSSVariableValue('body-image-type');
}
if (methodName === 'customizeGray') {
- // If the gray palette has been generated by Odoo standard option,
- // the hue of all gray is the same and the saturation has been
- // increased/decreased by the same amount for all grays in
- // comparaison with BS grays. However the system supports any
- // gray palette so we base our hue and extra saturation displayed
- // values on one gray, let's say the middle one: gray-500.
- const gray = weUtils.getCSSVariableValue('500');
- const grayRGB = ColorpickerWidget.convertCSSColorToRgba(gray);
- const hsl = ColorpickerWidget.convertRgbToHsl(grayRGB.red, grayRGB.green, grayRGB.blue);
-
- const baseGray = weUtils.getCSSVariableValue('base-500');
- const baseGrayRGB = ColorpickerWidget.convertCSSColorToRgba(baseGray);
- const baseHSL = ColorpickerWidget.convertRgbToHsl(baseGrayRGB.red, baseGrayRGB.green, baseGrayRGB.blue);
-
- this.grayParams['gray-hue'] = hsl.hue;
- this.grayParams['gray-extra-saturation'] = hsl.saturation - baseHSL.saturation;
+ // See updateUI override
return this.grayParams[params.param];
}
return this._super(...arguments);
@@ -1075,6 +1135,9 @@ options.registry.OptionsTab = options.Class.extend({
if (widgetName === 'body_bg_image_opt') {
return false;
}
+ if (params.param === this.GRAY_PARAMS.HUE) {
+ return this.grayHueIsDefined;
+ }
return this._super(...arguments);
},
/**
diff --git a/addons/website/views/snippets/snippets.xml b/addons/website/views/snippets/snippets.xml
index 8767ac1c1dc..23b01cbc466 100644
--- a/addons/website/views/snippets/snippets.xml
+++ b/addons/website/views/snippets/snippets.xml
@@ -1218,10 +1218,8 @@
t-attf-class="o_we_user_value_widget o_we_gray_preview bg-#{grayCode}"/>
-