[IMP] web_editor: rebuild the text style dropdown
This commit improves the text style dropdown by adding new styles with responsive font sizes. This will allow to solve the biggest responsive font-size problem we have right now: users add a cover snippet with a big font-size (it is currently hardcoded as 62px font size in snippets). On mobile, it stays 62 and it's too big. Using displayN classes of bootstrap will allow to solve that problem. Previous commit also changed the way custom font-sizes work, so after this commit, and after snippets are adapted every text will now be responsive. task-1958098 Part-of: odoo/odoo#129791
This commit is contained in:
committed by
qsm-odoo
parent
194f73a9bb
commit
c91f5fdc47
@@ -2023,7 +2023,9 @@ export class OdooEditor extends EventTarget {
|
||||
if (!this.isSelectionInEditable()) {
|
||||
this.historyResetLatestComputedSelection(true);
|
||||
}
|
||||
this.execCommand(buttonEl.dataset.call, buttonEl.dataset.arg1);
|
||||
const arg1 = buttonEl.dataset.arg1;
|
||||
const args = arg1 && arg1.split(",") || [];
|
||||
this.execCommand(buttonEl.dataset.call, ...args);
|
||||
|
||||
ev.preventDefault();
|
||||
this._updateToolbar();
|
||||
@@ -3113,16 +3115,22 @@ export class OdooEditor extends EventTarget {
|
||||
const listUIClasses = {UL: 'fa-list-ul', OL: 'fa-list-ol', CL: 'fa-tasks'};
|
||||
const block = closestBlock(sel.anchorNode);
|
||||
let activeLabel = undefined;
|
||||
for (const [style, tag, isList] of [
|
||||
['paragraph', 'P', false],
|
||||
['pre', 'PRE', false],
|
||||
['heading1', 'H1', false],
|
||||
['heading2', 'H2', false],
|
||||
['heading3', 'H3', false],
|
||||
['heading4', 'H4', false],
|
||||
['heading5', 'H5', false],
|
||||
['heading6', 'H6', false],
|
||||
['blockquote', 'BLOCKQUOTE', false],
|
||||
for (const [style, cssSelector, isList] of [
|
||||
['paragraph', 'p:not(.small, .lead)', false],
|
||||
['pre', 'pre', false],
|
||||
['heading1', 'h1:not(.display-1, .display-2, .display-3, .display-4)', false],
|
||||
['heading2', 'h2', false],
|
||||
['heading3', 'h3', false],
|
||||
['heading4', 'h4', false],
|
||||
['heading5', 'h5', false],
|
||||
['heading6', 'h6', false],
|
||||
['display-1', 'h1.display-1', false],
|
||||
['display-2', 'h1.display-2', false],
|
||||
['display-3', 'h1.display-3', false],
|
||||
['display-4', 'h1.display-4', false],
|
||||
['blockquote', 'blockquote', false],
|
||||
['small', '.small', false],
|
||||
['light', '.lead', false],
|
||||
['unordered', 'UL', true],
|
||||
['ordered', 'OL', true],
|
||||
['checklist', 'CL', true],
|
||||
@@ -3132,8 +3140,8 @@ export class OdooEditor extends EventTarget {
|
||||
button.classList.toggle('active', false);
|
||||
} else if (button) {
|
||||
const isActive = isList
|
||||
? block.tagName === 'LI' && getListMode(block.parentElement) === tag
|
||||
: block.tagName === tag;
|
||||
? block.tagName === 'LI' && getListMode(block.parentElement) === cssSelector
|
||||
: block.matches(cssSelector);
|
||||
button.classList.toggle('active', isActive);
|
||||
|
||||
if (!isList && isActive) {
|
||||
|
||||
@@ -51,6 +51,8 @@ import {
|
||||
resetOuids,
|
||||
firstLeaf,
|
||||
lastLeaf,
|
||||
FONT_SIZE_CLASSES,
|
||||
TEXT_STYLE_CLASSES,
|
||||
} from '../utils/utils.js';
|
||||
|
||||
const TEXT_CLASSES_REGEX = /\btext-[^\s]*\b/;
|
||||
@@ -322,7 +324,7 @@ export const editorCommands = {
|
||||
redo: editor => editor.historyRedo(),
|
||||
|
||||
// Change tags
|
||||
setTag(editor, tagName) {
|
||||
setTag(editor, tagName, extraClass = "") {
|
||||
const range = getDeepRange(editor.editable, { correctTripleClick: true });
|
||||
const selectedBlocks = [...new Set(getTraversedNodes(editor.editable, range).map(closestBlock))];
|
||||
const deepestSelectedBlocks = selectedBlocks.filter(block => (
|
||||
@@ -340,7 +342,24 @@ export const editorCommands = {
|
||||
if (inLI && tagName === "P") {
|
||||
inLI.oToggleList(0);
|
||||
} else {
|
||||
setTagName(block, tagName);
|
||||
const newEl = setTagName(block, tagName);
|
||||
newEl.classList.remove(
|
||||
...FONT_SIZE_CLASSES,
|
||||
...TEXT_STYLE_CLASSES,
|
||||
// We want to be able to edit the case `<h2 class="h3">`
|
||||
// but in that case, we want to display "Header 2" and
|
||||
// not "Header 3" as it is more important to display
|
||||
// the semantic tag being used (especially for h1 ones).
|
||||
// This is why those are not in `TEXT_STYLE_CLASSES`.
|
||||
"h1", "h2", "h3", "h4", "h5", "h6"
|
||||
);
|
||||
delete newEl.style.fontSize;
|
||||
if (extraClass) {
|
||||
newEl.classList.add(extraClass);
|
||||
}
|
||||
if (newEl.classList.length === 0) {
|
||||
newEl.removeAttribute("class");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// eg do not change a <div> into a h1: insert the h1
|
||||
|
||||
@@ -67,6 +67,11 @@ export const PROTECTED_BLOCK_TAG = ['TR','TD','TABLE','TBODY','UL','OL','LI'];
|
||||
export const FONT_SIZE_CLASSES = ["display-1-fs", "display-2-fs", "display-3-fs", "display-4-fs", "h1-fs",
|
||||
"h2-fs", "h3-fs", "h4-fs", "h5-fs", "h6-fs", "base-fs", "small"];
|
||||
|
||||
/**
|
||||
* Array of all the classes used by the editor to change the text style.
|
||||
*/
|
||||
export const TEXT_STYLE_CLASSES = ["display-1", "display-2", "display-3", "display-4", "lead"];
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Position and sizes
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -964,7 +969,7 @@ const formatsSpecs = {
|
||||
.find(cls => node.classList.contains(cls)),
|
||||
addStyle: (node, props) => node.classList.add(props.className),
|
||||
removeStyle: (node) => {
|
||||
node.classList.remove(...FONT_SIZE_CLASSES);
|
||||
node.classList.remove(...FONT_SIZE_CLASSES, ...TEXT_STYLE_CLASSES);
|
||||
if (node.classList.length === 0) {
|
||||
node.removeAttribute("class");
|
||||
}
|
||||
@@ -1828,10 +1833,12 @@ export function isColorGradient(value) {
|
||||
*/
|
||||
export function getFontSizeDisplayValue(sel, getCSSVariableValue, convertNumericToUnit) {
|
||||
const tagNameRelatedToFontSize = ["h1", "h2", "h3", "h4", "h5", "h6"];
|
||||
const styleClassesRelatedToFontSize = ["display-1", "display-2", "display-3", "display-4"];
|
||||
const closestStartContainerEl = closestElement(sel.getRangeAt(0).startContainer);
|
||||
const closestFontSizedEl = closestStartContainerEl.closest(`
|
||||
[style*='font-size'],
|
||||
${FONT_SIZE_CLASSES.map(className => `.${className}`)},
|
||||
${styleClassesRelatedToFontSize.map(className => `.${className}`)},
|
||||
${tagNameRelatedToFontSize}
|
||||
`);
|
||||
let remValue;
|
||||
@@ -1851,13 +1858,15 @@ export function getFontSizeDisplayValue(sel, getCSSVariableValue, convertNumeric
|
||||
// the toolbar because it's responsive.
|
||||
const fontSizeClass = FONT_SIZE_CLASSES.find(
|
||||
className => closestFontSizedEl.classList.contains(className));
|
||||
let fsName;
|
||||
if (fontSizeClass) {
|
||||
const fsName = fontSizeClass.substring(0, fontSizeClass.length - 3); // Without -fs
|
||||
remValue = parseFloat(getCSSVariableValue(`${fsName}-font-size`));
|
||||
fsName = fontSizeClass.substring(0, fontSizeClass.length - 3); // Without -fs
|
||||
} else {
|
||||
const tagName = closestFontSizedEl.tagName.toLowerCase();
|
||||
remValue = parseFloat(getCSSVariableValue(`${tagName}-font-size`));
|
||||
fsName = styleClassesRelatedToFontSize.find(
|
||||
className => closestFontSizedEl.classList.contains(className))
|
||||
|| closestFontSizedEl.tagName.toLowerCase();
|
||||
}
|
||||
remValue = parseFloat(getCSSVariableValue(`${fsName}-font-size`));
|
||||
}
|
||||
// It's default font size (no font size class / style).
|
||||
if (remValue === undefined) {
|
||||
|
||||
@@ -13,34 +13,50 @@
|
||||
<span title="Text style">Normal</span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li id="display-1-dropdown-item">
|
||||
<a class="dropdown-item" href="#" id="display-1" data-call="setTag" data-arg1="h1,display-1">Header 1 Display 1</a>
|
||||
</li>
|
||||
<li id="display-2-dropdown-item">
|
||||
<a class="dropdown-item" href="#" id="display-2" data-call="setTag" data-arg1="h1,display-2">Header 1 Display 2</a>
|
||||
</li>
|
||||
<li id="display-3-dropdown-item">
|
||||
<a class="dropdown-item" href="#" id="display-3" data-call="setTag" data-arg1="h1,display-3">Header 1 Display 3</a>
|
||||
</li>
|
||||
<li id="display-4-dropdown-item">
|
||||
<a class="dropdown-item" href="#" id="display-4" data-call="setTag" data-arg1="h1,display-4">Header 1 Display 4</a>
|
||||
</li>
|
||||
<li t-if="props.showHeading1" id="heading1-dropdown-item">
|
||||
<a class="dropdown-item" href="#" id="heading1" data-call="setTag" data-arg1="h1">Header 1</a>
|
||||
</li>
|
||||
<li t-if="props.showHeading2" id="heading2-dropdown-item">
|
||||
<a class="dropdown-item" href="#" id="heading2" data-call="setTag" data-arg1="h2">Header 2</a>
|
||||
</li>
|
||||
<li t-if="props.showHeading3" id="heading3-dropdown-item">
|
||||
<a class="dropdown-item" href="#" id="heading3" data-call="setTag" data-arg1="h3">Header 3</a>
|
||||
</li>
|
||||
<li t-if="props.showHeading4" id="heading4-dropdown-item">
|
||||
<a class="dropdown-item" href="#" id="heading4" data-call="setTag" data-arg1="h4">Header 4</a>
|
||||
</li>
|
||||
<li t-if="props.showHeading5" id="heading5-dropdown-item">
|
||||
<a class="dropdown-item" href="#" id="heading5" data-call="setTag" data-arg1="h5">Header 5</a>
|
||||
</li>
|
||||
<li t-if="props.showHeading6" id="heading6-dropdown-item">
|
||||
<a class="dropdown-item" href="#" id="heading6" data-call="setTag" data-arg1="h6">Header 6</a>
|
||||
</li>
|
||||
<li id="paragraph-dropdown-item">
|
||||
<a class="dropdown-item" href="#" id="paragraph" data-call="setTag" data-arg1="p">Normal</a>
|
||||
</li>
|
||||
<li id="light-dropdown-item">
|
||||
<a class="dropdown-item" href="#" id="light" data-call="setTag" data-arg1="p,lead">Light</a>
|
||||
</li>
|
||||
<li id="small-dropdown-item">
|
||||
<a class="dropdown-item" href="#" id="small" data-call="setTag" data-arg1="p,small">Small</a>
|
||||
</li>
|
||||
<li id="pre-dropdown-item">
|
||||
<a class="dropdown-item" href="#" id="pre" data-call="setTag" data-arg1="pre"><pre>Code</pre></a>
|
||||
</li>
|
||||
<li t-if="props.showHeading1" id="heading1-dropdown-item">
|
||||
<a class="dropdown-item" href="#" id="heading1" data-call="setTag" data-arg1="h1"><h1>Header 1</h1></a>
|
||||
</li>
|
||||
<li t-if="props.showHeading2" id="heading2-dropdown-item">
|
||||
<a class="dropdown-item" href="#" id="heading2" data-call="setTag" data-arg1="h2"><h2>Header 2</h2></a>
|
||||
</li>
|
||||
<li t-if="props.showHeading3" id="heading3-dropdown-item">
|
||||
<a class="dropdown-item" href="#" id="heading3" data-call="setTag" data-arg1="h3"><h3>Header 3</h3></a>
|
||||
</li>
|
||||
<li t-if="props.showHeading4" id="heading4-dropdown-item">
|
||||
<a class="dropdown-item" href="#" id="heading4" data-call="setTag" data-arg1="h4"><h4>Header 4</h4></a>
|
||||
</li>
|
||||
<li t-if="props.showHeading5" id="heading5-dropdown-item">
|
||||
<a class="dropdown-item" href="#" id="heading5" data-call="setTag" data-arg1="h5"><h5>Header 5</h5></a>
|
||||
</li>
|
||||
<li t-if="props.showHeading6" id="heading6-dropdown-item">
|
||||
<a class="dropdown-item" href="#" id="heading6" data-call="setTag" data-arg1="h6"><h6>Header 6</h6></a>
|
||||
<a class="dropdown-item" href="#" id="pre" data-call="setTag" data-arg1="pre">Code</a>
|
||||
</li>
|
||||
<li id="blockquote-dropdown-item">
|
||||
<a class="dropdown-item" href="#" id="blockquote" data-call="setTag" data-arg1="blockquote">
|
||||
<blockquote>Quote</blockquote>
|
||||
</a>
|
||||
<a class="dropdown-item" href="#" id="blockquote" data-call="setTag" data-arg1="blockquote">Quote</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user