From 1df15b2ceaef09b48a39aa6046b577da11ea2f72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Fri, 26 Nov 2021 15:32:41 +0100 Subject: Got categories working. --- static/components/input-list.ts | 101 +++++++++++++++++++++++++++++++-------- static/components/vevent-edit.ts | 8 +++- 2 files changed, 88 insertions(+), 21 deletions(-) (limited to 'static/components') diff --git a/static/components/input-list.ts b/static/components/input-list.ts index 326cb2b5..899e8f4f 100644 --- a/static/components/input-list.ts +++ b/static/components/input-list.ts @@ -2,11 +2,15 @@ export { InputList } /* This file replaces input_list.js */ +/* + TODO allow each item to be a larger unit, possibly containing multiple input + fields. +*/ class InputList extends HTMLElement { el: HTMLInputElement; - values: [HTMLInputElement, any][] = []; + _listeners: [string, (e: Event) => void][] = []; constructor() { super(); @@ -14,20 +18,27 @@ class InputList extends HTMLElement { } connectedCallback() { + for (let child of this.children) { + child.remove(); + } this.addInstance(); } - addInstance() { + 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 + for invalid input. Check new_el.validity, and new_el.validationMessage + */ if (new_el.value === '') { - let sibling = this.previousElementSibling || this.nextElementSibling; - // this.remove(); - // that.values = that.values.filter((p) => p[0] == this) - that.values = that.values.filter((p) => p[0] != this); - this.remove(); - (sibling as HTMLInputElement).focus(); + let sibling = (this.previousElementSibling || this.nextElementSibling) + /* Only remove ourselves if we have siblings + Otherwise we just linger */ + if (sibling) { + this.remove(); + (sibling as HTMLInputElement).focus(); + } } else { if (!this.nextElementSibling) { that.addInstance(); @@ -36,24 +47,76 @@ class InputList extends HTMLElement { } } }); - this.values.push([new_el, '']) - // this.appendChild(new_el); - this.replaceChildren(... this.values.map((p) => p[0])) + + for (let [type, proc] of this._listeners) { + new_el.addEventListener(type, proc); + } + + return new_el; + } + + addInstance() { + let new_el = this.createInstance(); + this.appendChild(new_el); } get value(): any[] { - return [] + let value_list = [] + for (let child of this.children) { + value_list.push((child as any).value); + } + if (value_list[value_list.length - 1] === '') { + value_list.pop(); + } + return value_list } set value(new_value: any[]) { - let els = []; + + let all_equal = true; + for (let i = 0; i < this.children.length; i++) { + let sv = (this.children[i] as any).value + all_equal + &&= (sv == new_value[i]) + || (sv === '' && new_value[i] == undefined) + } + if (all_equal) return; + + /* Copy our current input elements into a dictionary. + This allows us to only create new elements where needed + */ + let values = new Map; + for (let child of this.children) { + values.set((child as HTMLInputElement).value, child); + } + + let output_list: HTMLInputElement[] = [] for (let value of new_value) { - let new_el = this.el.cloneNode() as HTMLInputElement; - new_el.value = value; - els.push(new_el); + let element; + /* Only create element if needed */ + if ((element = values.get(value))) { + output_list.push(element) + /* clear dictionary */ + values.set(value, false); + } else { + let new_el = this.createInstance(); + new_el.value = value; + output_list.push(new_el); + } + } + /* final, trailing, element */ + output_list.push(this.createInstance()); + + this.replaceChildren(...output_list); + } + + addEventListener(type: string, proc: ((e: Event) => void)) { + // if (type != 'input') throw "Only input supported"; + + this._listeners.push([type, proc]) + + for (let child of this.children) { + child.addEventListener(type, proc); } - /* Final element (empty) */ - els.push(this.el.cloneNode() as HTMLInputElement); - this.replaceChildren(...els); } } diff --git a/static/components/vevent-edit.ts b/static/components/vevent-edit.ts index 4408cbb8..b9b733a0 100644 --- a/static/components/vevent-edit.ts +++ b/static/components/vevent-edit.ts @@ -1,9 +1,10 @@ export { ComponentEdit } import { ComponentVEvent } from './vevent' +import { InputList } from './input-list' import { DateTimeInput } from './date-time-input' -import { vcal_objects, event_calendar_mapping } from '../globals' +import { vcal_objects } from '../globals' import { VEvent } from '../vevent' import { create_event } from '../server_connect' @@ -55,18 +56,21 @@ class ComponentEdit extends ComponentVEvent { // for (let el of this.getElementsByClassName("interactive")) { for (let el of this.querySelectorAll("[data-property]")) { // console.log(el); - el.addEventListener('input', () => { + el.addEventListener('input', (e) => { let obj = vcal_objects.get(this.uid) + console.log(el, e); if (obj === undefined) { throw 'No object with uid ' + this.uid } if (!(el instanceof HTMLInputElement || el instanceof DateTimeInput || el instanceof HTMLTextAreaElement + || el instanceof InputList )) { console.log(el, 'not an HTMLInputElement'); return; } + // console.log(`obj[${el.dataset.property!}] = `, el.value); obj.setProperty( el.dataset.property!, el.value) -- cgit v1.2.3