import TypedEvent, { Listener, Disposable } from "./lib/TypedEvent"; import { AnyObject } from "./lib/types"; import { t } from "./lib"; // TODO: Document export abstract class InputGroup { private _name: string = ""; private _element?: HTMLElement; public initialData: Data; protected currentData: Partial = {}; public constructor(name: string, initialData: Data) { this.name = name; this.initialData = initialData; } public set name(name: string) { if (name.length === 0) throw new RangeError("empty name"); this._name = name; } public get name(): string { return this._name; } public get data(): Partial { return { ...this.currentData }; } public get element(): HTMLElement { if (this._element == null) { const element = document.createElement("div"); element.className = `input-group input-group-${this.name}`; const content = this.createContent(); if (content instanceof Array) { content.forEach(element.appendChild); } else { element.appendChild(content); } this._element = element; } return this._element; } public reset(): void { this.currentData = {}; } protected updateData(data: Partial): void { this.currentData = { ...this.currentData, ...data }; // TODO: Update item. } protected abstract createContent(): HTMLElement | HTMLElement[]; // public abstract get isValid(): boolean; } export interface SubmitFormEvent { nativeEvent: Event; data: AnyObject; } // TODO: Document export class FormContainer { public readonly title: string; private inputGroupsByName: { [name: string]: InputGroup } = {}; private enabledInputGroupNames: string[] = []; // Event manager for submit events. private readonly submitEventManager = new TypedEvent(); public constructor( title: string, inputGroups: InputGroup[] = [], enabledInputGroups: string[] = [] ) { this.title = title; if (inputGroups.length > 0) { this.inputGroupsByName = inputGroups.reduce((prevVal, inputGroup) => { prevVal[inputGroup.name] = inputGroup; return prevVal; }, this.inputGroupsByName); } if (enabledInputGroups.length > 0) { this.enabledInputGroupNames = [ ...this.enabledInputGroupNames, ...enabledInputGroups.filter( name => this.inputGroupsByName[name] != null ) ]; } } public getInputGroup(inputGroupName: string): InputGroup | null { return this.inputGroupsByName[inputGroupName] || null; } public addInputGroup( inputGroup: InputGroup, index: number | null = null ): FormContainer { this.inputGroupsByName[inputGroup.name] = inputGroup; // Remove the current stored name if exist. this.enabledInputGroupNames = this.enabledInputGroupNames.filter( name => name === inputGroup.name ); if (index !== null) { if (index <= 0) { this.enabledInputGroupNames = [ inputGroup.name, ...this.enabledInputGroupNames ]; } else if (index >= this.enabledInputGroupNames.length) { this.enabledInputGroupNames = [ ...this.enabledInputGroupNames, inputGroup.name ]; } else { this.enabledInputGroupNames = [ // part of the array before the specified index ...this.enabledInputGroupNames.slice(0, index), // inserted item inputGroup.name, // part of the array after the specified index ...this.enabledInputGroupNames.slice(index) ]; } } else { this.enabledInputGroupNames = [ ...this.enabledInputGroupNames, inputGroup.name ]; } return this; } public removeInputGroup(inputGroupName: string): FormContainer { // delete this.inputGroupsByName[inputGroupName]; // Remove the current stored name. this.enabledInputGroupNames = this.enabledInputGroupNames.filter( name => name === inputGroupName ); return this; } public getFormElement( type: "creation" | "update" = "update" ): HTMLFormElement { const form = document.createElement("form"); form.className = "visual-console-item-edition"; form.addEventListener("submit", e => { e.preventDefault(); this.submitEventManager.emit({ nativeEvent: e, data: this.enabledInputGroupNames.reduce((data, name) => { if (this.inputGroupsByName[name]) { data = { ...data, ...this.inputGroupsByName[name].data }; } return data; }, {}) }); }); const formContent = document.createElement("div"); formContent.className = "input-groups"; this.enabledInputGroupNames.forEach(name => { if (this.inputGroupsByName[name]) { formContent.appendChild(this.inputGroupsByName[name].element); } }); // Add buttons. const submitBtn = document.createElement("input"); submitBtn.className = "sub upd"; submitBtn.type = "submit"; submitBtn.value = type === "creation" ? t("Create") : t("Update"); form.appendChild(formContent); form.appendChild(submitBtn); return form; } public reset(): void { this.enabledInputGroupNames.forEach(name => { if (this.inputGroupsByName[name]) { this.inputGroupsByName[name].reset(); } }); } // public get isValid(): boolean { // for (let i = 0; i < this.enabledInputGroupNames.length; i++) { // const inputGroup = this.inputGroupsByName[this.enabledInputGroupNames[i]]; // if (inputGroup && !inputGroup.isValid) return false; // } // return true; // } public onSubmit(listener: Listener): Disposable { return this.submitEventManager.on(listener); } }