Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 8 additions & 84 deletions core/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,13 +207,13 @@ class Editor {
const oldValue = mutations[0].oldValue.replace(CursorBlot.CONTENTS, '');
const oldText = new Delta().insert(oldValue);
const newText = new Delta().insert(textBlot.value());
const relativeSelectionInfo = selectionInfo && [
new Range(selectionInfo[0].index - index, selectionInfo[0].length),
new Range(selectionInfo[1].index - index, selectionInfo[1].length),
];
const relativeSelectionInfo = selectionInfo && {
oldRange: shiftRange(selectionInfo.oldRange, -index),
newRange: shiftRange(selectionInfo.newRange, -index),
};
const diffDelta = new Delta()
.retain(index)
.concat(diffDeltas(oldText, newText, relativeSelectionInfo));
.concat(oldText.diff(newText, relativeSelectionInfo));
change = diffDelta.reduce((delta, op) => {
if (op.insert) {
return delta.insert(op.insert, formats);
Expand All @@ -224,7 +224,7 @@ class Editor {
} else {
this.delta = this.getDelta();
if (!change || !equal(oldDelta.compose(change), this.delta)) {
change = diffDeltas(oldDelta, this.delta, selectionInfo);
change = oldDelta.diff(this.delta, selectionInfo);
}
}
return change;
Expand Down Expand Up @@ -339,84 +339,8 @@ function normalizeDelta(delta) {
}, new Delta());
}

function splitDelta(delta, index) {
return [delta.slice(0, index), delta.slice(index)];
}

function diffDeltas(oldDelta, newDelta, selectionInfo = undefined) {
if (selectionInfo == null) {
return oldDelta.diff(newDelta);
}

// generate better diffs than Delta#diff by taking into account the
// old and new selection. for example, a text change from "xxx" to "xx"
// could be a delete or forwards-delete of any one of the x's, or the
// result of selecting two of the x's and typing "x".
const [oldSelection, newSelection] = selectionInfo;
const oldDeltaLength = oldDelta.length();
const newDeltaLength = newDelta.length();
if (oldSelection.length === 0 && newSelection.length === 0) {
// see if we have an insert or delete before or after cursor
const oldCursor = oldSelection.index;
const newCursor = newSelection.index;
const [oldBefore, oldAfter] = splitDelta(oldDelta, oldCursor);
const [newBefore, newAfter] = splitDelta(newDelta, newCursor);
if (equal(oldAfter, newAfter)) {
const prefixLength = Math.min(oldCursor, newCursor);
const [oldPrefix, oldMiddle] = splitDelta(oldBefore, prefixLength);
const [newPrefix, newMiddle] = splitDelta(newBefore, prefixLength);
if (equal(oldPrefix, newPrefix)) {
// insert or delete right before cursor
return new Delta()
.retain(prefixLength)
.concat(oldMiddle.diff(newMiddle));
}
} else if (equal(oldBefore, newBefore)) {
const suffixLength = Math.min(
oldDeltaLength - oldCursor,
newDeltaLength - newCursor,
);
const [oldMiddle, oldSuffix] = splitDelta(
oldAfter,
oldDeltaLength - oldCursor - suffixLength,
);
const [newMiddle, newSuffix] = splitDelta(
newAfter,
newDeltaLength - newCursor - suffixLength,
);
if (equal(oldSuffix, newSuffix)) {
// insert or delete right after cursor
return new Delta().retain(oldCursor).concat(oldMiddle.diff(newMiddle));
}
}
}
if (oldSelection.length > 0 && newSelection.length === 0) {
// see if diff could be a splice of the old selection range
const oldPrefix = oldDelta.slice(0, oldSelection.index);
const oldSuffix = oldDelta.slice(oldSelection.index + oldSelection.length);
const prefixLength = oldPrefix.length();
const suffixLength = oldSuffix.length();
if (newDeltaLength >= prefixLength + suffixLength) {
const newPrefix = newDelta.slice(0, prefixLength);
const newSuffix = newDelta.slice(newDeltaLength - suffixLength);
if (equal(oldPrefix, newPrefix) && equal(oldSuffix, newSuffix)) {
const oldMiddle = oldDelta.slice(
prefixLength,
oldDeltaLength - suffixLength,
);
const newMiddle = newDelta.slice(
prefixLength,
newDeltaLength - suffixLength,
);
return new Delta()
.retain(prefixLength)
.concat(newMiddle)
.delete(oldMiddle.length());
}
}
}

return oldDelta.diff(newDelta);
function shiftRange({ index, length }, amount) {
return new Range(index + amount, length);
}

export default Editor;
2 changes: 1 addition & 1 deletion core/quill.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ class Quill {
const oldRange = this.selection.lastRange;
const [newRange] = this.selection.getRange();
const selectionInfo =
oldRange && newRange ? [oldRange, newRange] : undefined;
oldRange && newRange ? { oldRange, newRange } : undefined;
modify.call(
this,
() => this.editor.update(null, mutations, selectionInfo),
Expand Down
16 changes: 11 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"eventemitter3": "^3.1.0",
"extend": "^3.0.2",
"parchment": "quilljs/parchment#2674d396d363e3b4668111590426405e3754d1a0",
"quill-delta": "4.0.1"
"quill-delta": "4.1.0"
},
"devDependencies": {
"babel-core": "^6.26.3",
Expand Down