[FIX] web_editor: make class-based colors selectable for custom buttons
Before this commit selecting a class-based color (gray scale, o-color-1~5) was ignored when configuring a custom button colors. After this commit the color's class is applied. Additionally, upon switching between Custom and other types, the custom UI is now cleaned up. task-2653874 closes odoo/odoo#78720 X-original-commit: 26d37812f0217ae913c8ddf761bcb26b5c44bff5 Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com>
This commit is contained in:
@@ -317,6 +317,19 @@ function _isColorGradient(value) {
|
||||
// FIXME duplicated in odoo-editor/utils.js
|
||||
return value && value.includes('-gradient(');
|
||||
}
|
||||
/**
|
||||
* Returns the class of the element that matches the specified prefix.
|
||||
*
|
||||
* @private
|
||||
* @param {Element} el element from which to recover the color class
|
||||
* @param {string[]} colorNames
|
||||
* @param {string} prefix prefix of the color class to recover
|
||||
* @returns {string} color class matching the prefix or an empty string
|
||||
*/
|
||||
function _getColorClass(el, colorNames, prefix) {
|
||||
const prefixedColorNames = _computeColorClasses(colorNames, prefix);
|
||||
return el.classList.value.split(' ').filter(cl => prefixedColorNames.includes(cl)).join(' ');
|
||||
}
|
||||
|
||||
return {
|
||||
CSS_SHORTHANDS: CSS_SHORTHANDS,
|
||||
@@ -335,5 +348,6 @@ return {
|
||||
getBgImageURL: _getBgImageURL,
|
||||
backgroundImageCssToParts: _backgroundImageCssToParts,
|
||||
backgroundImagePartsToCss: _backgroundImagePartsToCss,
|
||||
getColorClass: _getColorClass,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@ const core = require('web.core');
|
||||
const OdooEditorLib = require('@web_editor/../lib/odoo-editor/src/OdooEditor');
|
||||
const wysiwygUtils = require('@web_editor/js/wysiwyg/wysiwyg_utils');
|
||||
const Widget = require('web.Widget');
|
||||
const {isColorGradient} = require('web_editor.utils');
|
||||
|
||||
const getDeepRange = OdooEditorLib.getDeepRange;
|
||||
const getInSelection = OdooEditorLib.getInSelection;
|
||||
@@ -93,9 +94,11 @@ const Link = Widget.extend({
|
||||
this.data.isNewWindow = this.data.isNewWindow || this.linkEl.target === '_blank';
|
||||
}
|
||||
|
||||
const allBtnColorPrefixes = /(^|\s+)(bg|text|border)(-[a-z0-9_-]*)?/gi;
|
||||
const allBtnClassSuffixes = /(^|\s+)btn(-[a-z0-9_-]*)?/gi;
|
||||
const allBtnShapes = /\s*(rounded-circle|flat)\s*/gi;
|
||||
this.data.className = this.data.iniClassName
|
||||
.replace(allBtnColorPrefixes, ' ')
|
||||
.replace(allBtnClassSuffixes, ' ')
|
||||
.replace(allBtnShapes, ' ');
|
||||
// 'o_submit' class will force anchor to be handled as a button in linkdialog.
|
||||
@@ -131,7 +134,6 @@ const Link = Widget.extend({
|
||||
}
|
||||
|
||||
this._updateOptionsUI();
|
||||
this._adaptPreview();
|
||||
|
||||
if (!this.options.noFocusUrl) {
|
||||
// ensure the focus in the first input of the link modal
|
||||
@@ -160,9 +162,16 @@ const Link = Widget.extend({
|
||||
if (!data.classes.includes('btn') && this.data.iniClassName.includes("btn-link")) {
|
||||
data.classes += " btn btn-link";
|
||||
}
|
||||
if (!['btn-custom', 'btn-outline-custom', 'btn-fill-custom'].some(className =>
|
||||
if (['btn-custom', 'btn-outline-custom', 'btn-fill-custom'].some(className =>
|
||||
data.classes.includes(className)
|
||||
)) {
|
||||
this.$link.css('color', data.classes.includes(data.customTextColor) ? '' : data.customTextColor);
|
||||
this.$link.css('background-color', data.classes.includes(data.customFill) || isColorGradient(data.customFill) ? '' : data.customFill);
|
||||
this.$link.css('background-image', isColorGradient(data.customFill) ? data.customFill : '');
|
||||
this.$link.css('border-width', data.customBorderWidth);
|
||||
this.$link.css('border-style', data.customBorderStyle);
|
||||
this.$link.css('border-color', data.customBorder);
|
||||
} else {
|
||||
this.$link.css('color', '');
|
||||
this.$link.css('background-color', '');
|
||||
this.$link.css('background-image', '');
|
||||
@@ -289,6 +298,7 @@ const Link = Widget.extend({
|
||||
const customBorder = this._getLinkCustomBorder();
|
||||
const customBorderWidth = this._getLinkCustomBorderWidth();
|
||||
const customBorderStyle = this._getLinkCustomBorderStyle();
|
||||
const customClasses = this._getLinkCustomClasses();
|
||||
const size = this._getLinkSize();
|
||||
const shape = this._getLinkShape();
|
||||
const shapes = shape ? shape.split(',') : [];
|
||||
@@ -296,6 +306,7 @@ const Link = Widget.extend({
|
||||
const shapeClasses = shapes.slice(style ? 1 : 0).join(' ');
|
||||
const classes = (this.data.className || '') +
|
||||
(type ? (` btn btn-${style}${type}`) : '') +
|
||||
(type === 'custom' ? customClasses : '') +
|
||||
(type && shapeClasses ? (` ${shapeClasses}`) : '') +
|
||||
(type && size ? (' btn-' + size) : '');
|
||||
var isNewWindow = this._isNewWindow(url);
|
||||
@@ -410,6 +421,14 @@ const Link = Widget.extend({
|
||||
* @returns {string}
|
||||
*/
|
||||
_getLinkCustomFill: function () {},
|
||||
/**
|
||||
* Returns the custom text, fill and border color classes for custom type.
|
||||
*
|
||||
* @abstract
|
||||
* @private
|
||||
* @returns {string}
|
||||
*/
|
||||
_getLinkCustomClasses: function () {},
|
||||
/**
|
||||
* Abstract method: return true if the link should open in a new window.
|
||||
*
|
||||
|
||||
@@ -3,9 +3,16 @@ odoo.define('wysiwyg.widgets.LinkTools', function (require) {
|
||||
|
||||
const Link = require('wysiwyg.widgets.Link');
|
||||
const {ColorPaletteWidget} = require('web_editor.ColorPalette');
|
||||
const {ColorpickerWidget} = require('web.Colorpicker');
|
||||
const OdooEditorLib = require('@web_editor/../lib/odoo-editor/src/OdooEditor');
|
||||
const dom = require('web.dom');
|
||||
const {getNumericAndUnit, isColorGradient} = require('web_editor.utils');
|
||||
const {
|
||||
computeColorClasses,
|
||||
getCSSVariableValue,
|
||||
getColorClass,
|
||||
getNumericAndUnit,
|
||||
isColorGradient,
|
||||
} = require('web_editor.utils');
|
||||
|
||||
const setSelection = OdooEditorLib.setSelection;
|
||||
|
||||
@@ -17,7 +24,6 @@ const LinkTools = Link.extend({
|
||||
events: _.extend({}, Link.prototype.events, {
|
||||
'click we-select we-button': '_onPickSelectOption',
|
||||
'click we-checkbox': '_onClickCheckbox',
|
||||
'click .link-custom-color span[data-toggle]': '_onClickCustomColor',
|
||||
'change .link-custom-color-border input': '_onChangeCustomBorderWidth',
|
||||
'keypress .link-custom-color-border input': '_onKeyPressCustomBorderWidth',
|
||||
'click we-select [name="link_border_style"] we-button': '_onBorderStyleSelectOption',
|
||||
@@ -33,7 +39,8 @@ const LinkTools = Link.extend({
|
||||
}
|
||||
const link = node || this.getOrCreateLink(editable);
|
||||
this._super(parent, options, editable, data, $button, link);
|
||||
// Keep track of each colorpicker.
|
||||
// Keep track of each selected custom color and colorpicker.
|
||||
this.customColors = {};
|
||||
this.colorpickers = {};
|
||||
},
|
||||
/**
|
||||
@@ -120,32 +127,45 @@ const LinkTools = Link.extend({
|
||||
* @override
|
||||
*/
|
||||
_getLinkCustomTextColor: function () {
|
||||
return this.$('we-selection-items[name="link-custom-color-text"] .o_we_color_preview').css('background-color') || '';
|
||||
return this.customColors['color'];
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
_getLinkCustomBorder: function () {
|
||||
return this.$('we-selection-items[name="link_border_color"] .o_we_color_preview').css('background-color') || '';
|
||||
return this.customColors['border-color'];
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
_getLinkCustomBorderWidth: function () {
|
||||
return this.$('we-selection-items[name="link_border_color"] input').val() || '';
|
||||
return this.$('.link-custom-color-border input').val() || '';
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
_getLinkCustomBorderStyle: function () {
|
||||
return this.$('we-selection-items[name="link_border_style"] we-button.active').data('value') || '';
|
||||
return this.$('.link-custom-color-border we-button.active').data('value') || '';
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
_getLinkCustomFill: function () {
|
||||
const $colorPreview = this.$('we-selection-items[name="link-custom-color-fill"] .o_we_color_preview');
|
||||
return $colorPreview.css('background-image') || $colorPreview.css('background-color') || '';
|
||||
return this.customColors['background-color'];
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
_getLinkCustomClasses: function () {
|
||||
let textClass = this.customColors['color'];
|
||||
if (!computeColorClasses(this.colorpickers['color'].getColorNames(), 'text-').includes(textClass)) {
|
||||
textClass = '';
|
||||
}
|
||||
let fillClass = this.customColors['background-color'];
|
||||
if (!computeColorClasses(this.colorpickers['background-color'].getColorNames(), 'bg-').includes(fillClass)) {
|
||||
fillClass = '';
|
||||
}
|
||||
return ` ${textClass} ${fillClass}`;
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
@@ -175,42 +195,118 @@ const LinkTools = Link.extend({
|
||||
this.$('.link-size-row, .link-shape-row').toggleClass('d-none', !this.colorCombinationClass);
|
||||
// Show custom colors only for Custom style.
|
||||
this.$('.link-custom-color').toggleClass('d-none', el.dataset.value !== 'custom');
|
||||
if (el.dataset.value === 'custom') {
|
||||
const textColor = this.$link[0].style['color'];
|
||||
this.$('.link-custom-color-text .o_we_color_preview').css('background-color', textColor);
|
||||
if (this.colorpickers['color'] && textColor && textColor !== 'false') {
|
||||
// Keep currently selected tab when setting color.
|
||||
this.colorpickers['color'].setSelectedColor(null, textColor, false);
|
||||
}
|
||||
const backgroundColor = this.$link[0].style['background-color'];
|
||||
this.$('.link-custom-color-fill .o_we_color_preview').css('background-color', backgroundColor);
|
||||
const backgroundImage = this.$link[0].style['background-image'];
|
||||
this.$('.link-custom-color-fill .o_we_color_preview').css('background-image', backgroundImage);
|
||||
const backgroundFill = (backgroundImage !== 'false' && backgroundImage) || backgroundColor;
|
||||
if (this.colorpickers['background-color'] && backgroundFill && backgroundFill !== 'false') {
|
||||
// Keep currently selected tab when setting color.
|
||||
this.colorpickers['background-color'].setSelectedColor(null, backgroundFill, false);
|
||||
}
|
||||
const borderWidth = this.$link[0].style['border-width'];
|
||||
const numberAndUnit = getNumericAndUnit(borderWidth);
|
||||
this.$('.link-custom-color-border input').val(numberAndUnit ? numberAndUnit[0] : "1");
|
||||
let borderStyle = this.$link[0].style['border-style'];
|
||||
if (!borderStyle || borderStyle === 'none') {
|
||||
borderStyle = 'solid';
|
||||
}
|
||||
const $activeBorderStyleButton = this.$(`.link-custom-color-border [name="link_border_style"] we-button[data-value="${borderStyle}"]`);
|
||||
$activeBorderStyleButton.addClass('active');
|
||||
$activeBorderStyleButton.siblings('we-button').removeClass("active");
|
||||
const $activeBorderStyleToggler = $activeBorderStyleButton.closest('we-select').find('we-toggler');
|
||||
$activeBorderStyleToggler.empty();
|
||||
$activeBorderStyleButton.find('div').clone().appendTo($activeBorderStyleToggler);
|
||||
const borderColor = this.$link[0].style['border-color'];
|
||||
this.$('.link-custom-color-border .o_we_color_preview').css('background-color', borderColor);
|
||||
if (this.colorpickers['border-color'] && borderColor && borderColor !== 'false') {
|
||||
// Keep currently selected tab when setting color.
|
||||
this.colorpickers['border-color'].setSelectedColor(null, borderColor, false);
|
||||
}
|
||||
|
||||
this._updateColorpicker('color');
|
||||
this._updateColorpicker('background-color');
|
||||
this._updateColorpicker('border-color');
|
||||
|
||||
const borderWidth = this.linkEl.style['border-width'];
|
||||
const numberAndUnit = getNumericAndUnit(borderWidth);
|
||||
this.$('.link-custom-color-border input').val(numberAndUnit ? numberAndUnit[0] : "1");
|
||||
let borderStyle = this.linkEl.style['border-style'];
|
||||
if (!borderStyle || borderStyle === 'none') {
|
||||
borderStyle = 'solid';
|
||||
}
|
||||
const $activeBorderStyleButton = this.$(`.link-custom-color-border [name="link_border_style"] we-button[data-value="${borderStyle}"]`);
|
||||
$activeBorderStyleButton.addClass('active');
|
||||
$activeBorderStyleButton.siblings('we-button').removeClass("active");
|
||||
const $activeBorderStyleToggler = $activeBorderStyleButton.closest('we-select').find('we-toggler');
|
||||
$activeBorderStyleToggler.empty();
|
||||
$activeBorderStyleButton.find('div').clone().appendTo($activeBorderStyleToggler);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Updates the colorpicker associated to a given property - updated with its selected color.
|
||||
*
|
||||
* @private
|
||||
* @param {string} cssProperty
|
||||
*/
|
||||
_updateColorpicker: async function (cssProperty) {
|
||||
const prefix = {
|
||||
'color': 'text-',
|
||||
'background-color': 'bg-',
|
||||
}[cssProperty];
|
||||
|
||||
let colorpicker = this.colorpickers[cssProperty];
|
||||
if (!colorpicker) {
|
||||
colorpicker = new ColorPaletteWidget(this, {
|
||||
excluded: ['transparent_grayscale'],
|
||||
$editable: $(this.options.wysiwyg.odooEditor.editable),
|
||||
withGradients: cssProperty === 'background-color',
|
||||
});
|
||||
this.colorpickers[cssProperty] = colorpicker;
|
||||
const target = this.el.querySelector({
|
||||
'color': '.link-custom-color-text .dropdown-menu',
|
||||
'background-color': '.link-custom-color-fill .dropdown-menu',
|
||||
'border-color': '.link-custom-color-border .o_we_so_color_palette .dropdown-menu',
|
||||
}[cssProperty]);
|
||||
await colorpicker.appendTo($(target));
|
||||
colorpicker.on('custom_color_picked color_picked color_hover color_leave', this, (ev) => {
|
||||
// Reset color styles in link content to make sure new color is not hidden.
|
||||
// Only done when applied to avoid losing state during preview.
|
||||
if (['custom_color_picked', 'color_picked'].includes(ev.name)) {
|
||||
const selection = window.getSelection();
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(this.linkEl);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
this.options.wysiwyg.odooEditor.execCommand('applyColor', '', 'color');
|
||||
this.options.wysiwyg.odooEditor.execCommand('applyColor', '', 'backgroundColor');
|
||||
}
|
||||
|
||||
let color = ev.data.color;
|
||||
const colorNames = colorpicker.getColorNames();
|
||||
const colorClasses = prefix ? computeColorClasses(colorNames, prefix) : [];
|
||||
const colorClass = `${prefix}${color}`;
|
||||
if (colorClasses.includes(colorClass)) {
|
||||
color = colorClass;
|
||||
} else if (colorNames.includes(color)) {
|
||||
// Store as color value.
|
||||
color = getCSSVariableValue(color);
|
||||
}
|
||||
this.customColors[cssProperty] = color;
|
||||
this.applyLinkToDom(this._getData());
|
||||
if (['custom_color_picked', 'color_picked'].includes(ev.name)) {
|
||||
this.options.wysiwyg.odooEditor.historyStep();
|
||||
this._updateOptionsUI();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Update selected color.
|
||||
const colorNames = colorpicker.getColorNames();
|
||||
let color = this.linkEl.style[cssProperty];
|
||||
const colorClasses = prefix ? computeColorClasses(colorNames, prefix) : [];
|
||||
const colorClass = prefix && getColorClass(this.linkEl, colorNames, prefix);
|
||||
const isColorClass = colorClasses.includes(colorClass);
|
||||
if (isColorClass) {
|
||||
color = colorClass;
|
||||
} else if (cssProperty === 'background-color') {
|
||||
const gradientColor = this.linkEl.style['background-image'];
|
||||
if (isColorGradient(gradientColor)) {
|
||||
color = gradientColor;
|
||||
}
|
||||
}
|
||||
this.customColors[cssProperty] = color;
|
||||
if (cssProperty === 'border-color') {
|
||||
// Highlight matching named color if any.
|
||||
const colorName = colorpicker.colorToColorNames[ColorpickerWidget.normalizeCSSColor(color)];
|
||||
colorpicker.setSelectedColor(null, colorName || color, false);
|
||||
} else {
|
||||
colorpicker.setSelectedColor(null, isColorClass ? color.replace(prefix, '') : color, false);
|
||||
}
|
||||
|
||||
// Update preview.
|
||||
const $colorPreview = this.$('.link-custom-color-' + (cssProperty === 'border-color' ? 'border' : cssProperty === 'color' ? 'text' : 'fill') + ' .o_we_color_preview');
|
||||
const previewClasses = computeColorClasses(colorNames, 'bg-');
|
||||
$colorPreview[0].classList.remove(...previewClasses);
|
||||
if (isColorClass) {
|
||||
$colorPreview.addClass(`bg-${color.replace(prefix, '')}`);
|
||||
$colorPreview.css('background-color', '');
|
||||
$colorPreview.css('background-image', '');
|
||||
} else {
|
||||
$colorPreview.css('background-color', isColorGradient(color) ? 'rgba(0, 0, 0, 0)' : color);
|
||||
$colorPreview.css('background-image', isColorGradient(color) ? color : '');
|
||||
}
|
||||
},
|
||||
|
||||
@@ -234,60 +330,6 @@ const LinkTools = Link.extend({
|
||||
this._updateOptionsUI();
|
||||
this._adaptPreview();
|
||||
},
|
||||
/**
|
||||
* Sets the color on the link.
|
||||
*
|
||||
* @private
|
||||
* @param {Event} ev
|
||||
*/
|
||||
_onClickCustomColor: function (ev) {
|
||||
const cssProperty = ev.target.dataset.cssProperty;
|
||||
let color = this.$link.css(cssProperty);
|
||||
if (cssProperty === 'background-color') {
|
||||
const gradientColor = this.$link.css('background-image');
|
||||
if (isColorGradient(gradientColor)) {
|
||||
color = gradientColor;
|
||||
}
|
||||
}
|
||||
const colorpicker = new ColorPaletteWidget(this, {
|
||||
excluded: ['transparent_grayscale'],
|
||||
$editable: $(this.options.wysiwyg.odooEditor.editable),
|
||||
selectedColor: color,
|
||||
withGradients: cssProperty === 'background-color',
|
||||
});
|
||||
this.colorpickers[cssProperty] = colorpicker;
|
||||
colorpicker.appendTo($(ev.target).closest('.dropdown').find('.dropdown-menu'));
|
||||
colorpicker.on('custom_color_picked color_picked color_hover color_leave', this, (ev) => {
|
||||
// Reset color styles in link content to make sure new color is not hidden.
|
||||
// Only done when applied to avoid losing state during preview.
|
||||
if (['custom_color_picked', 'color_picked'].includes(ev.name)) {
|
||||
const selection = window.getSelection();
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(this.$link[0]);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
this.options.wysiwyg.odooEditor.execCommand('applyColor', '', 'color');
|
||||
this.options.wysiwyg.odooEditor.execCommand('applyColor', '', 'backgroundColor');
|
||||
}
|
||||
let color = ev.data.color;
|
||||
let gradientColor = '';
|
||||
if (cssProperty === 'background-color') {
|
||||
if (isColorGradient(color)) {
|
||||
gradientColor = color;
|
||||
color = 'rgba(0, 0, 0, 0)';
|
||||
}
|
||||
this.$link.css('background-image', gradientColor);
|
||||
}
|
||||
this.$link.css(cssProperty, color);
|
||||
if (['custom_color_picked', 'color_picked'].includes(ev.name)) {
|
||||
const $colorPreview = this.$('.link-custom-color-' + (cssProperty === 'border-color' ? 'border' : cssProperty === 'color' ? 'text' : 'fill') + ' .o_we_color_preview');
|
||||
$colorPreview.css('background-color', color);
|
||||
$colorPreview.css('background-image', gradientColor);
|
||||
this.options.wysiwyg.odooEditor.historyStep();
|
||||
this._updateOptionsUI();
|
||||
}
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Sets the border width on the link.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user