diff --git a/addons/web_editor/static/src/js/common/utils.js b/addons/web_editor/static/src/js/common/utils.js index 912b4717c69..e7e2a4fad97 100644 --- a/addons/web_editor/static/src/js/common/utils.js +++ b/addons/web_editor/static/src/js/common/utils.js @@ -139,6 +139,33 @@ function _areCssValuesEqual(value1, value2, cssProp, $target) { const numValue2 = _convertValueToUnit(value2, data[1], cssProp, $target); return (Math.abs(numValue1 - numValue2) < Number.EPSILON); } +/** + * @param {string|number} name + * @returns {boolean} + */ +function _isColorCombinationName(name) { + const number = parseInt(name); + return (!isNaN(number) && number % 100 !== 0); +} +/** + * @param {string[]} colorNames + * @param {string} [prefix='bg-'] + * @returns {string[]} + */ +function _computeColorClasses(colorNames, prefix = 'bg-') { + let hasCCClasses = false; + const classes = colorNames.map(c => { + if (_isColorCombinationName(c)) { + hasCCClasses = true; + return `o_cc${c}`; + } + return (prefix + c); + }); + if (hasCCClasses) { + classes.push('o_cc'); + } + return classes; +} return { CSS_SHORTHANDS: CSS_SHORTHANDS, @@ -148,5 +175,7 @@ return { convertNumericToUnit: _convertNumericToUnit, getNumericAndUnit: _getNumericAndUnit, areCssValuesEqual: _areCssValuesEqual, + isColorCombinationName: _isColorCombinationName, + computeColorClasses: _computeColorClasses, }; }); 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 0b30bf856ce..212ab507755 100644 --- a/addons/web_editor/static/src/js/editor/snippets.options.js +++ b/addons/web_editor/static/src/js/editor/snippets.options.js @@ -1086,11 +1086,15 @@ const ColorpickerUserValueWidget = SelectUserValueWidget.extend({ * @returns {Promise} */ _renderColorPalette: function () { - const options = {}; - options.selectedColor = this._value; + const options = { + selectedColor: this._value, + }; if (this.options.dataAttributes.excluded) { options.excluded = this.options.dataAttributes.excluded.replace(/ /g, '').split(','); } + if (this.options.dataAttributes.withCombinations) { + options.withCombinations = !!this.options.dataAttributes.withCombinations; + } const oldColorPalette = this.colorPalette; this.colorPalette = new ColorPaletteWidget(this, options); if (oldColorPalette) { @@ -1108,14 +1112,17 @@ const ColorpickerUserValueWidget = SelectUserValueWidget.extend({ _updateUI: async function (color) { await this._super(...arguments); - this.colorPreviewEl.classList.remove(...this.colorPalette.getColorNames().map(c => 'bg-' + c)); + const classes = weUtils.computeColorClasses(this.colorPalette.getColorNames()); + this.colorPreviewEl.classList.remove(...classes); this.colorPreviewEl.style.removeProperty('background-color'); if (this._value) { if (ColorpickerWidget.isCSSColor(this._value)) { this.colorPreviewEl.style.backgroundColor = this._value; + } else if (weUtils.isColorCombinationName(this._value)) { + this.colorPreviewEl.classList.add('o_cc', `o_cc${this._value}`); } else { - this.colorPreviewEl.classList.add('bg-' + this._value); + this.colorPreviewEl.classList.add(`bg-${this._value}`); } } @@ -1631,9 +1638,15 @@ const SnippetOptionWidget = Widget.extend({ // other potential color names (to remove) and if we know about a prefix // (otherwise we suppose that we should use the actual related color). if (params.colorNames && params.colorPrefix) { - const classes = params.colorNames.map(c => params.colorPrefix + c); + const classes = weUtils.computeColorClasses(params.colorNames, params.colorPrefix); this.$target[0].classList.remove(...classes); + if (weUtils.isColorCombinationName(widgetValue)) { + // Those are the special color combinations classes. Just have + // to add it (and adding the potential extra class) then leave. + this.$target[0].classList.add('o_cc', `o_cc${widgetValue}`, params.extraClass); + return; + } if (params.colorNames.includes(widgetValue)) { const originalCSSValue = window.getComputedStyle(this.$target[0])[cssProps[0]]; const className = params.colorPrefix + widgetValue; @@ -1924,7 +1937,8 @@ const SnippetOptionWidget = Widget.extend({ case 'selectStyle': { if (params.colorPrefix && params.colorNames) { for (const c of params.colorNames) { - if (this.$target[0].classList.contains(params.colorPrefix + c)) { + const className = weUtils.computeColorClasses([c], params.colorPrefix)[0]; + if (this.$target[0].classList.contains(className)) { return c; } } diff --git a/addons/web_editor/static/src/js/wysiwyg/widgets/color_palette.js b/addons/web_editor/static/src/js/wysiwyg/widgets/color_palette.js index 60fdec4108d..4f6d677a1cb 100644 --- a/addons/web_editor/static/src/js/wysiwyg/widgets/color_palette.js +++ b/addons/web_editor/static/src/js/wysiwyg/widgets/color_palette.js @@ -7,6 +7,7 @@ const session = require('web.session'); const {ColorpickerWidget} = require('web.Colorpicker'); const Widget = require('web.Widget'); const summernoteCustomColors = require('web_editor.rte.summernote_custom_colors'); +const weUtils = require('web_editor.utils'); const qweb = core.qweb; @@ -14,9 +15,10 @@ const ColorPaletteWidget = Widget.extend({ // ! for xmlDependencies, see loadDependencies function template: 'web_editor.snippet.option.colorpicker', events: { - 'click button': '_onColorButtonClick', - 'mouseenter button': '_onColorButtonEnter', - 'mouseleave button': '_onColorButtonLeave', + 'click .o_we_color_btn': '_onColorButtonClick', + 'mouseenter .o_we_color_btn': '_onColorButtonEnter', + 'mouseleave .o_we_color_btn': '_onColorButtonLeave', + 'click .o_we_colorpicker_switch_pane_btn': '_onSwitchPaneButtonClick', }, custom_events: { 'colorpicker_select': '_onColorPickerSelect', @@ -42,9 +44,13 @@ const ColorPaletteWidget = Widget.extend({ excluded: [], excludeSectionOf: null, $editable: $(), + withCombinations: false, }, options || {}); this.selectedColor = ''; + this.resetButton = this.options.resetButton; + this.withCombinations = this.options.withCombinations; + this.trigger_up('request_editable', {callback: val => this.options.$editable = val}); }, /** @@ -60,28 +66,20 @@ const ColorPaletteWidget = Widget.extend({ start: async function () { const res = this._super.apply(this, arguments); - const $colorSection = this.$('.o_colorpicker_sections'); - const $wrapper = $colorSection.find('.o_colorpicker_section_tabs'); + const $colorSection = this.$('.o_colorpicker_sections[data-color-tab="theme-colors"]'); const $clpicker = qweb.has_template('web_editor.colorpicker') ? $(qweb.render('web_editor.colorpicker')) : $(`
`); - $clpicker.appendTo($wrapper); + $clpicker.find('button').addClass('o_we_color_btn'); + $clpicker.appendTo($colorSection); // Remove excluded palettes (note: only hide them to still be able // to remove their related colors on the DOM target) - _.each(this.options.excluded, function (exc) { - $colorSection.find('[data-name="' + exc + '"]').addClass('d-none'); + _.each(this.options.excluded, exc => { + this.$('[data-name="' + exc + '"]').addClass('d-none'); }); if (this.options.excludeSectionOf) { - $colorSection.find('[data-name]:has([data-color="' + this.options.excludeSectionOf + '"])').addClass('d-none'); - } - - if (this.options.resetButton) { - let $section = this.$('.o_colorpicker_section[data-name="theme"]'); - if ($section.hasClass('d-none')) { - $section = $section.insertBefore('
'); - } - this._createColorButton('', ['o_colorpicker_reset', 'float-right']).appendTo($section); + this.$('[data-name]:has([data-color="' + this.options.excludeSectionOf + '"])').addClass('d-none'); } this.el.querySelectorAll('.o_colorpicker_section').forEach(elem => { @@ -109,9 +107,14 @@ const ColorPaletteWidget = Widget.extend({ this.el.querySelectorAll('button[data-color]').forEach(elem => { const colorName = elem.dataset.color; const $color = $(elem); - $color.addClass('bg-' + colorName); + const isCCName = weUtils.isColorCombinationName(colorName); + if (isCCName) { + $color.find('.o_we_cc_preview_wrapper').addClass(`o_cc o_cc${colorName}`); + } else { + $color.addClass(`bg-${colorName}`); + } this.colorNames.push(colorName); - if (!elem.classList.contains('d-none')) { + if (!isCCName && !elem.classList.contains('d-none')) { const color = ColorpickerWidget.normalizeCSSColor(this.style.getPropertyValue('--' + colorName).trim()); this.colorToColorNames[color] = colorName; } @@ -140,7 +143,7 @@ const ColorPaletteWidget = Widget.extend({ this.colorPicker = new ColorpickerWidget(this, { defaultColor: defaultColor, }); - await this.colorPicker.prependTo(this.$el); + await this.colorPicker.prependTo($colorSection); return res; }, /** @@ -217,12 +220,8 @@ const ColorPaletteWidget = Widget.extend({ _addCustomColorButton: function (color, classes = []) { classes.push('o_custom_color'); const $themeSection = this.$('.o_colorpicker_section[data-name="theme"]'); - // There is 8 buttons on a colorpalette line, the clear button is always the last of the first line. - if (this.options.resetButton && $themeSection.find('button').length < 8) { - const $resetButton = $themeSection.find('.o_colorpicker_reset'); - return this._createColorButton(color, classes).insertBefore($resetButton); - } - return this._createColorButton(color, classes).appendTo($themeSection); + const $button = this._createColorButton(color, classes); + return $button.appendTo($themeSection); }, /** * Return a color button. @@ -233,7 +232,7 @@ const ColorPaletteWidget = Widget.extend({ */ _createColorButton: function (color, classes) { return $(' + +
+
+ + + + + + +
+
+ + +
diff --git a/addons/web_editor/static/tests/field_html_tests.js b/addons/web_editor/static/tests/field_html_tests.js index ea20cdc5623..d1e83c32393 100644 --- a/addons/web_editor/static/tests/field_html_tests.js +++ b/addons/web_editor/static/tests/field_html_tests.js @@ -201,7 +201,7 @@ QUnit.module('web_editor', {}, function () { assert.ok($field.find('.note-back-color-preview').hasClass('show'), "should display the color picker"); - await testUtils.dom.click($field.find('.note-toolbar .note-back-color-preview button[style="background-color:#00FFFF;"]')); + await testUtils.dom.click($field.find('.note-toolbar .note-back-color-preview .o_we_color_btn[style="background-color:#00FFFF;"]')); assert.ok(!$field.find('.note-back-color-preview').hasClass('show'), "should close the color picker"); @@ -227,7 +227,7 @@ QUnit.module('web_editor', {}, function () { // text is selected await openColorpicker('.note-toolbar .note-back-color-preview'); - await testUtils.dom.click($field.find('.note-toolbar .note-back-color-preview button.bg-gamma')); + await testUtils.dom.click($field.find('.note-toolbar .note-back-color-preview .o_we_color_btn.bg-gamma')); assert.strictEqual($field.find('.note-editable').html(), '

toto toto toto

tata

', @@ -386,7 +386,7 @@ QUnit.module('web_editor', {}, function () { } await openColorpicker('.note-toolbar .note-back-color-preview'); - await testUtils.dom.click($field.find('.note-toolbar .note-back-color-preview button.bg-gamma')); + await testUtils.dom.click($field.find('.note-toolbar .note-back-color-preview .o_we_color_btn.bg-gamma')); await testUtils.form.clickSave(form); diff --git a/addons/website/static/src/js/editor/snippets.options.js b/addons/website/static/src/js/editor/snippets.options.js index 89310998fde..5bde2b6d1c8 100644 --- a/addons/website/static/src/js/editor/snippets.options.js +++ b/addons/website/static/src/js/editor/snippets.options.js @@ -5,8 +5,9 @@ const {ColorpickerWidget} = require('web.Colorpicker'); const config = require('web.config'); var core = require('web.core'); var Dialog = require('web.Dialog'); -const wUtils = require('website.utils'); +const weUtils = require('web_editor.utils'); var options = require('web_editor.snippets.options'); +const wUtils = require('website.utils'); require('website.s_popup_options'); var _t = core._t; diff --git a/addons/website/static/src/scss/website.wysiwyg.scss b/addons/website/static/src/scss/website.wysiwyg.scss index 1eaaa7d97b8..a2f210f70da 100644 --- a/addons/website/static/src/scss/website.wysiwyg.scss +++ b/addons/website/static/src/scss/website.wysiwyg.scss @@ -135,7 +135,7 @@ $i: 1; clear: both; } - > button { + > .o_we_color_btn { &:hover, &.selected { @@ -152,8 +152,11 @@ $i: 1; } } - .note-palette-title { - color: $o-we-color-text-light; + .note-palette-title, a, button:not(.o_we_color_combination_btn) { + + &, &:hover { + color: $o-we-color-text-light; + } } .palette-reset { diff --git a/addons/website/views/snippets/snippets.xml b/addons/website/views/snippets/snippets.xml index 35a819eb40a..904d855565c 100644 --- a/addons/website/views/snippets/snippets.xml +++ b/addons/website/views/snippets/snippets.xml @@ -325,18 +325,12 @@ data-js="MainColorpicker" data-selector="section, .carousel-item, section .row > div, .o_record_cover_container" data-exclude=".parallax, .o_gallery .carousel-item, .s_col_no_bgcolor, .s_col_no_bgcolor.row > div, .o_gallery .row > div, .s_carousel_wrapper, .s_tabs .oe_structure > *"> - - Color combinations 1 - Color combinations 2 - Color combinations 3 - Color combinations 4 - Color combinations 5 -