aboutsummaryrefslogtreecommitdiff
path: root/input/number.js
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2024-09-15 14:32:48 +0700
committerShulhan <ms@kilabit.info>2024-09-15 14:32:48 +0700
commitd1e96e09438b4a5c7580b86c469e817a61be991f (patch)
tree4d81fb2fd62207bbb9162b81083c721ec8fd8e29 /input/number.js
parent1cc9c9dd68a3a59c685505228336430624608852 (diff)
downloadpakakeh.ts-d1e96e09438b4a5c7580b86c469e817a61be991f.tar.xz
all: commit all generate JavaScript files
This is to simplify development on third party where they can clone and include the file directly without installing or running anything to build the files.
Diffstat (limited to 'input/number.js')
-rw-r--r--input/number.js170
1 files changed, 170 insertions, 0 deletions
diff --git a/input/number.js b/input/number.js
new file mode 100644
index 0000000..135066c
--- /dev/null
+++ b/input/number.js
@@ -0,0 +1,170 @@
+// SPDX-FileCopyrightText: 2021 M. Shulhan <ms@kilabit.info>
+// SPDX-License-Identifier: GPL-3.0-or-later
+const WUI_INPUT_NUMBER_CLASS = "wui_input_number";
+const WUI_INPUT_NUMBER_CLASS_HINT = "wui_input_number_hint";
+const WUI_INPUT_NUMBER_CLASS_HINT_TOGGLER = "wui_input_number_hint_toggler";
+const WUI_INPUT_NUMBER_CLASS_INPUT = "wui_input_number_input";
+const WUI_INPUT_NUMBER_CLASS_LABEL = "wui_input_number_label";
+//
+// WuiInputNumber create an HTML input that allow number only, with optional
+// max and min options.
+// The required options are "label" and "value".
+//
+// Format of generated HTML output,
+//
+// <div [id=${id}] class="${WUI_INPUT_NUMBER_CLASS}">
+// <div>
+// <label class="${WUI_INPUT_NUMBER_CLASS_LABEL} [${class_label}]">
+// ${label} | HTMLElement
+// </label>
+// <input
+// class="${WUI_INPUT_NUMBER_CLASS_INPUT} [${class_input}]"
+// [max=${max}]
+// [min=${min}]
+// [disabled=${is_disabled}]
+// value=${value}
+// >
+// [<span class="${WUI_INPUT_NUMBER_CLASS_HINT_TOGGLER}"> i</span>]
+// </div>
+// [<div class="${WUI_INPUT_NUMBER_CLASS_HINT}">${hint}</div>]
+// </div>
+//
+// User can set onChangeHandler to receive new value when the input value
+// changes and valid; otherwise, if the value is invalid, the input
+// background will changes accordingly.
+//
+export class WuiInputNumber {
+ constructor(opts) {
+ this.opts = opts;
+ this.value = 0;
+ this.value = opts.value;
+ this.el = document.createElement("div");
+ if (opts.id) {
+ this.el.id = opts.id;
+ }
+ this.el.classList.add(WUI_INPUT_NUMBER_CLASS);
+ this.el.style.padding = "2px";
+ const wrapper = document.createElement("div");
+ this.generateLabel(wrapper);
+ this.generateInput(wrapper);
+ if (opts.hint) {
+ this.generateHintToggler(wrapper);
+ }
+ this.el.appendChild(wrapper);
+ if (opts.hint) {
+ this.generateHint();
+ }
+ }
+ generateLabel(wrapper) {
+ this.el_label = document.createElement("label");
+ this.el_label.classList.add(WUI_INPUT_NUMBER_CLASS_LABEL);
+ if (this.opts.class_label) {
+ this.el_label.classList.add(this.opts.class_label);
+ }
+ if (typeof this.opts.label === "string") {
+ this.el_label.innerHTML = `${this.opts.label} `;
+ }
+ else {
+ this.el_label.appendChild(this.opts.label);
+ }
+ wrapper.appendChild(this.el_label);
+ }
+ generateInput(wrapper) {
+ this.el_input = document.createElement("input");
+ this.el_input.classList.add(WUI_INPUT_NUMBER_CLASS_INPUT);
+ if (this.opts.class_input) {
+ this.el_input.classList.add(this.opts.class_input);
+ }
+ this.el_input.type = "number";
+ this.el_input.step = "any";
+ this.el_input.value = "" + this.opts.value;
+ let hint = "";
+ if (this.opts.max) {
+ this.el_input.max = "" + this.opts.max;
+ hint = "The maximum value is " + this.opts.max;
+ }
+ if (this.opts.min) {
+ this.el_input.min = "" + this.opts.min;
+ if (hint == "") {
+ hint = "The ";
+ }
+ else {
+ hint += " and ";
+ }
+ hint += "minimum value is " + this.opts.min;
+ }
+ if (hint !== "") {
+ this.el_input.title = hint;
+ }
+ if (this.opts.is_disabled) {
+ this.el_input.disabled = true;
+ }
+ this.el_input.onkeyup = (ev) => {
+ return this.onKeyUp(ev);
+ };
+ wrapper.appendChild(this.el_input);
+ }
+ generateHintToggler(wrapper) {
+ this.el_hint_toggler = document.createElement("span");
+ this.el_hint_toggler.classList.add(WUI_INPUT_NUMBER_CLASS_HINT_TOGGLER);
+ this.el_hint_toggler.innerHTML = " &#x2139;";
+ this.el_hint_toggler.onmouseover = () => {
+ this.el_hint_toggler.style.cursor = "pointer";
+ };
+ this.el_hint_toggler.onclick = () => {
+ this.onClickHintToggler();
+ };
+ wrapper.appendChild(this.el_hint_toggler);
+ }
+ generateHint() {
+ const hint = this.opts.hint || "";
+ this.el_hint = document.createElement("div");
+ this.el_hint.classList.add(WUI_INPUT_NUMBER_CLASS_HINT);
+ this.el_hint.innerHTML = hint;
+ if (this.opts.is_hint_toggled) {
+ this.el_hint.style.display = "block";
+ }
+ else {
+ this.el_hint.style.display = "none";
+ }
+ this.el_hint.style.borderRadius = "2px";
+ this.el_hint.style.padding = "4px";
+ this.el_hint.style.marginTop = "2px";
+ this.el.appendChild(this.el_hint);
+ }
+ onClickHintToggler() {
+ if (this.el_hint.style.display === "none") {
+ this.el_hint.style.display = "block";
+ }
+ else {
+ this.el_hint.style.display = "none";
+ }
+ }
+ onKeyUp(ev) {
+ const target = ev.target;
+ ev.preventDefault();
+ const newValue = +target.value;
+ if (newValue === null) {
+ this.el_input.style.backgroundColor = "lightsalmon";
+ return false;
+ }
+ if (this.opts.max && newValue > this.opts.max) {
+ this.el_input.style.backgroundColor = "lightsalmon";
+ return false;
+ }
+ if (this.opts.min && newValue < this.opts.min) {
+ this.el_input.style.backgroundColor = "lightsalmon";
+ return false;
+ }
+ this.el_input.style.backgroundColor = "white";
+ this.value = newValue;
+ if (this.opts.onChangeHandler) {
+ this.opts.onChangeHandler(this.value);
+ }
+ return true;
+ }
+ // set the input value.
+ set(v) {
+ this.el_input.value = "" + v;
+ }
+}