scripts/core/ui_save.js
//this code is currently disabled
//XXX todo: review this rewritten version of saveUIData/loadUIData
import * as util from '../util/util.js';
import {Vector2, Vector3} from '../util/vectormath.js';
export const UI_SAVE_VERSION = 2;
function debuglog() {
if (window.DEBUG && window.DEBUG.uipaths) {
console.warn.apply(...arguments);
}
}
//avoid circular module ref
let UIBase;
export function setUIBase(cls) {
UIBase = cls;
}
export function saveUIData(node, key) {
if (key === undefined) {
throw new Error("ui_base.saveUIData(): key cannot be undefined");
}
let paths = new Map();
let rec = (path, n) => {
if (!(n instanceof HTMLElement)) {
return;
}
if (n instanceof UIBase) {
let path2 = n.constructor.define().tagname + "|" + path;
paths.set(path2, n.saveData());
}
let ni = 0;
for (let n2 of n.childNodes) {
let path2 = path + `[${ni}]`;
rec(path2, n2);
ni++;
}
if (n.shadow) {
let ni = 0;
for (let n2 of n.shadow.childNodes) {
let path2 = path + `{${ni}}`;
rec(path2, n2);
ni++;
}
}
}
rec("", node, undefined, 0, false);
let paths2 = {};
for (let [path, data] of paths) {
let bad = !data;
bad = bad || (typeof data === "object" && Object.keys(data).length === 0);
if (!bad) {
paths2[path] = data;
}
}
paths = paths2;
return JSON.stringify({
version : UI_SAVE_VERSION,
key,
paths
});
}
//window._saveUIData = saveUIData;
import {tokdef, parser, lexer, PUTLParseError} from '../path-controller/util/parseutil.js';
export function makeParser() {
const tk = (name, re, func) => new tokdef(name, re, func);
let p;
const tokens = [
tk("LSBRACKET", /\[/),
tk("RSBRACKET", /\]/),
tk("LBRACE", /\{/),
tk("RBRACE", /\}/),
tk("NUM", /[0-9]+/, t => t.setValue(parseInt(t.value))),
tk("WS", /[ \t]/, token => undefined), //drop token
];
function p_error(t) {
console.warn(t);
p.userdata = undefined; //prevent reference leak
throw new PUTLParseError("Parse error");
}
const l = new lexer(tokens);
p = new parser(l, p_error);
function consumeAll() {
while (!p.at_end()) {
p.next();
}
}
function p_Start() {
let node = p.userdata;
while (!p.at_end()) {
let t = p.peeknext();
//console.log(node.tagName.toLowerCase());
if (t.type === "LSBRACKET") {
p.next();
let idx = p.expect("NUM");
if (idx >= node.childNodes.length || !(node.childNodes[idx] instanceof HTMLElement)) {
let li = p.lexer.lexpos;
let path = p.lexer.lexdata;
debuglog(idx, p.lexer.lexpos, path.slice(li-3, path.length), node.childNodes);
consumeAll();
return undefined;
}
node = node.childNodes[idx];
p.expect('RSBRACKET');
} else if (t.type === "LBRACE") {
p.next();
let idx = p.expect("NUM");
if (!node.shadow || idx >= node.shadow.childNodes.length || !(node.shadow.childNodes[idx] instanceof HTMLElement)) {
let li = p.lexer.lexpos;
let path = p.lexer.lexdata;
debuglog(idx, p.lexer.lexpos, path.slice(li-3, path.length), node, node.shadow ? node.shadow.childNodes : undefined);
consumeAll();
return undefined;
}
node = node.shadow.childNodes[idx];
p.expect("RBRACE");
} else {
p.expect("LBRACE");
}
}
return node;
}
p.start = p_Start;
return p;
}
const pathParser = makeParser();
export function loadPath(node, key, json) {
console.log(key);
key = key.split("|");
let tagname = key[0].trim();
let path = (key[1] || "").trim();
if (path === "") {
if (tagname === node.constructor.define().tagname) {
node.loadData(json);
} else {
debuglog("Failed to load ui save path", key);
}
return;
}
pathParser.userdata = node;
let child;
try {
child = pathParser.parse(path);
} catch (error) {
if (error instanceof PUTLParseError) {
console.error("Parse error parsing ui save path " + path);
} else {
throw error;
}
}
if (child && child.constructor.define().tagname !== tagname) {
debuglog("Failed to load ui save path", key);
child = undefined;
} else if (!child) {
debuglog("Failed to load ui save path", key);
}
pathParser.userdata = undefined; //prevent reference leak
if (child) {
child.loadData(json);
}
}
export function loadUIData(node, json) {
if (typeof json === 'string') {
json = JSON.parse(json);
}
for (let k in json.paths) {
let v = json.paths[k];
//paranoia check
if (v === undefined) {
continue;
}
loadPath(node, k, v);
}
}
//window._loadUIData = loadUIData;