[FIX] web_editor: properly paste pre in pre

Commit [1] attempted to fix unexpected behavior when copy-pasting from a
<pre> to a <pre>, where the pasted text was smaller the intended, and
preceded and followed by new lines. The chosen approach had uninteded
side effects though as it removed any empty paragraph after the <pre>.
The source of the issue it tried to fix was that the pasted <pre> was
inserted as a new <pre>, splitting the existing element in two in the
process, instead of simply inserting the text content.

[1] 449cacf

task-3086603

closes odoo/odoo#109208

X-original-commit: dfcc3abe3396eaf764c3c3c8510b654649ed82f8
Signed-off-by: David Monjoie (dmo) <dmo@odoo.com>
This commit is contained in:
Antoine Guenet
2023-01-05 16:52:10 +01:00
parent 759d6972c2
commit 2f196d1eb1
2 changed files with 27 additions and 7 deletions
@@ -20,7 +20,6 @@ import {
isBlock,
isColorGradient,
isContentTextNode,
isEmptyBlock,
isSelectionFormat,
isShrunkBlock,
isVisible,
@@ -46,6 +45,7 @@ import {
getRowIndex,
parseHTML,
formatSelection,
getDeepestPosition,
} from '../utils/utils.js';
const TEXT_CLASSES_REGEX = /\btext-[^\s]*\b/g;
@@ -175,10 +175,16 @@ export const editorCommands = {
container.replaceChildren(...container.firstChild.childNodes);
}
startNode = startNode || editor.document.getSelection().anchorNode;
// In case the html inserted is all contained in a single root <p> or <li>
// tag, we take the all content of the <p> or <li> and avoid inserting the
// <p> or <li>.
if (container.childElementCount === 1 && (container.firstChild.nodeName === 'P' || container.firstChild.nodeName === 'LI')) {
// <p> or <li>. The same is true for a <pre> inside a <pre>.
if (container.childElementCount === 1 && (
container.firstChild.nodeName === 'P' ||
container.firstChild.nodeName === 'LI' ||
container.firstChild.nodeName === 'PRE' && closestElement(startNode, 'pre')
)) {
const p = container.firstElementChild;
container.replaceChildren(...p.childNodes);
} else if (container.childElementCount > 1) {
@@ -194,7 +200,6 @@ export const editorCommands = {
}
}
startNode = startNode || editor.document.getSelection().anchorNode;
if (startNode.nodeType === Node.ELEMENT_NODE) {
if (selection.anchorOffset === 0) {
const textNode = editor.document.createTextNode('');
@@ -268,9 +273,6 @@ export const editorCommands = {
if (offset) {
const [left, right] = splitElement(currentNode.parentElement, offset);
currentNode = insertBefore ? right : left;
if (isEmptyBlock(right)) {
right.remove();
}
} else {
currentNode = currentNode.parentElement;
}
@@ -72,6 +72,24 @@ describe('insert HTML', () => {
contentAfter: '<p>ab</p><p>c</p><p>d[]e<br></p>',
});
});
it('should keep a paragraph after a div block', async () => {
await testEditor(BasicEditor, {
contentBefore: '<p>[]<br></p>',
stepFunction: async editor => {
await editor.execCommand('insert', parseHTML('<div><p>content</p></div>'));
},
contentAfter: '<div><p>content</p></div><p>[]<br></p>',
});
});
it('should not split a pre to insert another pre but just insert the text', async () => {
await testEditor(BasicEditor, {
contentBefore: '<pre>abc[]<br>ghi</pre>',
stepFunction: async editor => {
await editor.execCommand('insert', parseHTML('<pre>def</pre>'));
},
contentAfter: '<pre>abcdef[]<br>ghi</pre>',
});
});
});
describe('not collapsed selection', () => {
it('should delete selection and insert html in its place', async () => {