',
after: getTableHtml([[[4, 33.33, ''], [6, 50, '(0, 0)'], [2, 16.67, '']]], TEST_WIDTH),
title: "should have converted a column with an offset to two columns, then completed the column",
});
this.testConvertGrid({
before: '
',
after: getTableHtml([
[[4, 33.33, ''], [6, 50, '(0, 0)'], [1, 8.33, ''], [1, 8.33, '']],
[[6, 50, '(0, 1)'], [6, 50, '']]
], TEST_WIDTH),
title: "should have converted a column with an offset to two columns, then completed the column (overflowing)",
});
});
QUnit.module('Normalize styles');
// Test normalizeColors, normalizeRem and formatTables
QUnit.test('convert rgb color to hexadecimal', async function (assert) {
assert.expect(1);
const $editable = $(
`
`
);
convertInline.normalizeColors($editable);
assert.strictEqual($editable.html(),
`
`,
"should have converted several rgb colors to hexadecimal"
);
});
QUnit.test('convert rem sizes to px', async function (assert) {
assert.expect(2);
const testDom = `
`;
let $editable = $(`
${testDom}
`);
document.body.append($editable[0]);
convertInline.normalizeRem($editable);
assert.strictEqual($editable.html(),
`
`,
"should have converted several rem sizes to px using the default rem size"
);
$editable.remove();
$editable = $(`
${testDom}
`);
document.body.append($editable[0]);
convertInline.normalizeRem($editable, 20);
assert.strictEqual($editable.html(),
`
`,
"should have converted several rem sizes to px using a set rem size"
);
$editable.remove();
});
QUnit.test('move padding from snippet containers to cells', async function (assert) {
assert.expect(1);
const testTable = `
` +
`` +
`` +
`(0, 0, 0) | ` +
`(0, 1, 0) | ` +
`(0, 2, 0) | ` +
`(0, 3, 0) | ` +
`(0, 4, 0) | ` +
`
` +
`` +
`` +
`` +
`` +
`` +
`(0, 0, 1) | ` +
`(0, 1, 1) | ` +
`(0, 2, 1) | ` +
`(0, 3, 1) | ` +
` ` +
`` +
` ` +
` | ` +
`
` +
`` +
`(1, 0, 0) | ` +
`(1, 1, 0) | ` +
`(1, 2, 0) | ` +
`(1, 3, 0) | ` +
`(1, 4, 0) | ` +
`
` +
`` +
`
`;
const expectedTable = `
` +
`` +
`` +
`(0, 0, 0) | ` + // TL
`(0, 1, 0) | ` + // T
`(0, 2, 0) | ` + // T
`(0, 3, 0) | ` + // T
`(0, 4, 0) | ` + // TR
`
` +
`` +
`` + // LR
`` +
`` +
`` +
`(0, 0, 1) | ` + // TBL
`(0, 1, 1) | ` + // TB
`(0, 2, 1) | ` + // TB
`(0, 3, 1) | ` + // TBR
` ` +
`` +
` ` +
` | ` +
`
` +
`` +
`(1, 0, 0) | ` + // BL
`(1, 1, 0) | ` + // B
`(1, 2, 0) | ` + // B
`(1, 3, 0) | ` + // B
`(1, 4, 0) | ` + // BR
`
` +
`` +
`
`;
// table.o_mail_snippet_general
const $editable = $(`
${testTable}
`);
convertInline.formatTables($editable);
assert.strictEqual($editable.html(), expectedTable,
"should have moved the padding from table.o_mail_snippet_general and table in it to their respective cells"
);
});
QUnit.test('add a tbody to any table that doesn\'t have one', async function (assert) {
assert.expect(1);
const $editable = $(`
`);
$editable.find('tr').unwrap();
convertInline.formatTables($editable);
assert.strictEqual($editable.html(), `
`,
"should have added a tbody to a table that didn't have one"
);
});
QUnit.test('add number heights to parents of elements with percent heights', async function (assert) {
assert.expect(3);
let $editable = $(`
`);
convertInline.formatTables($editable);
assert.strictEqual($editable.html(), `
`,
"should have added a 0 height to the parent of a 100% height element"
);
$editable = $(`
`);
convertInline.formatTables($editable);
assert.strictEqual($editable.html(), `
`,
"should not have changed the height of the parent of a 100% height element"
);
$editable = $(`
`);
convertInline.formatTables($editable);
assert.strictEqual($editable.html(), `
`,
"should have changed the height of the grandparent of a 100% height element"
);
});
QUnit.test('express align-self with vertical-align on table cells', async function (assert) {
assert.expect(3);
let $editable = $(`
`);
convertInline.formatTables($editable);
assert.strictEqual($editable.html(), `
`,
"should have added a top vertical alignment"
);
$editable = $(`
`);
convertInline.formatTables($editable);
assert.strictEqual($editable.html(), `
`,
"should have added a middle vertical alignment"
);
$editable = $(`
`);
convertInline.formatTables($editable);
assert.strictEqual($editable.html(), `
`,
"should have added a bottom vertical alignment"
);
});
QUnit.module('Convert snippets and mailing bodies to tables');
// Test addTables
QUnit.test('convert snippets to tables', async function (assert) {
assert.expect(2);
let $editable = $(
`
`
);
convertInline.addTables($editable);
assert.strictEqual($editable.html(),
getRegularTableHtml(1, 1, 12, 100)
.split('style=').join('class="o_mail_snippet_general" style=')
.replace(/
]*>\(0, 0\)/, ' | ' + getRegularTableHtml(1, 1, 12, 100).replace(/ | ]*>\(0, 0\)/, ' | Snippet ')),
"should have converted .o_mail_snippet_general to a special table structure with a table in it"
);
$editable = $(
``
);
convertInline.addTables($editable);
assert.strictEqual($editable.html(),
getRegularTableHtml(1, 1, 12, 100)
.split('style=').join('class="o_mail_snippet_general" style=')
.replace(/ | ]*>\(0, 0\)/, ' | '),
"should have converted .o_mail_snippet_general to a special table structure, keeping the table in it"
);
});
QUnit.test('convert mailing bodies to tables', async function (assert) {
assert.expect(2);
let $editable = $(
``
);
convertInline.addTables($editable);
assert.strictEqual($editable.html(),
getRegularTableHtml(1, 1, 12, 100)
.split('style=').join('class="o_layout" style=')
.replace(' font-size: unset; line-height: inherit;', '') // o_layout keeps those default values
.replace(/ | ]*>\(0, 0\)/, ' | ' + getRegularTableHtml(1, 1, 12, 100).replace(/ | ]*>\(0, 0\)/, ' | Mailing ')),
"should have converted .o_layout to a special table structure with a table in it"
);
$editable = $(
``
);
convertInline.addTables($editable);
assert.strictEqual($editable.html(),
getRegularTableHtml(1, 1, 12, 100)
.split('style=').join('class="o_layout" style=')
.replace(' font-size: unset; line-height: inherit;', '') // o_layout keeps those default values
.replace(/ | ]*>\(0, 0\)/, ' | '),
"should have converted .o_layout to a special table structure, keeping the table in it"
);
});
QUnit.module('Convert classes to inline styles');
// Test classToStyle
QUnit.test('convert Bootstrap classes to inline styles', async function (assert) {
assert.expect(1);
const $editable = $(``);
$(document.body).append($editable); // editable needs to be in the DOM to compute its dynamic styles.
convertInline.classToStyle($editable, convertInline.getCSSRules($editable[0].ownerDocument));
// Some positional properties (eg., padding-right, margin-left) are not
// concatenated (eg., as padding, margin) because they were defined with
// variables (var) or calculated (calc).
const containerStyle = `margin: 0px auto; box-sizing: border-box; max-width: 1320px; padding-left: 16px; padding-right: 16px; width: 100%;`;
const rowStyle = `box-sizing: border-box; margin-left: -16px; margin-right: -16px; margin-top: 0px;`;
const colStyle = `box-sizing: border-box; margin-top: 0px; padding-left: 16px; padding-right: 16px; max-width: 100%; width: 100%;`;
assert.strictEqual($editable.html(),
``,
"should have converted the classes of a simple Bootstrap grid to inline styles"
);
$editable.remove();
});
QUnit.test('simplify border/margin/padding styles', async function (assert) {
assert.expect(12);
const $styleSheet = $('');
document.head.appendChild($styleSheet[0])
const styleSheet = [...document.styleSheets].find(sheet => sheet.title === 'test-stylesheet');
// border-radius
styleSheet.insertRule(`
.test-border-radius {
border-top-right-radius: 10%;
border-bottom-right-radius: 20%;
border-bottom-left-radius: 30%;
border-top-left-radius: 40%;
}
`, 0);
let $editable = $(``);
convertInline.classToStyle($editable, convertInline.getCSSRules($editable[0].ownerDocument));
assert.strictEqual($editable.html(),
``,
"should have converted border-[position]-radius styles (from class) to border-radius");
styleSheet.deleteRule(0);
// convert all positional styles to a style in the form `property: a b c d`
styleSheet.insertRule(`
.test-border {
border-top-style: dotted;
border-right-style: dashed;
border-left-style: solid;
}
`, 0);
$editable = $(``);
convertInline.classToStyle($editable, convertInline.getCSSRules($editable[0].ownerDocument));
assert.strictEqual($editable.html(),
``,
"should have converted border-[position]-style styles (from class) to border-style");
styleSheet.deleteRule(0);
styleSheet.insertRule(`
.test-margin {
margin-right: 20px;
margin-bottom: 30px;
margin-left: 40px;
}
`, 0);
$editable = $(``);
convertInline.classToStyle($editable, convertInline.getCSSRules($editable[0].ownerDocument));
assert.strictEqual($editable.html(),
``,
"should have converted margin-[position] styles (from class) to margin");
styleSheet.deleteRule(0);
styleSheet.insertRule(`
.test-padding {
padding-top: 10px;
padding-bottom: 30px;
padding-left: 40px;
}
`, 0);
$editable = $(``);
convertInline.classToStyle($editable, convertInline.getCSSRules($editable[0].ownerDocument));
assert.strictEqual($editable.html(),
``,
"should have converted padding-[position] styles (from class) to padding");
styleSheet.deleteRule(0);
// convert all positional styles to a style in the form `property: a`
styleSheet.insertRule(`
.test-border-uniform {
border-top-style: dotted;
border-right-style: dotted;
border-bottom-style: dotted;
border-left-style: dotted;
}
`, 0);
$editable = $(``);
convertInline.classToStyle($editable, convertInline.getCSSRules($editable[0].ownerDocument));
assert.strictEqual($editable.html(),
``,
"should have converted uniform border-[position]-style styles (from class) to border-style");
styleSheet.deleteRule(0);
styleSheet.insertRule(`
.test-margin-uniform {
margin-top: 10px;
margin-right: 10px;
margin-bottom: 10px;
margin-left: 10px;
}
`, 0);
$editable = $(``);
convertInline.classToStyle($editable, convertInline.getCSSRules($editable[0].ownerDocument));
assert.strictEqual($editable.html(),
``,
"should have converted uniform margin-[position] styles (from class) to margin");
styleSheet.deleteRule(0);
styleSheet.insertRule(`
.test-padding-uniform {
padding-top: 10px;
padding-right: 10px;
padding-bottom: 10px;
padding-left: 10px;
}
`, 0);
$editable = $(``);
convertInline.classToStyle($editable, convertInline.getCSSRules($editable[0].ownerDocument));
assert.strictEqual($editable.html(),
``,
"should have converted uniform padding-[position] styles (from class) to padding");
styleSheet.deleteRule(0);
// do not convert positional styles that include an "inherit" value
styleSheet.insertRule(`
.test-border-inherit {
border-top-style: dotted;
border-right-style: dashed;
border-bottom-style: inherit;
border-left-style: solid;
}
`, 0);
$editable = $(``);
convertInline.classToStyle($editable, convertInline.getCSSRules($editable[0].ownerDocument));
assert.strictEqual($editable.html(),
``,
"should not have converted border-[position]-style styles (from class) to border-style as they include an inherit");
styleSheet.deleteRule(0);
styleSheet.insertRule(`
.test-margin-inherit {
margin-top: 10px;
margin-right: inherit;
margin-bottom: 30px;
margin-left: 40px;
}
`, 0);
$editable = $(``);
convertInline.classToStyle($editable, convertInline.getCSSRules($editable[0].ownerDocument));
assert.strictEqual($editable.html(),
``,
"should not have converted margin-[position] styles (from class) to margin as they include an inherit");
styleSheet.deleteRule(0);
styleSheet.insertRule(`
.test-padding-inherit {
padding-top: 10px;
padding-right: 20px;
padding-bottom: inherit;
padding-left: 40px;
}
`, 0);
$editable = $(``);
convertInline.classToStyle($editable, convertInline.getCSSRules($editable[0].ownerDocument));
assert.strictEqual($editable.html(),
``,
"should have converted padding-[position] styles (from class) to padding as they include an inherit");
styleSheet.deleteRule(0);
// do not convert positional styles that include an "initial" value
// note: `border: initial` is automatically removed (tested in "remove
// unsupported styles")
styleSheet.insertRule(`
.test-margin-initial {
margin-top: initial;
margin-right: 20px;
margin-bottom: 30px;
margin-left: 40px;
}
`, 0);
$editable = $(``);
convertInline.classToStyle($editable, convertInline.getCSSRules($editable[0].ownerDocument));
assert.strictEqual($editable.html(),
``,
"should not have converted margin-[position] styles (from class) to margin as they include an initial");
styleSheet.deleteRule(0);
styleSheet.insertRule(`
.test-padding-initial {
padding-top: 10px;
padding-right: 20px;
padding-bottom: 30px;
padding-left: initial;
}
`, 0);
$editable = $(``);
convertInline.classToStyle($editable, convertInline.getCSSRules($editable[0].ownerDocument));
assert.strictEqual($editable.html(),
``,
"should not have converted padding-[position] styles (from class) to padding as they include an initial");
styleSheet.deleteRule(0);
$styleSheet.remove();
});
QUnit.test('remove unsupported styles', async function (assert) {
assert.expect(9);
const $styleSheet = $('');
document.head.appendChild($styleSheet[0])
const styleSheet = [...document.styleSheets].find(sheet => sheet.title === 'test-stylesheet');
// text-decoration-[prop]
styleSheet.insertRule(`
.test-decoration {
text-decoration-line: underline;
text-decoration-color: red;
text-decoration-style: solid;
text-decoration-thickness: 10px;
}
`, 0);
let $editable = $(``);
convertInline.classToStyle($editable, convertInline.getCSSRules($editable[0].ownerDocument));
assert.strictEqual($editable.html(),
``,
"should have removed all text-decoration-[prop] styles (from class) and kept a simple text-decoration");
styleSheet.deleteRule(0);
// border[\w-]*: initial
styleSheet.insertRule(`
.test-border-initial {
border-top-style: dotted;
border-right-style: dashed;
border-bottom-style: double;
border-left-style: initial;
}
`, 0);
$editable = $(``);
convertInline.classToStyle($editable, convertInline.getCSSRules($editable[0].ownerDocument));
assert.strictEqual($editable.html(),
``,
"should have removed border initial");
styleSheet.deleteRule(0);
// display: block
styleSheet.insertRule(`
.test-block {
display: block;
}
`, 0);
$editable = $(``);
convertInline.classToStyle($editable, convertInline.getCSSRules($editable[0].ownerDocument));
assert.strictEqual($editable.html(),
``,
"should have removed display block");
styleSheet.deleteRule(0);
// !important
styleSheet.insertRule(`
.test-unimportant-color {
color: blue;
}
`, 0);
$editable = $(``);
convertInline.classToStyle($editable, convertInline.getCSSRules($editable[0].ownerDocument));
assert.strictEqual($editable.html(),
``,
"should have converted a simple color");
styleSheet.insertRule(`
.test-important-color {
color: red !important;
}
`, 0);
$editable = $(``);
convertInline.classToStyle($editable, convertInline.getCSSRules($editable[0].ownerDocument));
assert.strictEqual($editable.html(),
``,
"should have converted an important color and removed the !important");
styleSheet.deleteRule(0);
styleSheet.deleteRule(0);
// animation
styleSheet.insertRule(`
.test-animation {
animation: example 5s linear 2s infinite alternate;
}
`, 0);
$editable = $(``);
convertInline.classToStyle($editable, convertInline.getCSSRules($editable[0].ownerDocument));
assert.strictEqual($editable.html(),
``,
"should have removed animation style");
styleSheet.deleteRule(0);
styleSheet.insertRule(`
.test-animation-specific {
animation-name: example;
animation-duration: 5s;
animation-timing-function: linear;
animation-delay: 2s;
animation-iteration-count: infinite;
animation-direction: alternate;
}
`, 0);
$editable = $(``);
convertInline.classToStyle($editable, convertInline.getCSSRules($editable[0].ownerDocument));
assert.strictEqual($editable.html(),
``,
"should have removed all specific animation styles");
styleSheet.deleteRule(0);
// flex
styleSheet.insertRule(`
.test-flex {
flex: 0 1 auto;
flex-flow: column wrap;
}
`, 0);
$editable = $(``);
convertInline.classToStyle($editable, convertInline.getCSSRules($editable[0].ownerDocument));
assert.strictEqual($editable.html(),
``,
"should have removed all flex styles");
styleSheet.deleteRule(0);
styleSheet.insertRule(`
.test-flex-specific {
display: flex;
flex-direction: row;
flex-wrap: wrap;
flex-basis: auto;
flex-shrink: 3;
flex-grow: 4;
}
`, 0);
$editable = $(``);
convertInline.classToStyle($editable, convertInline.getCSSRules($editable[0].ownerDocument));
assert.strictEqual($editable.html(),
``,
"should have removed all specific flex styles");
styleSheet.deleteRule(0);
$styleSheet.remove();
});
QUnit.test('give .o_layout the styles of the body', async function (assert) {
assert.expect(1);
const $iframe = $('');
$(document.body).append($iframe);
const $iframeEditable = $('');
$iframe.contents().find('body').append($iframeEditable);
const $styleSheet = $('');
$iframe.contents().find('head').append($styleSheet);
const styleSheet = [...$iframe.contents()[0].styleSheets].find(sheet => sheet.title === 'test-stylesheet');
styleSheet.insertRule(`
body {
background-color: red;
color: white;
font-size: 50px;
}
`, 0);
$iframeEditable.append(``);
convertInline.classToStyle($iframeEditable, convertInline.getCSSRules($iframeEditable[0].ownerDocument));
assert.strictEqual($iframeEditable.html(),
``,
"should have given all styles of body to .o_layout");
styleSheet.deleteRule(0);
$iframe.remove();
});
QUnit.test('convert classes to styles, preserving specificity', async function (assert) {
assert.expect(4);
const $styleSheet = $('');
document.head.appendChild($styleSheet[0])
const styleSheet = [...document.styleSheets].find(sheet => sheet.title === 'test-stylesheet');
styleSheet.insertRule(`
div.test-color {
color: green;
}
`, 0);
styleSheet.insertRule(`
.test-color {
color: red;
}
`, 1);
styleSheet.insertRule(`
.test-color {
color: blue;
}
`, 2);
let $editable = $(` `);
convertInline.classToStyle($editable, convertInline.getCSSRules($editable[0].ownerDocument));
assert.strictEqual($editable.html(),
``,
"should have prioritized the last defined style");
$editable = $(``);
convertInline.classToStyle($editable, convertInline.getCSSRules($editable[0].ownerDocument));
assert.strictEqual($editable.html(),
``,
"should have prioritized the more specific style");
$editable = $(``);
convertInline.classToStyle($editable, convertInline.getCSSRules($editable[0].ownerDocument));
assert.strictEqual($editable.html(),
``,
"should have prioritized the inline style");
styleSheet.insertRule(`
.test-color {
color: black !important;
}
`, 0);
$editable = $(``);
convertInline.classToStyle($editable, convertInline.getCSSRules($editable[0].ownerDocument));
assert.strictEqual($editable.html(),
``,
"should have prioritized the important style");
styleSheet.deleteRule(0);
styleSheet.deleteRule(0);
styleSheet.deleteRule(0);
styleSheet.deleteRule(0);
$styleSheet.remove();
});
});
});
|