107 lines
3.2 KiB
JavaScript
107 lines
3.2 KiB
JavaScript
import {TOOL_INFO_CLASSNAME, WIDE_CLASSNAME} from '../config.js';
|
|
import {hash} from '../helper.js';
|
|
import {Tool} from '../tool.js';
|
|
|
|
export class StateTool extends Tool {
|
|
stored = [];
|
|
|
|
async setContainer(container) {
|
|
super.setContainer(container);
|
|
|
|
const buttons = document.createElement('div');
|
|
const save = document.createElement('button');
|
|
const list = document.createElement('div');
|
|
|
|
save.innerHTML = 'Save';
|
|
|
|
save.classList.add(WIDE_CLASSNAME);
|
|
buttons.style.display = 'flex';
|
|
buttons.style.flexDirection = 'row';
|
|
buttons.appendChild(save);
|
|
list.style.display = 'flex';
|
|
list.style.flexDirection = 'column';
|
|
this.div.appendChild(buttons);
|
|
this.div.appendChild(list);
|
|
|
|
save.addEventListener('click', async () => {
|
|
const state = this.sim.toJSON();
|
|
this.stored.push(state);
|
|
const item = await this.createItem(state);
|
|
list.appendChild(item);
|
|
});
|
|
|
|
// Check url query parameter, and load specified state if found
|
|
await this.fromUrl();
|
|
}
|
|
|
|
async toUrl(state) {
|
|
const stateText = JSON.stringify(state);
|
|
const digest = await hash(stateText);
|
|
const rawUrl = `./?state=${stateText}&digest=${digest}`;
|
|
const url = encodeURI(rawUrl);
|
|
return {url, digest};
|
|
}
|
|
|
|
async fromUrl() {
|
|
const paramsString = window.location.search;
|
|
const searchParams = new URLSearchParams(paramsString);
|
|
const stateEnc = searchParams.get("state");
|
|
const rxDigest = searchParams.get("digest");
|
|
if (stateEnc) {
|
|
const stateText = decodeURI(stateEnc);
|
|
console.log('decoded state text', stateText);
|
|
const state = JSON.parse(stateText);
|
|
const digest = await hash(stateText);
|
|
if (digest !== rxDigest) {
|
|
throw new Error('state query parameter does not match digest query parameter');
|
|
}
|
|
// Tools in this system can be very powerful
|
|
this.sim.fromJSON(state);
|
|
}
|
|
}
|
|
|
|
getStateDescription(state) {
|
|
const date = new Date(state.dateSaved);
|
|
const Y = date.getFullYear().toString();
|
|
const M = (date.getMonth() + 1).toString().padStart(2, '0');
|
|
const D = date.getDate().toString().padStart(2, '0');
|
|
const h = date.getHours().toString().padStart(2, '0');
|
|
const m = date.getMinutes().toString().padStart(2, '0');
|
|
const s = date.getSeconds().toString().padStart(2, '0');
|
|
return `${Y}-${M}-${D} ${h}:${m}:${s}`;
|
|
}
|
|
|
|
async createItem(state) {
|
|
const item = document.createElement('div');
|
|
item.style.display = 'flex';
|
|
item.style.flexDirection = 'row';
|
|
item.style.flexWrap = 'wrap';
|
|
|
|
const description = document.createElement('button');
|
|
description.style.flex = '2';
|
|
description.classList.add(TOOL_INFO_CLASSNAME);
|
|
description.innerHTML = this.getStateDescription(state);
|
|
|
|
const load = document.createElement('button');
|
|
load.style.flex = '1';
|
|
|
|
const link = document.createElement('a');
|
|
const {url, digest} = await this.toUrl(state);
|
|
link.href = url;
|
|
link.innerHTML = digest.slice(0, 5);
|
|
|
|
load.appendChild(link);
|
|
|
|
item.appendChild(description);
|
|
item.appendChild(load);
|
|
|
|
load.addEventListener('click', (e) => {
|
|
e.preventDefault();
|
|
// Tools in this system can wield great power
|
|
this.sim.fromJSON(state);
|
|
});
|
|
|
|
return item;
|
|
}
|
|
}
|