From 0cdafa9daa1128a54541e74dd87b4bc97a27e898 Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Mon, 3 May 2010 17:25:31 +0200 Subject: [PATCH] first undo manager support --- demo/editor.html | 6 ++ jsTestDriver.conf | 3 +- src/ace/Document.js | 144 +++++++++++++++++++++++++++++++++++++---- src/ace/Editor.js | 8 +++ src/ace/KeyBinding.js | 12 ++++ src/ace/UndoManager.js | 35 ++++++++++ 6 files changed, 194 insertions(+), 14 deletions(-) create mode 100644 src/ace/UndoManager.js 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