diff --git a/addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js b/addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js
index 0d06cd5739f..65a663dc700 100644
--- a/addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js
+++ b/addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js
@@ -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) {
diff --git a/addons/web_editor/static/src/js/editor/odoo-editor/src/commands/commands.js b/addons/web_editor/static/src/js/editor/odoo-editor/src/commands/commands.js
index bff7f560336..0d25e024013 100644
--- a/addons/web_editor/static/src/js/editor/odoo-editor/src/commands/commands.js
+++ b/addons/web_editor/static/src/js/editor/odoo-editor/src/commands/commands.js
@@ -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 `
`
+ // 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
into a h1: insert the h1
diff --git a/addons/web_editor/static/src/js/editor/odoo-editor/src/utils/utils.js b/addons/web_editor/static/src/js/editor/odoo-editor/src/utils/utils.js
index d5c4225128f..e64b6b85cf4 100644
--- a/addons/web_editor/static/src/js/editor/odoo-editor/src/utils/utils.js
+++ b/addons/web_editor/static/src/js/editor/odoo-editor/src/utils/utils.js
@@ -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) {
diff --git a/addons/web_editor/static/src/xml/editor.xml b/addons/web_editor/static/src/xml/editor.xml
index 4ed62eb704e..13f0c9bbb4b 100644
--- a/addons/web_editor/static/src/xml/editor.xml
+++ b/addons/web_editor/static/src/xml/editor.xml
@@ -13,34 +13,50 @@
Normal