summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2023-10-23 02:20:07 +0700
committerShulhan <ms@kilabit.info>2023-10-24 22:27:14 +0700
commit891a860299ac76739d59f46280cbed63ff07743e (patch)
treedcf3ccf2c280b20ca1bf2692b794e1976cd34706
parenta798d320563a1f9061a572e2b00537b38e34c4f0 (diff)
downloadpakakeh.ts-891a860299ac76739d59f46280cbed63ff07743e.tar.xz
all: reformat all files
I cannot remember how I reformat those files previously, probably without any tools. This changes reformat the TypeScript files using prettier and HTML files using js-beautify.
-rw-r--r--editor/editor.ts1153
-rw-r--r--editor/example.ts46
-rw-r--r--editor/index.html19
-rw-r--r--index.html23
-rw-r--r--input/checkboxes.ts239
-rw-r--r--input/example.ts404
-rw-r--r--input/index.html21
-rw-r--r--input/number.ts302
-rw-r--r--input/option.ts4
-rw-r--r--input/select.ts272
-rw-r--r--input/string.ts234
-rw-r--r--notif/example.ts68
-rw-r--r--notif/index.html38
-rw-r--r--notif/notif.ts78
-rw-r--r--response.ts8
-rw-r--r--tsconfig.json20
-rw-r--r--vfs/example.ts285
-rw-r--r--vfs/index.html19
-rw-r--r--vfs/vfs.ts304
-rw-r--r--websocket_client.ts260
20 files changed, 1903 insertions, 1894 deletions
diff --git a/editor/editor.ts b/editor/editor.ts
index 7a4fda8..b8fd42a 100644
--- a/editor/editor.ts
+++ b/editor/editor.ts
@@ -1,409 +1,418 @@
// SPDX-FileCopyrightText: 2021 M. Shulhan <ms@kilabit.info>
// SPDX-License-Identifier: GPL-3.0-or-later
-import { WuiVfsNodeInterface } from "../vfs/vfs"
+import { WuiVfsNodeInterface } from "../vfs/vfs";
-const WUI_EDITOR_CLASS = "wui_editor"
-const WUI_EDITOR_CLASS_LINE = "wui_editor_line"
-const WUI_EDITOR_CLASS_LINE_NUMBER = "wui_editor_line_number"
-const WUI_EDITOR_CLASS_LINE_TEXT = "wui_editor_line_text"
+const WUI_EDITOR_CLASS = "wui_editor";
+const WUI_EDITOR_CLASS_LINE = "wui_editor_line";
+const WUI_EDITOR_CLASS_LINE_NUMBER = "wui_editor_line_number";
+const WUI_EDITOR_CLASS_LINE_TEXT = "wui_editor_line_text";
export interface WuiEditorOptions {
- id: string
- is_editable: boolean
+ id: string;
+ is_editable: boolean;
- // Handler that will be called when user select lines.
- OnSelection(begin: number, end: number): void
+ // Handler that will be called when user select lines.
+ OnSelection(begin: number, end: number): void;
- // Handler that will be called when user press CTRL+S.
- OnSave(content: string): void
+ // Handler that will be called when user press CTRL+S.
+ OnSave(content: string): void;
}
export class WuiEditor {
- id: string
- is_editable: boolean
- lines: WuiEditorLine[] = []
- private el!: HTMLElement
- private sel!: Selection
- private active_file: WuiVfsNodeInterface | null = null
- private active_text: HTMLElement | null = null
- private range_begin: number = -1
- private range_end: number = -1
- private raw_lines: string[] = []
- private range!: Range
- private is_key_control: boolean = false
- private unre: WuiEditorUndoRedo = new WuiEditorUndoRedo()
+ id: string;
+ is_editable: boolean;
+ lines: WuiEditorLine[] = [];
+ private el!: HTMLElement;
+ private sel!: Selection;
+ private active_file: WuiVfsNodeInterface | null = null;
+ private active_text: HTMLElement | null = null;
+ private range_begin: number = -1;
+ private range_end: number = -1;
+ private raw_lines: string[] = [];
+ private range!: Range;
+ private is_key_control: boolean = false;
+ private unre: WuiEditorUndoRedo = new WuiEditorUndoRedo();
- constructor(public opts: WuiEditorOptions) {
- this.id = opts.id
- this.is_editable = opts.is_editable
+ constructor(public opts: WuiEditorOptions) {
+ this.id = opts.id;
+ this.is_editable = opts.is_editable;
- let el = document.getElementById(opts.id)
- if (!el) {
- console.error("WuiEditor: element ID not found:", opts.id)
- return
- }
- this.el = el
+ let el = document.getElementById(opts.id);
+ if (!el) {
+ console.error("WuiEditor: element ID not found:", opts.id);
+ return;
+ }
+ this.el = el;
- this.initStyle()
+ this.initStyle();
- this.el.classList.add(WUI_EDITOR_CLASS)
+ this.el.classList.add(WUI_EDITOR_CLASS);
- let sel = window.getSelection()
- if (!sel) {
- console.error("WuiEditor: cannot get window selection", opts.id)
- return
- }
- this.sel = sel
- this.range = document.createRange()
+ let sel = window.getSelection();
+ if (!sel) {
+ console.error("WuiEditor: cannot get window selection", opts.id);
+ return;
+ }
+ this.sel = sel;
+ this.range = document.createRange();
- document.onkeyup = (ev: KeyboardEvent) => {
- this.onKeyupDocument(this, ev)
- }
- }
+ document.onkeyup = (ev: KeyboardEvent) => {
+ this.onKeyupDocument(this, ev);
+ };
+ }
- // GetContent return content of file.
- GetContent(): string {
- let content = ""
- for (let x = 0; x < this.lines.length; x++) {
- if (x > 0) {
- content += "\n"
- }
- content += this.lines[x].el_text.innerText
- }
- return content
- }
+ // GetContent return content of file.
+ GetContent(): string {
+ let content = "";
+ for (let x = 0; x < this.lines.length; x++) {
+ if (x > 0) {
+ content += "\n";
+ }
+ content += this.lines[x].el_text.innerText;
+ }
+ return content;
+ }
- GetSelectionRange(): WuiEditorSelectionRangeInterface {
- return {
- begin_at: this.range_begin,
- end_at: this.range_end,
- } as WuiEditorSelectionRangeInterface
- }
+ GetSelectionRange(): WuiEditorSelectionRangeInterface {
+ return {
+ begin_at: this.range_begin,
+ end_at: this.range_end,
+ } as WuiEditorSelectionRangeInterface;
+ }
- OnClickText(text: HTMLElement) {
- let sel = window.getSelection()
- if (sel) {
- this.sel = sel
- }
- }
+ OnClickText(text: HTMLElement) {
+ let sel = window.getSelection();
+ if (sel) {
+ this.sel = sel;
+ }
+ }
- OnKeyup(x: number, text: HTMLElement, ev: KeyboardEvent) {
- let text_before: string
- let text_after: string
- let off: number
+ OnKeyup(x: number, text: HTMLElement, ev: KeyboardEvent) {
+ let text_before: string;
+ let text_after: string;
+ let off: number;
- switch (ev.key) {
- case "Alt":
- case "ArrowDown":
- case "ArrowLeft":
- case "ArrowRight":
- case "ArrowUp":
- case "CapsLock":
- case "ContextMenu":
- case "End":
- case "Home":
- case "Insert":
- case "OS":
- case "PageDown":
- case "PageUp":
- case "Pause":
- case "PrintScreen":
- case "ScrollLock":
- case "Shift":
- break
+ switch (ev.key) {
+ case "Alt":
+ case "ArrowDown":
+ case "ArrowLeft":
+ case "ArrowRight":
+ case "ArrowUp":
+ case "CapsLock":
+ case "ContextMenu":
+ case "End":
+ case "Home":
+ case "Insert":
+ case "OS":
+ case "PageDown":
+ case "PageUp":
+ case "Pause":
+ case "PrintScreen":
+ case "ScrollLock":
+ case "Shift":
+ break;
- case "Backspace":
- ev.preventDefault()
+ case "Backspace":
+ ev.preventDefault();
- text_before = this.raw_lines[x]
- let el_text_curr = this.lines[x].el_text
- text_after = el_text_curr.innerText
+ text_before = this.raw_lines[x];
+ let el_text_curr = this.lines[x].el_text;
+ text_after = el_text_curr.innerText;
- off = this.sel.focusOffset
- if (off > 0) {
- this.unre.DoUpdate(x, text_before, text_after)
+ off = this.sel.focusOffset;
+ if (off > 0) {
+ this.unre.DoUpdate(x, text_before, text_after);
- this.raw_lines[x] = text_after
- this.setCaret(el_text_curr, off)
- return false
- }
+ this.raw_lines[x] = text_after;
+ this.setCaret(el_text_curr, off);
+ return false;
+ }
- // Join current line with previous.
- let el_text_prev = this.lines[x - 1].el_text
+ // Join current line with previous.
+ let el_text_prev = this.lines[x - 1].el_text;
- this.unre.DoJoin(x - 1, el_text_prev.innerText, el_text_curr.innerText)
+ this.unre.DoJoin(x - 1, el_text_prev.innerText, el_text_curr.innerText);
- off = el_text_prev.innerText.length
- el_text_prev.innerText = el_text_prev.innerText + el_text_curr.innerText
- this.raw_lines[x - 1] = el_text_prev.innerText
+ off = el_text_prev.innerText.length;
+ el_text_prev.innerText =
+ el_text_prev.innerText + el_text_curr.innerText;
+ this.raw_lines[x - 1] = el_text_prev.innerText;
- // Remove the current line
- this.deleteLine(x)
- this.setCaret(el_text_prev, off)
- return false
+ // Remove the current line
+ this.deleteLine(x);
+ this.setCaret(el_text_prev, off);
+ return false;
- case "Control":
- this.is_key_control = false
- break
+ case "Control":
+ this.is_key_control = false;
+ break;
- case "Enter":
- ev.preventDefault()
- break
+ case "Enter":
+ ev.preventDefault();
+ break;
- case "r":
- if (this.is_key_control) {
- ev.preventDefault()
- return
- }
- break
+ case "r":
+ if (this.is_key_control) {
+ ev.preventDefault();
+ return;
+ }
+ break;
- case "z":
- if (this.is_key_control) {
- ev.preventDefault()
- return
- }
- break
+ case "z":
+ if (this.is_key_control) {
+ ev.preventDefault();
+ return;
+ }
+ break;
- default:
- if (this.is_key_control) {
- break
- }
- this.unre.DoUpdate(x, this.raw_lines[x], this.lines[x].el_text.innerText)
- this.raw_lines[x] = this.lines[x].el_text.innerText
- }
- return true
- }
+ default:
+ if (this.is_key_control) {
+ break;
+ }
+ this.unre.DoUpdate(
+ x,
+ this.raw_lines[x],
+ this.lines[x].el_text.innerText,
+ );
+ this.raw_lines[x] = this.lines[x].el_text.innerText;
+ }
+ return true;
+ }
- OnKeydownOnLine(x: number, el_text: HTMLElement, ev: KeyboardEvent) {
- let text_before: string
- let text_after: string
- let off: number
+ OnKeydownOnLine(x: number, el_text: HTMLElement, ev: KeyboardEvent) {
+ let text_before: string;
+ let text_after: string;
+ let off: number;
- switch (ev.key) {
- case "ArrowUp":
- if (x == 0) {
- return false
- }
- ev.preventDefault()
+ switch (ev.key) {
+ case "ArrowUp":
+ if (x == 0) {
+ return false;
+ }
+ ev.preventDefault();
- let el_text = this.lines[x - 1].el_text
- let off = this.sel.focusOffset
- if (off > el_text.innerText.length) {
- off = el_text.innerText.length
- }
- this.setCaret(el_text, off)
+ let el_text = this.lines[x - 1].el_text;
+ let off = this.sel.focusOffset;
+ if (off > el_text.innerText.length) {
+ off = el_text.innerText.length;
+ }
+ this.setCaret(el_text, off);
- if (x == 1) {
- this.el.scrollTop = 0
- } else if (x * 23 < this.el.scrollTop) {
- this.el.scrollTop -= 25
- }
- return false
+ if (x == 1) {
+ this.el.scrollTop = 0;
+ } else if (x * 23 < this.el.scrollTop) {
+ this.el.scrollTop -= 25;
+ }
+ return false;
- case "ArrowDown":
- if (x == this.lines.length - 1) {
- return false
- }
- ev.preventDefault()
+ case "ArrowDown":
+ if (x == this.lines.length - 1) {
+ return false;
+ }
+ ev.preventDefault();
- el_text = this.lines[x + 1].el_text
- off = this.sel.focusOffset
- if (off > el_text.innerText.length) {
- off = el_text.innerText.length
- }
- this.setCaret(el_text, off)
+ el_text = this.lines[x + 1].el_text;
+ off = this.sel.focusOffset;
+ if (off > el_text.innerText.length) {
+ off = el_text.innerText.length;
+ }
+ this.setCaret(el_text, off);
- x += 2
- if (x * 25 >= this.el.clientHeight + this.el.scrollTop) {
- this.el.scrollTop += 25
- }
- return false
+ x += 2;
+ if (x * 25 >= this.el.clientHeight + this.el.scrollTop) {
+ this.el.scrollTop += 25;
+ }
+ return false;
- case "Control":
- this.is_key_control = true
- break
+ case "Control":
+ this.is_key_control = true;
+ break;
- case "Delete":
- ev.preventDefault()
+ case "Delete":
+ ev.preventDefault();
- let is_join_line_after = false
- let el_text_current = this.lines[x].el_text
+ let is_join_line_after = false;
+ let el_text_current = this.lines[x].el_text;
- off = this.sel.focusOffset
- text_before = el_text_current.innerText
- text_after = ""
+ off = this.sel.focusOffset;
+ text_before = el_text_current.innerText;
+ text_after = "";
- if (text_before.length === 0 || off === text_before.length) {
- // Current line is empty, join the next line to current
- // line; or
- // Current offset is at the end of text, join the next
- // line to current line.
- is_join_line_after = true
- }
+ if (text_before.length === 0 || off === text_before.length) {
+ // Current line is empty, join the next line to current
+ // line; or
+ // Current offset is at the end of text, join the next
+ // line to current line.
+ is_join_line_after = true;
+ }
- if (is_join_line_after) {
- if (x+1 < this.lines.length) {
- let el_text_after = this.lines[x+1].el_text
- text_after = el_text_after.innerText
- el_text_after.innerText = ""
+ if (is_join_line_after) {
+ if (x + 1 < this.lines.length) {
+ let el_text_after = this.lines[x + 1].el_text;
+ text_after = el_text_after.innerText;
+ el_text_after.innerText = "";
- this.unre.DoJoin(x, text_before, text_after)
+ this.unre.DoJoin(x, text_before, text_after);
- this.deleteLine(x+1)
- text_after = text_before + text_after
- }
- } else {
- text_after = text_before.slice(0, off) + text_before.slice(off+1, text_before.length)
+ this.deleteLine(x + 1);
+ text_after = text_before + text_after;
+ }
+ } else {
+ text_after =
+ text_before.slice(0, off) +
+ text_before.slice(off + 1, text_before.length);
- this.unre.DoUpdate(x, text_before, text_after)
- }
+ this.unre.DoUpdate(x, text_before, text_after);
+ }
- this.lines[x].el_text.innerText = text_after
- this.raw_lines[x] = text_after
- this.setCaret(el_text_current, off)
- break
+ this.lines[x].el_text.innerText = text_after;
+ this.raw_lines[x] = text_after;
+ this.setCaret(el_text_current, off);
+ break;
- case "Enter":
- ev.preventDefault()
+ case "Enter":
+ ev.preventDefault();
- off = this.sel.focusOffset
- let text = this.lines[x].el_text.innerText
- text_before = text.slice(0, off)
- text_after = text.slice(off, text.length)
+ off = this.sel.focusOffset;
+ let text = this.lines[x].el_text.innerText;
+ text_before = text.slice(0, off);
+ text_after = text.slice(off, text.length);
- this.unre.DoSplit(x, text_before, text_after)
+ this.unre.DoSplit(x, text_before, text_after);
- this.lines[x].el_text.innerText = text_before
- this.raw_lines[x] = text_before
+ this.lines[x].el_text.innerText = text_before;
+ this.raw_lines[x] = text_before;
- this.insertNewline(x + 1, text_after)
- if (x + 3 >= this.raw_lines.length) {
- this.el.scrollTop = this.el.scrollHeight
- }
- break
+ this.insertNewline(x + 1, text_after);
+ if (x + 3 >= this.raw_lines.length) {
+ this.el.scrollTop = this.el.scrollHeight;
+ }
+ break;
- case "Tab":
- ev.preventDefault()
+ case "Tab":
+ ev.preventDefault();
- el_text = this.lines[x].el_text
- off = this.sel.focusOffset
- text_before = el_text.innerText
- text_after =
- text_before.slice(0, off) + "\t" + text_before.slice(off, text_before.length)
+ el_text = this.lines[x].el_text;
+ off = this.sel.focusOffset;
+ text_before = el_text.innerText;
+ text_after =
+ text_before.slice(0, off) +
+ "\t" +
+ text_before.slice(off, text_before.length);
- this.unre.DoUpdate(x, text_before, text_after)
- el_text.innerText = text_after
- this.raw_lines[x] = text_after
+ this.unre.DoUpdate(x, text_before, text_after);
+ el_text.innerText = text_after;
+ this.raw_lines[x] = text_after;
- this.setCaret(el_text, off + 1)
- break
+ this.setCaret(el_text, off + 1);
+ break;
- case "r":
- if (this.is_key_control) {
- ev.preventDefault()
- this.doRedo()
- return
- }
- break
+ case "r":
+ if (this.is_key_control) {
+ ev.preventDefault();
+ this.doRedo();
+ return;
+ }
+ break;
- case "s":
- if (this.is_key_control) {
- ev.preventDefault()
- ev.stopPropagation()
- if (this.opts.OnSave) {
- this.opts.OnSave(this.GetContent())
- }
- return false
- }
- break
+ case "s":
+ if (this.is_key_control) {
+ ev.preventDefault();
+ ev.stopPropagation();
+ if (this.opts.OnSave) {
+ this.opts.OnSave(this.GetContent());
+ }
+ return false;
+ }
+ break;
- case "z":
- if (this.is_key_control) {
- ev.preventDefault()
- this.doUndo()
- return
- }
- break
- }
- }
+ case "z":
+ if (this.is_key_control) {
+ ev.preventDefault();
+ this.doUndo();
+ return;
+ }
+ break;
+ }
+ }
- OnMouseDownAtLine(x: number) {
- this.range_begin = x
- }
+ OnMouseDownAtLine(x: number) {
+ this.range_begin = x;
+ }
- OnMouseUpAtLine(x: number) {
- this.range_end = x
- if (this.range_end < this.range_begin) {
- return
- }
- let y = 0
- for (; y < this.range_begin; y++) {
- this.el.children[y].setAttribute("style", "")
- }
- for (; y <= this.range_end; y++) {
- this.el.children[y].setAttribute("style", "background-color:lightsalmon")
- }
- for (; y < this.el.children.length; y++) {
- this.el.children[y].setAttribute("style", "")
- }
- if (this.opts.OnSelection) {
- this.opts.OnSelection(this.range_begin, this.range_end)
- }
- }
+ OnMouseUpAtLine(x: number) {
+ this.range_end = x;
+ if (this.range_end < this.range_begin) {
+ return;
+ }
+ let y = 0;
+ for (; y < this.range_begin; y++) {
+ this.el.children[y].setAttribute("style", "");
+ }
+ for (; y <= this.range_end; y++) {
+ this.el.children[y].setAttribute("style", "background-color:lightsalmon");
+ }
+ for (; y < this.el.children.length; y++) {
+ this.el.children[y].setAttribute("style", "");
+ }
+ if (this.opts.OnSelection) {
+ this.opts.OnSelection(this.range_begin, this.range_end);
+ }
+ }
- //
- // SetEditOff make the content not editable.
- //
- SetEditOff() {
- for (let x = 0; x < this.lines.length; x++) {
- this.lines[x].SetEditOff()
- }
- }
+ //
+ // SetEditOff make the content not editable.
+ //
+ SetEditOff() {
+ for (let x = 0; x < this.lines.length; x++) {
+ this.lines[x].SetEditOff();
+ }
+ }
- //
- // SetEditOn make the content to be editable.
- //
- SetEditOn() {
- for (let x = 0; x < this.lines.length; x++) {
- this.lines[x].SetEditOn()
- }
- }
+ //
+ // SetEditOn make the content to be editable.
+ //
+ SetEditOn() {
+ for (let x = 0; x < this.lines.length; x++) {
+ this.lines[x].SetEditOn();
+ }
+ }
- // Open the node for editing.
- // The content MUST be encoded in base64.
- Open(node: WuiVfsNodeInterface): void {
- this.active_file = node
+ // Open the node for editing.
+ // The content MUST be encoded in base64.
+ Open(node: WuiVfsNodeInterface): void {
+ this.active_file = node;
- let content = atob(node.content)
- content = content.replace("\r\n", "\n")
- this.raw_lines = content.split("\n")
+ let content = atob(node.content);
+ content = content.replace("\r\n", "\n");
+ this.raw_lines = content.split("\n");
- this.lines = []
- for (let x = 0; x < this.raw_lines.length; x++) {
- let line = new WuiEditorLine(x, this.raw_lines[x], this)
- this.lines.push(line)
- }
+ this.lines = [];
+ for (let x = 0; x < this.raw_lines.length; x++) {
+ let line = new WuiEditorLine(x, this.raw_lines[x], this);
+ this.lines.push(line);
+ }
- this.render()
- }
+ this.render();
+ }
- // ClearSelection clear selection range indicator.
- ClearSelection() {
- if (this.range_begin < 0 || this.range_end == 0) {
- return
- }
- for (let x = this.range_begin; x <= this.range_end; x++) {
- this.el.children[x].setAttribute("style", "")
- }
- this.range_begin = -1
- this.range_end = -1
- }
+ // ClearSelection clear selection range indicator.
+ ClearSelection() {
+ if (this.range_begin < 0 || this.range_end == 0) {
+ return;
+ }
+ for (let x = this.range_begin; x <= this.range_end; x++) {
+ this.el.children[x].setAttribute("style", "");
+ }
+ this.range_begin = -1;
+ this.range_end = -1;
+ }
- private initStyle() {
- let style = document.createElement("style")
- style.type = "text/css"
- style.innerText = `
+ private initStyle() {
+ let style = document.createElement("style");
+ style.type = "text/css";
+ style.innerText = `
[contenteditable] {
outline: 0px solid transparent;
}
@@ -439,274 +448,278 @@ export class WuiEditor {
white-space: pre-wrap;
width: calc(100% - 60px);
}
- `
- document.head.appendChild(style)
- }
+ `;
+ document.head.appendChild(style);
+ }
- private doJoin(changes: WuiEditorActionChangesInterface) {
- this.lines[changes.curr_line].el_text.innerText = changes.curr_text
- this.deleteLine(changes.next_line)
- this.setCaret(this.lines[changes.curr_line].el_text, 0)
- }
+ private doJoin(changes: WuiEditorActionChangesInterface) {
+ this.lines[changes.curr_line].el_text.innerText = changes.curr_text;
+ this.deleteLine(changes.next_line);
+ this.setCaret(this.lines[changes.curr_line].el_text, 0);
+ }
- private doSplit(changes: WuiEditorActionChangesInterface) {
- this.lines[changes.curr_line].el_text.innerText = changes.curr_text
- this.insertNewline(changes.next_line, changes.next_text)
- }
+ private doSplit(changes: WuiEditorActionChangesInterface) {
+ this.lines[changes.curr_line].el_text.innerText = changes.curr_text;
+ this.insertNewline(changes.next_line, changes.next_text);
+ }
- private doUpdate(changes: WuiEditorActionChangesInterface) {
- this.lines[changes.curr_line].el_text.innerText = changes.curr_text
- this.setCaret(this.lines[changes.curr_line].el_text, 0)
- }
+ private doUpdate(changes: WuiEditorActionChangesInterface) {
+ this.lines[changes.curr_line].el_text.innerText = changes.curr_text;
+ this.setCaret(this.lines[changes.curr_line].el_text, 0);
+ }
- private doRedo() {
- const act = this.unre.Redo()
- if (!act) {
- return
- }
- switch (act.kind) {
- case "join":
- this.doJoin(act.after)
- break
- case "split":
- this.doSplit(act.after)
- break
- case "update":
- this.doUpdate(act.after)
- break
- }
- }
+ private doRedo() {
+ const act = this.unre.Redo();
+ if (!act) {
+ return;
+ }
+ switch (act.kind) {
+ case "join":
+ this.doJoin(act.after);
+ break;
+ case "split":
+ this.doSplit(act.after);
+ break;
+ case "update":
+ this.doUpdate(act.after);
+ break;
+ }
+ }
- private doUndo() {
- const act = this.unre.Undo()
- if (!act) {
- return
- }
- switch (act.kind) {
- case "join":
- this.doSplit(act.before)
- break
- case "split":
- this.doJoin(act.before)
- break
- case "update":
- this.doUpdate(act.before)
- break
- }
- }
+ private doUndo() {
+ const act = this.unre.Undo();
+ if (!act) {
+ return;
+ }
+ switch (act.kind) {
+ case "join":
+ this.doSplit(act.before);
+ break;
+ case "split":
+ this.doJoin(act.before);
+ break;
+ case "update":
+ this.doUpdate(act.before);
+ break;
+ }
+ }
- private deleteLine(x: number) {
- this.lines.splice(x, 1)
- this.raw_lines.splice(x, 1)
+ private deleteLine(x: number) {
+ this.lines.splice(x, 1);
+ this.raw_lines.splice(x, 1);
- // Reset the line numbers.
- for (; x < this.lines.length; x++) {
- this.lines[x].SetNumber(x)
- }
- this.render()
- }
+ // Reset the line numbers.
+ for (; x < this.lines.length; x++) {
+ this.lines[x].SetNumber(x);
+ }
+ this.render();
+ }
- private insertNewline(x: number, text: string) {
- let newline = new WuiEditorLine(x, text, this)
- for (let y = x; y < this.lines.length; y++) {
- this.lines[y].SetNumber(y + 1)
- }
+ private insertNewline(x: number, text: string) {
+ let newline = new WuiEditorLine(x, text, this);
+ for (let y = x; y < this.lines.length; y++) {
+ this.lines[y].SetNumber(y + 1);
+ }
- this.lines.splice(x, 0, newline)
- this.raw_lines.splice(x, 0, text)
+ this.lines.splice(x, 0, newline);
+ this.raw_lines.splice(x, 0, text);
- this.render()
- this.setCaret(newline.el_text, 0)
- }
+ this.render();
+ this.setCaret(newline.el_text, 0);
+ }
- private onKeyupDocument(ed: WuiEditor, ev: KeyboardEvent) {
- switch (ev.key) {
- case "Escape":
- ev.preventDefault()
- ed.ClearSelection()
- break
- }
- return true
- }
+ private onKeyupDocument(ed: WuiEditor, ev: KeyboardEvent) {
+ switch (ev.key) {
+ case "Escape":
+ ev.preventDefault();
+ ed.ClearSelection();
+ break;
+ }
+ return true;
+ }
- private render() {
- this.el.innerHTML = ""
- for (const line of this.lines) {
- this.el.appendChild(line.el)
- }
- }
+ private render() {
+ this.el.innerHTML = "";
+ for (const line of this.lines) {
+ this.el.appendChild(line.el);
+ }
+ }
- private setCaret(el_text: HTMLElement, off: number) {
- if (el_text.firstChild) {
- this.range.setStart(el_text.firstChild, off)
- } else {
- this.range.setStart(el_text, off)
- }
- this.range.collapse(true)
- this.sel.removeAllRanges()
- this.sel.addRange(this.range)
- }
+ private setCaret(el_text: HTMLElement, off: number) {
+ if (el_text.firstChild) {
+ this.range.setStart(el_text.firstChild, off);
+ } else {
+ this.range.setStart(el_text, off);
+ }
+ this.range.collapse(true);
+ this.sel.removeAllRanges();
+ this.sel.addRange(this.range);
+ }
}
class WuiEditorLine {
- private line_num: number = 0
- el!: HTMLElement
- el_number!: HTMLElement
- el_text!: HTMLElement
+ private line_num: number = 0;
+ el!: HTMLElement;
+ el_number!: HTMLElement;
+ el_text!: HTMLElement;
- constructor(public x: number, public text: string, ed: WuiEditor) {
- this.line_num = x
- this.el = document.createElement("div")
- this.el.classList.add(WUI_EDITOR_CLASS_LINE)
+ constructor(
+ public x: number,
+ public text: string,
+ ed: WuiEditor,
+ ) {
+ this.line_num = x;
+ this.el = document.createElement("div");
+ this.el.classList.add(WUI_EDITOR_CLASS_LINE);
- this.el_number = document.createElement("span")
- this.el_number.classList.add(WUI_EDITOR_CLASS_LINE_NUMBER)
- this.el_number.innerText = this.line_num + 1 + ""
+ this.el_number = document.createElement("span");
+ this.el_number.classList.add(WUI_EDITOR_CLASS_LINE_NUMBER);
+ this.el_number.innerText = this.line_num + 1 + "";
- this.el_number.onmousedown = (ev: MouseEvent) => {
- ed.OnMouseDownAtLine(this.line_num)
- }
- this.el_number.onmouseup = (ev: MouseEvent) => {
- ed.OnMouseUpAtLine(this.line_num)
- }
+ this.el_number.onmousedown = (ev: MouseEvent) => {
+ ed.OnMouseDownAtLine(this.line_num);
+ };
+ this.el_number.onmouseup = (ev: MouseEvent) => {
+ ed.OnMouseUpAtLine(this.line_num);
+ };
- this.el_text = document.createElement("span")
- this.el_text.classList.add(WUI_EDITOR_CLASS_LINE_TEXT)
- this.el_text.innerText = text
- this.el_text.contentEditable = "true"
+ this.el_text = document.createElement("span");
+ this.el_text.classList.add(WUI_EDITOR_CLASS_LINE_TEXT);
+ this.el_text.innerText = text;
+ this.el_text.contentEditable = "true";
- this.el_text.onclick = (ev: MouseEvent) => {
- ed.OnClickText(this.el_text)
- }
+ this.el_text.onclick = (ev: MouseEvent) => {
+ ed.OnClickText(this.el_text);
+ };
- this.el_text.onkeydown = (ev: KeyboardEvent) => {
- return ed.OnKeydownOnLine(this.line_num, this.el_text, ev)
- }
- this.el_text.onkeyup = (ev: KeyboardEvent) => {
- return ed.OnKeyup(this.line_num, this.el_text, ev)
- }
+ this.el_text.onkeydown = (ev: KeyboardEvent) => {
+ return ed.OnKeydownOnLine(this.line_num, this.el_text, ev);
+ };
+ this.el_text.onkeyup = (ev: KeyboardEvent) => {
+ return ed.OnKeyup(this.line_num, this.el_text, ev);
+ };
- this.el_text.addEventListener("paste", (ev: ClipboardEvent) => {
- if (!ev.clipboardData) {
- return
- }
- ev.preventDefault()
- const text = ev.clipboardData.getData("text/plain")
- document.execCommand("insertHTML", false, text)
- })
+ this.el_text.addEventListener("paste", (ev: ClipboardEvent) => {
+ if (!ev.clipboardData) {
+ return;
+ }
+ ev.preventDefault();
+ const text = ev.clipboardData.getData("text/plain");
+ document.execCommand("insertHTML", false, text);
+ });
- this.el.appendChild(this.el_number)
- this.el.appendChild(this.el_text)
- }
+ this.el.appendChild(this.el_number);
+ this.el.appendChild(this.el_text);
+ }
- SetNumber(x: number) {
- this.line_num = x
- this.el_number.innerText = x + 1 + ""
- }
+ SetNumber(x: number) {
+ this.line_num = x;
+ this.el_number.innerText = x + 1 + "";
+ }
- SetEditOn() {
- this.el_text.contentEditable = "true"
- }
+ SetEditOn() {
+ this.el_text.contentEditable = "true";
+ }
- SetEditOff() {
- this.el_text.contentEditable = "false"
- }
+ SetEditOff() {
+ this.el_text.contentEditable = "false";
+ }
}
//
// WuiEditorUndoRedo store the state of actions.
//
class WuiEditorUndoRedo {
- private idx: number = 0
- private actions: WuiEditorActionInterface[] = []
+ private idx: number = 0;
+ private actions: WuiEditorActionInterface[] = [];
- DoJoin(prevLine: number, prevText: string, curr_text: string) {
- let curr_line = prevLine + 1
- let action: WuiEditorActionInterface = {
- kind: "join",
- before: {
- curr_line: prevLine,
- curr_text: prevText,
- next_line: prevLine + 1,
- next_text: curr_text,
- },
- after: {
- curr_line: prevLine,
- curr_text: prevText + curr_text,
- next_line: prevLine + 1,
- next_text: "",
- },
- }
- if (this.actions.length > 0) {
- this.actions = this.actions.slice(0, this.idx)
- }
- this.actions.push(action)
- this.idx++
- }
+ DoJoin(prevLine: number, prevText: string, curr_text: string) {
+ let curr_line = prevLine + 1;
+ let action: WuiEditorActionInterface = {
+ kind: "join",
+ before: {
+ curr_line: prevLine,
+ curr_text: prevText,
+ next_line: prevLine + 1,
+ next_text: curr_text,
+ },
+ after: {
+ curr_line: prevLine,
+ curr_text: prevText + curr_text,
+ next_line: prevLine + 1,
+ next_text: "",
+ },
+ };
+ if (this.actions.length > 0) {
+ this.actions = this.actions.slice(0, this.idx);
+ }
+ this.actions.push(action);
+ this.idx++;
+ }
- DoSplit(curr_line: number, curr_text: string, next_text: string) {
- let action = {
- kind: "split",
- before: {
- curr_line: curr_line,
- curr_text: curr_text + next_text,
- next_line: curr_line + 1,
- next_text: "",
- },
- after: {
- curr_line: curr_line,
- curr_text: curr_text,
- next_line: curr_line + 1,
- next_text: next_text,
- },
- }
- if (this.actions.length > 0) {
- this.actions = this.actions.slice(0, this.idx)
- }
- this.actions.push(action)
- this.idx++
- }
+ DoSplit(curr_line: number, curr_text: string, next_text: string) {
+ let action = {
+ kind: "split",
+ before: {
+ curr_line: curr_line,
+ curr_text: curr_text + next_text,
+ next_line: curr_line + 1,
+ next_text: "",
+ },
+ after: {
+ curr_line: curr_line,
+ curr_text: curr_text,
+ next_line: curr_line + 1,
+ next_text: next_text,
+ },
+ };
+ if (this.actions.length > 0) {
+ this.actions = this.actions.slice(0, this.idx);
+ }
+ this.actions.push(action);
+ this.idx++;
+ }
- DoUpdate(line_num: number, text_before: string, text_after: string) {
- const action: WuiEditorActionInterface = {
- kind: "update",
- before: {
- curr_line: line_num,
- curr_text: text_before,
- next_line: 0,
- next_text: "",
- },
- after: {
- curr_line: line_num,
- curr_text: text_after,
- next_line: 0,
- next_text: "",
- },
- }
+ DoUpdate(line_num: number, text_before: string, text_after: string) {
+ const action: WuiEditorActionInterface = {
+ kind: "update",
+ before: {
+ curr_line: line_num,
+ curr_text: text_before,
+ next_line: 0,
+ next_text: "",
+ },
+ after: {
+ curr_line: line_num,
+ curr_text: text_after,
+ next_line: 0,
+ next_text: "",
+ },
+ };
- if (this.actions.length > 0) {
- this.actions = this.actions.slice(0, this.idx)
- }
- this.actions.push(action)
- this.idx++
- }
+ if (this.actions.length > 0) {
+ this.actions = this.actions.slice(0, this.idx);
+ }
+ this.actions.push(action);
+ this.idx++;
+ }
- Undo(): WuiEditorActionInterface | null {
- if (this.idx == 0) {
- return null
- }
- this.idx--
- return this.actions[this.idx]
- }
+ Undo(): WuiEditorActionInterface | null {
+ if (this.idx == 0) {
+ return null;
+ }
+ this.idx--;
+ return this.actions[this.idx];
+ }
- Redo(): WuiEditorActionInterface | null {
- if (this.idx == this.actions.length) {
- return null
- }
- let action = this.actions[this.idx]
- this.idx++
- return action
- }
+ Redo(): WuiEditorActionInterface | null {
+ if (this.idx == this.actions.length) {
+ return null;
+ }
+ let action = this.actions[this.idx];
+ this.idx++;
+ return action;
+ }
}
// There are three kind of action
@@ -716,19 +729,19 @@ class WuiEditorUndoRedo {
// * join: join line using backspace.
//
interface WuiEditorActionInterface {
- kind: string
- before: WuiEditorActionChangesInterface
- after: WuiEditorActionChangesInterface
+ kind: string;
+ before: WuiEditorActionChangesInterface;
+ after: WuiEditorActionChangesInterface;
}
interface WuiEditorActionChangesInterface {
- curr_line: number
- curr_text: string
- next_line: number
- next_text: string
+ curr_line: number;
+ curr_text: string;
+ next_line: number;
+ next_text: string;
}
interface WuiEditorSelectionRangeInterface {
- begin_at: number
- end_at: number
+ begin_at: number;
+ end_at: number;
}
diff --git a/editor/example.ts b/editor/example.ts
index 4cca24d..19bc0b9 100644
--- a/editor/example.ts
+++ b/editor/example.ts
@@ -1,19 +1,19 @@
// SPDX-FileCopyrightText: 2019 M. Shulhan <ms@kilabit.info>
// SPDX-License-Identifier: GPL-3.0-or-later
-import { WuiEditor, WuiEditorOptions } from "./editor.js"
-import { WuiVfsNodeInterface } from "../vfs/vfs.js"
+import { WuiEditor, WuiEditorOptions } from "./editor.js";
+import { WuiVfsNodeInterface } from "../vfs/vfs.js";
let nodeFile: WuiVfsNodeInterface = {
- name: "Test",
- path: "/test",
- is_dir: false,
- content_type: "text/plain",
- mod_time: 0,
- size: 0,
- mode: "",
- childs: [],
- content: btoa(`mkdir -p \${HOME}/aur/stackdriver-collectd
+ name: "Test",
+ path: "/test",
+ is_dir: false,
+ content_type: "text/plain",
+ mod_time: 0,
+ size: 0,
+ mode: "",
+ childs: [],
+ content: btoa(`mkdir -p \${HOME}/aur/stackdriver-collectd
git -C \${HOME}/aur/stackdriver-collectd clone \\
ssh://aur@aur.archlinux.org/stackdriver-collectd.git .
@@ -44,17 +44,17 @@ sudo systemctl status stackdriver-collectd
sudo systemctl restart telegraf
sudo systemctl status telegraf
`),
-}
+};
let opts = {
- id: "editor",
- is_editable: true,
- OnSelection: (begin: number, end: number) => {
- console.log("OnSelection: ", begin, end)
- },
- OnSave: (content: string) => {
- console.log("OnSave: ", content)
- }
-}
-let wuiEditor = new WuiEditor(opts)
-wuiEditor.Open(nodeFile)
+ id: "editor",
+ is_editable: true,
+ OnSelection: (begin: number, end: number) => {
+ console.log("OnSelection: ", begin, end);
+ },
+ OnSave: (content: string) => {
+ console.log("OnSave: ", content);
+ },
+};
+let wuiEditor = new WuiEditor(opts);
+wuiEditor.Open(nodeFile);
diff --git a/editor/index.html b/editor/index.html
index 46f5441..04a64f5 100644
--- a/editor/index.html
+++ b/editor/index.html
@@ -2,12 +2,15 @@
<!-- SPDX-FileCopyrightText: 2021 M. Shulhan <ms@kilabit.info> -->
<!-- SPDX-License-Identifier: GPL-3.0-or-later -->
<html>
- <head>
- <meta charset="UTF-8" />
- <title>WUI - editor</title>
- </head>
- <body>
- <div id="editor"></div>
- <script type="module" src="/editor/example.js"></script>
- </body>
+
+<head>
+ <meta charset="UTF-8" />
+ <title>WUI - editor</title>
+</head>
+
+<body>
+ <div id="editor"></div>
+ <script type="module" src="/editor/example.js"></script>
+</body>
+
</html>
diff --git a/index.html b/index.html
index 3d33ed4..93cfdaa 100644
--- a/index.html
+++ b/index.html
@@ -2,14 +2,17 @@
<!-- SPDX-FileCopyrightText: 2021 M. Shulhan <ms@kilabit.info -->
<!-- SPDX-License-Identifier: GPL-3.0-or-later -->
<html>
- <head>
- <meta charset="UTF-8" />
- <title>WUI - web user interface</title>
- </head>
- <body>
- <h3><a href="/editor"> Editor </a></h3>
- <h3><a href="/input"> Input </a></h3>
- <h3><a href="/notif"> Notification </a></h3>
- <h3><a href="/vfs"> VFS </a></h3>
- </body>
+
+<head>
+ <meta charset="UTF-8" />
+ <title>WUI - web user interface</title>
+</head>
+
+<body>
+ <h3><a href="/editor"> Editor </a></h3>
+ <h3><a href="/input"> Input </a></h3>
+ <h3><a href="/notif"> Notification </a></h3>
+ <h3><a href="/vfs"> VFS </a></h3>
+</body>
+
</html>
diff --git a/input/checkboxes.ts b/input/checkboxes.ts
index 480859d..72d3da8 100644
--- a/input/checkboxes.ts
+++ b/input/checkboxes.ts
@@ -1,32 +1,33 @@
// SPDX-FileCopyrightText: 2021 M. Shulhan <ms@kilabit.info>
// SPDX-License-Identifier: GPL-3.0-or-later
-import { WuiInputOption } from "./option.js"
+import { WuiInputOption } from "./option.js";
export interface WuiKeyValue {
- [key: string]: string
+ [key: string]: string;
}
export interface WuiKeySelectOption {
- [key: string]: WuiInputOption
+ [key: string]: WuiInputOption;
}
export interface WuiInputCheckboxesOpts {
- label: string
- name: string
- options: WuiKeySelectOption
- id?: string
- hint?: string
- is_disabled?: boolean
- is_hint_toggled?: boolean
- onChangeHandler?: (values: string[]) => void
+ label: string;
+ name: string;
+ options: WuiKeySelectOption;
+ id?: string;
+ hint?: string;
+ is_disabled?: boolean;
+ is_hint_toggled?: boolean;
+ onChangeHandler?: (values: string[]) => void;
}
-const WUI_INPUT_CHECKBOXES_CLASS = "wui_input_checkboxes"
-const WUI_INPUT_CHECKBOXES_CLASS_HINT = "wui_input_checkboxes_hint"
-const WUI_INPUT_CHECKBOXES_CLASS_HINT_TOGGLER = "wui_input_checkboxes_hint_toggler"
-const WUI_INPUT_CHECKBOXES_CLASS_INPUT = "wui_input_checkboxes_input"
-const WUI_INPUT_CHECKBOXES_CLASS_LABEL = "wui_input_checkboxes_label"
+const WUI_INPUT_CHECKBOXES_CLASS = "wui_input_checkboxes";
+const WUI_INPUT_CHECKBOXES_CLASS_HINT = "wui_input_checkboxes_hint";
+const WUI_INPUT_CHECKBOXES_CLASS_HINT_TOGGLER =
+ "wui_input_checkboxes_hint_toggler";
+const WUI_INPUT_CHECKBOXES_CLASS_INPUT = "wui_input_checkboxes_input";
+const WUI_INPUT_CHECKBOXES_CLASS_LABEL = "wui_input_checkboxes_label";
//
// WuiInputCheckboxes create an HTML input for selecting one or more item
@@ -57,124 +58,124 @@ const WUI_INPUT_CHECKBOXES_CLASS_LABEL = "wui_input_checkboxes_label"
// The onChangeHandler receive all checked values.
//
export class WuiInputCheckboxes {
- el: HTMLElement
- private el_label!: HTMLElement
- private el_fieldset!: HTMLFieldSetElement
- private el_hint!: HTMLElement
- private el_hint_toggler!: HTMLElement
- private values: string[] = []
+ el: HTMLElement;
+ private el_label!: HTMLElement;
+ private el_fieldset!: HTMLFieldSetElement;
+ private el_hint!: HTMLElement;
+ private el_hint_toggler!: HTMLElement;
+ private values: string[] = [];
- constructor(public opts: WuiInputCheckboxesOpts) {
- this.el = document.createElement("div")
- if (opts.id) {
- this.el.id = opts.id
- }
- this.el.classList.add(WUI_INPUT_CHECKBOXES_CLASS)
- this.el.style.padding = "2px"
+ constructor(public opts: WuiInputCheckboxesOpts) {
+ this.el = document.createElement("div");
+ if (opts.id) {
+ this.el.id = opts.id;
+ }
+ this.el.classList.add(WUI_INPUT_CHECKBOXES_CLASS);
+ this.el.style.padding = "2px";
- this.generateLabel(this.el)
- if (opts.hint) {
- this.generateHintToggler(this.el)
- }
- this.generateInput(this.el)
+ this.generateLabel(this.el);
+ if (opts.hint) {
+ this.generateHintToggler(this.el);
+ }
+ this.generateInput(this.el);
- if (opts.hint) {
- this.generateHint()
- }
- }
+ if (opts.hint) {
+ this.generateHint();
+ }
+ }
- private generateLabel(wrapper: HTMLElement) {
- this.el_label = document.createElement("label")
- this.el_label.classList.add(WUI_INPUT_CHECKBOXES_CLASS_LABEL)
- this.el_label.innerHTML = `${this.opts.label} `
- wrapper.appendChild(this.el_label)
- }
+ private generateLabel(wrapper: HTMLElement) {
+ this.el_label = document.createElement("label");
+ this.el_label.classList.add(WUI_INPUT_CHECKBOXES_CLASS_LABEL);
+ this.el_label.innerHTML = `${this.opts.label} `;
+ wrapper.appendChild(this.el_label);
+ }
- private generateInput(wrapper: HTMLElement) {
- this.el_fieldset = document.createElement("fieldset")
- this.el_fieldset.classList.add(WUI_INPUT_CHECKBOXES_CLASS_INPUT)
+ private generateInput(wrapper: HTMLElement) {
+ this.el_fieldset = document.createElement("fieldset");
+ this.el_fieldset.classList.add(WUI_INPUT_CHECKBOXES_CLASS_INPUT);
- for (let key in this.opts.options) {
- let option = this.opts.options[key]
- let value = option.value
+ for (let key in this.opts.options) {
+ let option = this.opts.options[key];
+ let value = option.value;
- let wrapper = document.createElement("div")
+ let wrapper = document.createElement("div");
- let el_cb = document.createElement("input")
- el_cb.type = "checkbox"
- el_cb.name = this.opts.name
- el_cb.value = option.value
- if (option.selected) {
- el_cb.checked = true
- this.values.push(value)
- }
- el_cb.onclick = () => {
- this.onClickCheckbox(el_cb.value, el_cb.checked)
- }
- wrapper.appendChild(el_cb)
+ let el_cb = document.createElement("input");
+ el_cb.type = "checkbox";
+ el_cb.name = this.opts.name;
+ el_cb.value = option.value;
+ if (option.selected) {
+ el_cb.checked = true;
+ this.values.push(value);
+ }
+ el_cb.onclick = () => {
+ this.onClickCheckbox(el_cb.value, el_cb.checked);
+ };
+ wrapper.appendChild(el_cb);
- let el_label = document.createElement("label")
- el_label.innerHTML = key
- wrapper.appendChild(el_label)
+ let el_label = document.createElement("label");
+ el_label.innerHTML = key;
+ wrapper.appendChild(el_label);
- this.el_fieldset.appendChild(wrapper)
- }
+ this.el_fieldset.appendChild(wrapper);
+ }
- if (this.opts.is_disabled) {
- this.el_fieldset.disabled = true
- }
+ if (this.opts.is_disabled) {
+ this.el_fieldset.disabled = true;
+ }
- wrapper.appendChild(this.el_fieldset)
- }
+ wrapper.appendChild(this.el_fieldset);
+ }
- private generateHintToggler(wrapper: HTMLElement) {
- this.el_hint_toggler = document.createElement("span")
- this.el_hint_toggler.classList.add(WUI_INPUT_CHECKBOXES_CLASS_HINT_TOGGLER)
- this.el_hint_toggler.innerHTML = " &#x2139;"
+ private generateHintToggler(wrapper: HTMLElement) {
+ this.el_hint_toggler = document.createElement("span");
+ this.el_hint_toggler.classList.add(WUI_INPUT_CHECKBOXES_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)
- }
+ 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() {
- this.el_hint = document.createElement("div")
- this.el_hint.classList.add(WUI_INPUT_CHECKBOXES_CLASS_HINT)
- this.el_hint.innerHTML = this.opts.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)
- }
+ private generateHint() {
+ this.el_hint = document.createElement("div");
+ this.el_hint.classList.add(WUI_INPUT_CHECKBOXES_CLASS_HINT);
+ this.el_hint.innerHTML = this.opts.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);
+ }
- private onClickHintToggler() {
- if (this.el_hint.style.display === "none") {
- this.el_hint.style.display = "block"
- } else {
- this.el_hint.style.display = "none"
- }
- }
+ private onClickHintToggler() {
+ if (this.el_hint.style.display === "none") {
+ this.el_hint.style.display = "block";
+ } else {
+ this.el_hint.style.display = "none";
+ }
+ }
- private onClickCheckbox(value: string, selected: boolean) {
- for (let x = 0; x < this.values.length; x++) {
- if (this.values[x] === value) {
- this.values.splice(x, 1)
- }
- }
- if (selected) {
- this.values.push(value)
- }
- if (this.opts.onChangeHandler) {
- this.opts.onChangeHandler(this.values)
- }
- }
+ private onClickCheckbox(value: string, selected: boolean) {
+ for (let x = 0; x < this.values.length; x++) {
+ if (this.values[x] === value) {
+ this.values.splice(x, 1);
+ }
+ }
+ if (selected) {
+ this.values.push(value);
+ }
+ if (this.opts.onChangeHandler) {
+ this.opts.onChangeHandler(this.values);
+ }
+ }
}
diff --git a/input/example.ts b/input/example.ts
index 05555f1..660ea20 100644
--- a/input/example.ts
+++ b/input/example.ts
@@ -1,242 +1,242 @@
// SPDX-FileCopyrightText: 2021 M. Shulhan <ms@kilabit.info>
// SPDX-License-Identifier: GPL-3.0-or-later
-import { WuiInputString, WuiInputStringOpts } from "./string.js"
-import { WuiInputNumber, WuiInputNumberOpts } from "./number.js"
-import { WuiInputSelect, WuiInputSelectOpts } from "./select.js"
-import { WuiInputCheckboxes, WuiInputCheckboxesOpts } from "./checkboxes.js"
+import { WuiInputString, WuiInputStringOpts } from "./string.js";
+import { WuiInputNumber, WuiInputNumberOpts } from "./number.js";
+import { WuiInputSelect, WuiInputSelectOpts } from "./select.js";
+import { WuiInputCheckboxes, WuiInputCheckboxesOpts } from "./checkboxes.js";
function exampleInputString() {
- let el_example = document.createElement("div")
+ let el_example = document.createElement("div");
- let el_title = document.createElement("h3")
- el_title.innerText = "Input string"
- el_example.appendChild(el_title)
+ let el_title = document.createElement("h3");
+ el_title.innerText = "Input string";
+ el_example.appendChild(el_title);
- let el_out = document.createElement("span")
+ let el_out = document.createElement("span");
- let opts: WuiInputStringOpts = {
- id: "my_input_string",
- label: "Input string with ID",
- value: "Hello, input string",
- hint: "The input ID is 'my_input_string'",
- onChangeHandler: (v: string) => {
- el_out.innerText = v
- },
- }
- let el_input_string = new WuiInputString(opts)
- el_example.appendChild(el_input_string.el)
+ let opts: WuiInputStringOpts = {
+ id: "my_input_string",
+ label: "Input string with ID",
+ value: "Hello, input string",
+ hint: "The input ID is 'my_input_string'",
+ onChangeHandler: (v: string) => {
+ el_out.innerText = v;
+ },
+ };
+ let el_input_string = new WuiInputString(opts);
+ el_example.appendChild(el_input_string.el);
- opts = {
- label: "Input string disabled",
- value: "Hello, disabled input string",
- is_disabled: true,
- hint: "The input string is disabled",
- is_hint_toggled: true,
- onChangeHandler: (v: string) => {
- el_out.innerText = v
- },
- }
- el_input_string = new WuiInputString(opts)
- el_example.appendChild(el_input_string.el)
+ opts = {
+ label: "Input string disabled",
+ value: "Hello, disabled input string",
+ is_disabled: true,
+ hint: "The input string is disabled",
+ is_hint_toggled: true,
+ onChangeHandler: (v: string) => {
+ el_out.innerText = v;
+ },
+ };
+ el_input_string = new WuiInputString(opts);
+ el_example.appendChild(el_input_string.el);
- opts = {
- label: "Input string without hint",
- value: "Hello, input string without hint",
- onChangeHandler: (v: string) => {
- el_out.innerText = v
- },
- }
- el_input_string = new WuiInputString(opts)
- el_example.appendChild(el_input_string.el)
+ opts = {
+ label: "Input string without hint",
+ value: "Hello, input string without hint",
+ onChangeHandler: (v: string) => {
+ el_out.innerText = v;
+ },
+ };
+ el_input_string = new WuiInputString(opts);
+ el_example.appendChild(el_input_string.el);
- let el_out_label = document.createElement("div")
- el_out_label.innerText = "Input string changes to "
- el_out_label.appendChild(el_out)
- el_example.appendChild(el_out_label)
+ let el_out_label = document.createElement("div");
+ el_out_label.innerText = "Input string changes to ";
+ el_out_label.appendChild(el_out);
+ el_example.appendChild(el_out_label);
- document.body.appendChild(el_example)
+ document.body.appendChild(el_example);
}
function exampleInputNumber() {
- let el_example = document.createElement("div")
+ let el_example = document.createElement("div");
- let el_title = document.createElement("h3")
- el_title.innerText = "Input number"
- el_example.appendChild(el_title)
+ let el_title = document.createElement("h3");
+ el_title.innerText = "Input number";
+ el_example.appendChild(el_title);
- let el_out = document.createElement("span")
+ let el_out = document.createElement("span");
- let opts: WuiInputNumberOpts = {
- label: "Input number",
- value: 1,
- onChangeHandler: (val: number) => {
- el_out.innerText = ""+val
- },
- }
- let input_num = new WuiInputNumber(opts)
- el_example.appendChild(input_num.el)
+ let opts: WuiInputNumberOpts = {
+ label: "Input number",
+ value: 1,
+ onChangeHandler: (val: number) => {
+ el_out.innerText = "" + val;
+ },
+ };
+ let input_num = new WuiInputNumber(opts);
+ el_example.appendChild(input_num.el);
- opts = {
- id: "my_input_number",
- label: "Input number with ID",
- value: 10,
- hint: "The ID for this input is 'my_input_number'",
- onChangeHandler: (val: number) => {
- el_out.innerText = ""+val
- },
- }
- input_num = new WuiInputNumber(opts)
- el_example.appendChild(input_num.el)
+ opts = {
+ id: "my_input_number",
+ label: "Input number with ID",
+ value: 10,
+ hint: "The ID for this input is 'my_input_number'",
+ onChangeHandler: (val: number) => {
+ el_out.innerText = "" + val;
+ },
+ };
+ input_num = new WuiInputNumber(opts);
+ el_example.appendChild(input_num.el);
- opts = {
- label: "Input number disabled",
- value: 1000,
- hint: "Input number with 'is_disabled' set to true",
- is_disabled: true,
- is_hint_toggled: true,
- onChangeHandler: (val: number) => {
- el_out.innerText = ""+val
- },
- }
- input_num = new WuiInputNumber(opts)
- el_example.appendChild(input_num.el)
+ opts = {
+ label: "Input number disabled",
+ value: 1000,
+ hint: "Input number with 'is_disabled' set to true",
+ is_disabled: true,
+ is_hint_toggled: true,
+ onChangeHandler: (val: number) => {
+ el_out.innerText = "" + val;
+ },
+ };
+ input_num = new WuiInputNumber(opts);
+ el_example.appendChild(input_num.el);
- opts = {
- label: "Input number with hint",
- value: 10000,
- hint: "This is the <b>hint</b>",
- onChangeHandler: (val: number) => {
- el_out.innerText = ""+val
- },
- }
- input_num = new WuiInputNumber(opts)
- el_example.appendChild(input_num.el)
+ opts = {
+ label: "Input number with hint",
+ value: 10000,
+ hint: "This is the <b>hint</b>",
+ onChangeHandler: (val: number) => {
+ el_out.innerText = "" + val;
+ },
+ };
+ input_num = new WuiInputNumber(opts);
+ el_example.appendChild(input_num.el);
- opts = {
- label: "Input number with max and min",
- value: 10,
- max: 12,
- min: -20,
- onChangeHandler: (val: number) => {
- el_out.innerText = ""+val
- },
- }
- input_num = new WuiInputNumber(opts)
- el_example.appendChild(input_num.el)
+ opts = {
+ label: "Input number with max and min",
+ value: 10,
+ max: 12,
+ min: -20,
+ onChangeHandler: (val: number) => {
+ el_out.innerText = "" + val;
+ },
+ };
+ input_num = new WuiInputNumber(opts);
+ el_example.appendChild(input_num.el);
- let el_out_label = document.createElement("div")
- el_out_label.innerText = "Input number changes to "
- el_out_label.appendChild(el_out)
- el_example.appendChild(el_out_label)
+ let el_out_label = document.createElement("div");
+ el_out_label.innerText = "Input number changes to ";
+ el_out_label.appendChild(el_out);
+ el_example.appendChild(el_out_label);
- document.body.appendChild(el_example)
+ document.body.appendChild(el_example);
}
function exampleInputSelect() {
- let el_example = document.createElement("div")
- document.body.appendChild(el_example)
+ let el_example = document.createElement("div");
+ document.body.appendChild(el_example);
- let el_title = document.createElement("h3")
- el_title.innerText = "Input select"
- el_example.appendChild(el_title)
+ let el_title = document.createElement("h3");
+ el_title.innerText = "Input select";
+ el_example.appendChild(el_title);
- let el_log = document.createElement("div")
+ let el_log = document.createElement("div");
- let opts: WuiInputSelectOpts = {
- name: "my_fruit_price",
- label: "Input select",
- options: {
- mango: {
- value: "1000",
- selected: false,
- },
- papaya: {
- value: "200",
- selected: false,
- },
- rambutan: {
- value: "100",
- selected: true,
- },
- },
- hint: "Select one of the option to see the price.",
- is_hint_toggled: true,
- onChangeHandler: (key: string, value: string) => {
- el_log.innerText = `The select input changes to '${key}' with price '${value}'`
- },
- }
- let input = new WuiInputSelect(opts)
- el_example.appendChild(input.el)
- el_example.appendChild(el_log)
+ let opts: WuiInputSelectOpts = {
+ name: "my_fruit_price",
+ label: "Input select",
+ options: {
+ mango: {
+ value: "1000",
+ selected: false,
+ },
+ papaya: {
+ value: "200",
+ selected: false,
+ },
+ rambutan: {
+ value: "100",
+ selected: true,
+ },
+ },
+ hint: "Select one of the option to see the price.",
+ is_hint_toggled: true,
+ onChangeHandler: (key: string, value: string) => {
+ el_log.innerText = `The select input changes to '${key}' with price '${value}'`;
+ },
+ };
+ let input = new WuiInputSelect(opts);
+ el_example.appendChild(input.el);
+ el_example.appendChild(el_log);
}
function exampleInputCheckboxes() {
- let el_example = document.createElement("div")
- document.body.appendChild(el_example)
+ let el_example = document.createElement("div");
+ document.body.appendChild(el_example);
- let el_title = document.createElement("h3")
- el_title.innerText = "Input checkboxes"
- el_example.appendChild(el_title)
+ let el_title = document.createElement("h3");
+ el_title.innerText = "Input checkboxes";
+ el_example.appendChild(el_title);
- let el_log = document.createElement("div")
+ let el_log = document.createElement("div");
- let opts: WuiInputCheckboxesOpts = {
- name: "my_fruits",
- label: "Input checkboxes",
- options: {
- mango: {
- value: "1000",
- selected: false,
- },
- papaya: {
- value: "200",
- selected: false,
- },
- rambutan: {
- value: "100",
- selected: true,
- },
- },
- hint: "Select fruits.",
- onChangeHandler: (values: string[]) => {
- el_log.innerText = `You are selecting ${values}`
- },
- }
- let input = new WuiInputCheckboxes(opts)
- el_example.appendChild(input.el)
+ let opts: WuiInputCheckboxesOpts = {
+ name: "my_fruits",
+ label: "Input checkboxes",
+ options: {
+ mango: {
+ value: "1000",
+ selected: false,
+ },
+ papaya: {
+ value: "200",
+ selected: false,
+ },
+ rambutan: {
+ value: "100",
+ selected: true,
+ },
+ },
+ hint: "Select fruits.",
+ onChangeHandler: (values: string[]) => {
+ el_log.innerText = `You are selecting ${values}`;
+ },
+ };
+ let input = new WuiInputCheckboxes(opts);
+ el_example.appendChild(input.el);
- opts = {
- name: "my_fruits",
- label: "Input checkboxes",
- options: {
- mango: {
- value: "1000",
- selected: false,
- },
- papaya: {
- value: "200",
- selected: false,
- },
- rambutan: {
- value: "100",
- selected: true,
- },
- },
- hint: "Input select with 'is_disabled' and 'is_hint_toggled' is set to 'true'.",
- is_disabled: true,
- is_hint_toggled: true,
- onChangeHandler: (values: string[]) => {
- el_log.innerText = `You are selecting ${values}`
- },
- }
- input = new WuiInputCheckboxes(opts)
- el_example.appendChild(input.el)
+ opts = {
+ name: "my_fruits",
+ label: "Input checkboxes",
+ options: {
+ mango: {
+ value: "1000",
+ selected: false,
+ },
+ papaya: {
+ value: "200",
+ selected: false,
+ },
+ rambutan: {
+ value: "100",
+ selected: true,
+ },
+ },
+ hint: "Input select with 'is_disabled' and 'is_hint_toggled' is set to 'true'.",
+ is_disabled: true,
+ is_hint_toggled: true,
+ onChangeHandler: (values: string[]) => {
+ el_log.innerText = `You are selecting ${values}`;
+ },
+ };
+ input = new WuiInputCheckboxes(opts);
+ el_example.appendChild(input.el);
- el_example.appendChild(el_log)
+ el_example.appendChild(el_log);
}
-exampleInputString()
-exampleInputNumber()
-exampleInputSelect()
-exampleInputCheckboxes()
+exampleInputString();
+exampleInputNumber();
+exampleInputSelect();
+exampleInputCheckboxes();
diff --git a/input/index.html b/input/index.html
index 2144d51..0e20989 100644
--- a/input/index.html
+++ b/input/index.html
@@ -2,13 +2,16 @@
<!-- SPDX-FileCopyrightText: 2021 M. Shulhan <ms@kilabit.info> -->
<!-- SPDX-License-Identifier: GPL-3.0-or-later -->
<html>
- <head>
- <meta charset="UTF-8" />
- <title>WUI - input</title>
- <style>
- </style>
- </head>
- <body>
- <script type="module" src="/input/example.js"></script>
- </body>
+
+<head>
+ <meta charset="UTF-8" />
+ <title>WUI - input</title>
+ <style>
+ </style>
+</head>
+
+<body>
+ <script type="module" src="/input/example.js"></script>
+</body>
+
</html>
diff --git a/input/number.ts b/input/number.ts
index 309fffd..0b59dbe 100644
--- a/input/number.ts
+++ b/input/number.ts
@@ -2,24 +2,24 @@
// SPDX-License-Identifier: GPL-3.0-or-later
export interface WuiInputNumberOpts {
- label: string | HTMLElement
- value: number
- id?: string
- hint?: string
- max?: number
- min?: number
- class_label?: string // Additional CSS class for label.
- class_input?: string // Additional CSS class for input.
- is_disabled?: boolean
- is_hint_toggled?: boolean // If true, the hint will be displayed first instead of hidden.
- onChangeHandler: (new_value: number) => void
+ label: string | HTMLElement;
+ value: number;
+ id?: string;
+ hint?: string;
+ max?: number;
+ min?: number;
+ class_label?: string; // Additional CSS class for label.
+ class_input?: string; // Additional CSS class for input.
+ is_disabled?: boolean;
+ is_hint_toggled?: boolean; // If true, the hint will be displayed first instead of hidden.
+ 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"
+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
@@ -50,162 +50,158 @@ const WUI_INPUT_NUMBER_CLASS_LABEL = "wui_input_number_label"
// 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
+ 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
+ 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"
+ 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)
+ 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()
- }
- }
+ 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)
- if (this.opts.class_label) {
- this.el_label.classList.add(this.opts.class_label)
- }
+ private generateLabel(wrapper: HTMLElement) {
+ 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)
- }
+ 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);
+ }
- private generateInput(wrapper: HTMLElement) {
- this.el_input = document.createElement(
- "input",
- ) as HTMLInputElement
- this.el_input.classList.add(WUI_INPUT_NUMBER_CLASS_INPUT)
- if (this.opts.class_input) {
- this.el_input.classList.add(this.opts.class_input)
- }
+ private generateInput(wrapper: HTMLElement) {
+ this.el_input = document.createElement("input") as HTMLInputElement;
+ 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
+ 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
- }
+ 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 (hint !== "") {
+ this.el_input.title = hint;
+ }
- if (this.opts.is_disabled) {
- this.el_input.disabled = true
- }
+ if (this.opts.is_disabled) {
+ this.el_input.disabled = true;
+ }
- this.el_input.onkeyup = (ev: KeyboardEvent) => {
- return this.onKeyUp(ev)
- }
+ this.el_input.onkeyup = (ev: KeyboardEvent) => {
+ return this.onKeyUp(ev);
+ };
- wrapper.appendChild(this.el_input)
- }
+ 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;"
+ 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)
- }
+ 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 || ""
+ 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
- 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)
- }
+ 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);
+ }
- private onClickHintToggler() {
- if (this.el_hint.style.display === "none") {
- this.el_hint.style.display = "block"
- } else {
- this.el_hint.style.display = "none"
- }
- }
+ 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
+ private onKeyUp(ev: KeyboardEvent) {
+ let target = ev.target as HTMLInputElement;
- ev.preventDefault()
- let 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
- }
+ ev.preventDefault();
+ let 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: number) {
- this.el_input.value = "" + v
- }
+ // Set the input value.
+ Set(v: number) {
+ this.el_input.value = "" + v;
+ }
}
diff --git a/input/option.ts b/input/option.ts
index f30b84c..bdb21a2 100644
--- a/input/option.ts
+++ b/input/option.ts
@@ -2,6 +2,6 @@
// SPDX-License-Identifier: GPL-3.0-or-later
export interface WuiInputOption {
- value: string
- selected: boolean
+ value: string;
+ selected: boolean;
}
diff --git a/input/select.ts b/input/select.ts
index 8883caf..6bf4810 100644
--- a/input/select.ts
+++ b/input/select.ts
@@ -1,36 +1,35 @@
// SPDX-FileCopyrightText: 2021 M. Shulhan <ms@kilabit.info>
// SPDX-License-Identifier: GPL-3.0-or-later
-import { WuiInputOption } from "./option.js"
+import { WuiInputOption } from "./option.js";
export interface WuiKeyValue {
- [key: string]: string
+ [key: string]: string;
}
export interface WuiKeySelectOption {
- [key: string]: WuiInputOption
+ [key: string]: WuiInputOption;
}
export interface WuiInputSelectOpts {
- label: string | HTMLElement
- name: string
- options: WuiKeySelectOption
- id?: string
- hint?: string
- class_label?: string // Additional CSS class for label.
- class_input?: string // Additional CSS class for input.
- is_disabled?: boolean
- is_hint_toggled?: boolean
- onChangeHandler?: (key: string, value: string) => void
+ label: string | HTMLElement;
+ name: string;
+ options: WuiKeySelectOption;
+ id?: string;
+ hint?: string;
+ class_label?: string; // Additional CSS class for label.
+ class_input?: string; // Additional CSS class for input.
+ is_disabled?: boolean;
+ is_hint_toggled?: boolean;
+ onChangeHandler?: (key: string, value: string) => void;
}
-const WUI_INPUT_SELECT_CLASS = "wui_input_select"
-const WUI_INPUT_SELECT_CLASS_HINT = "wui_input_select_hint"
-const WUI_INPUT_SELECT_CLASS_HINT_TOGGLER = "wui_input_select_hint_toggler"
-const WUI_INPUT_SELECT_CLASS_INPUT = "wui_input_select_input"
-const WUI_INPUT_SELECT_CLASS_LABEL = "wui_input_select_label"
+const WUI_INPUT_SELECT_CLASS = "wui_input_select";
+const WUI_INPUT_SELECT_CLASS_HINT = "wui_input_select_hint";
+const WUI_INPUT_SELECT_CLASS_HINT_TOGGLER = "wui_input_select_hint_toggler";
+const WUI_INPUT_SELECT_CLASS_INPUT = "wui_input_select_input";
+const WUI_INPUT_SELECT_CLASS_LABEL = "wui_input_select_label";
-//
// WuiInputSelect create an HTML input for selecting one more item.
//
// Format of generated HTML output,
@@ -57,145 +56,142 @@ const WUI_INPUT_SELECT_CLASS_LABEL = "wui_input_select_label"
//
// User can set onChangeHandler to receive new value when the input value
// changes.
-//
export class WuiInputSelect {
- el: HTMLElement
- private el_label!: HTMLElement
- private el_input!: HTMLSelectElement
- private el_hint!: HTMLElement
- private el_hint_toggler!: HTMLElement
- private value_key: WuiKeyValue = {} // The reverse of options.options
- private value: string = ""
+ el: HTMLElement;
+ private el_label!: HTMLElement;
+ private el_input!: HTMLSelectElement;
+ private el_hint!: HTMLElement;
+ private el_hint_toggler!: HTMLElement;
+ private value_key: WuiKeyValue = {}; // The reverse of options.options
+ private value: string = "";
- constructor(public opts: WuiInputSelectOpts) {
- this.el = document.createElement("div")
- if (opts.id) {
- this.el.id = opts.id
- }
- this.el.classList.add(WUI_INPUT_SELECT_CLASS)
- this.el.style.padding = "2px"
+ constructor(public opts: WuiInputSelectOpts) {
+ this.el = document.createElement("div");
+ if (opts.id) {
+ this.el.id = opts.id;
+ }
+ this.el.classList.add(WUI_INPUT_SELECT_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)
+ 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()
- }
- }
+ if (opts.hint) {
+ this.generateHint();
+ }
+ }
- private generateLabel(wrapper: HTMLElement) {
- this.el_label = document.createElement("label")
- this.el_label.classList.add(WUI_INPUT_SELECT_CLASS_LABEL)
- if (this.opts.class_label) {
- this.el_label.classList.add(this.opts.class_label)
- }
+ private generateLabel(wrapper: HTMLElement) {
+ this.el_label = document.createElement("label");
+ this.el_label.classList.add(WUI_INPUT_SELECT_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)
- }
+ 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);
+ }
- private generateInput(wrapper: HTMLElement) {
- this.el_input = document.createElement("select")
- this.el_input.name = this.opts.name
- this.el_input.classList.add(WUI_INPUT_SELECT_CLASS_INPUT)
- if (this.opts.class_input) {
- this.el_input.classList.add(this.opts.class_input)
- }
+ private generateInput(wrapper: HTMLElement) {
+ this.el_input = document.createElement("select");
+ this.el_input.name = this.opts.name;
+ this.el_input.classList.add(WUI_INPUT_SELECT_CLASS_INPUT);
+ if (this.opts.class_input) {
+ this.el_input.classList.add(this.opts.class_input);
+ }
- for (let key in this.opts.options) {
- let option = this.opts.options[key]
+ for (let key in this.opts.options) {
+ let option = this.opts.options[key];
- let el_option = document.createElement("option")
- el_option.value = option.value
- el_option.innerHTML = key
+ let el_option = document.createElement("option");
+ el_option.value = option.value;
+ el_option.innerHTML = key;
- if (option.selected) {
- el_option.selected = true
- }
+ if (option.selected) {
+ el_option.selected = true;
+ }
- this.el_input.appendChild(el_option)
+ this.el_input.appendChild(el_option);
- this.value_key[option.value] = key
- }
+ this.value_key[option.value] = key;
+ }
- if (this.opts.is_disabled) {
- this.el_input.disabled = true
- }
+ if (this.opts.is_disabled) {
+ this.el_input.disabled = true;
+ }
- if (this.opts.onChangeHandler) {
- this.el_input.onclick = (ev: Event) => {
- ev.preventDefault()
- ev.stopPropagation()
- this.onClickInput()
- }
- }
+ if (this.opts.onChangeHandler) {
+ this.el_input.onclick = (ev: Event) => {
+ ev.preventDefault();
+ ev.stopPropagation();
+ this.onClickInput();
+ };
+ }
- wrapper.appendChild(this.el_input)
- }
+ wrapper.appendChild(this.el_input);
+ }
- private generateHintToggler(wrapper: HTMLElement) {
- this.el_hint_toggler = document.createElement("span")
- this.el_hint_toggler.classList.add(
- WUI_INPUT_SELECT_CLASS_HINT_TOGGLER,
- )
- this.el_hint_toggler.innerHTML = " &#x2139;"
+ private generateHintToggler(wrapper: HTMLElement) {
+ this.el_hint_toggler = document.createElement("span");
+ this.el_hint_toggler.classList.add(WUI_INPUT_SELECT_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)
- }
+ 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() {
- this.el_hint = document.createElement("div")
- this.el_hint.classList.add(WUI_INPUT_SELECT_CLASS_HINT)
- this.el_hint.innerHTML = this.opts.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)
- }
+ private generateHint() {
+ this.el_hint = document.createElement("div");
+ this.el_hint.classList.add(WUI_INPUT_SELECT_CLASS_HINT);
+ this.el_hint.innerHTML = this.opts.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);
+ }
- private onClickHintToggler() {
- if (this.el_hint.style.display === "none") {
- this.el_hint.style.display = "block"
- } else {
- this.el_hint.style.display = "none"
- }
- }
+ private onClickHintToggler() {
+ if (this.el_hint.style.display === "none") {
+ this.el_hint.style.display = "block";
+ } else {
+ this.el_hint.style.display = "none";
+ }
+ }
- private onClickInput() {
- if (!this.opts.onChangeHandler) {
- return false
- }
+ private onClickInput() {
+ if (!this.opts.onChangeHandler) {
+ return false;
+ }
- let value = this.el_input.value
- let key = this.value_key[value]
- if (this.value !== value) {
- this.opts.onChangeHandler(key, value)
- this.value = value
- }
- }
+ let value = this.el_input.value;
+ let key = this.value_key[value];
+ if (this.value !== value) {
+ this.opts.onChangeHandler(key, value);
+ this.value = value;
+ }
+ }
- // Set the input value.
- Set(v: string) {
- this.el_input.value = v
- }
+ // Set the input value.
+ Set(v: string) {
+ this.el_input.value = v;
+ }
}
diff --git a/input/string.ts b/input/string.ts
index 2381a01..d428c32 100644
--- a/input/string.ts
+++ b/input/string.ts
@@ -2,24 +2,23 @@
// SPDX-License-Identifier: GPL-3.0-or-later
export interface WuiInputStringOpts {
- label: string | HTMLElement
- value: string
- id?: string
- hint?: string
- class_label?: string // Additional CSS class for label.
- class_input?: string // Additional CSS class for input.
- is_disabled?: boolean
- is_hint_toggled?: boolean // If true, the hint will be displayed first instead of hidden.
- onChangeHandler?: (new_value: string) => void
+ label: string | HTMLElement;
+ value: string;
+ id?: string;
+ hint?: string;
+ class_label?: string; // Additional CSS class for label.
+ class_input?: string; // Additional CSS class for input.
+ is_disabled?: boolean;
+ is_hint_toggled?: boolean; // If true, the hint will be displayed first instead of hidden.
+ onChangeHandler?: (new_value: string) => void;
}
-const WUI_INPUT_STRING_CLASS = "wui_input_string"
-const WUI_INPUT_STRING_CLASS_HINT = "wui_input_string_hint"
-const WUI_INPUT_STRING_CLASS_HINT_TOGGLER = "wui_input_string_hint_toggler"
-const WUI_INPUT_STRING_CLASS_INPUT = "wui_input_string_input"
-const WUI_INPUT_STRING_CLASS_LABEL = "wui_input_string_label"
+const WUI_INPUT_STRING_CLASS = "wui_input_string";
+const WUI_INPUT_STRING_CLASS_HINT = "wui_input_string_hint";
+const WUI_INPUT_STRING_CLASS_HINT_TOGGLER = "wui_input_string_hint_toggler";
+const WUI_INPUT_STRING_CLASS_INPUT = "wui_input_string_input";
+const WUI_INPUT_STRING_CLASS_LABEL = "wui_input_string_label";
-//
// WuiInputString create an HTML input for string with predefined options.
// The required options are "label" and "value".
//
@@ -45,129 +44,118 @@ const WUI_INPUT_STRING_CLASS_LABEL = "wui_input_string_label"
//
// User can set onChangeHandler to receive new value when the input value
// changes.
-//
export class WuiInputString {
- el: HTMLElement
- private el_label!: HTMLElement
- private el_input!: HTMLInputElement
- private el_hint!: HTMLElement
- private el_hint_toggler!: HTMLElement
- private value: string = ""
+ el: HTMLElement;
+ private el_label!: HTMLElement;
+ private el_input!: HTMLInputElement;
+ private el_hint!: HTMLElement;
+ private el_hint_toggler!: HTMLElement;
+ private value: string = "";
- constructor(public opts: WuiInputStringOpts) {
- this.value = opts.value
+ constructor(public opts: WuiInputStringOpts) {
+ this.value = opts.value;
- this.el = document.createElement("div")
- if (opts.id) {
- this.el.id = opts.id
- }
- this.el.classList.add(WUI_INPUT_STRING_CLASS)
- this.el.style.padding = "2px"
+ this.el = document.createElement("div");
+ if (opts.id) {
+ this.el.id = opts.id;
+ }
+ this.el.classList.add(WUI_INPUT_STRING_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)
+ 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()
- }
- }
+ if (opts.hint) {
+ this.generateHint();
+ }
+ }
- private generateLabel(wrapper: HTMLElement) {
- this.el_label = document.createElement("label")
- this.el_label.classList.add(WUI_INPUT_STRING_CLASS_LABEL)
- if (this.opts.class_label) {
- this.el_label.classList.add(this.opts.class_label)
- }
+ private generateLabel(wrapper: HTMLElement) {
+ this.el_label = document.createElement("label");
+ this.el_label.classList.add(WUI_INPUT_STRING_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)
- }
+ 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);
+ }
- private generateInput(wrapper: HTMLElement) {
- this.el_input = document.createElement(
- "input",
- ) as HTMLInputElement
- this.el_input.classList.add(WUI_INPUT_STRING_CLASS_INPUT)
- if (this.opts.class_input) {
- this.el_input.classList.add(this.opts.class_input)
- }
+ private generateInput(wrapper: HTMLElement) {
+ this.el_input = document.createElement("input") as HTMLInputElement;
+ this.el_input.classList.add(WUI_INPUT_STRING_CLASS_INPUT);
+ if (this.opts.class_input) {
+ this.el_input.classList.add(this.opts.class_input);
+ }
- this.el_input.value = "" + this.opts.value
+ this.el_input.value = "" + this.opts.value;
- if (this.opts.is_disabled) {
- this.el_input.disabled = true
- }
+ if (this.opts.is_disabled) {
+ this.el_input.disabled = true;
+ }
- if (this.opts.onChangeHandler) {
- this.el_input.onkeyup = (ev: Event) => {
- if (this.opts.onChangeHandler) {
- if (
- this.value !==
- this.el_input.value
- ) {
- this.opts.onChangeHandler(
- this.el_input.value,
- )
- this.value =
- this.el_input.value
- }
- }
- }
- }
+ if (this.opts.onChangeHandler) {
+ this.el_input.onkeyup = (ev: Event) => {
+ if (this.opts.onChangeHandler) {
+ if (this.value !== this.el_input.value) {
+ this.opts.onChangeHandler(this.el_input.value);
+ this.value = this.el_input.value;
+ }
+ }
+ };
+ }
- wrapper.appendChild(this.el_input)
- }
+ wrapper.appendChild(this.el_input);
+ }
- private generateHintToggler(wrapper: HTMLElement) {
- this.el_hint_toggler = document.createElement("span")
- this.el_hint_toggler.classList.add(
- WUI_INPUT_STRING_CLASS_HINT_TOGGLER,
- )
- this.el_hint_toggler.innerHTML = " &#x2139;"
+ private generateHintToggler(wrapper: HTMLElement) {
+ this.el_hint_toggler = document.createElement("span");
+ this.el_hint_toggler.classList.add(WUI_INPUT_STRING_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)
- }
+ 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() {
- this.el_hint = document.createElement("div")
- this.el_hint.classList.add(WUI_INPUT_STRING_CLASS_HINT)
- this.el_hint.innerHTML = this.opts.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)
- }
+ private generateHint() {
+ this.el_hint = document.createElement("div");
+ this.el_hint.classList.add(WUI_INPUT_STRING_CLASS_HINT);
+ this.el_hint.innerHTML = this.opts.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);
+ }
- private onClickHintToggler() {
- if (this.el_hint.style.display === "none") {
- this.el_hint.style.display = "block"
- } else {
- this.el_hint.style.display = "none"
- }
- }
+ private onClickHintToggler() {
+ if (this.el_hint.style.display === "none") {
+ this.el_hint.style.display = "block";
+ } else {
+ this.el_hint.style.display = "none";
+ }
+ }
- // Set the input value.
- Set(v: string) {
- this.el_input.value = v
- }
+ // Set the input value.
+ Set(v: string) {
+ this.el_input.value = v;
+ }
}
diff --git a/notif/example.ts b/notif/example.ts
index e803145..a15f986 100644
--- a/notif/example.ts
+++ b/notif/example.ts
@@ -1,55 +1,59 @@
// SPDX-FileCopyrightText: 2021 M. Shulhan <ms@kilabit.info>
// SPDX-License-Identifier: GPL-3.0-or-later
-import { WuiNotif, WUI_NOTIF_CLASS_ERROR, WUI_NOTIF_CLASS_INFO } from "./notif.js"
+import {
+ WuiNotif,
+ WUI_NOTIF_CLASS_ERROR,
+ WUI_NOTIF_CLASS_INFO,
+} from "./notif.js";
-let inputMsg: HTMLTextAreaElement
-let wuiNotif: WuiNotif
+let inputMsg: HTMLTextAreaElement;
+let wuiNotif: WuiNotif;
function main() {
- wuiNotif = new WuiNotif()
+ wuiNotif = new WuiNotif();
- inputMsg = document.createElement("textarea") as HTMLTextAreaElement
- inputMsg.id = "input_msg"
- inputMsg.value = `Hello world, this is a notification with HTML format using <b>bold</b> and <u>underline</u> words.`
- document.body.appendChild(inputMsg)
+ inputMsg = document.createElement("textarea") as HTMLTextAreaElement;
+ inputMsg.id = "input_msg";
+ inputMsg.value = `Hello world, this is a notification with HTML format using <b>bold</b> and <u>underline</u> words.`;
+ document.body.appendChild(inputMsg);
- let el_wrapper = document.createElement("div")
- el_wrapper.style.marginTop = "10px"
- document.body.appendChild(el_wrapper)
+ let el_wrapper = document.createElement("div");
+ el_wrapper.style.marginTop = "10px";
+ document.body.appendChild(el_wrapper);
- let el_button_info = document.createElement("button")
- el_button_info.innerText = "Info"
- el_button_info.style.marginRight = "10px"
- el_button_info.onclick = notifInfo
- el_wrapper.appendChild(el_button_info)
+ let el_button_info = document.createElement("button");
+ el_button_info.innerText = "Info";
+ el_button_info.style.marginRight = "10px";
+ el_button_info.onclick = notifInfo;
+ el_wrapper.appendChild(el_button_info);
- let el_button_error = document.createElement("button")
- el_button_error.innerText = "Error"
- el_button_error.onclick = notifError
- el_wrapper.appendChild(el_button_error)
+ let el_button_error = document.createElement("button");
+ el_button_error.innerText = "Error";
+ el_button_error.onclick = notifError;
+ el_wrapper.appendChild(el_button_error);
- document.body.appendChild(document.createElement("p"))
+ document.body.appendChild(document.createElement("p"));
- let previewError = document.createElement("div")
- previewError.classList.add(`${WUI_NOTIF_CLASS_ERROR}`)
- previewError.innerText = `Preview of error style`
- document.body.appendChild(previewError)
+ let previewError = document.createElement("div");
+ previewError.classList.add(`${WUI_NOTIF_CLASS_ERROR}`);
+ previewError.innerText = `Preview of error style`;
+ document.body.appendChild(previewError);
- let previewInfo = document.createElement("div")
- previewInfo.classList.add(`${WUI_NOTIF_CLASS_INFO}`)
- previewInfo.innerText = `Preview of info style`
- document.body.appendChild(previewInfo)
+ let previewInfo = document.createElement("div");
+ previewInfo.classList.add(`${WUI_NOTIF_CLASS_INFO}`);
+ previewInfo.innerText = `Preview of info style`;
+ document.body.appendChild(previewInfo);
}
function notifInfo() {
- wuiNotif.Info(inputMsg.value)
+ wuiNotif.Info(inputMsg.value);
}
function notifError() {
- wuiNotif.Error(inputMsg.value)
+ wuiNotif.Error(inputMsg.value);
}
//----
-main()
+main();
diff --git a/notif/index.html b/notif/index.html
index 7797b29..5f00107 100644
--- a/notif/index.html
+++ b/notif/index.html
@@ -2,21 +2,25 @@
<!-- SPDX-FileCopyrightText: 2021 M. Shulhan <ms@kilabit.info -->
<!-- SPDX-License-Identifier: GPL-3.0-or-later -->
<html>
- <head>
- <meta charset="UTF-8" />
- <title>WUI - notif</title>
- <style>
- #input_msg {
- width: calc(100% - 1em);
- height: 4em;
- }
- .empty {
- height: 100vh;
- }
- </style>
- </head>
- <body>
- <p class="empty">Empty spaces.</p>
- <script type="module" src="/notif/example.js"></script>
- </body>
+
+<head>
+ <meta charset="UTF-8" />
+ <title>WUI - notif</title>
+ <style>
+ #input_msg {
+ width: calc(100% - 1em);
+ height: 4em;
+ }
+
+ .empty {
+ height: 100vh;
+ }
+ </style>
+</head>
+
+<body>
+ <p class="empty">Empty spaces.</p>
+ <script type="module" src="/notif/example.js"></script>
+</body>
+
</html>
diff --git a/notif/notif.ts b/notif/notif.ts
index 63f91cc..8bc5d84 100644
--- a/notif/notif.ts
+++ b/notif/notif.ts
@@ -1,57 +1,55 @@
// SPDX-FileCopyrightText: 2021 M. Shulhan <ms@kilabit.info>
// SPDX-License-Identifier: GPL-3.0-or-later
-export const WUI_NOTIF_ID = "wui_notif"
-export const WUI_NOTIF_CLASS_INFO = "wui_notif_info"
-export const WUI_NOTIF_CLASS_ERROR = "wui_notif_error"
+export const WUI_NOTIF_ID = "wui_notif";
+export const WUI_NOTIF_CLASS_INFO = "wui_notif_info";
+export const WUI_NOTIF_CLASS_ERROR = "wui_notif_error";
-//
// WuiNotif implement the HTML interface to display pop-up notification.
// The notification can be triggered by calling method Info() or Error().
// Each pop-up has 5 seconds duration, after that they will be removed
// automatically.
-//
export class WuiNotif {
- private el: HTMLElement
- private timeout: number = 5000 // 5 seconds timeout
+ private el: HTMLElement;
+ private timeout: number = 5000; // 5 seconds timeout
- constructor() {
- this.el = document.createElement("div")
- this.el.id = WUI_NOTIF_ID
+ constructor() {
+ this.el = document.createElement("div");
+ this.el.id = WUI_NOTIF_ID;
- document.body.appendChild(this.el)
+ document.body.appendChild(this.el);
- this.initStyle()
- }
+ this.initStyle();
+ }
- // Info show the msg as information.
- Info(msg: string) {
- let item = document.createElement("div")
- item.innerHTML = msg
- item.classList.add(WUI_NOTIF_CLASS_INFO)
- this.el.appendChild(item)
+ // Info show the msg as information.
+ Info(msg: string) {
+ let item = document.createElement("div");
+ item.innerHTML = msg;
+ item.classList.add(WUI_NOTIF_CLASS_INFO);
+ this.el.appendChild(item);
- setTimeout(() => {
- this.el.removeChild(item)
- }, this.timeout)
- }
+ setTimeout(() => {
+ this.el.removeChild(item);
+ }, this.timeout);
+ }
- // Info show the msg as an error.
- Error(msg: string) {
- let item = document.createElement("div")
- item.innerHTML = msg
- item.classList.add(WUI_NOTIF_CLASS_ERROR)
- this.el.appendChild(item)
+ // Info show the msg as an error.
+ Error(msg: string) {
+ let item = document.createElement("div");
+ item.innerHTML = msg;
+ item.classList.add(WUI_NOTIF_CLASS_ERROR);
+ this.el.appendChild(item);
- setTimeout(() => {
- this.el.removeChild(item)
- }, this.timeout)
- }
+ setTimeout(() => {
+ this.el.removeChild(item);
+ }, this.timeout);
+ }
- private initStyle() {
- let style = document.createElement("style")
- style.type = "text/css"
- style.innerText = `
+ private initStyle() {
+ let style = document.createElement("style");
+ style.type = "text/css";
+ style.innerText = `
#${WUI_NOTIF_ID} {
left: 10%;
position: fixed;
@@ -71,7 +69,7 @@ export class WuiNotif {
margin-bottom: 1em;
padding: 1em;
}
- `
- document.head.appendChild(style)
- }
+ `;
+ document.head.appendChild(style);
+ }
}
diff --git a/response.ts b/response.ts
index 6415636..f74161a 100644
--- a/response.ts
+++ b/response.ts
@@ -1,7 +1,6 @@
// SPDX-FileCopyrightText: 2021 M. Shulhan <ms@kilabit.info>
// SPDX-License-Identifier: GPL-3.0-or-later
-//
// WuiResponseInterface define an interface that will be returned by function
// or method with non-void type.
//
@@ -10,9 +9,8 @@
//
// If the function/method call failed, the code should be set to other value
// beside 200 with a message describe why its failed.
-//
export interface WuiResponseInterface {
- code: number
- message: string
- data?: any
+ code: number;
+ message: string;
+ data?: any;
}
diff --git a/tsconfig.json b/tsconfig.json
index c9ed64f..bcb70d1 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,12 +1,12 @@
{
- "compilerOptions": {
- "declaration": true,
- "esModuleInterop": true,
- "forceConsistentCasingInFileNames": true,
- "inlineSourceMap": true,
- "lib": ["es2015", "dom", "es2015.promise"],
- "module": "es2015",
- "strict": true,
- "target": "es2015"
- }
+ "compilerOptions": {
+ "declaration": true,
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "inlineSourceMap": true,
+ "lib": ["es2015", "dom", "es2015.promise"],
+ "module": "es2015",
+ "strict": true,
+ "target": "es2015"
+ }
}
diff --git a/vfs/example.ts b/vfs/example.ts
index 6a1c833..f2bc91d 100644
--- a/vfs/example.ts
+++ b/vfs/example.ts
@@ -1,162 +1,167 @@
// SPDX-FileCopyrightText: 2021 M. Shulhan <ms@kilabit.info>
// SPDX-License-Identifier: GPL-3.0-or-later
-import { WuiVfs, WuiVfsNodeInterface } from "./vfs.js"
-import { WuiResponseInterface } from "../response.js"
+import { WuiVfs, WuiVfsNodeInterface } from "./vfs.js";
+import { WuiResponseInterface } from "../response.js";
interface PathNodeInterface {
- [key: string]: WuiVfsNodeInterface
+ [key: string]: WuiVfsNodeInterface;
}
let dummyfs: PathNodeInterface = {
- "/": {
- name: "/",
- path: "/",
- is_dir: true,
- content: "",
- childs: [
- {
- name: "Dir 1",
- path: "/Dir 1",
- is_dir: true,
- content: "",
- childs: [
- {
- name: "File 1.1",
- path: "/Dir 1/File 1.1",
- is_dir: false,
- content: "This is the content of File 1.1",
- },
- {
- name: `File 1.2`,
- path: "/Dir 1/File 1.2",
- is_dir: false,
- content: "This is the content of File 1.2",
- },
- ],
- },
- {
- name: "Dir 2",
- path: "/Dir 2",
- is_dir: true,
- content: "",
- childs: [
- {
- name: "File 2.1",
- path: "/Dir 2/File 2.1",
- is_dir: false,
- content: "This is the content of File 2.1",
- },
- {
- name: "File 2.2",
- path: "/Dir 2/File 2.2",
- is_dir: false,
- content: "This is the content of File 2.2",
- },
- ],
- },
- ],
- },
- "/Dir 1": {
- name: "Dir 1",
- path: "/Dir 1",
- is_dir: true,
- content: "",
- childs: [
- {
- name: "File 1.1",
- path: "/Dir 1/File 1.1",
- is_dir: false,
- content: "This is the content of File 1.1",
- },
- {
- name: "File 1.2",
- path: "/Dir 1/File 1.2",
- is_dir: false,
- content: "This is the content of File 1.2",
- },
- ],
- },
- "/Dir 2": {
- name: "Dir 2",
- path: "/Dir 2",
- is_dir: true,
- content: "",
- childs: [
- {
- name: "File 2.1",
- path: "/Dir 2/File 2.1",
- is_dir: false,
- content: "This is the content of File 2.1",
- },
- {
- name: "File 2.2",
- path: "/Dir 2/File 2.2",
- is_dir: false,
- content: "This is the content of File 2.2",
- },
- ],
- }
-}
+ "/": {
+ name: "/",
+ path: "/",
+ is_dir: true,
+ content: "",
+ childs: [
+ {
+ name: "Dir 1",
+ path: "/Dir 1",
+ is_dir: true,
+ content: "",
+ childs: [
+ {
+ name: "File 1.1",
+ path: "/Dir 1/File 1.1",
+ is_dir: false,
+ content: "This is the content of File 1.1",
+ },
+ {
+ name: `File 1.2`,
+ path: "/Dir 1/File 1.2",
+ is_dir: false,
+ content: "This is the content of File 1.2",
+ },
+ ],
+ },
+ {
+ name: "Dir 2",
+ path: "/Dir 2",
+ is_dir: true,
+ content: "",
+ childs: [
+ {
+ name: "File 2.1",
+ path: "/Dir 2/File 2.1",
+ is_dir: false,
+ content: "This is the content of File 2.1",
+ },
+ {
+ name: "File 2.2",
+ path: "/Dir 2/File 2.2",
+ is_dir: false,
+ content: "This is the content of File 2.2",
+ },
+ ],
+ },
+ ],
+ },
+ "/Dir 1": {
+ name: "Dir 1",
+ path: "/Dir 1",
+ is_dir: true,
+ content: "",
+ childs: [
+ {
+ name: "File 1.1",
+ path: "/Dir 1/File 1.1",
+ is_dir: false,
+ content: "This is the content of File 1.1",
+ },
+ {
+ name: "File 1.2",
+ path: "/Dir 1/File 1.2",
+ is_dir: false,
+ content: "This is the content of File 1.2",
+ },
+ ],
+ },
+ "/Dir 2": {
+ name: "Dir 2",
+ path: "/Dir 2",
+ is_dir: true,
+ content: "",
+ childs: [
+ {
+ name: "File 2.1",
+ path: "/Dir 2/File 2.1",
+ is_dir: false,
+ content: "This is the content of File 2.1",
+ },
+ {
+ name: "File 2.2",
+ path: "/Dir 2/File 2.2",
+ is_dir: false,
+ content: "This is the content of File 2.2",
+ },
+ ],
+ },
+};
async function main() {
- let opts = {
- id: "vfs",
- Open: Open,
- OpenNode: OpenNode,
- }
+ let opts = {
+ id: "vfs",
+ Open: Open,
+ OpenNode: OpenNode,
+ };
- let wui_vfs = new WuiVfs(opts)
- wui_vfs.OpenDir("/")
+ let wui_vfs = new WuiVfs(opts);
+ wui_vfs.OpenDir("/");
}
-async function Open(path: string, is_dir: boolean): Promise<WuiResponseInterface> {
- console.log("Open:", path, is_dir)
- let res: WuiResponseInterface = {
- code: 200,
- message: "",
- }
+async function Open(
+ path: string,
+ is_dir: boolean,
+): Promise<WuiResponseInterface> {
+ console.log("Open:", path, is_dir);
+ let res: WuiResponseInterface = {
+ code: 200,
+ message: "",
+ };
- if (is_dir) {
- res.data = dummyfs[path]
- return res
- }
+ if (is_dir) {
+ res.data = dummyfs[path];
+ return res;
+ }
- res.data = {
- name: "",
- path: path,
- content: "",
- }
+ res.data = {
+ name: "",
+ path: path,
+ content: "",
+ };
- switch (path) {
- case "/Dir 1/File 1.1":
- res.data.name = "File 1.1"
- res.data.content = "This is the content of " + res.data.name
- break
- case "/Dir 1/File 1.2":
- res.data.name = "File 1.2"
- res.data.content = "This is the content of " + res.data.name
- break
- case "/Dir 2/File 2.1":
- res.data.name = "File 2.1"
- res.data.content = "This is the content of " + res.data.name
- break
- case "/Dir 2/File 2.2":
- res.data.name = "File 2.1"
- res.data.content = "This is the content of " + res.data.name
- break
- default:
- res.code = 404
- res.message = "path not found"
- }
+ switch (path) {
+ case "/Dir 1/File 1.1":
+ res.data.name = "File 1.1";
+ res.data.content = "This is the content of " + res.data.name;
+ break;
+ case "/Dir 1/File 1.2":
+ res.data.name = "File 1.2";
+ res.data.content = "This is the content of " + res.data.name;
+ break;
+ case "/Dir 2/File 2.1":
+ res.data.name = "File 2.1";
+ res.data.content = "This is the content of " + res.data.name;
+ break;
+ case "/Dir 2/File 2.2":
+ res.data.name = "File 2.1";
+ res.data.content = "This is the content of " + res.data.name;
+ break;
+ default:
+ res.code = 404;
+ res.message = "path not found";
+ }
- console.log("Open:", res)
+ console.log("Open:", res);
- return res
+ return res;
}
-async function OpenNode(node: WuiVfsNodeInterface): Promise<WuiResponseInterface> {
- return await Open(node.path, node.is_dir)
+async function OpenNode(
+ node: WuiVfsNodeInterface,
+): Promise<WuiResponseInterface> {
+ return await Open(node.path, node.is_dir);
}
-main()
+main();
diff --git a/vfs/index.html b/vfs/index.html
index 9ec2bd5..eed4206 100644
--- a/vfs/index.html
+++ b/vfs/index.html
@@ -2,12 +2,15 @@
<!-- SPDX-FileCopyrightText: 2021 M. Shulhan <ms@kilabit.info -->
<!-- SPDX-License-Identifier: GPL-3.0-or-later -->
<html>
- <head>
- <meta charset="UTF-8" />
- <title>WUI - Virtual File System (vfs)</title>
- </head>
- <body>
- <div id="vfs"></div>
- <script type="module" src="/vfs/example.js"></script>
- </body>
+
+<head>
+ <meta charset="UTF-8" />
+ <title>WUI - Virtual File System (vfs)</title>
+</head>
+
+<body>
+ <div id="vfs"></div>
+ <script type="module" src="/vfs/example.js"></script>
+</body>
+
</html>
diff --git a/vfs/vfs.ts b/vfs/vfs.ts
index a92583e..7c07814 100644
--- a/vfs/vfs.ts
+++ b/vfs/vfs.ts
@@ -1,195 +1,195 @@
// SPDX-FileCopyrightText: 2021 M. Shulhan <ms@kilabit.info>
// SPDX-License-Identifier: GPL-3.0-or-later
-import { WuiResponseInterface } from "../response"
+import { WuiResponseInterface } from "../response";
-const CLASS_VFS_PATH = "wui_vfs_path"
-const CLASS_VFS_LIST = "wui_vfs_list"
+const CLASS_VFS_PATH = "wui_vfs_path";
+const CLASS_VFS_LIST = "wui_vfs_list";
export interface WuiVfsNodeInterface {
- name: string
- path: string
- is_dir: boolean
- content_type?: string
- mod_time?: number
- size?: number
- mode?: string
- childs?: WuiVfsNodeInterface[]
- content: string // If its not empty, it MUST be encoded in base64.
+ name: string;
+ path: string;
+ is_dir: boolean;
+ content_type?: string;
+ mod_time?: number;
+ size?: number;
+ mode?: string;
+ childs?: WuiVfsNodeInterface[];
+ content: string; // If its not empty, it MUST be encoded in base64.
}
-type PathClickHandler = (path: string) => void
-type NodeClickHandler = (node: WuiVfsNodeInterface) => void
+type PathClickHandler = (path: string) => void;
+type NodeClickHandler = (node: WuiVfsNodeInterface) => void;
export interface WuiVfsOptions {
- id: string
+ id: string;
- // Open define an handler that will be called when a directory is clicked
- // from the WuiVfsPath.
- Open(path: string, is_dir: boolean): Promise<WuiResponseInterface>
+ // Open define an handler that will be called when a directory is clicked
+ // from the WuiVfsPath.
+ Open(path: string, is_dir: boolean): Promise<WuiResponseInterface>;
- // OpenNode define an handler that will be called when a file is clicked
- // from the WuiVfsList.
- OpenNode(node: WuiVfsNodeInterface): Promise<WuiResponseInterface>
+ // OpenNode define an handler that will be called when a file is clicked
+ // from the WuiVfsList.
+ OpenNode(node: WuiVfsNodeInterface): Promise<WuiResponseInterface>;
}
export class WuiVfs {
- private el!: HTMLElement
- private com_path!: WuiVfsPath
- private com_list!: WuiVfsList
+ private el!: HTMLElement;
+ private com_path!: WuiVfsPath;
+ private com_list!: WuiVfsList;
- constructor(public opts: WuiVfsOptions) {
- this.opts = opts
+ constructor(public opts: WuiVfsOptions) {
+ this.opts = opts;
- let el = document.getElementById(opts.id)
- if (!el) {
- console.error("WuiVfs: element id", opts.id, "not found")
- return
- }
- this.el = el
+ let el = document.getElementById(opts.id);
+ if (!el) {
+ console.error("WuiVfs: element id", opts.id, "not found");
+ return;
+ }
+ this.el = el;
- this.com_path = new WuiVfsPath((path: string) => {
- this.OpenDir(path)
- })
- this.el.appendChild(this.com_path.el)
+ this.com_path = new WuiVfsPath((path: string) => {
+ this.OpenDir(path);
+ });
+ this.el.appendChild(this.com_path.el);
- this.com_list = new WuiVfsList((node: WuiVfsNodeInterface) => {
- this.OpenNode(node)
- })
- this.el.appendChild(this.com_list.el)
- }
+ this.com_list = new WuiVfsList((node: WuiVfsNodeInterface) => {
+ this.OpenNode(node);
+ });
+ this.el.appendChild(this.com_list.el);
+ }
- // OpenNode is a handler that will be called when a node is clicked
- // inside the WuiVfsList.
- OpenNode(node: WuiVfsNodeInterface): void {
- if (node.is_dir) {
- this.OpenDir(node.path)
- } else {
- this.opts.OpenNode(node)
- }
- }
+ // OpenNode is a handler that will be called when a node is clicked
+ // inside the WuiVfsList.
+ OpenNode(node: WuiVfsNodeInterface): void {
+ if (node.is_dir) {
+ this.OpenDir(node.path);
+ } else {
+ this.opts.OpenNode(node);
+ }
+ }
- // OpenDir is a handler that will be called when a path is clicked
- // inside the WuiVfsPath.
- async OpenDir(path: string): Promise<void> {
- let res = await this.opts.Open(path, true)
- if (res.code != 200) {
- return
- }
- this.Set(res.data as WuiVfsNodeInterface)
- }
+ // OpenDir is a handler that will be called when a path is clicked
+ // inside the WuiVfsPath.
+ async OpenDir(path: string): Promise<void> {
+ let res = await this.opts.Open(path, true);
+ if (res.code != 200) {
+ return;
+ }
+ this.Set(res.data as WuiVfsNodeInterface);
+ }
- Set(node: WuiVfsNodeInterface) {
- if (node.is_dir) {
- this.com_path.Open(node)
- this.com_list.Open(node)
- }
- }
+ Set(node: WuiVfsNodeInterface) {
+ if (node.is_dir) {
+ this.com_path.Open(node);
+ this.com_list.Open(node);
+ }
+ }
}
class WuiVfsList {
- el: HTMLElement
- node: WuiVfsNodeInterface | null = null
+ el: HTMLElement;
+ node: WuiVfsNodeInterface | null = null;
- constructor(public onClick: NodeClickHandler) {
- this.el = document.createElement("div")
- this.el.classList.add(CLASS_VFS_LIST)
- this.el.style.borderWidth = "1px"
- this.el.style.borderStyle = "solid"
- this.el.style.borderColor = "silver"
- }
+ constructor(public onClick: NodeClickHandler) {
+ this.el = document.createElement("div");
+ this.el.classList.add(CLASS_VFS_LIST);
+ this.el.style.borderWidth = "1px";
+ this.el.style.borderStyle = "solid";
+ this.el.style.borderColor = "silver";
+ }
- Open(node: WuiVfsNodeInterface) {
- this.node = node
- this.el.innerHTML = ""
- if (!this.node.childs) {
- return
- }
- for (let c of this.node.childs) {
- let el = document.createElement("div")
- el.style.padding = "1em"
- el.style.cursor = "pointer"
- el.innerHTML = c.name
+ Open(node: WuiVfsNodeInterface) {
+ this.node = node;
+ this.el.innerHTML = "";
+ if (!this.node.childs) {
+ return;
+ }
+ for (let c of this.node.childs) {
+ let el = document.createElement("div");
+ el.style.padding = "1em";
+ el.style.cursor = "pointer";
+ el.innerHTML = c.name;
- if (c.is_dir) {
- el.style.backgroundColor = "cornsilk"
- }
+ if (c.is_dir) {
+ el.style.backgroundColor = "cornsilk";
+ }
- el.onclick = (ev: MouseEvent) => {
- this.onClick(c)
- }
- el.onmouseout = (event) => {
- if (c.is_dir) {
- el.style.backgroundColor = "cornsilk"
- } else {
- el.style.backgroundColor = "white"
- }
- }
- el.onmouseover = (event) => {
- el.style.backgroundColor = "aliceblue"
- }
+ el.onclick = (ev: MouseEvent) => {
+ this.onClick(c);
+ };
+ el.onmouseout = (event) => {
+ if (c.is_dir) {
+ el.style.backgroundColor = "cornsilk";
+ } else {
+ el.style.backgroundColor = "white";
+ }
+ };
+ el.onmouseover = (event) => {
+ el.style.backgroundColor = "aliceblue";
+ };
- this.el.appendChild(el)
- }
- }
+ this.el.appendChild(el);
+ }
+ }
}
class WuiVfsPath {
- el: HTMLElement
- private crumbs: string[]
- private onClick: PathClickHandler
+ el: HTMLElement;
+ private crumbs: string[];
+ private onClick: PathClickHandler;
- constructor(onClick: PathClickHandler) {
- this.el = document.createElement("div")
+ constructor(onClick: PathClickHandler) {
+ this.el = document.createElement("div");
- this.el.classList.add(CLASS_VFS_PATH)
- this.el.style.borderWidth = "1px"
- this.el.style.borderStyle = "solid"
- this.el.style.borderColor = "silver"
- this.crumbs = []
- this.onClick = onClick
- }
+ this.el.classList.add(CLASS_VFS_PATH);
+ this.el.style.borderWidth = "1px";
+ this.el.style.borderStyle = "solid";
+ this.el.style.borderColor = "silver";
+ this.crumbs = [];
+ this.onClick = onClick;
+ }
- Open(node: WuiVfsNodeInterface) {
- this.el.innerHTML = ""
- this.crumbs = []
- let paths = []
+ Open(node: WuiVfsNodeInterface) {
+ this.el.innerHTML = "";
+ this.crumbs = [];
+ let paths = [];
- if (node.path == "/") {
- paths.push(node.path)
- } else {
- paths = node.path.split("/")
- }
+ if (node.path == "/") {
+ paths.push(node.path);
+ } else {
+ paths = node.path.split("/");
+ }
- for (let x = 0; x < paths.length; x++) {
- let full_path = ""
- let p = ""
+ for (let x = 0; x < paths.length; x++) {
+ let full_path = "";
+ let p = "";
- if (x == 0) {
- p = "/"
- full_path = "/"
- } else {
- p = paths[x]
- full_path = paths.slice(0, x + 1).join("/")
- }
+ if (x == 0) {
+ p = "/";
+ full_path = "/";
+ } else {
+ p = paths[x];
+ full_path = paths.slice(0, x + 1).join("/");
+ }
- let crumb = document.createElement("span")
- crumb.style.display = "inline-block"
- crumb.style.padding = "1em"
- crumb.style.cursor = "pointer"
- crumb.innerHTML = p
+ let crumb = document.createElement("span");
+ crumb.style.display = "inline-block";
+ crumb.style.padding = "1em";
+ crumb.style.cursor = "pointer";
+ crumb.innerHTML = p;
- crumb.onclick = (event) => {
- this.onClick(full_path)
- }
- crumb.onmouseout = (event) => {
- crumb.style.backgroundColor = "white"
- }
- crumb.onmouseover = (event) => {
- crumb.style.backgroundColor = "aliceblue"
- }
+ crumb.onclick = (event) => {
+ this.onClick(full_path);
+ };
+ crumb.onmouseout = (event) => {
+ crumb.style.backgroundColor = "white";
+ };
+ crumb.onmouseover = (event) => {
+ crumb.style.backgroundColor = "aliceblue";
+ };
- this.el.appendChild(crumb)
- }
- }
+ this.el.appendChild(crumb);
+ }
+ }
}
diff --git a/websocket_client.ts b/websocket_client.ts
index ded53b2..7ffdbc0 100644
--- a/websocket_client.ts
+++ b/websocket_client.ts
@@ -1,165 +1,159 @@
// SPDX-FileCopyrightText: 2021 M. Shulhan <ms@kilabit.info>
// SPDX-License-Identifier: GPL-3.0-or-later
-import { WuiResponseInterface } from "./response.js"
+import { WuiResponseInterface } from "./response.js";
-const AUTO_RECONNECT_INTERVAL = 5000
+const AUTO_RECONNECT_INTERVAL = 5000;
interface RequestQueue {
- req: WuiWebSocketRequest
- cbSuccess: (res: WuiWebSocketResponse) => void
- cbFail: (err: string) => void
+ req: WuiWebSocketRequest;
+ cbSuccess: (res: WuiWebSocketResponse) => void;
+ cbFail: (err: string) => void;
}
export interface WuiWebSocketOptions {
- address: string
- auto_reconnect: boolean // If true the client will handle auto-reconnect.
- auto_reconnect_interval: number // The interval for auto-reconnect, default to 5 seconds.
- onBroadcast: (res: WuiWebSocketResponse) => void
- onConnected: () => void
- onDisconnected: () => void
- onError: () => void
+ address: string;
+ auto_reconnect: boolean; // If true the client will handle auto-reconnect.
+ auto_reconnect_interval: number; // The interval for auto-reconnect, default to 5 seconds.
+ onBroadcast: (res: WuiWebSocketResponse) => void;
+ onConnected: () => void;
+ onDisconnected: () => void;
+ onError: () => void;
}
export interface WuiWebSocketRequest {
- id: number
- method: string
- target: string
- body?: string
+ id: number;
+ method: string;
+ target: string;
+ body?: string;
}
export interface WuiWebSocketResponse {
- id: number
- code: number
- message: string
- body: string
+ id: number;
+ code: number;
+ message: string;
+ body: string;
}
export class WuiWebSocketClient {
- address: string
- conn!: WebSocket
- requestQueue: RequestQueue[] = []
- reconnect_id: number = 0
- isOpen: boolean = false
- error: string = ""
+ address: string;
+ conn!: WebSocket;
+ requestQueue: RequestQueue[] = [];
+ reconnect_id: number = 0;
+ isOpen: boolean = false;
+ error: string = "";
- constructor(public opts: WuiWebSocketOptions) {
- this.address = opts.address
- if (opts.auto_reconnect) {
- if (opts.auto_reconnect_interval <= 0) {
- opts.auto_reconnect_interval =
- AUTO_RECONNECT_INTERVAL
- }
- }
- this.connect()
- }
+ constructor(public opts: WuiWebSocketOptions) {
+ this.address = opts.address;
+ if (opts.auto_reconnect) {
+ if (opts.auto_reconnect_interval <= 0) {
+ opts.auto_reconnect_interval = AUTO_RECONNECT_INTERVAL;
+ }
+ }
+ this.connect();
+ }
- //
- // Send the request and wait for response similar to HTTP
- // request-response.
- //
- async Send(req: WuiWebSocketRequest): Promise<WuiResponseInterface> {
- return new Promise((resolve, reject) => {
- let wuiRes: WuiResponseInterface = {
- code: 0,
- message: "",
- }
- let reqQueue: RequestQueue = {
- req: req,
- cbSuccess: (res: WuiWebSocketResponse) => {
- wuiRes.code = res.code
- wuiRes.message = res.message
- if (
- res.code === 200 &&
- res.body.length > 0
- ) {
- wuiRes.data = JSON.parse(
- atob(res.body),
- )
- }
- resolve(wuiRes)
- },
- cbFail: (err: string) => {
- wuiRes.code = 500
- wuiRes.message = err
- resolve(wuiRes)
- },
- }
- this.requestQueue.push(reqQueue)
- this.conn.send(JSON.stringify(req))
- })
- }
+ //
+ // Send the request and wait for response similar to HTTP
+ // request-response.
+ //
+ async Send(req: WuiWebSocketRequest): Promise<WuiResponseInterface> {
+ return new Promise((resolve, reject) => {
+ let wuiRes: WuiResponseInterface = {
+ code: 0,
+ message: "",
+ };
+ let reqQueue: RequestQueue = {
+ req: req,
+ cbSuccess: (res: WuiWebSocketResponse) => {
+ wuiRes.code = res.code;
+ wuiRes.message = res.message;
+ if (res.code === 200 && res.body.length > 0) {
+ wuiRes.data = JSON.parse(atob(res.body));
+ }
+ resolve(wuiRes);
+ },
+ cbFail: (err: string) => {
+ wuiRes.code = 500;
+ wuiRes.message = err;
+ resolve(wuiRes);
+ },
+ };
+ this.requestQueue.push(reqQueue);
+ this.conn.send(JSON.stringify(req));
+ });
+ }
- connect() {
- this.conn = new WebSocket(this.address)
+ connect() {
+ this.conn = new WebSocket(this.address);
- this.conn.onclose = (ev: CloseEvent) => {
- this.onClose(ev)
- }
- this.conn.onerror = (ev: Event) => {
- this.onError(ev)
- }
- this.conn.onmessage = (ev: MessageEvent) => {
- this.onMessage(ev)
- }
- this.conn.onopen = (ev: Event) => {
- this.onOpen(ev)
- }
- }
+ this.conn.onclose = (ev: CloseEvent) => {
+ this.onClose(ev);
+ };
+ this.conn.onerror = (ev: Event) => {
+ this.onError(ev);
+ };
+ this.conn.onmessage = (ev: MessageEvent) => {
+ this.onMessage(ev);
+ };
+ this.conn.onopen = (ev: Event) => {
+ this.onOpen(ev);
+ };
+ }
- // onClose handle connection closed by cleaning up the request
- // queue.
- onClose(ev: CloseEvent) {
- for (let x = 0; x < this.requestQueue.length; x++) {
- this.requestQueue[x].cbFail("connection closed")
- }
+ // onClose handle connection closed by cleaning up the request
+ // queue.
+ onClose(ev: CloseEvent) {
+ for (let x = 0; x < this.requestQueue.length; x++) {
+ this.requestQueue[x].cbFail("connection closed");
+ }
- this.isOpen = false
- this.error = "connection is closed by server"
+ this.isOpen = false;
+ this.error = "connection is closed by server";
- if (this.opts.auto_reconnect && !this.reconnect_id) {
- this.reconnect_id = setInterval(() => {
- this.connect()
- }, this.opts.auto_reconnect_interval)
- }
- if (this.opts.onDisconnected) {
- this.opts.onDisconnected()
- }
- }
+ if (this.opts.auto_reconnect && !this.reconnect_id) {
+ this.reconnect_id = setInterval(() => {
+ this.connect();
+ }, this.opts.auto_reconnect_interval);
+ }
+ if (this.opts.onDisconnected) {
+ this.opts.onDisconnected();
+ }
+ }
- onError(ev: Event) {
- if (this.opts.onError) {
- this.opts.onError()
- }
- }
+ onError(ev: Event) {
+ if (this.opts.onError) {
+ this.opts.onError();
+ }
+ }
- onMessage(ev: MessageEvent) {
- let res: WuiWebSocketResponse = JSON.parse(ev.data)
+ onMessage(ev: MessageEvent) {
+ let res: WuiWebSocketResponse = JSON.parse(ev.data);
- for (let x = 0; x < this.requestQueue.length; x++) {
- let reqq = this.requestQueue[x]
- if (reqq.req.id === res.id) {
- reqq.cbSuccess(res)
- this.requestQueue.splice(x, 1)
- return
- }
- }
+ for (let x = 0; x < this.requestQueue.length; x++) {
+ let reqq = this.requestQueue[x];
+ if (reqq.req.id === res.id) {
+ reqq.cbSuccess(res);
+ this.requestQueue.splice(x, 1);
+ return;
+ }
+ }
- if (this.opts.onBroadcast && res.id == 0) {
- this.opts.onBroadcast(res)
- }
- }
+ if (this.opts.onBroadcast && res.id == 0) {
+ this.opts.onBroadcast(res);
+ }
+ }
- onOpen(ev: Event) {
- this.isOpen = true
- this.error = ""
+ onOpen(ev: Event) {
+ this.isOpen = true;
+ this.error = "";
- if (this.reconnect_id) {
- clearInterval(this.reconnect_id)
- this.reconnect_id = 0
- }
- if (this.opts.onConnected) {
- this.opts.onConnected()
- }
- }
+ if (this.reconnect_id) {
+ clearInterval(this.reconnect_id);
+ this.reconnect_id = 0;
+ }
+ if (this.opts.onConnected) {
+ this.opts.onConnected();
+ }
+ }
}