diff --git a/index.html b/index.html
index 807e6a413..18f1b275b 100644
--- a/index.html
+++ b/index.html
@@ -67,6 +67,7 @@
+
diff --git a/js/id/graph/history.js b/js/id/graph/history.js
index dba04ec7e..ac36d564f 100644
--- a/js/id/graph/history.js
+++ b/js/id/graph/history.js
@@ -1,7 +1,8 @@
iD.History = function(context) {
var stack, index,
imagery_used = 'Bing',
- dispatch = d3.dispatch('change', 'undone', 'redone');
+ dispatch = d3.dispatch('change', 'undone', 'redone'),
+ lock = false;
function perform(actions) {
actions = Array.prototype.slice.call(actions);
@@ -152,11 +153,20 @@ iD.History = function(context) {
reset: function() {
stack = [{graph: iD.Graph()}];
index = 0;
- this.load();
dispatch.change();
},
save: function() {
+ if (!lock) return;
+ context.storage(getKey('lock'), null);
+
+ if (!stack.length) {
+ context.storage(getKey('history'), null);
+ context.storage(getKey('nextIDs'), null);
+ context.storage(getKey('index'), null);
+ return;
+ }
+
var json = JSON.stringify(stack.map(function(i) {
return _.extend(i, {
graph: i.graph.entities
@@ -166,17 +176,22 @@ iD.History = function(context) {
context.storage(getKey('history'), json);
context.storage(getKey('nextIDs'), JSON.stringify(iD.Entity.id.next));
context.storage(getKey('index'), index);
- context.storage(getKey('lock'), '');
},
lock: function() {
if (context.storage(getKey('lock'))) return false;
context.storage(getKey('lock'), true);
- return true;
+ lock = true;
+ return lock;
+ },
+
+ restorableChanges: function() {
+ if (!this.lock()) return false;
+ return !!context.storage(getKey('history'));
},
load: function() {
- if (!this.lock()) return;
+ if (!lock) return;
var json = context.storage(getKey('history')),
nextIDs = context.storage(getKey('nextIDs')),
@@ -186,10 +201,15 @@ iD.History = function(context) {
if (nextIDs) iD.Entity.id.next = JSON.parse(nextIDs);
if (index_ !== null) index = parseInt(index_, 10);
- stack = JSON.parse(json).map(function(d) {
- d.graph = iD.Graph().load(d.graph);
+ context.storage(getKey('history', null));
+ context.storage(getKey('nextIDs', null));
+ context.storage(getKey('index', null));
+
+ stack = JSON.parse(json).map(function(d, i) {
+ d.graph = iD.Graph(stack[0].graph).load(d.graph);
return d;
});
+ dispatch.change();
}
diff --git a/js/id/id.js b/js/id/id.js
index e20b3b111..d58464ecb 100644
--- a/js/id/id.js
+++ b/js/id/id.js
@@ -4,6 +4,7 @@ window.iD = function () {
context.storage = function(k, v) {
if (arguments.length === 1) return storage[k];
+ else if (v === null) delete storage[k];
else storage[k] = v;
};
diff --git a/js/id/ui.js b/js/id/ui.js
index dbbff15c8..c22ca6b83 100644
--- a/js/id/ui.js
+++ b/js/id/ui.js
@@ -256,5 +256,10 @@ iD.ui = function(context) {
iD.ui.splash(context.container());
context.storage('sawSplash', true);
}
+
+ if (history.restorableChanges()) {
+ iD.ui.restore(context.container(), history);
+ }
+
};
};
diff --git a/js/id/ui/restore.js b/js/id/ui/restore.js
new file mode 100644
index 000000000..3df275d89
--- /dev/null
+++ b/js/id/ui/restore.js
@@ -0,0 +1,34 @@
+iD.ui.restore = function(selection, history) {
+ var modal = iD.ui.modal(selection);
+
+ modal.select('.modal')
+ .attr('class', 'modal-splash modal');
+
+ var introModal = modal.select('.content')
+ .append('div')
+ .attr('class', 'modal-section fillL')
+ .text('You have unsaved changes from a previous editing session. Do you wish to restore these changes?');
+
+ buttons = introModal
+ .append('div')
+ .attr('class', 'buttons cf')
+ .append('div')
+ .attr('class', 'button-wrap joined col4');
+
+ buttons.append('button')
+ .attr('class', 'save action button col6')
+ .text('Restore')
+ .on('click', function() {
+ history.load();
+ modal.remove();
+ });
+
+ buttons.append('button')
+ .attr('class', 'cancel button col6')
+ .text('Reset')
+ .on('click', function() {
+ modal.remove();
+ });
+
+ return modal;
+};