From 0485580b899007368f95822e21067bc0763f01b2 Mon Sep 17 00:00:00 2001 From: Ian Gulliver Date: Thu, 11 Jul 2019 22:30:53 +0000 Subject: [PATCH] Proper history tracking --- Architype.js | 68 +++++++++++++++++++++++++++++++++++++++++++++----- EditorLabel.js | 15 +++++++++-- EditorNode.js | 16 ++++++++++-- IdSource.js | 4 +++ 4 files changed, 93 insertions(+), 10 deletions(-) diff --git a/Architype.js b/Architype.js index 3d4a1d4..c9356f8 100644 --- a/Architype.js +++ b/Architype.js @@ -33,28 +33,56 @@ class Architype { this.render_.push(render); } - this.unserialize(JSON.parse(localStorage.getItem('currentState'))); + addEventListener('hashchange', (e) => { this.onHashChange(e); }); + + let fixUrl = false; + if (location.hash.length > 1) { + this.unserialize(JSON.parse(atob(location.hash.substring(1)))); + } else { + this.unserialize(JSON.parse(localStorage.getItem('currentState'))); + fixUrl = true; + } if (this.editor_.getEntries().length == 0) { this.editor_.addHelpAfter(); } this.editor_.selectNext(); this.observer_ = new MutationObserver(e => { this.onChange(e); }); + this.observer2_ = new MutationObserver(e => { this.snapshot(e); }); + this.observe(); + + this.saveAndRender(); + + if (fixUrl) { + history.replaceState(null, null, '#' + btoa(this.serializedStr_)); + } + } + + observe() { this.observer_.observe(this.editorElem_, { attributes: true, attributeFilter: ['data-arch-refresh'], childList: true, subtree: true, }); + this.observer2_.observe(this.editorElem_, { + attributes: true, + attributeFilter: ['data-arch-snapshot'], + childList: true, + subtree: true, + }); + } - this.onChange(); + unobserve() { + this.observer_.disconnect(); + this.observer2_.disconnect(); } serialize() { return { version: 1, - generation: ++this.generation_, - nextId: idSource.getId(), + generation: this.generation_, + nextId: idSource.peekId(), editor: this.editor_.serialize(), }; } @@ -64,6 +92,9 @@ class Architype { return; } + this.renderGeneration_ = -1; + this.drawGeneration_ = -1; + switch (ser.version) { case 1: this.generation_ = ser.generation; @@ -77,10 +108,35 @@ class Architype { } } - onChange(e) { + overwrite(ser) { + this.unobserve(); + this.editor_.clear(); + this.unserialize(ser); + this.observe(); + this.editor_.selectNext(); + this.saveAndRender(); + } + + onHashChange() { + if (location.hash.length > 1) { + this.overwrite(JSON.parse(atob(location.hash.substring(1)))); + } + } + + onChange() { + ++this.generation_; + this.saveAndRender(); + } + + snapshot() { + history.pushState(null, null, '#' + btoa(this.serializedStr_)); + } + + saveAndRender() { this.serialized_ = this.serialize(); this.startRender(); - localStorage.setItem('currentState', JSON.stringify(this.serialized_)); + this.serializedStr_ = JSON.stringify(this.serialized_); + localStorage.setItem('currentState', this.serializedStr_); } onKeyDown(e) { diff --git a/EditorLabel.js b/EditorLabel.js index 025361b..a5f54fd 100644 --- a/EditorLabel.js +++ b/EditorLabel.js @@ -9,8 +9,11 @@ class EditorLabel extends EditorEntryBase { this.input_.type = 'text'; this.input_.placeholder = 'label'; this.listen(this.input_, 'keydown', (e) => this.onInputKeyDown(e)); - this.listen(this.input_, 'input', (e) => this.onInput()); + this.listen(this.input_, 'input', (e) => this.onInput(e)); + this.listen(this.input_, 'blur', (e) => this.onBlur(e)); this.elem_.appendChild(this.input_); + + this.lastSnapshotLabel_ = null; } afterDomAdd() { @@ -30,6 +33,7 @@ class EditorLabel extends EditorEntryBase { setLabel(label) { this.input_.value = label; + this.lastSnapshotLabel_ = label; this.onInput(); } @@ -38,7 +42,14 @@ class EditorLabel extends EditorEntryBase { } onInput() { - this.input_.setAttribute('data-arch-refresh', ''); + this.elem_.setAttribute('data-arch-refresh', ''); + } + + onBlur() { + if (this.getLabel() != this.lastSnapshotLabel_) { + this.lastSnapshotLabel_ = this.getLabel(); + this.elem_.setAttribute('data-arch-snapshot', ''); + } } onInputKeyDown(e) { diff --git a/EditorNode.js b/EditorNode.js index 2c3c50c..e16ca12 100644 --- a/EditorNode.js +++ b/EditorNode.js @@ -8,9 +8,12 @@ class EditorNode extends EditorEntryBase { this.input_.type = 'text'; this.input_.placeholder = 'node name'; this.listen(this.input_, 'keydown', (e) => this.onInputKeyDown(e)); - this.listen(this.input_, 'input', (e) => this.onInput()); + this.listen(this.input_, 'input', (e) => this.onInput(e)); + this.listen(this.input_, 'blur', (e) => this.onBlur(e)); this.elem_.appendChild(this.input_); + this.lastSnapshotLabel_ = null; + if (label) { this.setLabel(label); } @@ -35,6 +38,7 @@ class EditorNode extends EditorEntryBase { setLabel(label) { this.input_.value = label; + this.lastSnapshotLabel_ = label; this.onInput(); } @@ -58,7 +62,15 @@ class EditorNode extends EditorEntryBase { } onInput() { - this.input_.setAttribute('data-arch-refresh', ''); + this.elem_.setAttribute('data-arch-refresh', ''); + } + + onBlur() { + if (this.getLabel() != this.lastSnapshotLabel_) { + console.log('changed'); + this.lastSnapshotLabel_ = this.getLabel(); + this.elem_.setAttribute('data-arch-snapshot', ''); + } } onInputKeyDown(e) { diff --git a/IdSource.js b/IdSource.js index 4fec2b2..aa0dda5 100644 --- a/IdSource.js +++ b/IdSource.js @@ -7,6 +7,10 @@ class IdSource { return ++this.nextId_; } + peekId() { + return this.nextId_; + } + setId(nextId) { this.nextId_ = nextId; }