291 lines
9.8 KiB
JavaScript
291 lines
9.8 KiB
JavaScript
const settingType = {
|
|
COLOR: [0, "#ff0000"],
|
|
TEXT: [1, ""],
|
|
NUMBER: [2, 0],
|
|
BOOLEAN: [3, false],
|
|
SELECT: [4, null]
|
|
}
|
|
class Setting {
|
|
constructor (name, storageName, type, disabled = false, defaultValue = null) {
|
|
this.tabName = null;
|
|
this.name = name;
|
|
this.storageName = storageName;
|
|
this.type = type[0];
|
|
this.disabled = disabled;
|
|
this.defaultValue = defaultValue ?? type[1];
|
|
}
|
|
|
|
set(value) {
|
|
this.value = value;
|
|
const settings = JSON.parse(localStorage.getItem(`${this.tabName}/settings`)) ?? {};
|
|
settings[this.name] = value;
|
|
localStorage.setItem(`${this.tabName}/settings`, JSON.stringify(settings));
|
|
}
|
|
|
|
update() {
|
|
this.value = (JSON.parse(localStorage.getItem(`${this.tabName}/settings`)) ?? {})[this.name] ?? this.defaultValue;
|
|
}
|
|
|
|
get() {
|
|
this.update();
|
|
return this.value;
|
|
}
|
|
|
|
enable() {
|
|
this.disabled = false;
|
|
}
|
|
|
|
disable() {
|
|
this.disabled = true;
|
|
}
|
|
|
|
#parseColor(colorString) {
|
|
if (colorString instanceof Array) return parseColor(colorString[0]);
|
|
if (typeof colorString != "string") return "#ffffff";
|
|
if (colorString.startsWith("rgb(")) {
|
|
const color = colorString.replace("rgb(", "").replace(")", "");
|
|
return `#${color.split(",").map(a => parseInt(a).toString(16)).join("")}`;
|
|
} else {
|
|
if (colorString.startsWith("#")) {
|
|
const color = colorString.slice(1);
|
|
if (color.length == 3) return `#${color.repeat(2)}`;
|
|
else if (color.length == 2) return `#${color.repeat(3)}`;
|
|
else if (color.length >= 6) return `#${color.slice(0, 6)}`;
|
|
else return `#${color}`;
|
|
}
|
|
}
|
|
}
|
|
|
|
build() {
|
|
const value = this.get();
|
|
const id = "betterSettings/" + this.modName + "/" + this.storageName;
|
|
const span = document.createElement("span");
|
|
span.className = "setting-span";
|
|
span.title = 'Default: "' + this.defaultValue + '"' + (this.disabled ? ". This setting is disabled." : "");
|
|
span.innerText = this.name + " ";
|
|
const element = document.createElement("input");
|
|
switch (this.type) {
|
|
case 0: {
|
|
element.type = "color";
|
|
element.disabled = this.disabled;
|
|
element.id = id;
|
|
element.value = value;
|
|
element.onchange = (ev) => {
|
|
this.set(this.#parseColor(ev.target.value));
|
|
}
|
|
break;
|
|
}
|
|
case 1: {
|
|
element.type = "text";
|
|
element.disabled = this.disabled;
|
|
element.id = id;
|
|
element.value = value;
|
|
element.onchange = (ev) => {
|
|
this.set(ev.target.value);
|
|
}
|
|
break;
|
|
}
|
|
case 2: {
|
|
element.type = "number";
|
|
element.disabled = this.disabled;
|
|
element.id = id;
|
|
element.value = value;
|
|
element.onchange = (ev) => {
|
|
this.set(parseFloat(ev.target.value));
|
|
}
|
|
break;
|
|
}
|
|
case 3: {
|
|
element.type = "input";
|
|
element.className = "toggleInput";
|
|
element.disabled = this.disabled;
|
|
element.id = id;
|
|
element.value = value ? "ON" : "OFF";
|
|
element.setAttribute("state", value ? "1" : "0");
|
|
element.onclick = (ev) => {
|
|
ev.target.value = ev.target.value == "ON" ? "OFF" : "ON";
|
|
ev.target.setAttribute("state", ev.target.getAttribute("state") == "1" ? "0" : "1");
|
|
this.set(ev.target.value == "ON");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
span.appendChild(element);
|
|
return span;
|
|
}
|
|
}
|
|
|
|
class SelectSetting extends Setting {
|
|
constructor (name, storageName, values, disabled = false, defaultValue = null) {
|
|
super(name, storageName, settingType.SELECT, disabled, defaultValue ?? values[0][1]);
|
|
this.values = values;
|
|
}
|
|
|
|
build() {
|
|
const value = this.get();
|
|
const id = "betterSettings/" + this.modName + "/" + this.storageName;
|
|
let selected = false;
|
|
const span = document.createElement("span");
|
|
span.className = "setting-span";
|
|
span.title = "Default: " + this.defaultValue;
|
|
span.innerText = this.name;
|
|
const element = document.createElement("select");
|
|
element.id = id;
|
|
for (const val of this.values) {
|
|
const option = document.createElement("option");
|
|
option.value = val[0];
|
|
option.innerText = val[1];
|
|
if (val[0] == value && !selected) {
|
|
option.selected = true;
|
|
selected = true;
|
|
}
|
|
element.appendChild(option);
|
|
}
|
|
element.onchange = (ev) => {
|
|
this.set(ev.target.value);
|
|
}
|
|
span.appendChild(element);
|
|
return span;
|
|
}
|
|
}
|
|
|
|
class SettingsTab {
|
|
constructor (tabName) {
|
|
this.categories = new Map();
|
|
this.registry = new Map();
|
|
this.tabName = tabName;
|
|
}
|
|
|
|
registerSetting(setting, category = "General") {
|
|
setting.tabName = this.tabName.toLowerCase().replace(/ /, "_");
|
|
setting.update();
|
|
if (this.categories.has(category)) this.categories.get(category).push(setting);
|
|
else this.categories.set(category, [setting]);
|
|
this.registry.set(setting.storageName, setting);
|
|
}
|
|
|
|
registerSettings(category = "General", ...settings) {
|
|
for (const setting of settings) {
|
|
this.registerSetting(setting, category);
|
|
}
|
|
}
|
|
|
|
set(name, value) {
|
|
this.registry.get(name)?.set(value);
|
|
}
|
|
|
|
get(name) {
|
|
return this.registry.get(name)?.get();
|
|
}
|
|
|
|
build() {
|
|
const result = document.createElement("div");
|
|
for (const key of this.categories.keys()) {
|
|
const category = document.createElement("div");
|
|
const title = document.createElement("span");
|
|
title.innerText = key;
|
|
title.className = "betterSettings-categoryTitle";
|
|
category.appendChild(title);
|
|
for (const setting of this.categories.get(key)) {
|
|
if (setting instanceof Setting) category.appendChild(setting.build());
|
|
}
|
|
result.append(category, document.createElement("br"));
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
class SettingsManager {
|
|
constructor () {
|
|
this.settings = new Map();
|
|
}
|
|
|
|
registerTab(settingsTab) {
|
|
this.settings.set(settingsTab.tabName, settingsTab);
|
|
}
|
|
|
|
getSettings() {
|
|
return this.settings;
|
|
}
|
|
}
|
|
|
|
const settingsManager = new SettingsManager();
|
|
{
|
|
const injectCss = () => {
|
|
const css = `.modSelectSettingsButton {
|
|
padding: 10px;
|
|
cursor: pointer;
|
|
}
|
|
.modSelectSettingsButton[current=true] {
|
|
background-color: rgb(71, 71, 71);
|
|
}
|
|
.modSelectSettingsButton:hover {
|
|
background-color: rgb(51, 51, 51);
|
|
}
|
|
#modSelectControls {
|
|
margin-bottom: 10px;
|
|
position: relative;
|
|
display: flex;
|
|
overflow-x: scroll;
|
|
}
|
|
.betterSettings-categoryTitle {
|
|
font-size: 1.25em;
|
|
}`;
|
|
const style = document.createElement("style");
|
|
style.innerHTML = css;
|
|
document.head.appendChild(style);
|
|
}
|
|
|
|
const inject = () => {
|
|
const settingsMenu = document.getElementById("settingsMenu");
|
|
const menuText = settingsMenu.querySelector(".menuText");
|
|
const menuTextChildren = menuText.children;
|
|
const generalDiv = document.createElement("div");
|
|
generalDiv.id = "betterSettings/div/general";
|
|
while (menuTextChildren.length > 0) {
|
|
generalDiv.appendChild(menuTextChildren[0]);
|
|
}
|
|
menuText.appendChild(generalDiv);
|
|
const controls = document.createElement("div");
|
|
controls.id = "modSelectControls";
|
|
const generalButton = document.createElement("button");
|
|
generalButton.setAttribute("current", true);
|
|
generalButton.id = "betterSettings/button/general";
|
|
generalButton.className = "modSelectSettingsButton";
|
|
generalButton.innerText = "General";
|
|
generalButton.onclick = (ev) => {
|
|
for (const element of controls.children) {
|
|
element.setAttribute("current", false);
|
|
document.getElementById(element.id.replace("button", "div")).style.display = "none";
|
|
}
|
|
ev.target.setAttribute("current", true);
|
|
document.getElementById("betterSettings/div/general").style.display = "";
|
|
}
|
|
controls.appendChild(generalButton);
|
|
const wrapper = document.createElement("div");
|
|
wrapper.appendChild(generalDiv);
|
|
for (const mod of settingsManager.getSettings().keys()) {
|
|
const modButton = document.createElement("button");
|
|
modButton.setAttribute("current", false);
|
|
modButton.id = "betterSettings/button/" + mod;
|
|
modButton.className = "modSelectSettingsButton";
|
|
modButton.innerText = mod;
|
|
modButton.onclick = (ev) => {
|
|
for (const element of controls.children) {
|
|
element.setAttribute("current", false);
|
|
document.getElementById(element.id.replace("button", "div")).style.display = "none";
|
|
}
|
|
ev.target.setAttribute("current", true);
|
|
document.getElementById("betterSettings/div/" + mod).style.display = "";
|
|
}
|
|
controls.appendChild(modButton);
|
|
const modDiv = document.createElement("div");
|
|
modDiv.style.display = "none";
|
|
modDiv.id = "betterSettings/div/" + mod;
|
|
modDiv.appendChild(settingsManager.getSettings().get(mod).build());
|
|
wrapper.appendChild(modDiv);
|
|
}
|
|
menuText.append(controls, wrapper);
|
|
}
|
|
runAfterLoadList.push(inject, injectCss);
|
|
} |