[FIX] web_editor: fix triple click on block followed by empty block
Triple click correction failed whenever the triple-click-selected block was followed by an empty block. The reason is that `getDeepestPosition` prevents the selection from being placed within a line break (`<br>`) and therefore returns the block itself (`<p>[]<br></p>` will be expressed as `(p, 0)`), so the heuristic to determine if triple click correction in needed in `getDeepRange` would fail as it assumed the `end` node was a leaf where it wasn't. This fixes the issue by applying the heurstic to the first leaf of the `end` node instead, and making the correction for there as well. task-3180922 closes odoo/odoo#112637 X-original-commit: 81653c320a1e431e4b9ae831bf0b8522588368e6 Signed-off-by: David Monjoie (dmo) <dmo@odoo.com>
This commit is contained in:
@@ -763,17 +763,18 @@ export function getDeepRange(editable, { range, sel, splitText, select, correctT
|
||||
}
|
||||
}
|
||||
}
|
||||
// A selection spanning multiple nodes and ending at position 0 of a
|
||||
// node, like the one resulting from a triple click, are corrected so
|
||||
// that it ends at the last position of the previous node instead.
|
||||
const beforeEnd = end.previousSibling;
|
||||
// A selection spanning multiple nodes and ending at position 0 of a node,
|
||||
// like the one resulting from a triple click, is corrected so that it ends
|
||||
// at the last position of the previous node instead.
|
||||
const endLeaf = firstLeaf(end);
|
||||
const beforeEnd = endLeaf.previousSibling;
|
||||
if (
|
||||
correctTripleClick &&
|
||||
!endOffset &&
|
||||
(start !== end || startOffset !== endOffset) &&
|
||||
(!beforeEnd || (beforeEnd.nodeType === Node.TEXT_NODE && !isVisibleStr(beforeEnd)))
|
||||
) {
|
||||
const previous = previousLeaf(end, editable, true);
|
||||
const previous = previousLeaf(endLeaf, editable, true);
|
||||
if (previous && closestElement(previous).isContentEditable) {
|
||||
[end, endOffset] = [previous, nodeSize(previous)];
|
||||
}
|
||||
|
||||
@@ -1190,6 +1190,11 @@ X[]
|
||||
// JW cAfter: '<p>[]def</p>',
|
||||
contentAfter: '<h1>[]<br></h1><p>def</p>',
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<h1>[abc</h1><p>]<br></p><p>def</p>',
|
||||
stepFunction: deleteForward,
|
||||
contentAfter: '<h1>[]<br></h1><p><br></p><p>def</p>',
|
||||
});
|
||||
});
|
||||
it('should delete last character of paragraph, ignoring the selected paragraph break', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
@@ -2668,6 +2673,11 @@ X[]
|
||||
// JW cAfter: '<p>[]def</p>',
|
||||
contentAfter: '<h1>[]<br></h1><p>def</p>',
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<h1>[abc</h1><p>]<br></p><p>def</p>',
|
||||
stepFunction: deleteBackward,
|
||||
contentAfter: '<h1>[]<br></h1><p><br></p><p>def</p>',
|
||||
});
|
||||
});
|
||||
it('should delete last character of paragraph, ignoring the selected paragraph break', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
@@ -2678,6 +2688,14 @@ X[]
|
||||
stepFunction: deleteBackward,
|
||||
contentAfter: '<p>ab[]</p><p>def</p>',
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<p>ab[c</p><p>]<br></p><p>def</p>',
|
||||
// This type of selection (typically done with a triple
|
||||
// click) is "corrected" before remove so triple clicking
|
||||
// doesn't remove a paragraph break.
|
||||
stepFunction: deleteBackward,
|
||||
contentAfter: '<p>ab[]</p><p><br></p><p>def</p>',
|
||||
});
|
||||
});
|
||||
it('should delete first character of paragraph, as well as selected paragraph break', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
@@ -2695,6 +2713,22 @@ X[]
|
||||
stepFunction: deleteBackward,
|
||||
contentAfter: '<p>ab[]</p><p t="unbreak">def</p>',
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<p>ab[c</p><p t="unbreak">]<br></p><p>def</p>',
|
||||
// This type of selection (typically done with a triple
|
||||
// click) is "corrected" before remove so triple clicking
|
||||
// doesn't remove a paragraph break.
|
||||
stepFunction: deleteBackward,
|
||||
contentAfter: '<p>ab[]</p><p t="unbreak"><br></p><p>def</p>',
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<p>ab[c</p><p>]<br></p><p t="unbreak">def</p>',
|
||||
// This type of selection (typically done with a triple
|
||||
// click) is "corrected" before remove so triple clicking
|
||||
// doesn't remove a paragraph break.
|
||||
stepFunction: deleteBackward,
|
||||
contentAfter: '<p>ab[]</p><p><br></p><p t="unbreak">def</p>',
|
||||
});
|
||||
});
|
||||
it('should delete first character of unbreakable, ignoring selected paragraph break', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
|
||||
Reference in New Issue
Block a user