mirror of
https://github.com/turboderp-org/exui.git
synced 2026-05-11 16:30:18 +00:00
511 lines
16 KiB
JavaScript
511 lines
16 KiB
JavaScript
import * as util from "./util.js";
|
|
|
|
export class Label {
|
|
constructor(className, data, data_id) {
|
|
this.data = data;
|
|
this.data_id = data_id;
|
|
this.element = util.newDiv(null, className);
|
|
this.element.innerHTML = "|";
|
|
}
|
|
|
|
refresh() {
|
|
this.element.innerHTML = this.data[this.data_id];
|
|
}
|
|
}
|
|
|
|
export class LabelTextbox {
|
|
constructor(classNameLabel, textLabel, className, placeholder, data, data_id, validateFunc, updateFunc, cb_auto_id = null, multiline = false) {
|
|
this.data = data;
|
|
this.data_id = data_id;
|
|
this.element = util.newVFlex("vflex_line");
|
|
|
|
if (textLabel) {
|
|
this.label = util.newDiv(null, classNameLabel);
|
|
this.label.innerHTML = textLabel;
|
|
}
|
|
|
|
if (!multiline) {
|
|
this.tb = document.createElement("input");
|
|
this.tb.className = className;
|
|
this.tb.type = "text";
|
|
} else {
|
|
this.tb = document.createElement("textarea");
|
|
this.tb.className = className;
|
|
this.tb.rows = 5;
|
|
}
|
|
|
|
if (placeholder) this.tb.placeholder = placeholder;
|
|
this.tb.spellcheck = false;
|
|
this.tb.value = this.data[this.data_id] ? this.data[this.data_id] : "";
|
|
|
|
this.tb.addEventListener("focus", () => {
|
|
//console.log(this.data[this.data_id]);
|
|
this.textbox_initial = this.tb.value;
|
|
});
|
|
|
|
this.tb.addEventListener("focusout", () => {
|
|
if (this.textbox_initial != this.tb.value) {
|
|
if (!validateFunc || validateFunc(this.tb.value)) {
|
|
this.data[this.data_id] = this.interpret(this.tb.value);
|
|
if (updateFunc) updateFunc();
|
|
} else {
|
|
this.tb.value = this.textbox_initial;
|
|
}
|
|
}
|
|
});
|
|
|
|
this.tb.addEventListener("keydown", (event) => {
|
|
if (event.key === "Escape") {
|
|
this.tb.value = this.textbox_initial;
|
|
this.tb.blur();
|
|
event.preventDefault();
|
|
}
|
|
if (event.key === "Enter" && !event.shiftKey) {
|
|
this.tb.blur();
|
|
}
|
|
});
|
|
|
|
if (textLabel) this.element.appendChild(this.label);
|
|
this.element.appendChild(this.tb);
|
|
|
|
this.cb_auto_id = cb_auto_id;
|
|
if (this.cb_auto_id) {
|
|
this.chkb = document.createElement("input");
|
|
this.chkb.type = "checkbox";
|
|
this.chkb.id = "checkbox_" + cb_auto_id;
|
|
this.chkb.className = "checkbox";
|
|
this.element.appendChild(this.chkb);
|
|
this.chkb_label = document.createElement("label");
|
|
this.chkb_label.htmlFor = this.chkb.id;
|
|
this.chkb_label.className = "checkbox-label";
|
|
this.chkb_label.innerHTML = "Auto";
|
|
this.element.appendChild(this.chkb_label);
|
|
|
|
this.chkb.addEventListener("change", () => {
|
|
this.data[this.cb_auto_id] = this.chkb.checked;
|
|
if (updateFunc) updateFunc();
|
|
});
|
|
}
|
|
}
|
|
|
|
interpret(value) {
|
|
return value;
|
|
}
|
|
|
|
refresh() {
|
|
let v = this.data[this.data_id] ? this.data[this.data_id] : null;
|
|
this.tb.value = v;
|
|
this.refreshCB();
|
|
}
|
|
|
|
refreshCB() {
|
|
if (this.cb_auto_id) {
|
|
this.chkb.checked = this.data[this.cb_auto_id];
|
|
if (this.chkb.checked)
|
|
this.tb.classList.add("hidden");
|
|
else
|
|
this.tb.classList.remove("hidden");
|
|
}
|
|
}
|
|
|
|
setVisible(visible) {
|
|
if (visible)
|
|
this.element.classList.remove("hidden");
|
|
else
|
|
this.element.classList.add("hidden");
|
|
}
|
|
}
|
|
|
|
export class LargeTextbox extends LabelTextbox {
|
|
constructor(className, placeholder, data, data_id, validateFunc, updateFunc) {
|
|
super(null, null, className, placeholder, data, data_id, validateFunc, updateFunc, null, true);
|
|
}
|
|
}
|
|
|
|
export class LabelTextboxButton extends LabelTextbox {
|
|
constructor(classNameLabel, textLabel, className, placeholder, data, data_id, validateFunc, updateFunc, cb_auto_id = null, buttonText, buttonFunc) {
|
|
super(classNameLabel, textLabel, className, placeholder, data, data_id, validateFunc, updateFunc, cb_auto_id);
|
|
|
|
this.buttonFunc = buttonFunc;
|
|
|
|
this.button = document.createElement("span");
|
|
this.button.className = "linkbutton enabled";
|
|
this.button.innerHTML = buttonText;
|
|
this.element.appendChild(this.button);
|
|
|
|
this.button.addEventListener("click", () => {
|
|
if (this.buttonFunc) this.buttonFunc();
|
|
});
|
|
}
|
|
}
|
|
|
|
export class LabelNumbox extends LabelTextbox {
|
|
constructor(classNameLabel, textLabel, className, placeholder, data, data_id, min, max, decimals, updateFunc, cb_auto_id = null) {
|
|
super(classNameLabel, textLabel, className, placeholder, data, data_id, null, updateFunc, cb_auto_id);
|
|
this.min = min;
|
|
this.max = max;
|
|
this.decimals = decimals;
|
|
}
|
|
|
|
interpret(value) {
|
|
let num = parseFloat(value);
|
|
if (isNaN(num)) num = 0;
|
|
if (num < this.min) num = this.min;
|
|
if (num > this.max) num = this.max;
|
|
num = parseFloat(num.toFixed(this.decimals));
|
|
return num;
|
|
}
|
|
|
|
refresh() {
|
|
this.tb.value = this.data[this.data_id].toFixed(this.decimals);
|
|
this.refreshCB();
|
|
}
|
|
}
|
|
|
|
export class LabelText {
|
|
constructor(classNameLabel, textLabel, className, data, data_id) {
|
|
this.data = data;
|
|
this.data_id = data_id;
|
|
this.element = util.newVFlex("vflex_line");
|
|
|
|
this.label = util.newDiv(null, classNameLabel);
|
|
this.label.innerHTML = textLabel;
|
|
|
|
this.text = util.newDiv(null, className);
|
|
|
|
this.element.appendChild(this.label);
|
|
this.element.appendChild(this.text);
|
|
}
|
|
|
|
refresh() {
|
|
this.text.innerHTML = this.data[this.data_id];
|
|
}
|
|
}
|
|
|
|
export class LabelCombobox {
|
|
constructor(classNameLabel, textLabel, className, options, data, data_id, updateFunc) {
|
|
this.data = data;
|
|
this.data_id = data_id;
|
|
this.element = util.newVFlex("vflex_line");
|
|
|
|
this.label = util.newDiv(null, classNameLabel);
|
|
this.label.innerHTML = textLabel;
|
|
|
|
this.cb = document.createElement("select");
|
|
this.cb.className = className;
|
|
for (let i = 0; i < options.length; i++) this.cb.add(new Option(options[i], options[i]));
|
|
|
|
this.cb.addEventListener("change", (event) => {
|
|
this.data[this.data_id] = this.cb.value;
|
|
if (updateFunc) updateFunc();
|
|
} );
|
|
|
|
this.element.appendChild(this.label);
|
|
this.element.appendChild(this.cb);
|
|
|
|
this.refresh();
|
|
}
|
|
|
|
refresh() {
|
|
this.cb.value = this.data[this.data_id];
|
|
}
|
|
}
|
|
|
|
export class LabelCheckbox {
|
|
constructor(classNameLabel, textLabel, className, text, data, data_id, updateFunc) {
|
|
this.data = data;
|
|
this.data_id = data_id;
|
|
this.element = util.newVFlex("vflex_line");
|
|
|
|
if (textLabel) {
|
|
this.label = util.newDiv(null, classNameLabel);
|
|
this.label.innerHTML = textLabel;
|
|
this.element.appendChild(this.label);
|
|
}
|
|
|
|
this.chkb = document.createElement("input");
|
|
this.chkb.type = "checkbox";
|
|
this.chkb.id = "checkbox_" + data_id;
|
|
this.chkb.className = "checkbox";
|
|
this.element.appendChild(this.chkb);
|
|
this.chkb_label = document.createElement("label");
|
|
this.chkb_label.htmlFor = this.chkb.id;
|
|
this.chkb_label.className = className;
|
|
this.chkb_label.innerHTML = text;
|
|
this.element.appendChild(this.chkb_label);
|
|
|
|
this.chkb.addEventListener("change", () => {
|
|
this.data[this.data_id] = this.chkb.checked;
|
|
if (updateFunc) updateFunc();
|
|
});
|
|
|
|
this.refresh();
|
|
}
|
|
|
|
refresh() {
|
|
this.chkb.checked = this.data[this.data_id];
|
|
}
|
|
}
|
|
|
|
export class Button {
|
|
constructor(text, clickFunc, extra_style = null) {
|
|
this.element = util.newDiv(null, "textbutton", text);
|
|
if (extra_style) this.element.classList.add(extra_style);
|
|
this.enabled = true;
|
|
this.clickFunc = clickFunc;
|
|
this.hidden = false;
|
|
|
|
this.element.addEventListener("click", () => {
|
|
if (!this.enabled) return;
|
|
if (this.clickFunc) this.clickFunc();
|
|
});
|
|
}
|
|
|
|
setEnabled(enabled) {
|
|
this.enabled = enabled;
|
|
this.refresh();
|
|
}
|
|
|
|
setHidden(hidden) {
|
|
this.hidden = hidden;
|
|
this.refresh();
|
|
}
|
|
|
|
refresh() {
|
|
if (this.enabled) {
|
|
this.element.classList.add("enabled");
|
|
this.element.classList.remove("disabled");
|
|
} else {
|
|
this.element.classList.remove("enabled");
|
|
this.element.classList.add("disabled");
|
|
}
|
|
if (this.hidden) {
|
|
this.element.classList.add("hidden");
|
|
} else {
|
|
this.element.classList.remove("hidden");
|
|
}
|
|
}
|
|
}
|
|
|
|
export class LinkButton {
|
|
constructor(text, confirmText, clickFunc, extraStyle = null) {
|
|
this.text = text;
|
|
this.confirmText = confirmText;
|
|
this.clickFunc = clickFunc;
|
|
|
|
this.element = util.newDiv(null, null);
|
|
this.inner = document.createElement("span");
|
|
this.inner.classList.add("linkbutton");
|
|
this.inner.classList.add("no-select");
|
|
if (extraStyle) this.inner.classList.add(extraStyle);
|
|
this.element.appendChild(this.inner);
|
|
|
|
this.enabled = true;
|
|
this.refresh();
|
|
|
|
this.inner.innerHTML = this.text;
|
|
|
|
this.inner.addEventListener("click", () => {
|
|
|
|
if (!this.enabled) return;
|
|
if (!this.confirmText) {
|
|
if (this.clickFunc) this.clickFunc();
|
|
} else {
|
|
if (this.inner.classList.contains("danger")) {
|
|
this.inner.innerHTML = this.text;
|
|
this.inner.classList.remove("danger");
|
|
if (this.clickFunc) this.clickFunc();
|
|
clearTimeout(this.timeoutID);
|
|
} else {
|
|
this.inner.innerHTML = this.confirmText;
|
|
this.inner.classList.add("danger");
|
|
this.timeoutID = setTimeout(() => {
|
|
this.inner.classList.remove("danger");
|
|
this.inner.innerHTML = this.text;
|
|
}, 2000);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
setEnabled(enabled) {
|
|
this.enabled = enabled;
|
|
this.refresh();
|
|
}
|
|
|
|
refresh() {
|
|
if (this.enabled) {
|
|
this.inner.classList.add("enabled");
|
|
this.inner.classList.remove("disabled");
|
|
} else {
|
|
this.inner.classList.remove("enabled");
|
|
this.inner.classList.add("disabled");
|
|
}
|
|
}
|
|
|
|
setVisible(visible) {
|
|
if (visible)
|
|
this.element.classList.remove("hidden");
|
|
else
|
|
this.element.classList.add("hidden");
|
|
}
|
|
|
|
}
|
|
|
|
export class EditableLabel {
|
|
constructor(value, allow_empty = false, editFunc = null) {
|
|
this.value = value;
|
|
this.element = util.newDiv(null, null);
|
|
this.inner = document.createElement("p");
|
|
this.inner.innerHTML = value;
|
|
this.element.appendChild(this.inner);
|
|
this.setEditable(false);
|
|
|
|
this.inner.addEventListener("click", () => {
|
|
if (this.inner.classList.contains("editable-label"))
|
|
this.beginEdit();
|
|
});
|
|
|
|
this.allow_empty = allow_empty;
|
|
this.editFunc = editFunc;
|
|
}
|
|
|
|
setEditable(editable) {
|
|
if (editable) {
|
|
this.inner.classList.add("editable-label");
|
|
} else {
|
|
this.inner.classList.remove("editable-label");
|
|
}
|
|
}
|
|
|
|
beginEdit() {
|
|
util.makeEditable(this.inner, (value) => {
|
|
if (!this.allow_empty && value.trim() == "") return false;
|
|
return true;
|
|
}, (id, value) => {
|
|
if (this.editFunc)
|
|
this.editFunc(value);
|
|
});
|
|
}
|
|
}
|
|
|
|
export class CollapsibleSection {
|
|
constructor(className, heading) {
|
|
|
|
this.element = util.newDiv(null, "block");
|
|
|
|
let div_head = util.newDiv(null, (className ? className + " " : "") + "block-header no-select");
|
|
div_head.innerHTML = "<span class='arrow'>⯆</span>" + heading;
|
|
this.element.appendChild(div_head);
|
|
|
|
div_head.addEventListener('click', function() {
|
|
let c = this.nextElementSibling;
|
|
let a = this.children[0];
|
|
if (c.classList.contains("shown")) {
|
|
a.innerHTML = "⯈";
|
|
c.classList.remove("shown");
|
|
} else {
|
|
a.innerHTML = "⯆";
|
|
c.classList.add("shown");
|
|
}
|
|
});
|
|
|
|
this.inner = util.newDiv(null, (className ? className + " " : "") + "block-contents shown");
|
|
this.element.appendChild(this.inner);
|
|
}
|
|
|
|
setVisible(visible) {
|
|
if (visible)
|
|
this.element.classList.remove("hidden");
|
|
else
|
|
this.element.classList.add("hidden");
|
|
}
|
|
}
|
|
|
|
export class SettingsSlider {
|
|
constructor(classNameLabel, textLabel, classNameSlider, classNameTextbox, decimals, min, max, alt_display, data, data_id, updateFunc = null) {
|
|
this.data = data;
|
|
this.data_id = data_id;
|
|
this.decimals = decimals;
|
|
this.min = min;
|
|
this.max = max;
|
|
this.alt_display = alt_display;
|
|
this.updateFunc = updateFunc;
|
|
|
|
this.element = util.newDiv(null, "item-split");
|
|
let label = util.newDiv(null, classNameLabel, textLabel);
|
|
|
|
this.exp = Math.pow(10, decimals);
|
|
|
|
this.slider = document.createElement('input');
|
|
this.slider.type= "range";
|
|
this.slider.className = classNameSlider;
|
|
this.slider.min = this.exp * this.min;
|
|
this.slider.max = this.exp * this.max;
|
|
this.slider.value = this.slider.min;
|
|
|
|
this.textbox = document.createElement('input');
|
|
this.textbox.type= "text";
|
|
this.textbox.className = classNameTextbox;
|
|
this.textbox.rows = 1;
|
|
this.textbox.spellcheck = false;
|
|
|
|
this.slider.addEventListener("input", (event) => {
|
|
this.sliderInput();
|
|
});
|
|
|
|
this.slider.addEventListener("change", (event) => {
|
|
if (updateFunc) updateFunc();
|
|
});
|
|
|
|
this.textbox.addEventListener("focus", (event) => {
|
|
this.originalValue = this.textbox.value;
|
|
});
|
|
|
|
this.textbox.addEventListener("blur", (event) => {
|
|
let nvalue = parseFloat(this.textbox.value);
|
|
if (isNaN(nvalue)) {
|
|
this.textbox.value = this.originalValue;
|
|
return;
|
|
}
|
|
if (nvalue < this.min) nvalue = this.min;
|
|
if (nvalue > this.max) nvalue = this.max;
|
|
nvalue *= this.exp;
|
|
this.slider.value = "" + nvalue;
|
|
this.sliderInput();
|
|
if (updateFunc) updateFunc();
|
|
});
|
|
|
|
this.refresh();
|
|
|
|
this.element.appendChild(label);
|
|
this.element.appendChild(this.slider);
|
|
this.element.appendChild(this.textbox);
|
|
}
|
|
|
|
sliderInput() {
|
|
let v = parseFloat(this.slider.value) / this.exp;
|
|
this.data[this.data_id] = v;
|
|
let t = v.toFixed(this.decimals);
|
|
let st = "";
|
|
if (this.alt_display) {
|
|
if (Object.keys(this.alt_display).includes(t)) st = this.alt_display[t];
|
|
}
|
|
if (st != "") { this.textbox.value = st; this.textbox.classList.add("special"); }
|
|
else { this.textbox.value = t; this.textbox.classList.remove("special"); }
|
|
}
|
|
|
|
refresh() {
|
|
let v = this.data[this.data_id];
|
|
v *= this.exp;
|
|
this.slider.value = "" + v;
|
|
this.sliderInput();
|
|
}
|
|
}
|
|
|
|
export class CheckboxLabel extends LabelCheckbox {
|
|
constructor(className, text, data, data_id, updateFunc) {
|
|
super(null, null, className, text, data, data_id, updateFunc);
|
|
}
|
|
}
|