take non-editable parts into account for new caret position

This commit is contained in:
Bruno Windels 2019-05-09 19:55:24 +02:00
parent 8d97c0033e
commit 1a577eed11

View file

@ -81,15 +81,16 @@ export default class EditorModel {
const diff = this._diff(newValue, inputType, caret); const diff = this._diff(newValue, inputType, caret);
const position = this._positionForOffset(diff.at, caret.atNodeEnd); const position = this._positionForOffset(diff.at, caret.atNodeEnd);
console.log("update at", {position, diff, newValue, prevValue: this.parts.reduce((text, p) => text + p.text, "")}); console.log("update at", {position, diff, newValue, prevValue: this.parts.reduce((text, p) => text + p.text, "")});
let removedOffsetDecrease = 0;
if (diff.removed) { if (diff.removed) {
this._removeText(position, diff.removed.length); removedOffsetDecrease = this._removeText(position, diff.removed.length);
} }
let addedLen = 0;
if (diff.added) { if (diff.added) {
this._addText(position, diff.added); addedLen = this._addText(position, diff.added);
} }
this._mergeAdjacentParts(); this._mergeAdjacentParts();
// TODO: now that parts can be outright deleted, this doesn't make sense anymore const caretOffset = diff.at - removedOffsetDecrease + addedLen;
const caretOffset = diff.at + (diff.added ? diff.added.length : 0);
const newPosition = this._positionForOffset(caretOffset, true); const newPosition = this._positionForOffset(caretOffset, true);
this._setActivePart(newPosition); this._setActivePart(newPosition);
this._updateCallback(newPosition); this._updateCallback(newPosition);
@ -157,13 +158,19 @@ export default class EditorModel {
} }
} }
/**
* removes `len` amount of characters at `pos`.
* @return {Number} how many characters before pos were also removed,
* usually because of non-editable parts that can only be removed in their entirety.
*/
_removeText(pos, len) { _removeText(pos, len) {
let {index, offset} = pos; let {index, offset} = pos;
let removedOffsetDecrease = 0;
while (len > 0) { while (len > 0) {
// part might be undefined here // part might be undefined here
let part = this._parts[index]; let part = this._parts[index];
const amount = Math.min(len, part.text.length - offset);
if (part.canEdit) { if (part.canEdit) {
const amount = Math.min(len, part.text.length - offset);
const replaceWith = part.remove(offset, amount); const replaceWith = part.remove(offset, amount);
if (typeof replaceWith === "string") { if (typeof replaceWith === "string") {
this._replacePart(index, this._partCreator.createDefaultPart(replaceWith)); this._replacePart(index, this._partCreator.createDefaultPart(replaceWith));
@ -175,31 +182,38 @@ export default class EditorModel {
} else { } else {
index += 1; index += 1;
} }
len -= amount;
offset = 0;
} else { } else {
len = part.length - (offset + len); removedOffsetDecrease += offset;
this._removePart(index); this._removePart(index);
} }
len -= amount;
offset = 0;
} }
return removedOffsetDecrease;
} }
/**
* inserts `str` into the model at `pos`.
* @return {Number} how far from position (in characters) the insertion ended.
* This can be more than the length of `str` when crossing non-editable parts, which are skipped.
*/
_addText(pos, str, actions) { _addText(pos, str, actions) {
let {index, offset} = pos; let {index} = pos;
const {offset} = pos;
let addLen = str.length;
const part = this._parts[index]; const part = this._parts[index];
if (part) { if (part) {
if (part.canEdit) { if (part.canEdit) {
if (part.insertAll(offset, str)) { if (part.insertAll(offset, str)) {
str = null; str = null;
} else { } else {
// console.log("splitting", offset, [part.text]);
const splitPart = part.split(offset); const splitPart = part.split(offset);
// console.log("splitted", [part.text, splitPart.text]);
index += 1; index += 1;
this._insertPart(index, splitPart); this._insertPart(index, splitPart);
} }
} else { } else {
// insert str after this part // not-editable, insert str after this part
addLen += part.text.length - offset;
index += 1; index += 1;
} }
} }
@ -209,6 +223,7 @@ export default class EditorModel {
this._insertPart(index, newPart); this._insertPart(index, newPart);
index += 1; index += 1;
} }
return addLen;
} }
_positionForOffset(totalOffset, atPartEnd) { _positionForOffset(totalOffset, atPartEnd) {