diff options
| author | qsm-odoo <qsm@odoo.com> | 2019-11-19 14:30:43 +0000 |
|---|---|---|
| committer | qsm-odoo <qsm@odoo.com> | 2019-12-01 15:49:57 +0000 |
| commit | 216cf93b4dab381286991dcf650e859931bf1a43 (patch) | |
| tree | 27bf2eec4d0c3fa17e9f1726ff3f3413057e5812 /addons/web/static/src/js/widgets | |
| parent | 702a0cd5c5caecb7ce747dc049f88f03182185ff (diff) | |
[REF] web, web_editor, *: review normalization of colors
* website
Review colorpicker methods to always allow to use normalized colors.
Also factorize some code in the color palette widget.
Part of https://github.com/odoo/odoo/pull/40282
In preparation of task-2122935 and other tasks
Diffstat (limited to 'addons/web/static/src/js/widgets')
| -rw-r--r-- | addons/web/static/src/js/widgets/colorpicker_dialog.js | 226 |
1 files changed, 123 insertions, 103 deletions
diff --git a/addons/web/static/src/js/widgets/colorpicker_dialog.js b/addons/web/static/src/js/widgets/colorpicker_dialog.js index 54baf3c5b4a..4f25710db68 100644 --- a/addons/web/static/src/js/widgets/colorpicker_dialog.js +++ b/addons/web/static/src/js/widgets/colorpicker_dialog.js @@ -76,7 +76,7 @@ var ColorpickerDialog = Dialog.extend({ this.$opacitySliderPointer = this.$('.o_opacity_pointer'); var defaultColor = this.options.defaultColor || '#FF0000'; - var rgba = ColorpickerDialog.convertColorToRgba(defaultColor); + var rgba = ColorpickerDialog.convertCSSColorToRgba(defaultColor); if (rgba) { this._updateRgba(rgba.red, rgba.green, rgba.blue, rgba.opacity); } @@ -143,7 +143,7 @@ var ColorpickerDialog = Dialog.extend({ * @param {string} hex - hexadecimal code */ _updateHex: function (hex) { - var rgb = ColorpickerDialog.convertHexToRgba(hex); + var rgb = ColorpickerDialog.convertCSSColorToRgba(hex); if (!rgb) { return; } @@ -164,14 +164,17 @@ var ColorpickerDialog = Dialog.extend({ * @param {integer} [a] */ _updateRgba: function (r, g, b, a) { - var hex = ColorpickerDialog.convertRgbToHex(r, g, b); + // We update the hexadecimal code by transforming into a css color and + // ignoring the opacity (we don't display opacity component in hexa as + // not supported on all browsers) + var hex = ColorpickerDialog.convertRgbaToCSSColor(r, g, b); if (!hex) { return; } _.extend(this.colorComponents, {red: r, green: g, blue: b}, a === undefined ? {} : {opacity: a}, - hex, + {hex: hex}, ColorpickerDialog.convertRgbToHsl(r, g, b) ); this._updateCssColor(); @@ -189,10 +192,12 @@ var ColorpickerDialog = Dialog.extend({ if (!rgb) { return; } + // We receive an hexa as we ignore the opacity + const hex = ColorpickerDialog.convertRgbaToCSSColor(rgb.red, rgb.green, rgb.blue); _.extend(this.colorComponents, {hue: h, saturation: s, lightness: l}, rgb, - ColorpickerDialog.convertRgbToHex(rgb.red, rgb.green, rgb.blue) + {hex: hex} ); this._updateCssColor(); }, @@ -217,8 +222,12 @@ var ColorpickerDialog = Dialog.extend({ * @private */ _updateCssColor: function () { + const r = this.colorComponents.red; + const g = this.colorComponents.green; + const b = this.colorComponents.blue; + const a = this.colorComponents.opacity; _.extend(this.colorComponents, - {cssColor: ColorpickerDialog.formatColor(this.colorComponents)} + {cssColor: ColorpickerDialog.convertRgbaToCSSColor(r, g, b, a)} ); }, @@ -359,84 +368,21 @@ var ColorpickerDialog = Dialog.extend({ //-------------------------------------------------------------------------- /** - * Converts any color to string RGBA. - * - * @static - * @param {Object|string} color - * @returns {string} rgba (red, green, blue, opacity) - */ -ColorpickerDialog.formatColor = function (color) { - if (typeof color === 'string') { - color = ColorpickerDialog.convertColorToRgba(color); - } - if (!color) { - return ''; - } - if (color.opacity === 100) { - return ColorpickerDialog.convertRgbToHex(color.red, color.green, color.blue).hex; - } - return _.str.sprintf('rgba(%s, %s, %s, %s)', - color.red, - color.green, - color.blue, - color.opacity / 100 - ); -}; -/** - * Converts any color to code to RGBA. - * - * @static - * @param {string} color - * @returns {Object|false} contains red, green, blue, opacity - */ -ColorpickerDialog.convertColorToRgba = function (color) { - var rgba = color.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)$/); - if (rgba) { - if (rgba[4] === undefined) { - rgba[4] = 1; - } - return { - red: parseInt(rgba[1]), - green: parseInt(rgba[2]), - blue: parseInt(rgba[3]), - opacity: Math.round(parseFloat(rgba[4]) * 100), - }; - } else { - return ColorpickerDialog.convertHexToRgba(color); - } -}; -/** - * Converts Hexadecimal code to RGB. - * - * @static - * @param {string} hex - hexadecimal code - * @returns {Object|false} contains red, green and blue - */ -ColorpickerDialog.convertHexToRgba = function (hex) { - if (!/^#([0-9A-F]{6}|[0-9A-F]{8})$/i.test(hex)) { - return false; - } - - return { - red: parseInt(hex.substr(1, 2), 16), - green: parseInt(hex.substr(3, 2), 16), - blue: parseInt(hex.substr(5, 2), 16), - opacity: (hex.length === 9 ? (parseInt(hex.substr(7, 2), 16) / 255) : 1) * 100, - }; -}; -/** - * Converts RGB color to HSL. + * Converts RGB color components to HSL components. * * @static - * @param {integer} r - * @param {integer} g - * @param {integer} b - * @returns {Object|false} contains hue, saturation and lightness + * @param {integer} r - [0, 255] + * @param {integer} g - [0, 255] + * @param {integer} b - [0, 255] + * @returns {Object|false} + * - hue [0, 360[ + * - saturation [0, 100] + * - lightness [0, 100] */ ColorpickerDialog.convertRgbToHsl = function (r, g, b) { - if (typeof (r) !== 'number' || isNaN(r) || r < 0 || r > 255 || - typeof (g) !== 'number' || isNaN(g) || g < 0 || g > 255 || - typeof (b) !== 'number' || isNaN(b) || b < 0 || b > 255) { + if (typeof (r) !== 'number' || isNaN(r) || r < 0 || r > 255 + || typeof (g) !== 'number' || isNaN(g) || g < 0 || g > 255 + || typeof (b) !== 'number' || isNaN(b) || b < 0 || b > 255) { return false; } @@ -471,20 +417,24 @@ ColorpickerDialog.convertRgbToHsl = function (r, g, b) { }; }; /** - * Converts HSL color to RGB. + * Converts HSL color components to RGB components. * * @static - * @param {integer} h - * @param {integer} s - * @param {integer} l - * @returns {Object|false} contains red, green and blue + * @param {integer} h - [0, 360[ + * @param {integer} s - [0, 100] + * @param {integer} l - [0, 100] + * @returns {Object|false} + * - red [0, 255] + * - green [0, 255] + * - blue [0, 255] */ ColorpickerDialog.convertHslToRgb = function (h, s, l) { - if (typeof (h) !== 'number' || isNaN(h) || h < 0 || h > 360 || - typeof (s) !== 'number' || isNaN(s) || s < 0 || s > 100 || - typeof (l) !== 'number' || isNaN(l) || l < 0 || l > 100) { + if (typeof (h) !== 'number' || isNaN(h) || h < 0 || h > 360 + || typeof (s) !== 'number' || isNaN(s) || s < 0 || s > 100 + || typeof (l) !== 'number' || isNaN(l) || l < 0 || l > 100) { return false; } + var huePrime = h / 60; var saturation = s / 100; var lightness = l / 100; @@ -537,28 +487,98 @@ ColorpickerDialog.convertHslToRgb = function (h, s, l) { blue: secondComponent, }; } + return false; }; /** - * Converts RGB color to Hexadecimal code. + * Converts RGBA color components to a normalized CSS color: if the opacity + * is invalid or equal to 100, a hex is returned; otherwise a rgba() css color + * is returned. + * + * Those choice have multiple reason: + * - A hex color is more common to c/c from other utilities on the web and is + * also shorter than rgb() css colors + * - Opacity in hexadecimal notations is not supported on all browsers and is + * also less common to use. * * @static - * @param {integer} r - * @param {integer} g - * @param {integer} b - * @returns {Object|false} contains hexadecimal code + * @param {integer} r - [0, 255] + * @param {integer} g - [0, 255] + * @param {integer} b - [0, 255] + * @param {float} a - [0, 100] + * @returns {string} */ -ColorpickerDialog.convertRgbToHex = function (r, g, b) { - if (typeof (r) !== 'number' || isNaN(r) || r < 0 || r > 255 || - typeof (g) !== 'number' || isNaN(g) || g < 0 || g > 255 || - typeof (b) !== 'number' || isNaN(b) || b < 0 || b > 255) { +ColorpickerDialog.convertRgbaToCSSColor = function (r, g, b, a) { + if (typeof (r) !== 'number' || isNaN(r) || r < 0 || r > 255 + || typeof (g) !== 'number' || isNaN(g) || g < 0 || g > 255 + || typeof (b) !== 'number' || isNaN(b) || b < 0 || b > 255) { return false; } - var red = r < 16 ? '0' + r.toString(16) : r.toString(16); - var green = g < 16 ? '0' + g.toString(16) : g.toString(16); - var blue = b < 16 ? '0' + b.toString(16) : b.toString(16); - return { - hex: _.str.sprintf('#%s%s%s', red, green, blue) - }; + if (typeof (a) !== 'number' || isNaN(a) || a < 0 || Math.abs(a - 100) < Number.EPSILON) { + const rr = r < 16 ? '0' + r.toString(16) : r.toString(16); + const gg = g < 16 ? '0' + g.toString(16) : g.toString(16); + const bb = b < 16 ? '0' + b.toString(16) : b.toString(16); + return (`#${rr}${gg}${bb}`).toUpperCase(); + } + return `rgba(${r}, ${g}, ${b}, ${parseFloat((a / 100.0).toFixed(3))})`; +}; +/** + * Converts a CSS color (rgb(), rgba(), hexadecimal) to RGBA color components. + * + * Note: we don't support using and displaying hexadecimal color with opacity + * but this method allows to receive one and returns the correct opacity value. + * + * @static + * @param {string} cssColor - hexadecimal code or rgb() or rgba() + * @returns {Object|false} + * - red [0, 255] + * - green [0, 255] + * - blue [0, 255] + * - opacity [0, 100.0] + */ +ColorpickerDialog.convertCSSColorToRgba = function (cssColor) { + // Check if cssColor is a rgba() or rgb() color + const rgba = cssColor.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)$/); + if (rgba) { + if (rgba[4] === undefined) { + rgba[4] = 1; + } + return { + red: parseInt(rgba[1]), + green: parseInt(rgba[2]), + blue: parseInt(rgba[3]), + opacity: Math.round(parseFloat(rgba[4]) * 100), + }; + } + + // Otherwise, check if cssColor is an hexadecimal code color + if (/^#([0-9A-F]{6}|[0-9A-F]{8})$/i.test(cssColor)) { + return { + red: parseInt(cssColor.substr(1, 2), 16), + green: parseInt(cssColor.substr(3, 2), 16), + blue: parseInt(cssColor.substr(5, 2), 16), + opacity: (cssColor.length === 9 ? (parseInt(cssColor.substr(7, 2), 16) / 255) : 1) * 100, + }; + } + + return false; +}; +/** + * Converts a CSS color (rgb(), rgba(), hexadecimal) to a normalized version + * of the same color (@see convertRgbaToCSSColor). + * + * Normalized color can be safely compared using string comparison. + * + * @static + * @param {string} cssColor - hexadecimal code or rgb() or rgba() + * @returns {string} - the normalized css color or the given css color if it + * failed to be normalized + */ +ColorpickerDialog.normalizeCSSColor = function (cssColor) { + const rgba = ColorpickerDialog.convertCSSColorToRgba(cssColor); + if (!rgba) { + return cssColor; + } + return ColorpickerDialog.convertRgbaToCSSColor(rgba.red, rgba.green, rgba.blue, rgba.opacity); }; return ColorpickerDialog; |
