diff --git a/demo/editor.html b/demo/editor.html
index 821536af..fd5b8c18 100644
--- a/demo/editor.html
+++ b/demo/editor.html
@@ -60,6 +60,7 @@
+
@@ -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");
diff --git a/jsTestDriver.conf b/jsTestDriver.conf
index 44db80ab..f047d8c9 100644
--- a/jsTestDriver.conf
+++ b/jsTestDriver.conf
@@ -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
diff --git a/src/ace/Document.js b/src/ace/Document.js
index 144ef517..0ed141f1 100644
--- a/src/ace/Document.js
+++ b/src/ace/Document.js
@@ -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