aboutsummaryrefslogtreecommitdiff
path: root/input/number.ts
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2021-09-05 15:28:30 +0700
committerShulhan <ms@kilabit.info>2021-09-05 18:36:42 +0700
commit437cee56693f69b2a58f37f8a5ff5b931ea803a2 (patch)
tree540378dcb05d299644d4679db85e80a1731fb9bd /input/number.ts
parent865173ec06c86ebb900c22b066dcf210f2e0452d (diff)
downloadpakakeh.ts-437cee56693f69b2a58f37f8a5ff5b931ea803a2.tar.xz
input: implement class for input number
The WuiInputNumber create an HTML input that allow number only, with optional max and min options. The required options is "label" and "value". Format of generated HTML output, <div [id=${id}] class="${WUI_INPUT_NUMBER_CLASS}"> <div> <label class="${WUI_INPUT_NUMBER_CLASS_LABEL}">${label}</label> <input class="${WUI_INPUT_NUMBER_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 value changes and valid; otherwise, if the value is invalid, the input background will changes accordingly.
Diffstat (limited to 'input/number.ts')
-rw-r--r--input/number.ts177
1 files changed, 177 insertions, 0 deletions
diff --git a/input/number.ts b/input/number.ts
new file mode 100644
index 0000000..11e561b
--- /dev/null
+++ b/input/number.ts
@@ -0,0 +1,177 @@
+export interface WuiInputNumberOpts {
+ label: string
+ value: number
+ id?: string
+ hint?: string
+ max?: number
+ min?: number
+ is_disabled?: boolean
+ onChangeHandler: (new_value: number) => void
+}
+
+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}">${label}</label>
+// <input
+// class="${WUI_INPUT_NUMBER_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 {
+ el: HTMLElement
+ private el_label!: HTMLElement
+ private el_input!: HTMLInputElement
+ private el_hint!: HTMLElement
+ private el_hint_toggler!: HTMLElement
+ private value: number = 0
+
+ constructor(public opts: WuiInputNumberOpts) {
+ 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"
+
+ let 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()
+ }
+ }
+
+ private generateLabel(wrapper: HTMLElement) {
+ this.el_label = document.createElement("label")
+ this.el_label.classList.add(WUI_INPUT_NUMBER_CLASS_LABEL)
+ this.el_label.innerHTML = `${this.opts.label} `
+ wrapper.appendChild(this.el_label)
+ }
+
+ private generateInput(wrapper: HTMLElement) {
+ this.el_input = document.createElement("input") as HTMLInputElement
+ this.el_input.classList.add(WUI_INPUT_NUMBER_CLASS_INPUT)
+ this.el_input.type = "number"
+ 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: KeyboardEvent) => {
+ return this.onKeyUp(ev)
+ }
+
+ wrapper.appendChild(this.el_input)
+ }
+
+ private generateHintToggler(wrapper: HTMLElement) {
+ 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)
+ }
+
+ private generateHint() {
+ let 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
+ this.el_hint.style.display = "none"
+ this.el_hint.style.backgroundColor = "gainsboro"
+ this.el_hint.style.borderRadius = "2px"
+ this.el_hint.style.padding = "4px"
+ this.el.appendChild(this.el_hint)
+ }
+
+ private onClickHintToggler() {
+ if (this.el_hint.style.display === "none") {
+ this.el_hint.style.display = "block"
+ } else {
+ this.el_hint.style.display = "none"
+ }
+ }
+
+ private onKeyUp(ev: KeyboardEvent) {
+ let target = ev.target as HTMLInputElement
+
+ ev.preventDefault()
+ let newValue = parseInt(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
+ }
+}