diff --git a/addons/web/static/src/js/widgets/colorpicker.js b/addons/web/static/src/js/widgets/colorpicker.js index 87a46e77a2f..6b17431259a 100644 --- a/addons/web/static/src/js/widgets/colorpicker.js +++ b/addons/web/static/src/js/widgets/colorpicker.js @@ -12,6 +12,8 @@ var ColorpickerWidget = Widget.extend({ xmlDependencies: ['/web/static/src/xml/colorpicker.xml'], template: 'Colorpicker', events: { + 'click': '_onClick', + 'keypress': '_onKeypress', 'mousedown .o_color_pick_area': '_onMouseDownPicker', 'mousedown .o_color_slider': '_onMouseDownSlider', 'mousedown .o_opacity_slider': '_onMouseDownOpacitySlider', @@ -39,18 +41,22 @@ var ColorpickerWidget = Widget.extend({ this.sliderFlag = false; this.opacitySliderFlag = false; this.colorComponents = {}; + this.uniqueId = _.uniqueId('colorpicker'); - var self = this; - var $body = $(document.body); - $body.on('mousemove.colorpicker', _.throttle(function (ev) { - self._onMouseMovePicker(ev); - self._onMouseMoveSlider(ev); - self._onMouseMoveOpacitySlider(ev); - }, 10)); - $body.on('mouseup.colorpicker', _.throttle(function (ev) { - self.pickerFlag = false; - self.sliderFlag = false; - self.opacitySliderFlag = false; + // Needs to be bound on document to work in all possible cases. + const $document = $(document); + $document.on(`mousemove.${this.uniqueId}`, _.throttle((ev) => { + this._onMouseMovePicker(ev); + this._onMouseMoveSlider(ev); + this._onMouseMoveOpacitySlider(ev); + }, 50)); + $document.on(`mouseup.${this.uniqueId}`, _.throttle((ev) => { + if (this.pickerFlag || this.sliderFlag || this.opacitySliderFlag) { + this._colorSelected(); + } + this.pickerFlag = false; + this.sliderFlag = false; + this.opacitySliderFlag = false; }, 10)); this.options = _.clone(options); @@ -66,12 +72,17 @@ var ColorpickerWidget = Widget.extend({ this.$opacitySlider = this.$('.o_opacity_slider'); this.$opacitySliderPointer = this.$('.o_opacity_pointer'); + const resizeObserver = new window.ResizeObserver(() => { + this._updateUI(); + }); + resizeObserver.observe(this.el); + var defaultColor = this.options.defaultColor || '#FF0000'; var rgba = ColorpickerWidget.convertCSSColorToRgba(defaultColor); if (rgba) { this._updateRgba(rgba.red, rgba.green, rgba.blue, rgba.opacity); } - this._updateUI(); + this.previewActive = true; return this._super.apply(this, arguments); }, /** @@ -79,7 +90,7 @@ var ColorpickerWidget = Widget.extend({ */ destroy: function () { this._super.apply(this, arguments); - $(document.body).off('.colorpicker'); + $(document).off(`.${this.uniqueId}`); }, //-------------------------------------------------------------------------- @@ -206,6 +217,14 @@ var ColorpickerWidget = Widget.extend({ ); this._updateCssColor(); }, + /** + * Trigger an event to annonce that the widget value has changed + * + * @private + */ + _colorSelected: function () { + this.trigger_up('colorpicker_select', this.colorComponents); + }, /** * Updates css color representation. * @@ -219,12 +238,35 @@ var ColorpickerWidget = Widget.extend({ _.extend(this.colorComponents, {cssColor: ColorpickerWidget.convertRgbaToCSSColor(r, g, b, a)} ); + if (this.previewActive) { + this.trigger_up('colorpicker_preview', this.colorComponents); + } }, //-------------------------------------------------------------------------- // Handlers //-------------------------------------------------------------------------- + /** + * @private + * @param {Event} ev + */ + _onKeypress: function (ev) { + if (ev.charCode === $.ui.keyCode.ENTER) { + if (ev.target.tagName === 'INPUT') { + this._onChangeInputs(ev); + } + ev.preventDefault(); + this.trigger_up('enter_key_color_colorpicker'); + } + }, + /** + * @param {Event} ev + */ + _onClick: function (ev) { + ev.originalEvent.__isColorpickerClick = true; + $(ev.target).find('> .o_opacity_pointer, > .o_slider_pointer, > .o_picker_pointer').addBack('.o_opacity_pointer, .o_slider_pointer, .o_picker_pointer').focus(); + }, /** * Updates color when the user starts clicking on the picker. * @@ -233,6 +275,7 @@ var ColorpickerWidget = Widget.extend({ */ _onMouseDownPicker: function (ev) { this.pickerFlag = true; + ev.preventDefault(); this._onMouseMovePicker(ev); }, /** @@ -265,6 +308,7 @@ var ColorpickerWidget = Widget.extend({ */ _onMouseDownSlider: function (ev) { this.sliderFlag = true; + ev.preventDefault(); this._onMouseMoveSlider(ev); }, /** @@ -293,6 +337,7 @@ var ColorpickerWidget = Widget.extend({ */ _onMouseDownOpacitySlider: function (ev) { this.opacitySliderFlag = true; + ev.preventDefault(); this._onMouseMoveOpacitySlider(ev); }, /** @@ -344,6 +389,7 @@ var ColorpickerWidget = Widget.extend({ break; } this._updateUI(); + this._colorSelected(); }, }); @@ -598,7 +644,9 @@ const ColorpickerDialog = Dialog.extend({ */ start: function () { const proms = [this._super(...arguments)]; - this.colorPicker = new ColorpickerWidget(this, this.options); + this.colorPicker = new ColorpickerWidget(this, _.extend({ + colorPreview: true, + }, this.options)); proms.push(this.colorPicker.appendTo(this.$el)); return Promise.all(proms); }, diff --git a/addons/web/static/src/scss/colorpicker.scss b/addons/web/static/src/scss/colorpicker.scss index ab8d2fb4a90..c53b31198d4 100644 --- a/addons/web/static/src/scss/colorpicker.scss +++ b/addons/web/static/src/scss/colorpicker.scss @@ -2,8 +2,8 @@ .o_colorpicker_widget { .o_color_pick_area { position: relative; - width: 200px; - height: 200px; + width: 79%; + height: 125px; background-image: linear-gradient(to bottom, hsl(0, 0%, 100%) 0%, hsla(0, 0%, 100%, 0) 50%, hsla(0, 0%, 0%, 0) 50%, hsl(0, 0%, 0%) 100%), linear-gradient(to right, hsl(0, 0%, 50%) 0%, hsla(0, 0%, 50%, 0) 100%); cursor: crosshair; @@ -18,14 +18,15 @@ } .o_color_slider { position: relative; - width: 18px; - height: 200px; + margin-left: 2.5%; + width: 4%; + height: 125px; background: linear-gradient(#F00 0%, #FF0 16.66%, #0F0 33.33%, #0FF 50%, #00F 66.66%, #F0F 83.33%, #F00 100%); cursor: pointer; .o_slider_pointer { - @include o-position-absolute($left: -4px); - width: 23px; + @include o-position-absolute($left: -100%); + width: 300%; height: 6px; border: 1px solid white; box-shadow: 0px 0px 2px 1px gray('600'); @@ -33,13 +34,14 @@ } .o_opacity_slider { position: relative; - width: 18px; - height: 200px; + margin-left: 5%; + width: 4%; + height: 125px; cursor: pointer; .o_opacity_pointer { - @include o-position-absolute($left: -4px); - width: 23px; + @include o-position-absolute($left: -100%); + width: 300%; height: 6px; border: 1px solid white; box-shadow: 0px 0px 2px 1px gray('600'); @@ -52,34 +54,38 @@ background-image: url('/web_editor/static/src/img/transparent.png'); } } + .o_color_picker_inputs { + padding-top: 3px; + font-size: 12px; display: flex; - flex-direction: column; - & > .form-row { - flex: 1; - .col { - display: flex; - flex-direction: column; - justify-content: space-around; - } - } + .o_color_preview_parent { + height: 20px; + width: 30px; background-image: url('/web_editor/static/src/img/transparent.png'); - } - .o_color_preview { - padding: 0.375rem 1.2rem; - } - .form-group { - margin-bottom: 0.3rem; - label { - margin-bottom: 0px; - font-size: 0.7rem; - font-weight: bold; + .o_color_preview { + height: inherit; + display: block; } } - .form-control { - height: 24px !important; - font-weight: bold; + .o_hex_div { + width: 38%; + display: flex; + border: 1px solid; + margin-right: 2%; + } + .o_rgba_div { + width: 60%; + border: 1px solid; + display: flex; + } + input { + width: 100%; + border: none; + height: 18px; + background-color: inherit; + color: inherit; } } } diff --git a/addons/web/static/src/xml/colorpicker.xml b/addons/web/static/src/xml/colorpicker.xml index 957bef83146..7fb81da8711 100644 --- a/addons/web/static/src/xml/colorpicker.xml +++ b/addons/web/static/src/xml/colorpicker.xml @@ -3,44 +3,30 @@
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+ +
+
hex
+
+ + + + + + RGBA + + RGB
-
-
-
- -
- -
-
-
- - -
-
- - -
-
- - -
-
- - -
-
-
diff --git a/addons/web_editor/static/src/js/editor/rte.summernote.js b/addons/web_editor/static/src/js/editor/rte.summernote.js index 68b00afb564..514dfdfe85c 100644 --- a/addons/web_editor/static/src/js/editor/rte.summernote.js +++ b/addons/web_editor/static/src/js/editor/rte.summernote.js @@ -30,11 +30,15 @@ var tplButton = renderer.getTemplate().button; var tplIconButton = renderer.getTemplate().iconButton; var tplDropdown = renderer.getTemplate().dropdown; -var applyColor = function (target, eventName, color) { +const processAndApplyColor = function (target, eventName, color, preview) { + if (!color) { + color = 'inherit'; + } else if (!ColorpickerWidget.isCSSColor(color)) { + color = (eventName === "foreColor" ? 'text-' : 'bg-') + color; + } var layoutInfo = dom.makeLayoutInfo(target); - $.summernote.pluginEvents[eventName](undefined, eventHandler.modules.editor, layoutInfo, color); + $.summernote.pluginEvents[eventName](undefined, eventHandler.modules.editor, layoutInfo, color, preview); }; - // Update and change the popovers content, and add history button renderer.createPalette = function ($container, options) { const $dropdownContent = $container.find(".colorPalette"); @@ -46,6 +50,10 @@ renderer.createPalette = function ($container, options) { const mutex = new concurrency.MutexedDropPrevious(); const $dropdown = $(elem).closest('.btn-group, .dropdown'); let manualOpening = false; + // Prevent dropdown closing on colorpicker click + $dropdown.on('hide.bs.dropdown', ev => { + return !(ev.clickEvent && ev.clickEvent.originalEvent && ev.clickEvent.originalEvent.__isColorpickerClick); + }); $dropdown.on('show.bs.dropdown', () => { if (manualOpening) { return true; @@ -62,14 +70,15 @@ renderer.createPalette = function ($container, options) { $editable: rte.Class.prototype.editable(), // Our parent is the root widget, we can't retrieve the editable section from it... selectedColor: $(targetElement).css(eventName === "foreColor" ? 'color' : 'backgroundColor'), }); - colorpicker.on('color_picked', null, ev => { - let color = ev.data.color; - if (!ColorpickerWidget.isCSSColor(color)) { - color = (eventName === "foreColor" ? 'text-' : 'bg-') + color; - } - applyColor(ev.data.target, eventName, color); + colorpicker.on('custom_color_picked color_picked', null, ev => { + processAndApplyColor(ev.data.target, eventName, ev.data.color); + }); + colorpicker.on('color_hover color_leave', null, ev => { + processAndApplyColor(ev.data.target, eventName, ev.data.color, true); + }); + colorpicker.on('enter_key_color_colorpicker', null, () => { + $dropdown.children('.dropdown-toggle').dropdown('hide'); }); - colorpicker.on('color_reset', null, ev => applyColor(ev.data.target, eventName, 'inherit')); return colorpicker.replace(hookEl).then(() => { if (oldColorpicker) { oldColorpicker.destroy(); 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 35fd4cef7c7..50b56ad435a 100644 --- a/addons/web_editor/static/src/js/editor/snippets.options.js +++ b/addons/web_editor/static/src/js/editor/snippets.options.js @@ -726,8 +726,10 @@ const SelectUserValueWidget = UserValueWidget.extend({ _onClick: function () { if (!this.menuTogglerEl.classList.contains('active')) { this.trigger_up('user_value_widget_opening'); + this.menuTogglerEl.classList.add('active'); + } else { + this.close(); } - this.menuTogglerEl.classList.toggle('active'); const activeButton = this._userValueWidgets.find(widget => widget.isActive()); if (activeButton) { this.menuEl.scrollTop = activeButton.el.offsetTop - (this.menuEl.offsetHeight / 2); @@ -980,10 +982,11 @@ const MultiUserValueWidget = UserValueWidget.extend({ const ColorpickerUserValueWidget = SelectUserValueWidget.extend({ className: (SelectUserValueWidget.prototype.className || '') + ' o_we_so_color_palette', custom_events: _.extend({}, SelectUserValueWidget.prototype.custom_events, { + 'custom_color_picked': '_onCustomColorPicked', 'color_picked': '_onColorPicked', 'color_hover': '_onColorHovered', 'color_leave': '_onColorLeft', - 'color_reset': '_onColorReset', + 'enter_key_color_colorpicker': '_onEnterKey' }), /** @@ -1009,6 +1012,17 @@ const ColorpickerUserValueWidget = SelectUserValueWidget.extend({ // Public //-------------------------------------------------------------------------- + /** + * @override + */ + close: function () { + this._super(...arguments); + if (this._customColorValue && this._customColorValue !== this._value) { + this._value = this._customColorValue; + this._customColorValue = false; + this._onUserValueChange(); + } + }, /** * @override */ @@ -1024,6 +1038,9 @@ const ColorpickerUserValueWidget = SelectUserValueWidget.extend({ if (typeof this._previewColor === 'string') { return this._previewColor; } + if (typeof this._customColorValue === 'string') { + return this._customColorValue; + } let value = this._super(...arguments); if (value && this.options.dataAttributes.hasOwnProperty('cssCompatible') && !ColorpickerWidget.isCSSColor(value)) { @@ -1093,6 +1110,16 @@ const ColorpickerUserValueWidget = SelectUserValueWidget.extend({ // Handlers //-------------------------------------------------------------------------- + /** + * Called when a custom color is selected -> preview the color + * and set the current value. Update of this value on close + * + * @private + * @param {Event} ev + */ + _onCustomColorPicked: function (ev) { + this._customColorValue = ev.data.color; + }, /** * Called when a color button is clicked -> confirms the preview. * @@ -1101,6 +1128,7 @@ const ColorpickerUserValueWidget = SelectUserValueWidget.extend({ */ _onColorPicked: function (ev) { this._previewColor = false; + this._customColorValue = false; this._value = ev.data.color; this._onUserValueChange(ev); }, @@ -1125,14 +1153,20 @@ const ColorpickerUserValueWidget = SelectUserValueWidget.extend({ this._onUserValueReset(ev); }, /** - * Called when the color reset button is clicked -> removes all color - * classes and color styles. - * * @private */ - _onColorReset: function (ev) { - this._value = ''; - this._onUserValueChange(ev); + _onEnterKey: function () { + this.close(); + }, + /** + * @override + */ + _onClick: function (ev) { + // Do not close the colorpalette on colorpicker click + if (!ev.originalEvent.__isColorpickerClick) { + this._super(...arguments); + } + ev.stopPropagation(); }, }); diff --git a/addons/web_editor/static/src/js/editor/summernote.js b/addons/web_editor/static/src/js/editor/summernote.js index 80ccd3d0c82..1053e0699bc 100644 --- a/addons/web_editor/static/src/js/editor/summernote.js +++ b/addons/web_editor/static/src/js/editor/summernote.js @@ -2307,12 +2307,14 @@ $.summernote.pluginEvents.color = function (event, editor, layoutInfo, sObjColor if (foreColor) { $.summernote.pluginEvents.foreColor(event, editor, layoutInfo, foreColor); } if (backColor) { $.summernote.pluginEvents.backColor(event, editor, layoutInfo, backColor); } }; -$.summernote.pluginEvents.foreColor = function (event, editor, layoutInfo, foreColor) { +$.summernote.pluginEvents.foreColor = function (event, editor, layoutInfo, foreColor, preview) { var $editable = layoutInfo.editable(); $.summernote.pluginEvents.applyFont(event, editor, layoutInfo, foreColor, null, null); - editor.afterCommand($editable); + if (!preview) { + editor.afterCommand($editable); + } }; -$.summernote.pluginEvents.backColor = function (event, editor, layoutInfo, backColor) { +$.summernote.pluginEvents.backColor = function (event, editor, layoutInfo, backColor, preview) { var $editable = layoutInfo.editable(); var r = range.create(); if (!r) return; @@ -2328,7 +2330,9 @@ $.summernote.pluginEvents.backColor = function (event, editor, layoutInfo, backC return; } $.summernote.pluginEvents.applyFont(event, editor, layoutInfo, null, backColor, null); - editor.afterCommand($editable); + if (!preview) { + editor.afterCommand($editable); + } }; options.onCreateLink = function (sLinkUrl) { 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 48d9c560c3c..75943dac1e7 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 @@ -3,7 +3,7 @@ odoo.define('web_editor.ColorPalette', function (require) { const core = require('web.core'); const session = require('web.session'); -const {ColorpickerDialog, ColorpickerWidget} = require('web.Colorpicker'); +const {ColorpickerWidget} = require('web.Colorpicker'); const Widget = require('web.Widget'); const summernoteCustomColors = require('web_editor.rte.summernote_custom_colors'); @@ -18,8 +18,10 @@ const ColorPaletteWidget = Widget.extend({ 'click button': '_onColorButtonClick', 'mouseenter button': '_onColorButtonEnter', 'mouseleave button': '_onColorButtonLeave', - 'click .o_colorpicker_reset': '_onColorResetButtonClick', - 'click .o_add_custom_color': '_onCustomColorButtonClick', + }, + custom_events: { + 'colorpicker_select': '_onColorPickerSelect', + 'colorpicker_preview': '_onColorPickerPreview', }, /** * @override @@ -71,7 +73,7 @@ const ColorPaletteWidget = Widget.extend({ /** * @override */ - start: function () { + start: async function () { const res = this._super.apply(this, arguments); const $colorSection = this.$('.o_colorpicker_sections'); @@ -81,14 +83,6 @@ const ColorPaletteWidget = Widget.extend({ : $(`
`); $clpicker.appendTo($wrapper); - this.el.querySelectorAll('.o_colorpicker_section').forEach(elem => { - $(elem).prepend('
' + (elem.dataset.display || '') + '
'); - }); - - if (this.options.resetButton) { - this.$('.o_colorpicker_reset').removeClass('d-none'); - } - // 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) { @@ -98,6 +92,18 @@ const ColorPaletteWidget = Widget.extend({ $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.el.querySelectorAll('.o_colorpicker_section').forEach(elem => { + $(elem).prepend('
' + (elem.dataset.display || '') + '
'); + }); + // Render common colors if (!this.options.excluded.includes('common')) { const $commonColorSection = this.$('[data-name="common"]'); @@ -126,20 +132,26 @@ const ColorPaletteWidget = Widget.extend({ } }); - // Render custom colors - this._buildCustomColors(); - - // Compute selected color + // Select selected Color and build customColors. + // If no color is selected selectedColor is an empty string (transparent is interpreted as no color) if (this.options.selectedColor) { const selectedColor = ColorpickerWidget.normalizeCSSColor(this.options.selectedColor); if (selectedColor !== 'rgba(0, 0, 0, 0)') { this.selectedColor = this.colorToColorNames[selectedColor] || selectedColor; } - const selectedButton = this.el.querySelector(`button[data-color="${this.selectedColor}"], button[style*="background-color:${this.selectedColor};"]`); - if (selectedButton) { - selectedButton.classList.add('selected'); - } } + this._buildCustomColors(); + this._markSelectedColor(); + + // Colorpicker + let defaultColor = this.selectedColor; + if (defaultColor && !ColorpickerWidget.isCSSColor(defaultColor)) { + defaultColor = ColorpickerWidget.normalizeCSSColor(this.style.getPropertyValue('--' + defaultColor).trim()); + } + this.colorPicker = new ColorpickerWidget(this, { + defaultColor: defaultColor, + }); + await this.colorPicker.prependTo(this.$el); // Add those at the very end so that we don't mark hidden colors as // selected. We want those colors to appear as selected custom colors if @@ -184,6 +196,7 @@ const ColorPaletteWidget = Widget.extend({ if (this.options.excluded.includes('custom')) { return; } + this.el.querySelectorAll('.o_custom_color').forEach(el => el.remove()); const existingColors = new Set(this.summernoteCustomColorsArray.concat( Object.keys(this.colorToColorNames) )); @@ -239,6 +252,11 @@ 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); }, /** @@ -263,20 +281,34 @@ const ColorPaletteWidget = Widget.extend({ */ _getButtonInfo: function (buttonEl) { const bgColor = buttonEl.style.backgroundColor; - const color = bgColor ? ColorpickerWidget.normalizeCSSColor(bgColor) : buttonEl.dataset.color; return { - color: color, + color: bgColor ? ColorpickerWidget.normalizeCSSColor(bgColor) : buttonEl.dataset.color || '', target: buttonEl, }; }, /** - * Set the selectedColor and inform parents + * Set the selectedColor and trigger an event * - * @param {Object} colorInfo + * @param {Object} color + * @param {string} eventName */ - _selectColor: function (colorInfo) { + _selectColor: function (colorInfo, eventName) { this.selectedColor = colorInfo.color = this.colorToColorNames[colorInfo.color] || colorInfo.color; - this.trigger_up('color_picked', colorInfo); + this.trigger_up(eventName, colorInfo); + this._buildCustomColors(); + this._markSelectedColor(); + }, + /** + * Mark the selected color + * + * @private + */ + _markSelectedColor: function () { + this.el.querySelectorAll('button.selected').forEach(el => el.classList.remove('selected')); + const selectedButton = this.el.querySelector(`button[data-color="${this.selectedColor}"], button[style*="background-color:${this.selectedColor};"]`); + if (selectedButton) { + selectedButton.classList.add('selected'); + } }, //-------------------------------------------------------------------------- @@ -292,7 +324,7 @@ const ColorPaletteWidget = Widget.extend({ _onColorButtonClick: function (ev) { const buttonEl = ev.currentTarget; const colorInfo = this._getButtonInfo(buttonEl); - this._selectColor(colorInfo); + this._selectColor(colorInfo, 'color_picked'); }, /** * Called when a color button is entered. @@ -305,59 +337,41 @@ const ColorPaletteWidget = Widget.extend({ this.trigger_up('color_hover', this._getButtonInfo(ev.currentTarget)); }, /** - * Called when a color button is left. + * Called when a color button is left the data color is the color currently selected. * * @private * @param {Event} ev */ _onColorButtonLeave: function (ev) { ev.stopPropagation(); - const selected = this.el.querySelector('button.selected'); - let params = null; - if (selected) { - params = this._getButtonInfo(selected); - } else { - params = { - color: '', - }; - } - params.target = ev.target; - this.trigger_up('color_leave', params); - }, - /** - * Called when the color reset button is clicked. - * - * @private - * @param {Event} ev - */ - _onColorResetButtonClick: function (ev) { - this.selectedColor = ''; - this.trigger_up('color_reset', { + this.trigger_up('color_leave', { + color: this.selectedColor, target: ev.target, }); }, /** - * Called when the custom color button is clicked. + * Called when an update is made on the colorpicker. * * @private * @param {Event} ev */ - _onCustomColorButtonClick: async function (ev) { - const target = ev.target; - let selectedColor = this.selectedColor; - if (!ColorpickerWidget.isCSSColor(selectedColor)) { - selectedColor = ColorpickerWidget.normalizeCSSColor(this.style.getPropertyValue('--' + selectedColor).trim()); - } - const colorpicker = new ColorpickerDialog(this, { - defaultColor: selectedColor, + _onColorPickerPreview: function (ev) { + this.trigger_up('color_hover', { + color: ev.data.cssColor, + target: this.colorPicker.el, }); - colorpicker.on('colorpicker:saved', this, ev => { - this._selectColor({ - color: ev.data.cssColor, - target: target, - }); - }); - colorpicker.open(); + }, + /** + * Called when a color is selected on the colorpicker (mouseup). + * + * @private + * @param {Event} ev + */ + _onColorPickerSelect: function (ev) { + this._selectColor({ + color: ev.data.cssColor, + target: this.colorPicker.el, + }, 'custom_color_picked'); }, }); diff --git a/addons/web_editor/static/src/scss/wysiwyg.scss b/addons/web_editor/static/src/scss/wysiwyg.scss index cac357a4af3..fca0e5345ea 100644 --- a/addons/web_editor/static/src/scss/wysiwyg.scss +++ b/addons/web_editor/static/src/scss/wysiwyg.scss @@ -174,7 +174,7 @@ $o-we-zindex: $o-we-overlay-zindex + 1 !default; } } .note-color ul.show { - min-width: 172px !important; + min-width: 216px !important; } // ANIMATIONS diff --git a/addons/web_editor/static/src/scss/wysiwyg_snippets.scss b/addons/web_editor/static/src/scss/wysiwyg_snippets.scss index d0c6026dfa8..6ad06de9082 100644 --- a/addons/web_editor/static/src/scss/wysiwyg_snippets.scss +++ b/addons/web_editor/static/src/scss/wysiwyg_snippets.scss @@ -422,7 +422,7 @@ body.editor_enable.editor_has_snippets { z-index: $zindex-dropdown; border: 1px solid var(--o-we-color); background-color: var(--o-we-bg-color-dark); - max-height: 400px; + max-height: 600px; overflow-y: auto; } } @@ -633,6 +633,7 @@ body.editor_enable.editor_has_snippets { // SNIPPET OPTIONS .colorpicker { + padding: 3px; .o_colorpicker_sections { font-size: 14px; @@ -643,6 +644,20 @@ body.editor_enable.editor_has_snippets { margin: 0; border: none; box-shadow: inset 0 0 0 1px var(--o-we-bg-color-dark); + + &.o_colorpicker_reset { + background-color: transparent; + + &::before { + @include o-position-absolute(0, 0, 0, 0); + font-family: FontAwesome !important; + content: "\f00d" !important;// fa-times + display: flex; + justify-content: center; + align-items: center; + color: $o-we-color-danger; + } + } } .o_colorpicker_section { @@ -668,7 +683,7 @@ body.editor_enable.editor_has_snippets { } } - &[data-name="transparent_grayscale"], &[data-name="theme"] { + &[data-name="transparent_grayscale"], &[data-name="theme"], &[data-name="reset"] { button { @include o-alpha-button-preview; @@ -894,7 +909,7 @@ body.editor_enable.editor_has_snippets { > div { display: flex; align-items: center; - + > * { margin: 0 2px; border: 1px solid $o-we-color-text-normal; @@ -903,7 +918,7 @@ body.editor_enable.editor_has_snippets { opacity: 0.5; transition: opacity 400ms ease 0s; cursor: pointer; - + &:hover { opacity: 1; } @@ -915,7 +930,7 @@ body.editor_enable.editor_has_snippets { .o_move_handle { padding: 3px 4px; cursor: move; - + &::before, &::after { content: '\f141'; display: block; diff --git a/addons/web_editor/static/src/xml/snippets.xml b/addons/web_editor/static/src/xml/snippets.xml index a240431b6e8..59d3d28d5cc 100644 --- a/addons/web_editor/static/src/xml/snippets.xml +++ b/addons/web_editor/static/src/xml/snippets.xml @@ -44,15 +44,7 @@
-
- +
diff --git a/addons/web_editor/views/editor.xml b/addons/web_editor/views/editor.xml index 584725eb515..ad0e4245b76 100644 --- a/addons/web_editor/views/editor.xml +++ b/addons/web_editor/views/editor.xml @@ -231,7 +231,7 @@
-
+