diff options
| author | Shulhan <ms@kilabit.info> | 2024-09-15 14:32:48 +0700 |
|---|---|---|
| committer | Shulhan <ms@kilabit.info> | 2024-09-15 14:32:48 +0700 |
| commit | d1e96e09438b4a5c7580b86c469e817a61be991f (patch) | |
| tree | 4d81fb2fd62207bbb9162b81083c721ec8fd8e29 /input/number.js | |
| parent | 1cc9c9dd68a3a59c685505228336430624608852 (diff) | |
| download | pakakeh.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.js | 170 |
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 = " ℹ"; + 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; + } +} |
