@twobirds/microcomponents
Version:
Micro Components Organization Class
226 lines (184 loc) • 4.59 kB
text/typescript
;
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();
});
});
}