Fix caret jump when backspacing into empty line at beginning of editor (#11128)
Fixes: vector-im/element-web#22335
This commit is contained in:
parent
36c81f6416
commit
ab98268901
2 changed files with 28 additions and 4 deletions
|
@ -104,10 +104,10 @@ export function getLineAndNodePosition(
|
||||||
} {
|
} {
|
||||||
const { parts } = model;
|
const { parts } = model;
|
||||||
const partIndex = caretPosition.index;
|
const partIndex = caretPosition.index;
|
||||||
const lineResult = findNodeInLineForPart(parts, partIndex);
|
let { offset } = caretPosition;
|
||||||
|
const lineResult = findNodeInLineForPart(parts, partIndex, offset);
|
||||||
const { lineIndex } = lineResult;
|
const { lineIndex } = lineResult;
|
||||||
let { nodeIndex } = lineResult;
|
let { nodeIndex } = lineResult;
|
||||||
let { offset } = caretPosition;
|
|
||||||
// we're at an empty line between a newline part
|
// we're at an empty line between a newline part
|
||||||
// and another newline part or end/start of parts.
|
// and another newline part or end/start of parts.
|
||||||
// set offset to 0 so it gets set to the <br> inside the line container
|
// set offset to 0 so it gets set to the <br> inside the line container
|
||||||
|
@ -120,7 +120,11 @@ export function getLineAndNodePosition(
|
||||||
return { lineIndex, nodeIndex, offset };
|
return { lineIndex, nodeIndex, offset };
|
||||||
}
|
}
|
||||||
|
|
||||||
function findNodeInLineForPart(parts: Part[], partIndex: number): { lineIndex: number; nodeIndex: number } {
|
function findNodeInLineForPart(
|
||||||
|
parts: Part[],
|
||||||
|
partIndex: number,
|
||||||
|
offset: number,
|
||||||
|
): { lineIndex: number; nodeIndex: number } {
|
||||||
let lineIndex = 0;
|
let lineIndex = 0;
|
||||||
let nodeIndex = -1;
|
let nodeIndex = -1;
|
||||||
|
|
||||||
|
@ -130,6 +134,10 @@ function findNodeInLineForPart(parts: Part[], partIndex: number): { lineIndex: n
|
||||||
for (let i = 0; i <= partIndex; ++i) {
|
for (let i = 0; i <= partIndex; ++i) {
|
||||||
const part = parts[i];
|
const part = parts[i];
|
||||||
if (part.type === Type.Newline) {
|
if (part.type === Type.Newline) {
|
||||||
|
// don't jump over the linebreak if the offset is before it
|
||||||
|
if (i == partIndex && offset === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
lineIndex += 1;
|
lineIndex += 1;
|
||||||
nodeIndex = -1;
|
nodeIndex = -1;
|
||||||
prevPart = undefined;
|
prevPart = undefined;
|
||||||
|
@ -140,7 +148,7 @@ function findNodeInLineForPart(parts: Part[], partIndex: number): { lineIndex: n
|
||||||
}
|
}
|
||||||
// only jump over caret node if we're not at our destination node already,
|
// only jump over caret node if we're not at our destination node already,
|
||||||
// as we'll assume in moveOutOfUnselectablePart that nodeIndex
|
// as we'll assume in moveOutOfUnselectablePart that nodeIndex
|
||||||
// refers to the node corresponding to the part,
|
// refers to the node corresponding to the part,
|
||||||
// and not an adjacent caret node
|
// and not an adjacent caret node
|
||||||
if (i < partIndex) {
|
if (i < partIndex) {
|
||||||
const nextPart = parts[i + 1];
|
const nextPart = parts[i + 1];
|
||||||
|
|
|
@ -46,6 +46,14 @@ describe("editor/caret: DOM position for caret", function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe("handling line breaks", function () {
|
describe("handling line breaks", function () {
|
||||||
|
it("at start of first line which is empty", function () {
|
||||||
|
const pc = createPartCreator();
|
||||||
|
const model = new EditorModel([pc.newline(), pc.plain("hello world")], pc);
|
||||||
|
const { offset, lineIndex, nodeIndex } = getLineAndNodePosition(model, { index: 0, offset: 0 });
|
||||||
|
expect(lineIndex).toBe(0);
|
||||||
|
expect(nodeIndex).toBe(-1);
|
||||||
|
expect(offset).toBe(0);
|
||||||
|
});
|
||||||
it("at end of last line", function () {
|
it("at end of last line", function () {
|
||||||
const pc = createPartCreator();
|
const pc = createPartCreator();
|
||||||
const model = new EditorModel([pc.plain("hello"), pc.newline(), pc.plain("world")], pc);
|
const model = new EditorModel([pc.plain("hello"), pc.newline(), pc.plain("world")], pc);
|
||||||
|
@ -62,6 +70,14 @@ describe("editor/caret: DOM position for caret", function () {
|
||||||
expect(nodeIndex).toBe(0);
|
expect(nodeIndex).toBe(0);
|
||||||
expect(offset).toBe(0);
|
expect(offset).toBe(0);
|
||||||
});
|
});
|
||||||
|
it("before empty line", function () {
|
||||||
|
const pc = createPartCreator();
|
||||||
|
const model = new EditorModel([pc.plain("hello"), pc.newline(), pc.newline(), pc.plain("world")], pc);
|
||||||
|
const { offset, lineIndex, nodeIndex } = getLineAndNodePosition(model, { index: 0, offset: 5 });
|
||||||
|
expect(lineIndex).toBe(0);
|
||||||
|
expect(nodeIndex).toBe(0);
|
||||||
|
expect(offset).toBe(5);
|
||||||
|
});
|
||||||
it("in empty line", function () {
|
it("in empty line", function () {
|
||||||
const pc = createPartCreator();
|
const pc = createPartCreator();
|
||||||
const model = new EditorModel([pc.plain("hello"), pc.newline(), pc.newline(), pc.plain("world")], pc);
|
const model = new EditorModel([pc.plain("hello"), pc.newline(), pc.newline(), pc.plain("world")], pc);
|
||||||
|
|
Loading…
Reference in a new issue