UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

184 lines (147 loc) 4.26 kB
import { noop } from "../../core/function/noop.js"; import { stringify } from "../../core/json/JsonUtils.js"; import { Option } from "./Option.js"; import { OptionAbstract } from "./OptionAbstract.js"; function isOption(c) { return typeof c.read === "function"; } export class OptionGroup extends OptionAbstract { /** * * @type {Array<OptionGroup|Option>} */ children = []; /** * * @param {string[]} path * @returns {OptionGroup|Option} * @throws when path could not be resolved */ resolve(path) { let n = this; for (let i = 0; i < path.length; i++) { const id = path[i]; const current = n; n = current.children.find(c => c.id === id); if (n === undefined) { throw new Error(`Failed to resolve path at '${id}'[${i}], in path: [${path.join(', ')}], available options:[${current.children.map(c => c.id).join(', ')}]`); } } return n; } /** * * @param {Option|OptionGroup} el * @returns {boolean} */ addChild(el) { if (this.getChildById(el.id) !== undefined) { console.error(`Option '${el.id}' already exists, new option is now added`); return false; } this.children.push(el); el.parent = this; return true; } /** * * @param {string} id * @returns {undefined|OptionGroup|Option} */ getChildById(id) { return this.children.find(c => c.id === id); } /** * * @param id * @param read * @param write * @param settings * @returns {OptionGroup} */ add(id, read, write, settings) { let option = new Option(id, read, write, settings); this.addChild(option); return this; } /** * * @param id * @returns {OptionGroup} */ addGroup(id) { let group = new OptionGroup(id); this.addChild(group); return group; } toJSON() { const result = {}; this.children.forEach((c) => { if (c.isTransient) { //skip transient options return; } result[c.id] = c.toJSON(); }); return result; } fromJSON(json) { this.children.forEach(c => { if (json.hasOwnProperty(c.id)) { c.fromJSON(json[c.id]); } }); } /** * * @param {function(Option)} visitor * @param {*} [thisArg] */ traverseOptions(visitor, thisArg) { this.children.forEach(function (c) { if (isOption(c)) { visitor.call(thisArg, c); } else { c.traverseOptions(visitor, thisArg); } }) } /** * * @param {string} path * @param {Storage} storage * @returns {Promise} */ attachToStorage(path, storage) { const group = this; const key = path; const p = new Promise(function (resolve, reject) { storage.load(key, resolve, reject); }); function store() { const json = group.toJSON(); const value = stringify(json); storage.store(key, value, noop, console.error, noop); } return p .then((loaded) => { if (loaded === undefined) { // no loaded data, assume options are loaded for hte first time return; } if (typeof loaded !== "string") { console.error(`expected loaded options to be a string, instead was '${typeof loaded}'`); return; } group.fromJSON(JSON.parse(loaded)); }) .finally(() => { group.traverseOptions(op => op.on.written.add(store)); }); } } /** * @readonly * @type {boolean} */ OptionGroup.prototype.isOptionGroup = true;