Fix bug in undo/redo + folds: The folds have to get onto the undo queue after the changeStack is empty. New events changeStart/End added.
This commit is contained in:
parent
acc318af90
commit
e871700e2e
3 changed files with 83 additions and 18 deletions
|
|
@ -183,12 +183,14 @@ var Document = function(text) {
|
||||||
var firstLine = lines.splice(0, 1)[0];
|
var firstLine = lines.splice(0, 1)[0];
|
||||||
var lastLine = lines.length == 0 ? null : lines.splice(lines.length - 1, 1)[0];
|
var lastLine = lines.length == 0 ? null : lines.splice(lines.length - 1, 1)[0];
|
||||||
|
|
||||||
|
this._dispatchEvent("changeStart");
|
||||||
position = this.insertInLine(position, firstLine);
|
position = this.insertInLine(position, firstLine);
|
||||||
if (lastLine !== null) {
|
if (lastLine !== null) {
|
||||||
position = this.insertNewLine(position); // terminate first line
|
position = this.insertNewLine(position); // terminate first line
|
||||||
position = this.insertLines(position.row, lines);
|
position = this.insertLines(position.row, lines);
|
||||||
position = this.insertInLine(position, lastLine || "");
|
position = this.insertInLine(position, lastLine || "");
|
||||||
}
|
}
|
||||||
|
this._dispatchEvent("changeEnd");
|
||||||
return position;
|
return position;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -200,6 +202,7 @@ var Document = function(text) {
|
||||||
args.push.apply(args, lines);
|
args.push.apply(args, lines);
|
||||||
this.$lines.splice.apply(this.$lines, args);
|
this.$lines.splice.apply(this.$lines, args);
|
||||||
|
|
||||||
|
this._dispatchEvent("changeStart");
|
||||||
var range = new Range(row, 0, row + lines.length, 0);
|
var range = new Range(row, 0, row + lines.length, 0);
|
||||||
var delta = {
|
var delta = {
|
||||||
action: "insertLines",
|
action: "insertLines",
|
||||||
|
|
@ -207,12 +210,15 @@ var Document = function(text) {
|
||||||
lines: lines
|
lines: lines
|
||||||
};
|
};
|
||||||
this._dispatchEvent("change", { data: delta });
|
this._dispatchEvent("change", { data: delta });
|
||||||
|
this._dispatchEvent("changeEnd");
|
||||||
return range.end;
|
return range.end;
|
||||||
},
|
},
|
||||||
|
|
||||||
this.insertNewLine = function(position) {
|
this.insertNewLine = function(position) {
|
||||||
position = this.$clipPosition(position);
|
position = this.$clipPosition(position);
|
||||||
var line = this.$lines[position.row] || "";
|
var line = this.$lines[position.row] || "";
|
||||||
|
|
||||||
|
this._dispatchEvent("changeStart");
|
||||||
this.$lines[position.row] = line.substring(0, position.column);
|
this.$lines[position.row] = line.substring(0, position.column);
|
||||||
this.$lines.splice(position.row + 1, 0, line.substring(position.column, line.length));
|
this.$lines.splice(position.row + 1, 0, line.substring(position.column, line.length));
|
||||||
|
|
||||||
|
|
@ -227,6 +233,7 @@ var Document = function(text) {
|
||||||
text: this.getNewLineCharacter()
|
text: this.getNewLineCharacter()
|
||||||
};
|
};
|
||||||
this._dispatchEvent("change", { data: delta });
|
this._dispatchEvent("change", { data: delta });
|
||||||
|
this._dispatchEvent("changeEnd");
|
||||||
|
|
||||||
return end;
|
return end;
|
||||||
};
|
};
|
||||||
|
|
@ -236,6 +243,8 @@ var Document = function(text) {
|
||||||
return position;
|
return position;
|
||||||
|
|
||||||
var line = this.$lines[position.row] || "";
|
var line = this.$lines[position.row] || "";
|
||||||
|
|
||||||
|
this._dispatchEvent("changeStart");
|
||||||
this.$lines[position.row] = line.substring(0, position.column) + text
|
this.$lines[position.row] = line.substring(0, position.column) + text
|
||||||
+ line.substring(position.column);
|
+ line.substring(position.column);
|
||||||
|
|
||||||
|
|
@ -250,6 +259,7 @@ var Document = function(text) {
|
||||||
text: text
|
text: text
|
||||||
};
|
};
|
||||||
this._dispatchEvent("change", { data: delta });
|
this._dispatchEvent("change", { data: delta });
|
||||||
|
this._dispatchEvent("changeEnd");
|
||||||
|
|
||||||
return end;
|
return end;
|
||||||
};
|
};
|
||||||
|
|
@ -265,6 +275,7 @@ var Document = function(text) {
|
||||||
var firstRow = range.start.row;
|
var firstRow = range.start.row;
|
||||||
var lastRow = range.end.row;
|
var lastRow = range.end.row;
|
||||||
|
|
||||||
|
this._dispatchEvent("changeStart");
|
||||||
if (range.isMultiLine()) {
|
if (range.isMultiLine()) {
|
||||||
var firstFullRow = range.start.column == 0 ? firstRow : firstRow + 1;
|
var firstFullRow = range.start.column == 0 ? firstRow : firstRow + 1;
|
||||||
var lastFullRow = lastRow - 1;
|
var lastFullRow = lastRow - 1;
|
||||||
|
|
@ -283,6 +294,7 @@ var Document = function(text) {
|
||||||
else {
|
else {
|
||||||
this.removeInLine(firstRow, range.start.column, range.end.column);
|
this.removeInLine(firstRow, range.start.column, range.end.column);
|
||||||
}
|
}
|
||||||
|
this._dispatchEvent("changeEnd");
|
||||||
return range.start;
|
return range.start;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -294,6 +306,7 @@ var Document = function(text) {
|
||||||
var line = this.getLine(row);
|
var line = this.getLine(row);
|
||||||
var removed = line.substring(startColumn, endColumn);
|
var removed = line.substring(startColumn, endColumn);
|
||||||
var newLine = line.substring(0, startColumn) + line.substring(endColumn, line.length);
|
var newLine = line.substring(0, startColumn) + line.substring(endColumn, line.length);
|
||||||
|
this._dispatchEvent("changeStart");
|
||||||
this.$lines.splice(row, 1, newLine);
|
this.$lines.splice(row, 1, newLine);
|
||||||
|
|
||||||
var delta = {
|
var delta = {
|
||||||
|
|
@ -302,6 +315,7 @@ var Document = function(text) {
|
||||||
text: removed
|
text: removed
|
||||||
};
|
};
|
||||||
this._dispatchEvent("change", { data: delta });
|
this._dispatchEvent("change", { data: delta });
|
||||||
|
this._dispatchEvent("changeEnd");
|
||||||
return range.start;
|
return range.start;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -313,6 +327,7 @@ var Document = function(text) {
|
||||||
* @return {String[]} The removed lines
|
* @return {String[]} The removed lines
|
||||||
*/
|
*/
|
||||||
this.removeLines = function(firstRow, lastRow) {
|
this.removeLines = function(firstRow, lastRow) {
|
||||||
|
this._dispatchEvent("changeStart");
|
||||||
var range = new Range(firstRow, 0, lastRow + 1, 0);
|
var range = new Range(firstRow, 0, lastRow + 1, 0);
|
||||||
var removed = this.$lines.splice(firstRow, lastRow - firstRow + 1);
|
var removed = this.$lines.splice(firstRow, lastRow - firstRow + 1);
|
||||||
|
|
||||||
|
|
@ -323,6 +338,7 @@ var Document = function(text) {
|
||||||
lines: removed
|
lines: removed
|
||||||
};
|
};
|
||||||
this._dispatchEvent("change", { data: delta });
|
this._dispatchEvent("change", { data: delta });
|
||||||
|
this._dispatchEvent("changeEnd");
|
||||||
return removed;
|
return removed;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -333,6 +349,7 @@ var Document = function(text) {
|
||||||
var range = new Range(row, firstLine.length, row+1, 0);
|
var range = new Range(row, firstLine.length, row+1, 0);
|
||||||
var line = firstLine + secondLine;
|
var line = firstLine + secondLine;
|
||||||
|
|
||||||
|
this._dispatchEvent("changeStart");
|
||||||
this.$lines.splice(row, 2, line);
|
this.$lines.splice(row, 2, line);
|
||||||
|
|
||||||
var delta = {
|
var delta = {
|
||||||
|
|
@ -341,6 +358,7 @@ var Document = function(text) {
|
||||||
text: this.getNewLineCharacter()
|
text: this.getNewLineCharacter()
|
||||||
};
|
};
|
||||||
this._dispatchEvent("change", { data: delta });
|
this._dispatchEvent("change", { data: delta });
|
||||||
|
this._dispatchEvent("changeEnd");
|
||||||
};
|
};
|
||||||
|
|
||||||
this.replace = function(range, text) {
|
this.replace = function(range, text) {
|
||||||
|
|
@ -352,6 +370,7 @@ var Document = function(text) {
|
||||||
if (text == this.getTextRange(range))
|
if (text == this.getTextRange(range))
|
||||||
return range.end;
|
return range.end;
|
||||||
|
|
||||||
|
this._dispatchEvent("changeStart");
|
||||||
this.remove(range);
|
this.remove(range);
|
||||||
if (text) {
|
if (text) {
|
||||||
var end = this.insert(range.start, text);
|
var end = this.insert(range.start, text);
|
||||||
|
|
@ -359,6 +378,7 @@ var Document = function(text) {
|
||||||
else {
|
else {
|
||||||
end = range.start;
|
end = range.start;
|
||||||
}
|
}
|
||||||
|
this._dispatchEvent("changeEnd");
|
||||||
|
|
||||||
return end;
|
return end;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ var EditSession = function(text, mode) {
|
||||||
});
|
});
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
this.$docChangeCounter = 0;
|
||||||
|
|
||||||
if (text instanceof Document) {
|
if (text instanceof Document) {
|
||||||
this.setDocument(text);
|
this.setDocument(text);
|
||||||
|
|
@ -89,26 +90,56 @@ var EditSession = function(text, mode) {
|
||||||
|
|
||||||
this.doc = doc;
|
this.doc = doc;
|
||||||
doc.on("change", this.onChange.bind(this));
|
doc.on("change", this.onChange.bind(this));
|
||||||
|
doc.on("changeStart", this.onChangeStart.bind(this));
|
||||||
|
doc.on("changeEnd", this.onChangeEnd.bind(this));
|
||||||
};
|
};
|
||||||
|
|
||||||
this.getDocument = function() {
|
this.getDocument = function() {
|
||||||
return this.doc;
|
return this.doc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.onChangeStart = function() {
|
||||||
|
console.log(">>> onChangeStart", this.$docChangeCounter);
|
||||||
|
this.$docChangeCounter ++;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.onChangeEnd = function() {
|
||||||
|
this.$docChangeCounter --;
|
||||||
|
console.log("<<< onChangeEnd", this.$docChangeCounter);
|
||||||
|
if (this.$docChangeCounter == 0
|
||||||
|
&& this.$deltaFolds && this.$deltaFolds.length)
|
||||||
|
{
|
||||||
|
this.$deltas = this.$deltaFolds.concat(this.$deltas);
|
||||||
|
this.$deltaFolds = [];
|
||||||
|
this.$informUndoManager.schedule();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
this.onChange = function(e) {
|
this.onChange = function(e) {
|
||||||
var delta = e.data;
|
var delta = e.data;
|
||||||
this.$modified = true;
|
this.$modified = true;
|
||||||
|
|
||||||
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));
|
||||||
this.$deltas.push(delta);
|
this.$deltas.push(delta);
|
||||||
if (removedFolds && removedFolds.length != 0) {
|
if (removedFolds && removedFolds.length != 0) {
|
||||||
this.$deltas.push({
|
this.$deltaFolds.push({
|
||||||
action: "removeFolds",
|
action: "removeFolds",
|
||||||
folds: removedFolds
|
folds: removedFolds
|
||||||
});
|
});
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
this.$informUndoManager.schedule();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -119,6 +150,7 @@ 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.getUndoManager().reset();
|
this.getUndoManager().reset();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -142,6 +174,7 @@ 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 = [];
|
||||||
|
|
||||||
if (this.$informUndoManager) {
|
if (this.$informUndoManager) {
|
||||||
this.$informUndoManager.cancel();
|
this.$informUndoManager.cancel();
|
||||||
|
|
@ -635,28 +668,35 @@ var EditSession = function(text, mode) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterFoldDeltas(deltas) {
|
|
||||||
return deltas.filter(function(delta) {
|
|
||||||
return delta.action == "removeFolds";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.undoChanges = function(deltas) {
|
this.undoChanges = function(deltas) {
|
||||||
if (!deltas.length)
|
if (!deltas.length)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var docDeltas = filterDocActions(deltas);
|
|
||||||
var foldDeltas = filterFoldDeltas(deltas);
|
|
||||||
this.$fromUndo = true;
|
this.$fromUndo = true;
|
||||||
this.doc.revertDeltas(docDeltas);
|
var docDeltas = filterDocActions(deltas);
|
||||||
foldDeltas.forEach(function(foldDelta) {
|
if (docDeltas.length == deltas.length) {
|
||||||
foldDelta.folds.forEach(function(fold) {
|
this.doc.revertDeltas(deltas);
|
||||||
this.addFold(fold);
|
} else {
|
||||||
}, this);
|
var groupDocDeltas = [];
|
||||||
}, this);
|
for (var i = deltas.length - 1; i != -1; i--) {
|
||||||
|
delta = deltas[i];
|
||||||
|
if (docActions.indexOf(delta.action) != -1) {
|
||||||
|
groupDocDeltas.push(delta);
|
||||||
|
} else {
|
||||||
|
groupDocDeltas.reverse()
|
||||||
|
this.doc.revertDeltas(groupDocDeltas);
|
||||||
|
this.$setUndoSelection(groupDocDeltas, true);
|
||||||
|
groupDocDeltas = [];
|
||||||
|
this.addFolds(delta.folds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.doc.revertDeltas(groupDocDeltas);
|
||||||
|
}
|
||||||
this.$fromUndo = false;
|
this.$fromUndo = false;
|
||||||
|
|
||||||
this.$setUndoSelection(docDeltas, true);
|
if (docDeltas.length == deltas.length) {
|
||||||
|
this.$setUndoSelection(docDeltas, true);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
this.redoChanges = function(deltas) {
|
this.redoChanges = function(deltas) {
|
||||||
|
|
@ -664,7 +704,6 @@ var EditSession = function(text, mode) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var docDeltas = filterDocActions(deltas);
|
var docDeltas = filterDocActions(deltas);
|
||||||
var foldDeltas = filterFoldDeltas(deltas);
|
|
||||||
this.$fromUndo = true;
|
this.$fromUndo = true;
|
||||||
this.doc.applyDeltas(docDeltas);
|
this.doc.applyDeltas(docDeltas);
|
||||||
this.$fromUndo = false;
|
this.$fromUndo = false;
|
||||||
|
|
|
||||||
|
|
@ -334,6 +334,12 @@ function Folding() {
|
||||||
return fold;
|
return fold;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.addFolds = function(folds) {
|
||||||
|
folds.forEach(function(fold) {
|
||||||
|
this.addFold(fold);
|
||||||
|
}, this);
|
||||||
|
};
|
||||||
|
|
||||||
this.removeFold = function(fold) {
|
this.removeFold = function(fold) {
|
||||||
var foldLine = fold.foldLine;
|
var foldLine = fold.foldLine;
|
||||||
var startRow = foldLine.start.row;
|
var startRow = foldLine.start.row;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue