UNPKG

@twobirds/microcomponents

Version:

Micro Components Organization Class

226 lines (184 loc) 4.59 kB
'use strict'; import { LooseObject, copyGettersSetters } from './helpers.js'; import { DC, addListener } from './MC.js'; import { observe } from './observables.js'; type inputTypes = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement; const getInputName = ( e: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement ): string => { return e.tagName.toLowerCase(); }; abstract class InputBase { constructor(e: inputTypes) {} abstract get val(): any; abstract set val(value: any); } class RadioHandler extends InputBase { #e: HTMLInputElement; constructor(e: HTMLInputElement) { super(e); this.#e = e; } get val(): string { let ret = new FormData(this.#e.form as HTMLFormElement).get(this.#e.name); //console.log('radio[', this.#e.name, '] = "' + ret + '"'); return ret as string; } set val(value: string) { let arr = [ ...(this.#e.form as HTMLFormElement).querySelectorAll( `input[type="radio"][name="${this.#e.name}"]` ), ] as HTMLInputElement[]; ( arr .filter((e) => e.getAttribute('value') === value) .shift() as HTMLInputElement ).checked = true; } } class CheckboxHandler extends InputBase { #e: HTMLInputElement; constructor(e: HTMLInputElement) { super(e); this.#e = e; } get val(): boolean { return this.#e.checked; } set val(value: boolean) { this.#e.checked = value; } } class InputHandler extends InputBase { #e: HTMLInputElement; constructor(e: HTMLInputElement) { super(e); this.#e = e; } get val(): string { return this.#e.value; } set val(value: string) { this.#e.value = value; } } class SelectHandler extends InputBase { #e: HTMLSelectElement; #multi: boolean = false; constructor(e: HTMLSelectElement) { super(e); this.#e = e; this.#multi = e.multiple; } get val(): string[] | string { const that = this, ret: string[] = []; // get all options [...that.#e.querySelectorAll('option')] .filter((o) => o.selected) .forEach((o) => { ret.push(o.value); }); if (this.#multi) return ret; return ret.length ? ret[0] : ''; } set val(value: string[] | string) { const that = this; value = typeof value === 'string' ? [value] : value; // set all options [...that.#e.querySelectorAll('option')].forEach((o) => { if (value.indexOf(o.value) > -1) { o.selected = true; } else { o.selected = false; } }); } } class TextAreaHandler extends InputBase { #e: HTMLTextAreaElement; constructor(e: HTMLTextAreaElement) { super(e); this.#e = e; } get val(): string { return this.#e.value || ''; } set val(value: string) { this.#e.value = value; } } const getInputHandlers = (e: HTMLElement | ShadowRoot): LooseObject => { let inputList = [ ...(e || document).querySelectorAll('input,select,textarea'), ], handlers: LooseObject = {}; inputList.forEach((i) => { const name: string | null = (i as inputTypes).getAttribute('name'); if (name) { let handler: any = false; switch (getInputName(i as inputTypes)) { case 'input': switch ((i as HTMLInputElement).type) { case 'radio': handler = new RadioHandler(i as HTMLInputElement); break; case 'checkbox': handler = new CheckboxHandler(i as HTMLInputElement); break; default: handler = new InputHandler(i as HTMLInputElement); } break; case 'select': handler = new SelectHandler(i as HTMLSelectElement); break; case 'textarea': handler = new TextAreaHandler(i as HTMLTextAreaElement); break; default: console.warn( 'handler missing:', name, 'for', i.tagName.toLowerCase(), i ); break; } if (handler) { DC.add(i, name, handler); Object.defineProperty(handlers, name, { enumerable: true, configurable: true, get: (): any => { return handler.val; }, set: (value: any) => { if (handler.val !== value) { handler.val = value; } }, }); } } }); return handlers; }; export function formValues( targetObject: LooseObject, propertyName: string, dom: HTMLElement | ShadowRoot ) { let handlers = getInputHandlers(dom); targetObject[propertyName] = Object.assign({}, handlers); observe(targetObject, propertyName); copyGettersSetters(handlers, targetObject[propertyName]); [...dom.querySelectorAll('input, textarea, select')].forEach((input) => { addListener(input as inputTypes, 'input', (ev: Event) => { //console.log('keyup', ev); targetObject[propertyName].notify(); }); }); }