diff --git a/js/id/graph/history.js b/js/id/graph/history.js index 8d2eb586d..501b0a037 100644 --- a/js/id/graph/history.js +++ b/js/id/graph/history.js @@ -1,85 +1,83 @@ iD.History = function() { - if (!(this instanceof iD.History)) return new iD.History(); - this.stack = [iD.Graph()]; - this.index = 0; -}; + var stack = [iD.Graph()], + index = 0; -iD.History.prototype = { + return { + graph: function () { + return stack[index]; + }, - graph: function() { - return this.stack[this.index]; - }, + merge: function (graph) { + for (var i = 0; i < stack.length; i++) { + stack[i] = stack[i].merge(graph); + } + }, - merge: function(graph) { - for (var i = 0; i < this.stack.length; i++) { - this.stack[i] = this.stack[i].merge(graph); - } - }, - - perform: function(action) { - this.stack = this.stack.slice(0, this.index + 1); - this.stack.push(action(this.graph())); - this.index++; - }, - - replace: function(action) { - // assert(this.index == this.stack.length - 1) - this.stack[this.index] = action(this.graph()); - }, - - undo: function() { - while (this.index > 0) { - this.index--; - if (this.stack[this.index].annotation) break; - } - }, - - redo: function() { - while (this.index < this.stack.length - 1) { - this.index++; - if (this.stack[this.index].annotation) break; - } - }, - - undoAnnotation: function() { - var index = this.index; - while (index >= 0) { - if (this.stack[index].annotation) return this.stack[index].annotation; - index--; - } - }, - - redoAnnotation: function() { - var index = this.index + 1; - while (index <= this.stack.length - 1) { - if (this.stack[index].annotation) return this.stack[index].annotation; + perform: function (action) { + stack = stack.slice(0, index + 1); + stack.push(action(this.graph())); index++; + }, + + replace: function (action) { + // assert(index == stack.length - 1) + stack[index] = action(this.graph()); + }, + + undo: function () { + while (index > 0) { + index--; + if (stack[index].annotation) break; + } + }, + + redo: function () { + while (index < stack.length - 1) { + index++; + if (stack[index].annotation) break; + } + }, + + undoAnnotation: function () { + var i = index; + while (i >= 0) { + if (stack[i].annotation) return stack[i].annotation; + i--; + } + }, + + redoAnnotation: function () { + var i = index + 1; + while (i <= stack.length - 1) { + if (stack[i].annotation) return stack[i].annotation; + i++; + } + }, + + // generate reports of changes for changesets to use + modify: function () { + return stack[index].modifications(); + }, + + create: function () { + return stack[index].creations(); + }, + + 'delete': function () { + return _.difference( + _.pluck(stack[0].entities, 'id'), + _.pluck(stack[index].entities, 'id') + ).map(function (id) { + return stack[0].fetch(id); + }); + }, + + changes: function () { + return { + modify: this.modify(), + create: this.create(), + 'delete': this['delete']() + }; } - }, - - // generate reports of changes for changesets to use - modify: function() { - return this.stack[this.index].modifications(); - }, - - create: function() { - return this.stack[this.index].creations(); - }, - - 'delete': function() { - return _.difference( - _.pluck(this.stack[0].entities, 'id'), - _.pluck(this.stack[this.index].entities, 'id') - ).map(function(id) { - return this.stack[0].fetch(id); - }.bind(this)); - }, - - changes: function() { - return { - modify: this.modify(), - create: this.create(), - 'delete': this['delete']() - }; } }; diff --git a/test/index.html b/test/index.html index 493a386ec..f427bbf7c 100644 --- a/test/index.html +++ b/test/index.html @@ -72,6 +72,7 @@ + diff --git a/test/spec/history.js b/test/spec/history.js new file mode 100644 index 000000000..ad2a2585b --- /dev/null +++ b/test/spec/history.js @@ -0,0 +1,41 @@ +describe("History", function () { + var history, spy, + graph = iD.Graph([], "action"), + action = function() { return graph; }; + + beforeEach(function () { + history = iD.History(); + }); + + describe("#graph", function () { + it("returns the current graph", function () { + expect(history.graph()).to.be.an.instanceOf(iD.Graph); + }); + }); + + describe("#perform", function () { + it("updates the graph", function () { + history.perform(action); + expect(history.graph()).to.equal(graph); + }); + + it("pushes the undo stack", function () { + history.perform(action); + expect(history.undoAnnotation()).to.equal("action"); + }); + }); + + describe("#undo", function () { + it("pops the undo stack", function () { + history.perform(action); + history.undo(); + expect(history.undoAnnotation()).to.be.undefined; + }); + + it("pushes the redo stack", function () { + history.perform(action); + history.undo(); + expect(history.redoAnnotation()).to.equal("action"); + }); + }); +});