[FIX] web_editor: compute deepest position offset according to used node

Before this commit when computing the deepest position for a non-visible
node, if that node had no next visible sibling it used the previous
siblings, but it still marked the offset within that sibling as 0.
Because of this, the selection sometimes got lost.
E.g. in Firefox, drop an "Image - Text" block and triple click on the
header text: upon changing its color the range got set to the text node
but ending at offset 0.

After this commit if the used node in the "previous sibling" from the
evaluated element, the offset is set to the length of that node.

task-2655176

closes odoo/odoo#77567

X-original-commit: 3c4426c71ebe080bcbd285e271c61bf1580c3afa
Signed-off-by: Antoine Guenet <Zinston@users.noreply.github.com>
Signed-off-by: Benoit Socias (bso) <bso-odoo@users.noreply.github.com>
This commit is contained in:
Benoit Socias
2021-10-01 07:41:00 +00:00
parent 0a34245591
commit 2e35193b94
2 changed files with 47 additions and 1 deletions
@@ -752,7 +752,7 @@ export function getDeepestPosition(node, offset) {
while (!isVisible(node) && (node.previousSibling || (!reversed && node.nextSibling))) {
reversed = reversed || !node.nextSibling;
node = reversed ? node.previousSibling : node.nextSibling;
offset = 0;
offset = reversed ? nodeSize(node) : 0;
didMove = true;
}
return didMove && isVisible(node) ? getDeepestPosition(node, offset) : [node, offset];
@@ -1208,6 +1208,52 @@ describe('Utils', () => {
.expect([anchorNode, anchorOffset, focusNode, focusOffset])
.to.eql([p1.firstChild, 0, p1.firstChild, 11]);
});
it('should limit the selection to the title text (nested)', () => {
const [p] = insertTestHtml(
`<p>
<span>
<font>title</font>
</span>
</p>`,
);
const span = p.childNodes[1];
const whiteBeforeFont = span.childNodes[0];
const title = span.childNodes[1].firstChild;
const whiteAfterFont = span.childNodes[2];
const range = document.createRange();
range.setStart(whiteBeforeFont, 0);
range.setEnd(whiteAfterFont, 10);
const result = getDeepRange(p.parentElement, { range, select: true });
const { startContainer, startOffset, endContainer, endOffset } = result;
window.chai
.expect([startContainer, startOffset, endContainer, endOffset])
.to.eql([title, 0, title, 5]);
const { anchorNode, anchorOffset, focusNode, focusOffset } =
document.getSelection();
window.chai
.expect([anchorNode, anchorOffset, focusNode, focusOffset])
.to.eql([title, 0, title, 5]);
});
it('should not limit the selection to the title text within p siblings', () => {
const [p0, p1, p2] = insertTestHtml(
`<p><br/></p><p>
<font>title</font>
</p><p><br/></p>`,
);
const range = document.createRange();
range.setStart(p0, 0);
range.setEnd(p2, 0);
const result = getDeepRange(p1.parentElement, { range, select: true });
const { startContainer, startOffset, endContainer, endOffset } = result;
window.chai
.expect([startContainer, startOffset, endContainer, endOffset])
.to.eql([p0, 0, p2, 0]);
const { anchorNode, anchorOffset, focusNode, focusOffset } =
document.getSelection();
window.chai
.expect([anchorNode, anchorOffset, focusNode, focusOffset])
.to.eql([p0, 0, p2, 0]);
});
});
describe('backward', () => {
it('should select the contents of an element', () => {