142 lines
4.2 KiB
JavaScript
142 lines
4.2 KiB
JavaScript
// Options picker
|
|
import {
|
|
OPTION_GROUP_CLASSNAME,
|
|
TALL_CLASSNAME,
|
|
TOOL_INFO_CLASSNAME,
|
|
WIDE_CLASSNAME,
|
|
} from '../config.js';
|
|
import {Tool} from '../tool.js';
|
|
import {show, hide} from '../helper.js';
|
|
|
|
export class OptionsTool extends Tool {
|
|
sectionNames = undefined;
|
|
groups = {};
|
|
|
|
constructor(sectionNames) {
|
|
super();
|
|
this.sectionNames = sectionNames;
|
|
}
|
|
|
|
setContainer(container) {
|
|
super.setContainer(container);
|
|
// Initialize
|
|
for (const sectionName of this.sectionNames) {
|
|
const group = this.sim.options.getSection(sectionName);
|
|
const item = this.visitItem(group);
|
|
this.div.appendChild(item);
|
|
}
|
|
}
|
|
|
|
// For now, `showIf` must be the name of a boolean property, with optional negation
|
|
shouldShow(option) {
|
|
if (option.showIf === undefined) return true;
|
|
const {name, value} = this.deconstructOption(option.showIf);
|
|
return this.sim.getOption(name) === value;
|
|
}
|
|
|
|
deconstructOption(showIf) {
|
|
let name = showIf;
|
|
let value = true;
|
|
if (name.startsWith('!')) {
|
|
value = false;
|
|
name = name.slice(1);
|
|
}
|
|
return {name, value};
|
|
}
|
|
|
|
visitItem(item, path) {
|
|
path = [path, item.name].filter(x => !!x).join('.');
|
|
switch (item.type) {
|
|
case 'group': {
|
|
const groupEl = document.createElement('div');
|
|
groupEl.classList.add(OPTION_GROUP_CLASSNAME);
|
|
const group = {groupEl, items: []};
|
|
this.groups[path] = group;
|
|
if (item.title) {
|
|
const heading = document.createElement('h3');
|
|
heading.innerHTML = item.title;
|
|
groupEl.appendChild(heading);
|
|
groupEl.items.push({itemEl: heading});
|
|
}
|
|
for (const next of item.items) {
|
|
const optionEl = this.visitItem(next, path);
|
|
group.items.push(next);
|
|
if (this.shouldShow(next)) {
|
|
groupEl.appendChild(optionEl);
|
|
}
|
|
if (next.showIf) {
|
|
const {name} = this.deconstructOption(next.showIf);
|
|
this.sim.onOptionSet(name, () => {
|
|
if (this.shouldShow(next)) {
|
|
show({
|
|
items: group.items,
|
|
item: next,
|
|
parentEl: groupEl,
|
|
itemEl: optionEl,
|
|
});
|
|
} else {
|
|
hide({
|
|
items: group.items,
|
|
item: next,
|
|
parentEl: groupEl,
|
|
itemEl: optionEl,
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
}
|
|
return groupEl;
|
|
}
|
|
case 'boolean': {
|
|
const button = document.createElement('button');
|
|
button.innerHTML = item.title;
|
|
if (item.wide === true) button.classList.add(WIDE_CLASSNAME);
|
|
if (item.tall === true) button.classList.add(TALL_CLASSNAME);
|
|
const value = this.sim.getOption(path);
|
|
button.style.opacity = value ? '100%' : '50%';
|
|
this.sim.onOptionSet(path, ({value}) => {
|
|
button.style.opacity = value ? '100%' : '50%';
|
|
});
|
|
button.addEventListener('click', () => {
|
|
const value = this.sim.getOption(path);
|
|
this.sim.setOption(path, !value);
|
|
});
|
|
return button;
|
|
}
|
|
case 'number': {
|
|
const div = document.createElement('div');
|
|
const title = document.createElement('button');
|
|
const input = document.createElement('input');
|
|
const maxLength = item.maxLength || 8;
|
|
div.appendChild(title);
|
|
div.appendChild(input);
|
|
div.classList.add(WIDE_CLASSNAME);
|
|
title.classList.add(TOOL_INFO_CLASSNAME);
|
|
if (item.wide) {
|
|
title.classList.add(WIDE_CLASSNAME);
|
|
input.classList.add(WIDE_CLASSNAME);
|
|
}
|
|
title.innerHTML = item.title;
|
|
input.value = this.sim.getOption(path);
|
|
|
|
input.addEventListener('input', () => {
|
|
input.value = input.value.slice(0, maxLength);
|
|
});
|
|
|
|
input.addEventListener('change', () => {
|
|
this.sim.setOption(path, input.value);
|
|
});
|
|
|
|
this.sim.onOptionSet(path, ({value}) => {
|
|
input.value = value;
|
|
});
|
|
|
|
return div;
|
|
}
|
|
default:
|
|
throw new Error('Unknown option type');
|
|
}
|
|
}
|
|
}
|