[FIX] mass_mailing: do tab style manipulations on start mass_mailing
When starting the mass_mailing design option, some manipulations are done on the `#design-element` style element. This can result in sudden style changes when clicking the design tab. This commit makes it so these manipulations are done as soon as mass_mailing starts. In order to do that, constants were shared from mass_mailing_snippets. closes odoo/odoo#88318 Related: odoo/enterprise#25753 Signed-off-by: David Monjoie (dmo) <dmo@odoo.com>
This commit is contained in:
@@ -88,6 +88,7 @@
|
||||
'mass_mailing/static/src/js/mailing_contact_view_list.js',
|
||||
'mass_mailing/static/src/js/mailing_filter_widget.js',
|
||||
'mass_mailing/static/src/js/mass_mailing.js',
|
||||
'mass_mailing/static/src/js/mass_mailing_design_constants.js',
|
||||
'mass_mailing/static/src/js/mass_mailing_widget.js',
|
||||
'mass_mailing/static/src/js/mailing_mailing_view_form_full_width.js',
|
||||
'mass_mailing/static/src/js/unsubscribe.js',
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
/** @odoo-module alias=mass_mailing.design_constants**/
|
||||
|
||||
export const CSS_PREFIX = '.o_mail_wrapper';
|
||||
export const DEFAULT_CSS_OBJECT = {
|
||||
h1: {
|
||||
'font-size': '35px',
|
||||
color: '#212529',
|
||||
'font-family': 'Arial,Helvetica Neue,Helvetica,sans-serif',
|
||||
},
|
||||
h2: {
|
||||
'font-size': '28px',
|
||||
color: '#212529',
|
||||
'font-family': 'Arial,Helvetica Neue,Helvetica,sans-serif',
|
||||
},
|
||||
h3: {
|
||||
'font-size': '24.5px',
|
||||
color: '#212529',
|
||||
'font-family': 'Arial,Helvetica Neue,Helvetica,sans-serif',
|
||||
},
|
||||
'p, p > *, li, li > *': {
|
||||
'font-size': '14px',
|
||||
color: '#212529',
|
||||
'font-family': 'Arial,Helvetica Neue,Helvetica,sans-serif',
|
||||
},
|
||||
'a:not(.btn), a.btn-link': {
|
||||
'text-decoration-line': 'none',
|
||||
color: '#276e72',
|
||||
},
|
||||
'a.btn-primary, a.btn-outline-primary, a.btn-fill-primary': {
|
||||
'font-size': '12.25px',
|
||||
color: '#FFFFFF',
|
||||
'background-color': '#35979c',
|
||||
'border-color': '#35979c',
|
||||
'border-style': 'solid',
|
||||
'border-width': '1px',
|
||||
},
|
||||
'a.btn-secondary, a.btn-outline-secondary, a.btn-fill-secondary': {
|
||||
'font-size': '12.25px',
|
||||
color: '#FFFFFF',
|
||||
'background-color': '#685563',
|
||||
'border-color': '#685563',
|
||||
'border-style': 'solid',
|
||||
'border-width': '1px',
|
||||
},
|
||||
hr: {
|
||||
'border-top-color': '#212529',
|
||||
'border-top-style': 'solid',
|
||||
'border-top-width': '1px',
|
||||
width: '100%',
|
||||
}
|
||||
};
|
||||
export const DEFAULT_CSS = Object.keys(DEFAULT_CSS_OBJECT).map( // selectors
|
||||
key => key.split(',').map( // each individual comma separated selector
|
||||
selector => `${CSS_PREFIX} ${selector.trim()} {\n ${ // selector {
|
||||
Object.keys(DEFAULT_CSS_OBJECT[key]).map( // css properties
|
||||
prop => `${prop}: ${DEFAULT_CSS_OBJECT[key][prop]}`) // [prop: value]
|
||||
.join(';\n ')}\n}` // prop: value;
|
||||
).join('\n')
|
||||
).join('\n'); // css text
|
||||
|
||||
export const BTN_SIZE_STYLES = {
|
||||
'btn-sm': {
|
||||
'padding': '0.25rem 0.5rem',
|
||||
'font-size': '0.875rem',
|
||||
'line-height': '1.5rem',
|
||||
},
|
||||
'btn-lg': {
|
||||
'padding': '0.5rem 1rem',
|
||||
'font-size': '1.25rem',
|
||||
'line-height': '1.5rem',
|
||||
},
|
||||
'btn-md': {
|
||||
'padding': false, // Property must be removed.
|
||||
'font-size': '14px',
|
||||
'line-height': false, // Property must be removed.
|
||||
},
|
||||
};
|
||||
export const DEFAULT_BUTTON_SIZE = 'btn-md';
|
||||
export const PRIORITY_STYLES = {
|
||||
'h1': ['font-family'],
|
||||
'h2': ['font-family'],
|
||||
'h3': ['font-family'],
|
||||
'p': ['font-family'],
|
||||
'a:not(.btn)': [],
|
||||
'a.btn-primary': [],
|
||||
'a.btn-secondary': [],
|
||||
'hr': [],
|
||||
};
|
||||
export const RE_CSS_TEXT_MATCH = /([^{]+)([^}]+)/;
|
||||
|
||||
/**
|
||||
* Take a css text and splits each comma-separated selector into separate
|
||||
* styles, applying the css prefix to each. Return the modified css text.
|
||||
*
|
||||
* @param {string} [css]
|
||||
* @returns {string}
|
||||
*/
|
||||
export const splitCss = css => {
|
||||
const styleElement = document.createElement('style');
|
||||
styleElement.textContent = css;
|
||||
// Temporarily insert the style element in the dom to have a stylesheet.
|
||||
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 => {
|
||||
if (!selector.trim().startsWith(CSS_PREFIX)) {
|
||||
selector = `${CSS_PREFIX} ${selector.trim()}`;
|
||||
}
|
||||
return `${selector.trim()} {${styles.replace('{', '').trim()}}`;
|
||||
}).join('');
|
||||
}).join('');
|
||||
return result;
|
||||
};
|
||||
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, ',');
|
||||
export const initializeDesignTabCss = $editable => {
|
||||
let styleElement = $editable.get(0).ownerDocument.querySelector('#design-element');
|
||||
if (styleElement) {
|
||||
styleElement.textContent = splitCss(styleElement.textContent);
|
||||
} else {
|
||||
// If a style element can't be found, create one and initialize it.
|
||||
styleElement = document.createElement('style');
|
||||
styleElement.setAttribute('id', 'design-element');
|
||||
// The style element needs to be within the layout of the email in
|
||||
// order to be saved along with it.
|
||||
$editable.find('.o_layout').prepend(styleElement);
|
||||
styleElement.textContent = splitCss(DEFAULT_CSS);
|
||||
}
|
||||
};
|
||||
|
||||
export const FONT_FAMILIES = [
|
||||
'Arial, "Helvetica Neue", Helvetica, sans-serif', // name: "Arial"
|
||||
'"Courier New", Courier, "Lucida Sans Typewriter", "Lucida Typewriter", monospace', // name: "Courier New"
|
||||
'Georgia, Times, "Times New Roman", serif', // name: "Georgia"
|
||||
'"Helvetica Neue", Helvetica, Arial, sans-serif', // name: "Helvetica Neue"
|
||||
'"Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif', // name: "Lucida Grande"
|
||||
'Tahoma, Verdana, Segoe, sans-serif', // name: "Tahoma"
|
||||
'TimesNewRoman, "Times New Roman", Times, Baskerville, Georgia, serif', // name: "Times New Roman"
|
||||
'"Trebuchet MS", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Tahoma, sans-serif', // name: "Trebuchet MS"
|
||||
'Verdana, Geneva, sans-serif', // name: "Verdana"
|
||||
].map(fontFamily => normalizeFontFamily(fontFamily));
|
||||
|
||||
export default {
|
||||
CSS_PREFIX, DEFAULT_CSS_OBJECT, DEFAULT_CSS, BTN_SIZE_STYLES,
|
||||
DEFAULT_BUTTON_SIZE, PRIORITY_STYLES, RE_CSS_TEXT_MATCH, FONT_FAMILIES,
|
||||
splitCss, getFontName, normalizeFontFamily, initializeDesignTabCss,
|
||||
}
|
||||
@@ -5,111 +5,12 @@ const options = require('web_editor.snippets.options');
|
||||
const {ColorpickerWidget} = require('web.Colorpicker');
|
||||
const SelectUserValueWidget = options.userValueWidgetsRegistry['we-select'];
|
||||
const weUtils = require('web_editor.utils');
|
||||
const {
|
||||
CSS_PREFIX, BTN_SIZE_STYLES,
|
||||
DEFAULT_BUTTON_SIZE, PRIORITY_STYLES, FONT_FAMILIES,
|
||||
getFontName, normalizeFontFamily, initializeDesignTabCss
|
||||
} = require('mass_mailing.design_constants');
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Constants
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
const _getFontName = fontFamily => fontFamily.split(',')[0].replace(/"/g, '').replace(/([a-z])([A-Z])/g, (v, a, b) => `${a} ${b}`).trim();
|
||||
const _normalizeFontFamily = fontFamily => fontFamily.replace(/"/g, '').replace(/, /g, ',');
|
||||
const FONT_FAMILIES = [
|
||||
'Arial, "Helvetica Neue", Helvetica, sans-serif', // name: "Arial"
|
||||
'"Courier New", Courier, "Lucida Sans Typewriter", "Lucida Typewriter", monospace', // name: "Courier New"
|
||||
'Georgia, Times, "Times New Roman", serif', // name: "Georgia"
|
||||
'"Helvetica Neue", Helvetica, Arial, sans-serif', // name: "Helvetica Neue"
|
||||
'"Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif', // name: "Lucida Grande"
|
||||
'Tahoma, Verdana, Segoe, sans-serif', // name: "Tahoma"
|
||||
'TimesNewRoman, "Times New Roman", Times, Baskerville, Georgia, serif', // name: "Times New Roman"
|
||||
'"Trebuchet MS", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Tahoma, sans-serif', // name: "Trebuchet MS"
|
||||
'Verdana, Geneva, sans-serif', // name: "Verdana"
|
||||
].map(fontFamily => _normalizeFontFamily(fontFamily));
|
||||
const CSS_PREFIX = '.o_mail_wrapper';
|
||||
const DEFAULT_CSS_OBJECT = {
|
||||
h1: {
|
||||
'font-size': '35px',
|
||||
color: '#212529',
|
||||
'font-family': 'Arial,Helvetica Neue,Helvetica,sans-serif',
|
||||
},
|
||||
h2: {
|
||||
'font-size': '28px',
|
||||
color: '#212529',
|
||||
'font-family': 'Arial,Helvetica Neue,Helvetica,sans-serif',
|
||||
},
|
||||
h3: {
|
||||
'font-size': '24.5px',
|
||||
color: '#212529',
|
||||
'font-family': 'Arial,Helvetica Neue,Helvetica,sans-serif',
|
||||
},
|
||||
'p, p > *, li, li > *': {
|
||||
'font-size': '14px',
|
||||
color: '#212529',
|
||||
'font-family': 'Arial,Helvetica Neue,Helvetica,sans-serif',
|
||||
},
|
||||
'a:not(.btn), a.btn-link': {
|
||||
'text-decoration-line': 'none',
|
||||
color: '#276e72',
|
||||
},
|
||||
'a.btn-primary, a.btn-outline-primary, a.btn-fill-primary': {
|
||||
'font-size': '12.25px',
|
||||
color: '#FFFFFF',
|
||||
'background-color': '#35979c',
|
||||
'border-color': '#35979c',
|
||||
'border-style': 'solid',
|
||||
'border-width': '1px',
|
||||
},
|
||||
'a.btn-secondary, a.btn-outline-secondary, a.btn-fill-secondary': {
|
||||
'font-size': '12.25px',
|
||||
color: '#FFFFFF',
|
||||
'background-color': '#685563',
|
||||
'border-color': '#685563',
|
||||
'border-style': 'solid',
|
||||
'border-width': '1px',
|
||||
},
|
||||
hr: {
|
||||
'border-top-color': '#212529',
|
||||
'border-top-style': 'solid',
|
||||
'border-top-width': '1px',
|
||||
width: '100%',
|
||||
}
|
||||
};
|
||||
const DEFAULT_CSS = Object.keys(DEFAULT_CSS_OBJECT).map( // selectors
|
||||
key => key.split(',').map( // each individual comma separated selector
|
||||
selector => `${CSS_PREFIX} ${selector.trim()} {\n ${ // selector {
|
||||
Object.keys(DEFAULT_CSS_OBJECT[key]).map( // css properties
|
||||
prop => `${prop}: ${DEFAULT_CSS_OBJECT[key][prop]}`) // [prop: value]
|
||||
.join(';\n ')}\n}` // prop: value;
|
||||
).join('\n')
|
||||
).join('\n'); // css text
|
||||
|
||||
const BTN_SIZE_STYLES = {
|
||||
'btn-sm': {
|
||||
'padding': '0.25rem 0.5rem',
|
||||
'font-size': '0.875rem',
|
||||
'line-height': '1.5rem',
|
||||
},
|
||||
'btn-lg': {
|
||||
'padding': '0.5rem 1rem',
|
||||
'font-size': '1.25rem',
|
||||
'line-height': '1.5rem',
|
||||
},
|
||||
'btn-md': {
|
||||
'padding': false, // Property must be removed.
|
||||
'font-size': '14px',
|
||||
'line-height': false, // Property must be removed.
|
||||
},
|
||||
};
|
||||
const DEFAULT_BUTTON_SIZE = 'btn-md';
|
||||
const PRIORITY_STYLES = {
|
||||
'h1': ['font-family'],
|
||||
'h2': ['font-family'],
|
||||
'h3': ['font-family'],
|
||||
'p': ['font-family'],
|
||||
'a:not(.btn)': [],
|
||||
'a.btn-primary': [],
|
||||
'a.btn-secondary': [],
|
||||
'hr': [],
|
||||
};
|
||||
const RE_CSS_TEXT_MATCH = /([^{]+)([^}]+)/;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Options
|
||||
@@ -261,7 +162,7 @@ options.userValueWidgetsRegistry['we-fontfamilypicker'] = SelectUserValueWidget.
|
||||
button.dataset.customizeCssProperty = fontFamily;
|
||||
button.dataset.cssProperty = 'font-family';
|
||||
button.dataset.selectorText = this.el.dataset.selectorText;
|
||||
button.textContent = _getFontName(fontFamily);
|
||||
button.textContent = getFontName(fontFamily);
|
||||
this.menuEl.appendChild(button);
|
||||
};
|
||||
return res;
|
||||
@@ -284,18 +185,8 @@ options.registry.DesignTab = options.Class.extend({
|
||||
const res = await this._super(...arguments);
|
||||
const $editable = this.options.wysiwyg.getEditable();
|
||||
this.document = $editable[0].ownerDocument;
|
||||
initializeDesignTabCss($editable);
|
||||
this.styleElement = this.document.querySelector('#design-element');
|
||||
if (this.styleElement) {
|
||||
this.styleElement.textContent = this._splitCss(this.styleElement.textContent);
|
||||
} else {
|
||||
// If a style element can't be found, create one and initialize it.
|
||||
this.styleElement = document.createElement('style');
|
||||
this.styleElement.setAttribute('id', 'design-element');
|
||||
// The style element needs to be within the layout of the email in
|
||||
// order to be saved along with it.
|
||||
$editable.find('.o_layout').prepend(this.styleElement);
|
||||
this.styleElement.textContent = this._splitCss(DEFAULT_CSS);
|
||||
}
|
||||
// When editing a stylesheet, its content is not updated so it won't be
|
||||
// saved along with the mailing. Therefore we need to write its cssText
|
||||
// into it. However, when doing that we lose its reference. So we need
|
||||
@@ -436,7 +327,7 @@ options.registry.DesignTab = options.Class.extend({
|
||||
if (params.possibleValues && params.possibleValues[1] === FONT_FAMILIES[0]) {
|
||||
// For font-family, we need to normalize it so it
|
||||
// matches an option value.
|
||||
return rule && _normalizeFontFamily(rule.style.getPropertyValue('font-family'));
|
||||
return rule && normalizeFontFamily(rule.style.getPropertyValue('font-family'));
|
||||
} else {
|
||||
return rule && rule.style.getPropertyValue(params.cssProperty);
|
||||
}
|
||||
@@ -476,31 +367,6 @@ options.registry.DesignTab = options.Class.extend({
|
||||
_getRule(selectorText) {
|
||||
return [...(this.styleSheet.cssRules || this.styleSheet.rules)].find(rule => rule.selectorText === selectorText);
|
||||
},
|
||||
/**
|
||||
* Take a css text and splits each comma-separated selector into separate
|
||||
* styles, applying the css prefix to each. Return the modified css text.
|
||||
*
|
||||
* @param {string} css
|
||||
* @returns {string}
|
||||
*/
|
||||
_splitCss(css) {
|
||||
const styleElement = this.document.createElement('style');
|
||||
styleElement.textContent = css;
|
||||
// Temporarily insert the style element in the dom to have a stylesheet.
|
||||
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 => {
|
||||
if (!selector.trim().startsWith(CSS_PREFIX)) {
|
||||
selector = `${CSS_PREFIX} ${selector.trim()}`;
|
||||
}
|
||||
return `${selector.trim()} {${styles.replace('{', '').trim()}}`;
|
||||
}).join('');
|
||||
}).join('');
|
||||
return result;
|
||||
},
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ var core = require('web.core');
|
||||
var FieldHtml = require('web_editor.field.html');
|
||||
var fieldRegistry = require('web.field_registry');
|
||||
var convertInline = require('web_editor.convertInline');
|
||||
const { initializeDesignTabCss } = require('mass_mailing.design_constants');
|
||||
|
||||
var _t = core._t;
|
||||
|
||||
@@ -125,6 +126,7 @@ var MassMailingFieldHtml = FieldHtml.extend({
|
||||
this.$content.find('.o_layout').addBack().data('name', 'Mailing');
|
||||
// We don't want to drop snippets directly within the wysiwyg.
|
||||
this.$content.removeClass('o_editable');
|
||||
initializeDesignTabCss(this.wysiwyg.getEditable());
|
||||
},
|
||||
/**
|
||||
* Returns true if the editable area is empty.
|
||||
@@ -289,6 +291,7 @@ var MassMailingFieldHtml = FieldHtml.extend({
|
||||
if (themeParams.name === 'basic') {
|
||||
this.$content[0].focus();
|
||||
}
|
||||
initializeDesignTabCss(this.wysiwyg.getEditable());
|
||||
this.wysiwyg.trigger('reload_snippet_dropzones');
|
||||
this.trigger_up('iframe_updated', { $iframe: this.wysiwyg.$iframe });
|
||||
this.wysiwyg.odooEditor.historyStep(true);
|
||||
|
||||
Reference in New Issue
Block a user