diff --git a/public/main.js b/public/main.js index 080e166..3b9f5df 100644 --- a/public/main.js +++ b/public/main.js @@ -22,61 +22,23 @@ let audioView = new AudioView(model); // Create a new project model.new(); -/* -export function importData(jsonData) -{ - //console.log('json data:', jsonData); - - // Stop playback to avoid glitching - stopPlayback(); - - // Show the Edit tab before loading the graph, - // so it can resize itself correctly - showTab('edit'); - - let graph = JSON.parse(jsonData); - editor.load(graph); -} - -export function exportData() -{ - return JSON.stringify(editor.graph); -} - document.body.onload = function () { - let graphData = localStorage.getItem('graph'); + if (window.location.hash) + return; - if (graphData && !window.location.hash) - { - console.log('loading saved graph'); + let serializedModelData = localStorage.getItem('latestModelData'); + if (!serializedModelData) + return; - try - { - importData(graphData); - } - catch (exc) - { - //alert('Graph failed to load'); - console.log(exc); - localStorage.removeItem('graph'); - editor = new GraphEditor(); - editor.newGraph(); - //location.reload(false); - } - } - else - { - editor.newGraph(); - } + importModel(serializedModelData); } window.onunload = function () { // Save the graph when unloading the page - localStorage.setItem('graph', exportData()); + localStorage.setItem('latestModelData', model.serialize()); } -*/ window.onkeydown = function (event) { @@ -132,6 +94,18 @@ window.onkeydown = function (event) } } +export function importModel(serializedModelData) +{ + // Stop playback to avoid glitching + stopPlayback(); + + if (model.deserialize(serializedModelData)) { + console.log('model restored from previous session'); + } else { + console.warn('could not restore model from previous session'); + } +} + export function startPlayback() { if (playing) diff --git a/public/model.js b/public/model.js index 0494a5c..723b78b 100644 --- a/public/model.js +++ b/public/model.js @@ -59,7 +59,7 @@ undo, however. It could be more of a direct state update, or it's a special undoable action. */ -import { assert, treeCopy, treeEq } from './utils.js'; +import { assert, treeCopy, treeEq, isString, isObject } from './utils.js'; /** * High-level description/scheme for each type of node @@ -693,6 +693,38 @@ export class Model this.broadcast(this.state, null); } + // Serializes the model into a string representation + serialize() + { + return JSON.stringify({ + state: this.state + }); + } + + // Tries to deserialize a string representation of a model + // + // Returns true if successfully deserialized and loaded, false otherwise + deserialize(data) + { + if (!isString(data)) { + return false; + } + + let json; + try { + json = JSON.parse(data); + } catch (e) { + return false; + } + + if (!isObject(json) || !isObject(json.state)) { + return false; + } + + this.load(json.state); + return true; + } + /** Check if the graph contains a specific type of node */ hasNode(nodeType) { diff --git a/public/utils.js b/public/utils.js index 9901f6d..cee53d2 100644 --- a/public/utils.js +++ b/public/utils.js @@ -168,6 +168,22 @@ export function treeEq(a, b) return a === b; } +/** +Test that a value is an object +*/ +export function isObject(val) +{ + return (typeof val === 'object') && (val !== null); +} + +/** +Test that a value is a string +*/ +export function isString(val) +{ + return (typeof val === 'string') || (val instanceof String); +} + /** Test that a value is integer */