first undo manager support

This commit is contained in:
Fabian Jakobs 2010-05-03 17:25:31 +02:00
commit 0cdafa9daa
6 changed files with 194 additions and 14 deletions

View file

@ -60,6 +60,7 @@
<script src="../src/ace/MEventEmitter.js" type="text/javascript" charset="utf-8"></script>
<script src="../src/ace/Search.js" type="text/javascript" charset="utf-8"></script>
<script src="../src/ace/Selection.js" type="text/javascript" charset="utf-8"></script>
<script src="../src/ace/UndoManager.js" type="text/javascript" charset="utf-8"></script>
<script src="../src/ace/Document.js" type="text/javascript" charset="utf-8"></script>
<script src="../src/ace/Tokenizer.js" type="text/javascript" charset="utf-8"></script>
<script src="../src/ace/BackgroundTokenizer.js" type="text/javascript" charset="utf-8"></script>
@ -149,10 +150,15 @@
var docs = {}
docs.js = new ace.Document(document.getElementById("jstext").innerHTML);
docs.js.setMode(new ace.mode.JavaScript());
docs.js.setUndoManager(new ace.UndoManager());
docs.css = new ace.Document(document.getElementById("csstext").innerHTML);
docs.css.setMode(new ace.mode.Css());
docs.css.setUndoManager(new ace.UndoManager());
docs.html = new ace.Document(document.getElementById("htmltext").innerHTML);
docs.html.setMode(new ace.mode.Html());
docs.html.setUndoManager(new ace.UndoManager());
var docEl = document.getElementById("doc");

View file

