first undo manager support
This commit is contained in:
parent
db2271f633
commit
0cdafa9daa
6 changed files with 194 additions and 14 deletions
|
|
@ -60,6 +60,7 @@
|
||||||
<script src="../src/ace/MEventEmitter.js" type="text/javascript" charset="utf-8"></script>
|
<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/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/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/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/Tokenizer.js" type="text/javascript" charset="utf-8"></script>
|
||||||
<script src="../src/ace/BackgroundTokenizer.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 = {}
|
var docs = {}
|
||||||
docs.js = new ace.Document(document.getElementById("jstext").innerHTML);
|
docs.js = new ace.Document(document.getElementById("jstext").innerHTML);
|
||||||
docs.js.setMode(new ace.mode.JavaScript());
|
docs.js.setMode(new ace.mode.JavaScript());
|
||||||
|
docs.js.setUndoManager(new ace.UndoManager());
|
||||||
|
|
||||||
docs.css = new ace.Document(document.getElementById("csstext").innerHTML);
|
docs.css = new ace.Document(document.getElementById("csstext").innerHTML);
|
||||||
docs.css.setMode(new ace.mode.Css());
|
docs.css.setMode(new ace.mode.Css());
|
||||||
|
docs.css.setUndoManager(new ace.UndoManager());
|
||||||
|
|
||||||
docs.html = new ace.Document(document.getElementById("htmltext").innerHTML);
|
docs.html = new ace.Document(document.getElementById("htmltext").innerHTML);
|
||||||
docs.html.setMode(new ace.mode.Html());
|
docs.html.setMode(new ace.mode.Html());
|
||||||
|
docs.html.setUndoManager(new ace.UndoManager());
|
||||||
|
|
||||||
var docEl = document.getElementById("doc");
|
var docEl = document.getElementById("doc");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@
|
||||||
server: http://localhost:4224
|
server: http://localhost:4224
|
||||||
|
|
||||||
load:
|
load:
|
||||||
- src/ace/ace.js
|
- src/ace/lib/core.js
|
||||||
|
- src/ace/lib/*.js
|
||||||
- src/ace/MEventEmitter.js
|
- src/ace/MEventEmitter.js
|
||||||
- src/ace/mode/Text.js
|
- src/ace/mode/Text.js
|
||||||
- src/ace/mode/TextHighlightRules.js
|
- src/ace/mode/TextHighlightRules.js
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@ ace.Document = function(text, mode) {
|
||||||
|
|
||||||
ace.implement(this, ace.MEventEmitter);
|
ace.implement(this, ace.MEventEmitter);
|
||||||
|
|
||||||
|
this.$undoManager = null;
|
||||||
|
|
||||||
this.$split = function(text) {
|
this.$split = function(text) {
|
||||||
return text.split(/\r\n|\r|\n/);
|
return text.split(/\r\n|\r|\n/);
|
||||||
};
|
};
|
||||||
|
|
@ -43,6 +45,33 @@ ace.Document = function(text, mode) {
|
||||||
this.$dispatchEvent("change", { data: data});
|
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() {
|
this.getTabString = function() {
|
||||||
if (this.getUseSoftTabs()) {
|
if (this.getUseSoftTabs()) {
|
||||||
return new Array(this.getTabSize()+1).join(" ");
|
return new Array(this.getTabSize()+1).join(" ");
|
||||||
|
|
@ -267,8 +296,8 @@ ace.Document = function(text, mode) {
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.insert = function(position, text) {
|
this.insert = function(position, text, fromUndo) {
|
||||||
var end = this.$insert(position, text);
|
var end = this.$insert(position, text, fromUndo);
|
||||||
this.fireChangeEvent(position.row, position.row == end.row ? position.row
|
this.fireChangeEvent(position.row, position.row == end.row ? position.row
|
||||||
: undefined);
|
: undefined);
|
||||||
return end;
|
return end;
|
||||||
|
|
@ -278,9 +307,28 @@ ace.Document = function(text, mode) {
|
||||||
var args = [row, 0];
|
var args = [row, 0];
|
||||||
args.push.apply(args, lines);
|
args.push.apply(args, lines);
|
||||||
this.lines.splice.apply(this.lines, args);
|
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;
|
this.modified = true;
|
||||||
if (this.lines.length <= 1) {
|
if (this.lines.length <= 1) {
|
||||||
this.$detectNewLine(text);
|
this.$detectNewLine(text);
|
||||||
|
|
@ -293,7 +341,7 @@ ace.Document = function(text, mode) {
|
||||||
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));
|
this.lines.splice(position.row + 1, 0, line.substring(position.column));
|
||||||
|
|
||||||
return {
|
var end = {
|
||||||
row : position.row + 1,
|
row : position.row + 1,
|
||||||
column : 0
|
column : 0
|
||||||
};
|
};
|
||||||
|
|
@ -303,7 +351,7 @@ ace.Document = function(text, mode) {
|
||||||
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);
|
||||||
|
|
||||||
return {
|
var end = {
|
||||||
row : position.row,
|
row : position.row,
|
||||||
column : position.column + text.length
|
column : position.column + text.length
|
||||||
};
|
};
|
||||||
|
|
@ -320,27 +368,56 @@ ace.Document = function(text, mode) {
|
||||||
this.$insertLines(position.row + 1, newLines.slice(1, -1));
|
this.$insertLines(position.row + 1, newLines.slice(1, -1));
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
var end = {
|
||||||
row : position.row + newLines.length - 1,
|
row : position.row + newLines.length - 1,
|
||||||
column : newLines[newLines.length - 1].length
|
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) {
|
this.$isNewLine = function(text) {
|
||||||
return (text == "\r\n" || text == "\r" || text == "\n");
|
return (text == "\r\n" || text == "\r" || text == "\n");
|
||||||
};
|
};
|
||||||
|
|
||||||
this.remove = function(range) {
|
this.remove = function(range, fromUndo) {
|
||||||
this.$remove(range);
|
this.$remove(range, fromUndo);
|
||||||
|
|
||||||
this.fireChangeEvent(range.start.row,
|
this.fireChangeEvent(range.start.row,
|
||||||
range.end.row == range.start.row ? range.start.row
|
range.end.row == range.start.row ? range.start.row
|
||||||
: undefined);
|
: undefined);
|
||||||
|
|
||||||
return range.start;
|
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;
|
this.modified = true;
|
||||||
|
|
||||||
var firstRow = range.start.row;
|
var firstRow = range.start.row;
|
||||||
|
|
@ -351,9 +428,38 @@ ace.Document = function(text, mode) {
|
||||||
|
|
||||||
this.lines.splice(firstRow, lastRow - firstRow + 1, row);
|
this.lines.splice(firstRow, lastRow - firstRow + 1, row);
|
||||||
|
|
||||||
|
|
||||||
return range.start;
|
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.replace = function(range, text) {
|
||||||
this.$remove(range);
|
this.$remove(range);
|
||||||
if (text) {
|
if (text) {
|
||||||
|
|
@ -372,8 +478,8 @@ ace.Document = function(text, mode) {
|
||||||
};
|
};
|
||||||
|
|
||||||
this.indentRows = function(range, indentString) {
|
this.indentRows = function(range, indentString) {
|
||||||
for (var i=range.start.row; i<= range.end.row; i++) {
|
for (var row=range.start.row; row<= range.end.row; row++) {
|
||||||
this.lines[i] = indentString + this.getLine(i);
|
this.$insert({row: row, column:0}, indentString);
|
||||||
}
|
}
|
||||||
this.fireChangeEvent(range.start.row, range.end.row);
|
this.fireChangeEvent(range.start.row, range.end.row);
|
||||||
return indentString.length;
|
return indentString.length;
|
||||||
|
|
@ -388,8 +494,20 @@ ace.Document = function(text, mode) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i=range.start.row; i<= range.end.row; i++) {
|
var deleteRange = {
|
||||||
this.lines[i] = this.getLine(i).substring(outdentLength);
|
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);
|
this.fireChangeEvent(range.start.row, range.end.row);
|
||||||
|
|
|
||||||
|
|
@ -780,4 +780,12 @@ ace.Editor = function(renderer, doc) {
|
||||||
this.selection.setSelectionRange(range);
|
this.selection.setSelectionRange(range);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.undo = function() {
|
||||||
|
this.doc.getUndoManager().undo();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.redo = function() {
|
||||||
|
this.doc.getUndoManager().redo();
|
||||||
|
};
|
||||||
|
|
||||||
}).call(ace.Editor.prototype);
|
}).call(ace.Editor.prototype);
|
||||||
|
|
@ -80,6 +80,18 @@ ace.KeyBinding = function(element, editor) {
|
||||||
this.editor.find(needle);
|
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["Insert"] = function() {
|
||||||
this.editor.toggleOverwrite();
|
this.editor.toggleOverwrite();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
35
src/ace/UndoManager.js
Normal file
35
src/ace/UndoManager.js
Normal 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);
|
||||||
Loading…
Add table
Add a link
Reference in a new issue