[FIX] web_editor: properly inline and inherit body line-height from var
Before this commit, the line-height of the body was not properly inherited where it should. It is defined as a CSS variable and its value was incorrectly retrieved (if the value is 1.5 and the font-size is 10px, `getComputedStyle` returns 15px instead of 1.5). Other properties related to fonts were likewise improperly inherited. X-original-commit: 12ae698bd9aff8466d69819e0b849752f967c126 Part-of: odoo/odoo#124465
This commit is contained in:
@@ -23,9 +23,10 @@ const FONT_PROPERTIES_TO_INHERIT = [
|
||||
'font-style',
|
||||
'text-decoration',
|
||||
'text-transform',
|
||||
'text-align',
|
||||
];
|
||||
// Attributes all tables should have in a mailing.
|
||||
const TABLE_ATTRIBUTES = {
|
||||
export const TABLE_ATTRIBUTES = {
|
||||
cellspacing: 0,
|
||||
cellpadding: 0,
|
||||
border: 0,
|
||||
@@ -34,11 +35,11 @@ const TABLE_ATTRIBUTES = {
|
||||
role: 'presentation',
|
||||
};
|
||||
// Cancel tables default styles.
|
||||
const TABLE_STYLES = {
|
||||
export const TABLE_STYLES = {
|
||||
'border-collapse': 'collapse',
|
||||
'text-align': 'inherit',
|
||||
'font-size': 'unset',
|
||||
'line-height': 'unset',
|
||||
'line-height': 'inherit',
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -450,11 +451,24 @@ function classToStyle($editable, cssRules) {
|
||||
// Compute dynamic styles (var, calc).
|
||||
writes.push(() => {
|
||||
let computedStyle;
|
||||
for (let styleName of node.style) {
|
||||
for (const styleName of node.style) {
|
||||
const styleValue = node.style.getPropertyValue(styleName);
|
||||
if (styleValue.includes('var(') || styleValue.includes('calc(')) {
|
||||
computedStyle = computedStyle || getComputedStyle(node);
|
||||
node.style.setProperty(styleName, computedStyle[styleName]);
|
||||
const prop = styleValue.includes('var(') ? styleValue.replace(/var\((.*)\)/, '$1') : styleName;
|
||||
const value = computedStyle.getPropertyValue(prop) || computedStyle.getPropertyValue(styleName);
|
||||
node.style.setProperty(styleName, value);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Fix inheritance of font properties on Outlook.
|
||||
writes.push(() => {
|
||||
const propsToConvert = FONT_PROPERTIES_TO_INHERIT.filter(prop => node.style[prop] === 'inherit');
|
||||
if (propsToConvert.length) {
|
||||
const computedStyle = getComputedStyle(node);
|
||||
for (const prop of propsToConvert) {
|
||||
node.style.setProperty(prop, computedStyle[prop]);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -668,7 +682,6 @@ async function toInline($editable, cssRules, $iframe) {
|
||||
listGroupToTable(editable);
|
||||
addTables($editable);
|
||||
handleMasonry(editable);
|
||||
normalizeColors($editable);
|
||||
const rootFontSizeProperty = getComputedStyle(editable.ownerDocument.documentElement).fontSize;
|
||||
const rootFontSize = parseFloat(rootFontSizeProperty.replace(/[^\d\.]/g, ''));
|
||||
normalizeRem($editable, rootFontSize);
|
||||
@@ -676,6 +689,7 @@ async function toInline($editable, cssRules, $iframe) {
|
||||
enforceTablesResponsivity(editable);
|
||||
flattenBackgroundImages(editable);
|
||||
formatTables($editable);
|
||||
normalizeColors($editable);
|
||||
responsiveToStaticForOutlook(editable);
|
||||
// Fix Outlook image rendering bug.
|
||||
for (const attributeName of ['width', 'height']) {
|
||||
@@ -936,15 +950,18 @@ function formatTables($editable) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Tables don't properly inherit alignments from their ancestors in Outlook.
|
||||
// Tables don't properly inherit certain styles from their ancestors in Outlook.
|
||||
for (const table of editable.querySelectorAll('table')) {
|
||||
if (table.style.textAlign === 'inherit') {
|
||||
let ancestor = table;
|
||||
while (ancestor && (!ancestor.style.textAlign || ancestor.style.textAlign === 'inherit')) {
|
||||
ancestor = ancestor.parentElement;
|
||||
}
|
||||
if (ancestor) {
|
||||
table.style.setProperty('text-align', ancestor.style.textAlign);
|
||||
const propsToConvert = FONT_PROPERTIES_TO_INHERIT.filter(prop => table.style[prop] === 'inherit' || !table.style[prop]);
|
||||
if (propsToConvert.length) {
|
||||
for (const prop of propsToConvert) {
|
||||
let ancestor = table;
|
||||
while (ancestor && (!ancestor.style[prop] || ancestor.style[prop] === 'inherit')) {
|
||||
ancestor = ancestor.parentElement;
|
||||
}
|
||||
if (ancestor) {
|
||||
table.style.setProperty(prop, ancestor.style[prop]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,21 +308,21 @@ QUnit.module('convert_inline', {}, function () {
|
||||
`<td>` +
|
||||
`<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\" width=\"100%\" align=\"center\" ` +
|
||||
`role=\"presentation\" style=\"width: 100% !important; border-collapse: collapse; text-align: inherit; ` +
|
||||
`font-size: unset; line-height: unset;\"><tr>` +
|
||||
`font-size: unset; line-height: inherit;\"><tr>` +
|
||||
`<td class="card-header"><span>HEADER</span></td>` +
|
||||
`</tr></table></td>`)
|
||||
.replace(/<td[^>]*>\(1, 0\)<\/td>/,
|
||||
`<td>` +
|
||||
`<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\" width=\"100%\" align=\"center\" ` +
|
||||
`role=\"presentation\" style=\"width: 100% !important; border-collapse: collapse; text-align: inherit; ` +
|
||||
`font-size: unset; line-height: unset;\"><tr>` +
|
||||
`font-size: unset; line-height: inherit;\"><tr>` +
|
||||
`<td class="card-body"><h2 class="card-title">TITLE</h2><small>BODY <img></small></td>` +
|
||||
`</tr></table></td>`)
|
||||
.replace(/<td[^>]*>\(2, 0\)<\/td>/,
|
||||
`<td>` +
|
||||
`<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\" width=\"100%\" align=\"center\" ` +
|
||||
`role=\"presentation\" style=\"width: 100% !important; border-collapse: collapse; text-align: inherit; ` +
|
||||
`font-size: unset; line-height: unset;\"><tr>` +
|
||||
`font-size: unset; line-height: inherit;\"><tr>` +
|
||||
`<td class="card-footer"><a href="#" class="btn">FOOTER</a></td>` +
|
||||
`</tr></table></td>`),
|
||||
});
|
||||
@@ -603,7 +603,7 @@ QUnit.module('convert_inline', {}, function () {
|
||||
assert.strictEqual($editable.html(),
|
||||
getRegularTableHtml(1, 1, 12, 100)
|
||||
.split('style=').join('class="o_layout" style=')
|
||||
.replace(' font-size: unset; line-height: unset;', '') // o_layout keeps those default values
|
||||
.replace(' font-size: unset; line-height: inherit;', '') // o_layout keeps those default values
|
||||
.replace(/<td[^>]*>\(0, 0\)/, '<td>' + getRegularTableHtml(1, 1, 12, 100).replace(/<td[^>]*>\(0, 0\)/, '<td><div>Mailing</div>')),
|
||||
"should have converted .o_layout to a special table structure with a table in it"
|
||||
);
|
||||
@@ -617,7 +617,7 @@ QUnit.module('convert_inline', {}, function () {
|
||||
assert.strictEqual($editable.html(),
|
||||
getRegularTableHtml(1, 1, 12, 100)
|
||||
.split('style=').join('class="o_layout" style=')
|
||||
.replace(' font-size: unset; line-height: unset;', '') // o_layout keeps those default values
|
||||
.replace(' font-size: unset; line-height: inherit;', '') // o_layout keeps those default values
|
||||
.replace(/<td[^>]*>\(0, 0\)/, '<td><table><tbody><tr><td>Mailing</td></tr></tbody></table>'),
|
||||
"should have converted .o_layout to a special table structure, keeping the table in it"
|
||||
);
|
||||
|
||||
@@ -8,6 +8,7 @@ import Widget from "web.Widget";
|
||||
import Wysiwyg from "web_editor.wysiwyg";
|
||||
import options from "web_editor.snippets.options";
|
||||
import { range } from "@web/core/utils/numbers";
|
||||
import { TABLE_ATTRIBUTES, TABLE_STYLES } from '@web_editor/js/backend/convert_inline';
|
||||
|
||||
const COLOR_PICKER_TEMPLATE = `
|
||||
<colorpicker>
|
||||
@@ -727,22 +728,8 @@ var textInput = function (target, char) {
|
||||
// Convert Inline
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
const tableAttributes = {
|
||||
cellspacing: 0,
|
||||
cellpadding: 0,
|
||||
border: 0,
|
||||
width: '100%',
|
||||
align: 'center',
|
||||
role: 'presentation',
|
||||
};
|
||||
const tableAttributesString = Object.keys(tableAttributes).map(key => `${key}="${tableAttributes[key]}"`).join(' ');
|
||||
const tableStyles = {
|
||||
'border-collapse': 'collapse',
|
||||
'text-align': 'inherit',
|
||||
'font-size': 'unset',
|
||||
'line-height': 'unset',
|
||||
};
|
||||
const tableStylesString = Object.keys(tableStyles).map(key => `${key}: ${tableStyles[key]};`).join(' ');
|
||||
const tableAttributesString = Object.keys(TABLE_ATTRIBUTES).map(key => `${key}="${TABLE_ATTRIBUTES[key]}"`).join(' ');
|
||||
const tableStylesString = Object.keys(TABLE_STYLES).map(key => `${key}: ${TABLE_STYLES[key]};`).join(' ');
|
||||
/**
|
||||
* Take a matrix representing a grid and return an HTML string of the Bootstrap
|
||||
* grid. The matrix is an array of rows, with each row being an array of cells.
|
||||
|
||||
Reference in New Issue
Block a user