diff --git a/addons/web_editor/static/lib/odoo-editor/src/commands/commands.js b/addons/web_editor/static/lib/odoo-editor/src/commands/commands.js index dd4097b6d12..6c3a8cb04ca 100644 --- a/addons/web_editor/static/lib/odoo-editor/src/commands/commands.js +++ b/addons/web_editor/static/lib/odoo-editor/src/commands/commands.js @@ -19,6 +19,8 @@ import { insertText, isBlock, isBold, + isItalic, + isUnderline, isColorGradient, isContentTextNode, isShrunkBlock, @@ -298,6 +300,16 @@ function deleteTable(editor, table) { setSelection(p, 0); } +function getTextNodes(editor) { + const selection = editor.document.getSelection(); + if (!selection.rangeCount || selection.getRangeAt(0).collapsed) { + return null; + } + getDeepRange(editor.editable, { splitText: true, select: true, correctTripleClick: true }); + return getSelectedNodes(editor.editable) + .filter(n => n.nodeType === Node.TEXT_NODE && n.nodeValue.trim().length); +} + // This is a whitelist of the commands that are implemented by the // editor itself rather than the node prototypes. It might be // possible to switch the conditions and test if the method exist on @@ -355,12 +367,9 @@ export const editorCommands = { // Formats // ------------------------------------------------------------------------- bold: editor => { - const selection = editor.document.getSelection(); - if (!selection.rangeCount || selection.getRangeAt(0).collapsed) return; - getDeepRange(editor.editable, { splitText: true, select: true, correctTripleClick: true }); - const isAlreadyBold = getSelectedNodes(editor.editable) - .filter(n => n.nodeType === Node.TEXT_NODE && n.nodeValue.trim().length) - .find(n => isBold(n.parentElement)); + const nodes = getTextNodes(editor); + if (!nodes) return; + const isAlreadyBold = nodes.find(n => isBold(n.parentElement)); applyInlineStyle(editor, el => { if (isAlreadyBold) { const block = closestBlock(el); @@ -370,8 +379,22 @@ export const editorCommands = { } }); }, - italic: editor => editor.document.execCommand('italic'), - underline: editor => editor.document.execCommand('underline'), + italic: editor => { + const nodes = getTextNodes(editor); + if (!nodes) return; + const isAlreadyItalic = nodes.find(n => isItalic(n.parentElement)); + applyInlineStyle(editor, el => { + el.style.fontStyle = isAlreadyItalic ? 'normal' : 'italic'; + }); + }, + underline: editor => { + const nodes = getTextNodes(editor); + if (!nodes) return; + const isAlreadyUnderline = nodes.find(n => isUnderline(n.parentElement)); + applyInlineStyle(editor, el => { + el.style.textDecoration = isAlreadyUnderline ? 'none' : 'underline'; + }); + }, strikeThrough: editor => editor.document.execCommand('strikeThrough'), removeFormat: editor => { editor.document.execCommand('removeFormat'); diff --git a/addons/web_editor/static/lib/odoo-editor/src/utils/utils.js b/addons/web_editor/static/lib/odoo-editor/src/utils/utils.js index 0bc25ea635a..0b590deef12 100644 --- a/addons/web_editor/static/lib/odoo-editor/src/utils/utils.js +++ b/addons/web_editor/static/lib/odoo-editor/src/utils/utils.js @@ -868,6 +868,26 @@ export function isBold(node) { const fontWeight = +getComputedStyle(closestElement(node)).fontWeight; return fontWeight > 500 || fontWeight > +getComputedStyle(closestBlock(node)).fontWeight; } +/** + * Return true if the given node font style equal italic + * + * @param {Node} node + * @returns {boolean} + */ +export function isItalic(node) { + const fontStyle = getComputedStyle(closestElement(node)).fontStyle; + return fontStyle === 'italic'; +} +/** + * Return true if the given node text-decoration style equal underline + * + * @param {Node} node + * @returns {boolean} + */ +export function isUnderline(node) { + const textDecoration = getComputedStyle(closestElement(node)).textDecorationLine; + return textDecoration === 'underline'; +} export function isUnbreakable(node) { if (!node || node.nodeType === Node.TEXT_NODE) { diff --git a/addons/website/static/tests/tours/rte.js b/addons/website/static/tests/tours/rte.js index 2e3d152d0ea..233f3787395 100644 --- a/addons/website/static/tests/tours/rte.js +++ b/addons/website/static/tests/tours/rte.js @@ -173,7 +173,7 @@ tour.register('rte_translator', { }, { content: "save new change", trigger: 'button[data-action=save]', - extra_trigger: '#wrap.o_dirty p u', + extra_trigger: '#wrap.o_dirty p span[style="text-decoration: underline;"]', }, { content: "click language dropdown (4)",