Fix bugs in undo/redo seleciton handling
This commit is contained in:
parent
86a0e98c36
commit
007125025f
1 changed files with 91 additions and 95 deletions
|
|
@ -107,10 +107,22 @@ var EditSession = function(text, mode) {
|
||||||
this.$docChangeCounter --;
|
this.$docChangeCounter --;
|
||||||
console.log("<<< onChangeEnd", this.$docChangeCounter);
|
console.log("<<< onChangeEnd", this.$docChangeCounter);
|
||||||
if (this.$docChangeCounter == 0
|
if (this.$docChangeCounter == 0
|
||||||
&& this.$deltaFolds && this.$deltaFolds.length)
|
&& !this.$fromUndo && this.$undoManager)
|
||||||
{
|
{
|
||||||
this.$deltas = this.$deltaFolds.concat(this.$deltas);
|
if (this.$deltasFold.length) {
|
||||||
this.$deltaFolds = [];
|
this.$deltas.push({
|
||||||
|
group: "fold",
|
||||||
|
deltas: this.$deltasFold
|
||||||
|
});
|
||||||
|
this.$deltasFold = [];
|
||||||
|
}
|
||||||
|
if (this.$deltasDoc) {
|
||||||
|
this.$deltas.push({
|
||||||
|
group: "doc",
|
||||||
|
deltas: this.$deltasDoc
|
||||||
|
});
|
||||||
|
this.$deltasDoc = [];
|
||||||
|
}
|
||||||
this.$informUndoManager.schedule();
|
this.$informUndoManager.schedule();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -122,24 +134,14 @@ var EditSession = function(text, mode) {
|
||||||
var removedFolds = this.$updateInternalDataOnChange(e);
|
var removedFolds = this.$updateInternalDataOnChange(e);
|
||||||
if (!this.$fromUndo && this.$undoManager && !delta.ignore) {
|
if (!this.$fromUndo && this.$undoManager && !delta.ignore) {
|
||||||
console.log("onChange", JSON.stringify(delta));
|
console.log("onChange", JSON.stringify(delta));
|
||||||
this.$deltas.push(delta);
|
this.$deltasDoc.push(delta);
|
||||||
if (removedFolds && removedFolds.length != 0) {
|
if (removedFolds && removedFolds.length != 0) {
|
||||||
this.$deltaFolds.push({
|
this.$deltasFold.push({
|
||||||
action: "removeFolds",
|
action: "removeFolds",
|
||||||
folds: removedFolds
|
folds: removedFolds
|
||||||
});
|
});
|
||||||
console.log("onChangeFold", removedFolds[0].toString());
|
console.log("onChangeFold", removedFolds[0].toString());
|
||||||
}
|
}
|
||||||
// Only inform the undoManager about new deltas if there
|
|
||||||
// are no deltaFolds. As there are some deltasFolds, the
|
|
||||||
// undoManager get notified by the onChangeEnd once the
|
|
||||||
// change stack is empty. Calling this.$informUndoManager here
|
|
||||||
// might cause the current deltas get flushed to the undoManager
|
|
||||||
// before the change stack is empty and as such the deltaFolds might
|
|
||||||
// get added at the wrong position.
|
|
||||||
else if (!this.$deltaFolds.length) {
|
|
||||||
this.$informUndoManager.schedule();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -150,7 +152,8 @@ var EditSession = function(text, mode) {
|
||||||
this.setValue = function(text) {
|
this.setValue = function(text) {
|
||||||
this.doc.setValue(text);
|
this.doc.setValue(text);
|
||||||
this.$deltas = [];
|
this.$deltas = [];
|
||||||
this.$deltaFolds = [];
|
this.$deltasDoc = [];
|
||||||
|
this.$deltasFold = [];
|
||||||
this.getUndoManager().reset();
|
this.getUndoManager().reset();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -174,7 +177,8 @@ var EditSession = function(text, mode) {
|
||||||
this.setUndoManager = function(undoManager) {
|
this.setUndoManager = function(undoManager) {
|
||||||
this.$undoManager = undoManager;
|
this.$undoManager = undoManager;
|
||||||
this.$deltas = [];
|
this.$deltas = [];
|
||||||
this.$deltaFolds = [];
|
this.$deltasDoc = [];
|
||||||
|
this.$deltasFold = [];
|
||||||
|
|
||||||
if (this.$informUndoManager) {
|
if (this.$informUndoManager) {
|
||||||
this.$informUndoManager.cancel();
|
this.$informUndoManager.cancel();
|
||||||
|
|
@ -655,106 +659,98 @@ var EditSession = function(text, mode) {
|
||||||
return this.doc.remove(range);
|
return this.doc.remove(range);
|
||||||
};
|
};
|
||||||
|
|
||||||
var docActions = [
|
|
||||||
"insertLines",
|
|
||||||
"insertText",
|
|
||||||
"removeLines",
|
|
||||||
"removeText"
|
|
||||||
];
|
|
||||||
|
|
||||||
function filterDocActions(deltas) {
|
|
||||||
return deltas.filter(function(delta) {
|
|
||||||
return docActions.indexOf(delta.action) != -1;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.undoChanges = function(deltas) {
|
this.undoChanges = function(deltas) {
|
||||||
if (!deltas.length)
|
if (!deltas.length)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.$fromUndo = true;
|
this.$fromUndo = true;
|
||||||
var docDeltas = filterDocActions(deltas);
|
var lastUndoRange = null;
|
||||||
if (docDeltas.length == deltas.length) {
|
|
||||||
this.doc.revertDeltas(deltas);
|
|
||||||
} else {
|
|
||||||
var groupDocDeltas = [];
|
|
||||||
for (var i = deltas.length - 1; i != -1; i--) {
|
for (var i = deltas.length - 1; i != -1; i--) {
|
||||||
delta = deltas[i];
|
delta = deltas[i];
|
||||||
if (docActions.indexOf(delta.action) != -1) {
|
if (delta.group == "doc") {
|
||||||
groupDocDeltas.push(delta);
|
this.doc.revertDeltas(delta.deltas);
|
||||||
|
lastUndoRange =
|
||||||
|
this.$setUndoSelection(delta.deltas, true, lastUndoRange);
|
||||||
} else {
|
} else {
|
||||||
groupDocDeltas.reverse()
|
delta.deltas.forEach(function(foldDelta) {
|
||||||
this.doc.revertDeltas(groupDocDeltas);
|
this.addFolds(foldDelta.folds);
|
||||||
this.$setUndoSelection(groupDocDeltas, true);
|
}, this);
|
||||||
groupDocDeltas = [];
|
|
||||||
this.addFolds(delta.folds);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.doc.revertDeltas(groupDocDeltas);
|
|
||||||
}
|
|
||||||
this.$fromUndo = false;
|
this.$fromUndo = false;
|
||||||
|
|
||||||
if (docDeltas.length == deltas.length) {
|
|
||||||
this.$setUndoSelection(docDeltas, true);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
this.redoChanges = function(deltas) {
|
this.redoChanges = function(deltas) {
|
||||||
if (!deltas.length)
|
if (!deltas.length)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var docDeltas = filterDocActions(deltas);
|
|
||||||
this.$fromUndo = true;
|
this.$fromUndo = true;
|
||||||
this.doc.applyDeltas(docDeltas);
|
var lastUndoRange = null;
|
||||||
|
for (var i = 0; i < deltas.length; i++) {
|
||||||
|
delta = deltas[i];
|
||||||
|
if (delta.group == "doc") {
|
||||||
|
this.doc.applyDeltas(delta.deltas);
|
||||||
|
lastUndoRange =
|
||||||
|
this.$setUndoSelection(delta.deltas, false, lastUndoRange);
|
||||||
|
}
|
||||||
|
}
|
||||||
this.$fromUndo = false;
|
this.$fromUndo = false;
|
||||||
|
|
||||||
this.$setUndoSelection(docDeltas, false);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
this.$setUndoSelection = function(deltas, isUndo) {
|
this.$setUndoSelection = function(deltas, isUndo, lastUndoRange) {
|
||||||
// invert deltas is they are an undo
|
function isInsert(delta) {
|
||||||
if (isUndo)
|
var insert =
|
||||||
deltas = deltas.map(function(delta) {
|
delta.action == "insertText" || delta.action == "insertLines";
|
||||||
var d = {
|
return isUndo ? !insert : insert;
|
||||||
range: delta.range
|
|
||||||
}
|
}
|
||||||
if (delta.action == "insertText" || delta.action == "insertLines")
|
|
||||||
d.action = "removeText"
|
|
||||||
else
|
|
||||||
d.action = "insertText"
|
|
||||||
return d;
|
|
||||||
}).reverse();
|
|
||||||
|
|
||||||
|
var delta = deltas[0];
|
||||||
var actions = [{}];
|
var range;
|
||||||
|
var lastDeltaIsInsert = false;
|
||||||
// collapse insert and remove operations
|
if (isInsert(delta)) {
|
||||||
for (var i=0; i<deltas.length; i++) {
|
range = delta.range.clone();
|
||||||
var delta = deltas[i];
|
lastDeltaIsInsert = true;
|
||||||
var isInsert = delta.action == "insertText" || delta.action == "insertLines";
|
} else {
|
||||||
var action = actions[actions.length-1];
|
range = Range.fromPoints(delta.range.start, delta.range.start);
|
||||||
if (action.isInsert !== isInsert) {
|
lastDeltaIsInsert = false;
|
||||||
actions.push({
|
|
||||||
isInsert: isInsert,
|
|
||||||
start: isInsert ? delta.range.start : delta.range.end,
|
|
||||||
end: isInsert ? delta.range.end : delta.range.start
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
if (isInsert)
|
for (var i = 1; i < deltas.length; i++) {
|
||||||
action.end = delta.range.end;
|
delta = deltas[i];
|
||||||
else
|
if (isInsert(delta)) {
|
||||||
action.start = delta.range.start;
|
if (range.compare(delta.range.start) == -1) {
|
||||||
|
range.setStart(delta.range.start);
|
||||||
|
}
|
||||||
|
if (range.compare(delta.range.end) == 1) {
|
||||||
|
range.setEnd(delta.range.end);
|
||||||
|
}
|
||||||
|
lastDeltaIsInsert = true;
|
||||||
|
} else {
|
||||||
|
if (range.compare(delta.range.start) == -1) {
|
||||||
|
range =
|
||||||
|
Range.fromPoints(delta.range.start, delta.range.start);
|
||||||
|
}
|
||||||
|
lastDeltaIsInsert = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// update selection based on last operation
|
// Check if this range and the last undo range has something in common.
|
||||||
this.selection.clearSelection();
|
// If true, merge the ranges.
|
||||||
var action = actions[actions.length-1];
|
if (lastUndoRange != null) {
|
||||||
if (action.isInsert)
|
var cmp = lastUndoRange.compareRange(range);
|
||||||
this.selection.setSelectionRange(Range.fromPoints(action.start, action.end));
|
if (cmp == 1) {
|
||||||
else
|
range.setStart(lastUndoRange.start);
|
||||||
this.selection.moveCursorToPosition(action.end);
|
} else if (cmp == -1) {
|
||||||
|
range.setEnd(lastUndoRange.end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!range.isEmpty()) {
|
||||||
|
this.selection.setSelectionRange(range);
|
||||||
|
} else {
|
||||||
|
this.selection.moveCursorToPosition(range.start);
|
||||||
|
}
|
||||||
|
return range;
|
||||||
},
|
},
|
||||||
|
|
||||||
this.replace = function(range, text) {
|
this.replace = function(range, text) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue