@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
184 lines (147 loc) • 4.26 kB
JavaScript
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;