From 417fc95b7277648e249be56623e34df8ef884e17 Mon Sep 17 00:00:00 2001 From: Antoine Guenet Date: Mon, 11 Apr 2022 10:28:15 +0000 Subject: [PATCH] [FIX] mass_mailing: prevent overriding font awesome font-family When changing a font-family style in the design tab, we need to make sure we don't override the font-family of font awesome icons or it will break them. This takes font-family out of its selector and applies it to special selectors that exclude `.fa`. task-2821155 X-original-commit: d25b38969d1d0f2f791ad33f2591ea4f3b7b5ed8 Part-of: odoo/odoo#92138 --- .../src/js/mass_mailing_design_constants.js | 41 +++++++++++++++---- .../static/src/js/mass_mailing_snippets.js | 19 ++++----- 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/addons/mass_mailing/static/src/js/mass_mailing_design_constants.js b/addons/mass_mailing/static/src/js/mass_mailing_design_constants.js index c8d201ac68b..1f9b9b70ca3 100644 --- a/addons/mass_mailing/static/src/js/mass_mailing_design_constants.js +++ b/addons/mass_mailing/static/src/js/mass_mailing_design_constants.js @@ -33,6 +33,16 @@ export const PRIORITY_STYLES = { export const RE_CSS_TEXT_MATCH = /([^{]+)([^}]+)/; export const RE_SELECTOR_ENDS_WITH_GT_STAR = />\s*\*\s*$/; +export const transformFontFamilySelector = selector => { + if (selector.trim().endsWith(':not(.fa)')) { + return [selector]; + } + if (!selector.endsWith('*')) { + return [`${selector.trim()}:not(.fa)`, `${selector.trim()} :not(.fa)`]; + } else if (RE_SELECTOR_ENDS_WITH_GT_STAR.test(selector)) { + return [`${selector.replace(RE_SELECTOR_ENDS_WITH_GT_STAR, '').trim()} :not(.fa)`]; + } +} /** * Take a css text and splits each comma-separated selector into separate * styles, applying the css prefix to each. Return the modified css text. @@ -47,16 +57,32 @@ export const splitCss = css => { document.head.appendChild(styleElement); const rules = [...styleElement.sheet.cssRules]; styleElement.remove(); - const result = rules.map(rule => { - const [, fullSelector, styles] = rule.cssText.match(RE_CSS_TEXT_MATCH); - return fullSelector.split(',').map(selector => { + const stylesToWrite = {}; + for (const rule of rules) { + const styles = rule.style; + for (let selector of rule.selectorText.split(',')) { if (!selector.trim().startsWith(CSS_PREFIX)) { selector = `${CSS_PREFIX} ${selector.trim()}`; } - return `${selector.trim()} {${styles.replace('{', '').trim()}}`; - }).join(''); - }).join(''); - return result; + for (const style of rule.style) { + let selectors = [selector]; + if (style === 'font-family') { + // Ensure font-family gets passed to all descendants and never + // overwrite font awesome. + selectors = transformFontFamilySelector(selector); + } + for (const selectorToWriteTo of selectors) { + if (!stylesToWrite[selectorToWriteTo]) { + stylesToWrite[selectorToWriteTo] = []; + } + stylesToWrite[selectorToWriteTo].push([style, styles[style]]); + } + } + } + } + return Object.entries(stylesToWrite).map(([selector, styles]) => ( + `${selector.trim()} {\n${styles.map(([styleName, style]) => ` ${styleName}: ${style};`).join('\n')}\n}` + )).join('\n'); }; export const getFontName = fontFamily => fontFamily.split(',')[0].replace(/"/g, '').replace(/([a-z])([A-Z])/g, (v, a, b) => `${a} ${b}`).trim(); export const normalizeFontFamily = fontFamily => fontFamily.replace(/"/g, '').replace(/, /g, ','); @@ -90,4 +116,5 @@ export default { CSS_PREFIX, BTN_SIZE_STYLES, DEFAULT_BUTTON_SIZE, PRIORITY_STYLES, RE_CSS_TEXT_MATCH, FONT_FAMILIES, RE_SELECTOR_ENDS_WITH_GT_STAR, splitCss, getFontName, normalizeFontFamily, initializeDesignTabCss, + transformFontFamilySelector, } diff --git a/addons/mass_mailing/static/src/js/mass_mailing_snippets.js b/addons/mass_mailing/static/src/js/mass_mailing_snippets.js index 98a84fe1ae8..1553e09536f 100644 --- a/addons/mass_mailing/static/src/js/mass_mailing_snippets.js +++ b/addons/mass_mailing/static/src/js/mass_mailing_snippets.js @@ -6,9 +6,10 @@ const {ColorpickerWidget} = require('web.Colorpicker'); const SelectUserValueWidget = options.userValueWidgetsRegistry['we-select']; const weUtils = require('web_editor.utils'); const { - CSS_PREFIX, BTN_SIZE_STYLES, RE_SELECTOR_ENDS_WITH_GT_STAR, + CSS_PREFIX, BTN_SIZE_STYLES, DEFAULT_BUTTON_SIZE, PRIORITY_STYLES, FONT_FAMILIES, - getFontName, normalizeFontFamily, initializeDesignTabCss + getFontName, normalizeFontFamily, initializeDesignTabCss, + transformFontFamilySelector, } = require('mass_mailing.design_constants'); @@ -237,18 +238,16 @@ options.registry.DesignTab = options.Class.extend({ if (params.cssProperty.includes('color')) { value = weUtils.normalizeColor(value); } - const selectors = this._getSelectors(params.selectorText); + let selectors = this._getSelectors(params.selectorText); const firstSelector = selectors[0].replace(CSS_PREFIX, '').trim(); if (params.cssProperty === 'font-family') { - // Ensure font-family gets passed to all descendants. - selectors.push(...selectors.map(selector => selector + ' *')); + // Ensure font-family gets passed to all descendants and never + // overwrite font awesome. + const newSelectors = []; for (const selector of selectors) { - if (!selector.endsWith('*')) { - selectors.push(`${selector} *`); - } else if (RE_SELECTOR_ENDS_WITH_GT_STAR.test(selector)) { - selectors.push(selector.replace(RE_SELECTOR_ENDS_WITH_GT_STAR, ' *')); - } + newSelectors.push(...transformFontFamilySelector(selector)); } + selectors = [...new Set(newSelectors)]; } for (const selector of selectors) { const priority = PRIORITY_STYLES[firstSelector].includes(params.cssProperty) ? ' !important' : '';