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");
+ });
+ });
+});