@ -2,7 +2,8 @@
server: http://localhost:4224
load:
- src/ace/ace.js
- src/ace/lib/core.js
- src/ace/lib/*.js
- src/ace/MEventEmitter.js
- src/ace/mode/Text.js
- src/ace/mode/TextHighlightRules.js

View file

@ -23,6 +23,8 @@ ace.Document = function(text, mode) {
ace.implement(this, ace.MEventEmitter);
this.$undoManager = null;
this.$split = function(text) {
return text.split(/\r\n|\r|\n/);
};
@ -43,6 +45,33 @@ ace.Document = function(text, mode) {
this.$dispatchEvent("change", { data: data});
};
this.setUndoManager = function(undoManager) {
this.$undoManager = undoManager;
this.$deltas = [];
if (this.$informUndoManager) {
this.$informUndoManager.cancel();
}
if (undoManager) {
undoManager.setDocument(this);
var self = this;
this.$informUndoManager = ace.deferredCall(function() {
undoManager.notify(self.$deltas);
self.$deltas = [];
});
}
};
this.$defaultUndoManager = {
undo: function() {},
redo: function() {}
};
this.getUndoManager = function() {
return this.$undoManager || this.$defaultUndoManager;
},
this.getTabString = function() {
if (this.getUseSoftTabs()) {
return new Array(this.getTabSize()+1).join(" ");
@ -267,8 +296,8 @@ ace.Document = function(text, mode) {
return null;
};
this.insert = function(position, text) {
var end = this.$insert(position, text);
this.insert = function(position, text, fromUndo) {
var end = this.$insert(position, text, fromUndo);
this.fireChangeEvent(position.row, position.row == end.row ? position.row
: undefined);
return end;
@ -278,9 +307,28 @@ ace.Document = function(text, mode) {
var args = [row, 0];
args.push.apply(args, lines);
this.lines.splice.apply(this.lines, args);
if (this.$undoManager) {
var nl = this.$getNewLineCharacter();
this.$deltas.push({
type: "insert",
range: {
start: {
row: row,
column: 0
},
end: {
row: row + lines.length,
column: 0
}
},
text: lines.join(nl) + nl
});
this.$informUndoManager.schedule();
}
},
this.$insert = function(position, text) {
this.$insert = function(position, text, fromUndo) {
this.modified = true;
if (this.lines.length <= 1) {
this.$detectNewLine(text);
@ -293,7 +341,7 @@ ace.Document = function(text, mode) {
this.lines[position.row] = line.substring(0, position.column);
this.lines.splice(position.row + 1, 0, line.substring(position.column));
return {
var end = {
row : position.row + 1,
column : 0
};
@ -303,7 +351,7 @@ ace.Document = function(text, mode) {
this.lines[position.row] = line.substring(0, position.column) + text
+ line.substring(position.column);
return {
var end = {
row : position.row,
column : position.column + text.length
};
@ -320,27 +368,56 @@ ace.Document = function(text, mode) {
this.$insertLines(position.row + 1, newLines.slice(1, -1));
}
return {
var end = {
row : position.row + newLines.length - 1,
column : newLines[newLines.length - 1].length
};
}
if (!fromUndo && this.$undoManager) {
var nl = this.$getNewLineCharacter();
this.$deltas.push({
type: "insert",
range: {
start: ace.copyObject(position),
end: ace.copyObject(end)
},
text: text
});
this.$informUndoManager.schedule();
}
return end;
};
this.$isNewLine = function(text) {
return (text == "\r\n" || text == "\r" || text == "\n");
};
this.remove = function(range) {
this.$remove(range);
this.remove = function(range, fromUndo) {
this.$remove(range, fromUndo);
this.fireChangeEvent(range.start.row,
range.end.row == range.start.row ? range.start.row
: undefined);
return range.start;
};
this.$remove = function(range) {
this.$remove = function(range, fromUndo) {
if (!fromUndo && this.$undoManager) {
var nl = this.$getNewLineCharacter();
this.$deltas.push({
type: "remove",
range: {
start: ace.copyObject(range.start),
end: ace.copyObject(range.end)
},
text: this.getTextRange(range)
});
this.$informUndoManager.schedule();
}
this.modified = true;
var firstRow = range.start.row;
@ -351,9 +428,38 @@ ace.Document = function(text, mode) {
this.lines.splice(firstRow, lastRow - firstRow + 1, row);
return range.start;
};
this.undoChanges = function(deltas) {
this.selection.clearSelection();
for (var i=0; i<deltas.length; i++) {
var delta = deltas[i];
if (delta.type == "insert") {
this.remove(delta.range, true);
this.selection.moveCursorToPosition(delta.range.start);
} else {
this.insert(delta.range.start, delta.text, true);
this.selection.setSelectionRange(delta.range);
}
}
},
this.redoChanges = function(deltas) {
this.selection.clearSelection();
for (var i=0; i<deltas.length; i++) {
var delta = deltas[i];
if (delta.type == "insert") {
this.insert(delta.range.start, delta.text, true);
this.selection.setSelectionRange(delta.range);
} else {
this.remove(delta.range, true);
this.selection.moveCursorToPosition(delta.range.start);
}
}
},
this.replace = function(range, text) {
this.$remove(range);
if (text) {
@ -372,8 +478,8 @@ ace.Document = function(text, mode) {
};
this.indentRows = function(range, indentString) {
for (var i=range.start.row; i<= range.end.row; i++) {
this.lines[i] = indentString + this.getLine(i);
for (var row=range.start.row; row<= range.end.row; row++) {
this.$insert({row: row, column:0}, indentString);
}
this.fireChangeEvent(range.start.row, range.end.row);
return indentString.length;
@ -388,8 +494,20 @@ ace.Document = function(text, mode) {
}
}
for (var i=range.start.row; i<= range.end.row; i++) {
this.lines[i] = this.getLine(i).substring(outdentLength);
var deleteRange = {
start: {
column: 0
},
end: {
column: outdentLength
}
};
for (var i=range.start.row; i<= range.end.row; i++)
{
deleteRange.start.row = i;
deleteRange.end.row = i;
this.$remove(deleteRange);
}
this.fireChangeEvent(range.start.row, range.end.row);

View file

@ -780,4 +780,12 @@ ace.Editor = function(renderer, doc) {
this.selection.setSelectionRange(range);
};
this.undo = function() {
this.doc.getUndoManager().undo();
};
this.redo = function() {
this.doc.getUndoManager().redo();
};
}).call(ace.Editor.prototype);

View file

@ -80,6 +80,18 @@ ace.KeyBinding = function(element, editor) {
this.editor.find(needle);
};
this["Control-Z"] = function() {
this.editor.undo();
};
this["Control-Shift=Z"] = function() {
this.editor.redo();
};
this["Control-Y"] = function() {
this.editor.redo();
};
this["Insert"] = function() {
this.editor.toggleOverwrite();
};

35
src/ace/UndoManager.js Normal file
View file

@ -0,0 +1,35 @@
ace.provide("ace.UndoManager");
ace.UndoManager = function() {
this.$undoStack = [];
this.$redoStack = [];
};
(function() {
this.$doc = null;
this.setDocument = function(doc) {
this.$doc = doc;
};
this.notify = function(deltas) {
this.$undoStack.push(deltas);
};
this.undo = function() {
var deltas = this.$undoStack.pop();
if (deltas) {
this.$doc.undoChanges(deltas);
this.$redoStack.push(deltas);
}
};
this.redo = function() {
var deltas = this.$redoStack.pop();
if (deltas) {
this.$doc.redoChanges(deltas);
this.$undoStack.push(deltas);
}
};
}).call(ace.UndoManager.prototype);