diff options
author | Hugo Hörnquist <hugo@lysator.liu.se> | 2023-09-13 00:01:28 +0200 |
---|---|---|
committer | Hugo Hörnquist <hugo@lysator.liu.se> | 2023-09-13 00:01:28 +0200 |
commit | a82b6c772089aa46e30c6c89ef48f514294df3cb (patch) | |
tree | e25d9b6fd1fefe8b6ac293a5c0b53293872a8f54 /static/ts/components/input-list.ts | |
parent | Add basic documentation for lens. (diff) | |
parent | Even more documentation. (diff) | |
download | calp-a82b6c772089aa46e30c6c89ef48f514294df3cb.tar.gz calp-a82b6c772089aa46e30c6c89ef48f514294df3cb.tar.xz |
Merge branch 'next' into datarewrite-structures
Diffstat (limited to '')
-rw-r--r-- | static/ts/components/input-list.ts (renamed from static/components/input-list.ts) | 84 |
1 files changed, 73 insertions, 11 deletions
diff --git a/static/components/input-list.ts b/static/ts/components/input-list.ts index 0afd4999..72d27cab 100644 --- a/static/components/input-list.ts +++ b/static/ts/components/input-list.ts @@ -1,29 +1,75 @@ +/** + * `<input-list />` + * + * A list of identical input fields, which forms a group. For example + * useful to handle keywords. + * + * @category Web Components + * @mergeTarget components + * @module + */ export { InputList } /* TODO allow each item to be a larger unit, possibly containing multiple input fields. */ +/** + A multi-valued input, done by creating extra input fields as needed. + + The first element of body MUST be an input element, which will be used as the + template for each instance. A tag input could for example look like + + @example + ```html + <input-list name="tags"> + <input type="text" placeholder="tag ..." /> + </input-list> + ``` + + Whenever one of the input elements `value` becomes the empty string, that tag + is removed, and whenever there is no element with the empty string as a + `value`, a new input element will be added onto the end. + */ class InputList extends HTMLElement { - el: HTMLInputElement; + /** The element used as our template. Will be sourced from the initial HTML code. */ + #el: HTMLInputElement; + /** + Registered listeners, which will be added onto each created entry + + Keys are event names ('input', 'change', ...) and values event handlers. + + This is a list of tuples rather than a dictionary, since multiple + listeners of the same type can be registered. + */ #listeners: [string, (e: Event) => void][] = []; constructor() { super(); - this.el = this.children[0].cloneNode(true) as HTMLInputElement; + this.#el = this.children[0].cloneNode(true) as HTMLInputElement; } + /** Clears all existing children upon mount */ connectedCallback() { for (let child of this.children) { child.remove(); } - this.addInstance(); + this.#addInstance(); } - createInstance(): HTMLInputElement { - let new_el = this.el.cloneNode(true) as HTMLInputElement + /** + Instanciates a new instance of the input element. + + An event listener for 'input' will be added, which will handle the + addition and removing of other elements. + + All event listeners attachet on the input-list component will also be + added. + */ + #createInstance(): HTMLInputElement { + let new_el = this.#el.cloneNode(true) as HTMLInputElement let that = this; new_el.addEventListener('input', function() { /* TODO .value is empty both if it's actually empty, but also @@ -39,7 +85,7 @@ class InputList extends HTMLElement { } } else { if (!this.nextElementSibling) { - that.addInstance(); + that.#addInstance(); // window.setTimeout(() => this.focus()) this.focus(); } @@ -53,12 +99,17 @@ class InputList extends HTMLElement { return new_el; } - addInstance() { - let new_el = this.createInstance(); + /** Add a new instance of the input element to the container */ + #addInstance() { + let new_el = this.#createInstance(); this.appendChild(new_el); } - get value(): any[] { + /** + * The value from each element, except the last which should always be empty. + * Has an unspecified type, since children:s value field might give non-strings. + */ + get value(): unknown[] { let value_list = [] for (let child of this.children) { value_list.push((child as any).value); @@ -69,6 +120,12 @@ class InputList extends HTMLElement { return value_list } + /** + Overwrite the current value with a new one. + + Each entry in the array will be mapped unto one instance of the template + input element. A final empty element will also be added. + */ set value(new_value: any[]) { let all_equal = true; @@ -97,17 +154,22 @@ class InputList extends HTMLElement { /* clear dictionary */ values.set(value, false); } else { - let new_el = this.createInstance(); + let new_el = this.#createInstance(); new_el.value = value; output_list.push(new_el); } } /* final, trailing, element */ - output_list.push(this.createInstance()); + output_list.push(this.#createInstance()); this.replaceChildren(...output_list); } + /** + Add an event listener to each of the inputs. + + This basically works as the "regular" version. + */ addEventListener(type: string, proc: ((e: Event) => void)) { // if (type != 'input') throw "Only input supported"; |