[IMP] web, web_editor: integrate colorpicker in colorpalette

Stop using the colorpicker dialog in the colorpalette widget.
Integrate the colorpicker widget in the colorpalette widget. Of course,
the colorpicker behaviors are adapted so that no useless rerendering
of the colorpalette is made on each value change.

The 'reset color' button is now a button like the other colors, no need
for a 'color_reset' event anymore. It is removed and replaced with a
'color_picked' event with color being an empty string. The clear button
now also work on hover.

Also, the topbar colorpalette for text and text background colors now
has the exact same behaviour as the background colorpalette: adding
color preview on hover.

The colorpalette now also closes on 'enter' keypress.

Part of https://github.com/odoo/odoo/pull/46088
task-2195313

closes odoo/odoo#46088

Related: odoo/enterprise#8696
Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com>
This commit is contained in:
fja-odoo
2020-05-15 11:05:00 +00:00
parent a72c9adbe5
commit 99910b526e
11 changed files with 294 additions and 186 deletions
+62 -14
View File
@@ -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);
},
+38 -32
View File
@@ -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;
}
}
}
+23 -37
View File
@@ -3,44 +3,30 @@
<t t-name="Colorpicker">
<div class="o_colorpicker_widget">
<div class="row">
<div class="col-12">
<div class="o_color_pick_area d-inline-block border">
<div class="o_picker_pointer rounded-circle" />
</div>
<div class="o_color_slider d-inline-block ml-2 border">
<div class="o_slider_pointer" />
</div>
<div class="o_opacity_slider d-inline-block ml-2 border" t-if="!widget.options.noTransparency">
<div class="o_opacity_pointer" />
</div>
<div class="o_color_pick_area d-inline-block border" t-att-style="widget.options.noTransparency ? 'width: 89%;' : None">
<div class="o_picker_pointer rounded-circle" tabindex="-1"/>
</div>
<div class="o_color_slider d-inline-block border">
<div class="o_slider_pointer" tabindex="-1"/>
</div>
<div class="o_opacity_slider d-inline-block border" t-if="!widget.options.noTransparency">
<div class="o_opacity_pointer" tabindex="-1"/>
</div>
<div class="o_color_picker_inputs">
<div t-if="widget.options.colorPreview" class="o_color_preview_parent">
<span class="rounded-0 o_color_preview"/>
</div>
<div class="o_hex_div"><input type="text" class="o_hex_input" data-color-method="hex" size="1"/>hex</div>
<div class="o_rgba_div">
<input type="text" class="o_red_input" data-color-method="rgb" size="1"/>
<input type="text" class="o_green_input" data-color-method="rgb" size="1"/>
<input type="text" class="o_blue_input" data-color-method="rgb" size="1"/>
<t t-if="!widget.options.noTransparency">
<input type="text" class="o_opacity_input" data-color-method="opacity" size="1"/>
RGBA
</t>
<t t-else="">RGB</t>
</div>
<form class="col-12 o_color_picker_inputs">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text rounded-0 o_color_preview" />
</div>
<input type="text" class="form-control o_hex_input" data-color-method="hex" />
</div>
<div class="form-row mt-2">
<div class="col form-group">
<label for="red">Red</label>
<input type="text" class="form-control o_red_input" data-color-method="rgb" id="red" />
</div>
<div class="col form-group">
<label for="green">Green</label>
<input type="text" class="form-control o_green_input" data-color-method="rgb" id="green" />
</div>
<div class="col form-group">
<label for="blue">Blue</label>
<input type="text" class="form-control o_blue_input" data-color-method="rgb" id="blue" />
</div>
<div class="col form-group" t-if="!widget.options.noTransparency">
<label for="opacity">Opacity %</label>
<input type="text" class="form-control o_opacity_input" data-color-method="opacity" id="opacity" />
</div>
</div>
</form>
</div>
</div>
</t>
@@ -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();
@@ -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();
},
});
@@ -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) {
@@ -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({
: $(`<colorpicker><div class="o_colorpicker_section" data-name="common"></div></colorpicker>`);
$clpicker.appendTo($wrapper);
this.el.querySelectorAll('.o_colorpicker_section').forEach(elem => {
$(elem).prepend('<div>' + (elem.dataset.display || '') + '</div>');
});
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('<div class="o_colorpicker_section" data-name="reset"/>');
}
this._createColorButton('', ['o_colorpicker_reset', 'float-right']).appendTo($section);
}
this.el.querySelectorAll('.o_colorpicker_section').forEach(elem => {
$(elem).prepend('<div>' + (elem.dataset.display || '') + '</div>');
});
// 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');
},
});
@@ -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
@@ -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;
@@ -44,15 +44,7 @@
<!-- options -->
<div t-name="web_editor.snippet.option.colorpicker" class="colorpicker">
<div class="o_colorpicker_sections px-1 pb8">
<div class="o_colorpicker_section">
<a class="btn w-50 float-left o_colorpicker_reset d-none">
<i class="fa fa-ban"/> Reset
</a>
<a class="btn w-50 o_add_custom_color" data-name="custom">
<i class="fa fa-plus"/> Custom
</a>
</div>
<div class="o_colorpicker_sections">
<div class="tab-content o_colorpicker_section_tabs"/>
</div>
</div>
+1 -1
View File
@@ -231,7 +231,7 @@
<button data-color="100"></button>
<button data-color="white"></button>
</div>
<div class="o_colorpicker_section" data-name="transparent_grayscale" data-display="Opacity Filters" data-icon-class="fa fa-eye-slash">
<div class="o_colorpicker_section" data-name="transparent_grayscale">
<button data-color="black-15"></button>
<button data-color="black-25"></button>
<button data-color="black-50"></button>