import { randomID } from '../../util/helpers.js'; import { Box } from './box.js'; export class FormElement extends Box { constructor(name, form, opts = {}) { const parentEl = opts.parentEl ?? form.el; super(name, parentEl, opts); this.form = form; this.id = opts.id ?? name; const { cb, cbEventTypes = ['change'], cbOnInit = false } = opts; if (cb) { cbEventTypes.forEach((eventType) => this.el.addEventListener(eventType, () => { cb(this, { initializing: false }); })); if (cbOnInit) { cb(this, { initializing: true }); } } } } export class Button extends FormElement { constructor(name, form, opts) { super(name, form, { ...opts, cbEventTypes: ['click'] }); this.button = document.createElement('button'); this.button.setAttribute('type', opts.type ?? 'button'); this.button.innerHTML = name; this.button.disabled = !!opts.disabled; if (opts.label) { this.label = document.createElement('label'); this.label.innerHTML = opts.label; this.label.appendChild(this.button); this.el.appendChild(this.label); } else { this.el.appendChild(this.button); } } } export class TextField extends FormElement { constructor(name, form, opts) { super(name, form, opts); this.label = document.createElement('label'); this.labelDiv = document.createElement('div'); this.label.appendChild(this.labelDiv); this.labelDiv.innerHTML = name; this.input = document.createElement('input'); this.input.disabled = !!opts.disabled; this.input.defaultValue = opts.defaultValue || ''; this.label.appendChild(this.input); this.el.appendChild(this.label); } get value() { return this.input?.value || null; } } export class TextArea extends FormElement { } export class SubFormArray extends FormElement { constructor(name, form, opts) { super(name, form, opts); this.subForms = []; } get value() { return this.subForms.map((subForm) => subForm.value); } remove(subForm) { const idx = this.subForms.findIndex((s) => s === subForm); this.subForms.splice(idx, 1); subForm.el.remove(); } } export class SubForm extends FormElement { constructor(name, form, opts) { const parentEl = opts.subFormArray ? opts.subFormArray.el : form.el; const subForm = form.document.form({ name, parentEl, tagName: 'div' }).lastElement; super(name, form, { ...opts, parentEl }); this.subForm = subForm; if (opts.subFormArray) { opts.subFormArray.subForms.push(this); } } get value() { return this.subForm.value; } } export class FileInput extends FormElement { constructor(name, form, opts) { super(name, form, opts); this.input = document.createElement('input'); this.input.type = 'file'; this.input.accept = 'application/json'; // this.input.classList.add('visually-hidden') this.label = document.createElement('label'); this.label.innerHTML = name; this.label.appendChild(this.input); this.el.appendChild(this.label); } } export class Form extends Box { constructor(document, opts = {}) { super(opts.name, opts.parentEl || document.el, { tagName: 'form', ...opts }); this.document = document; this.items = []; this.id = opts.id ?? `form_${randomID()}`; // Action should be handled by a submit button this.el.onsubmit = () => false; } button(opts) { this.items.push(new Button(opts.name, this, opts)); return this; } submit(opts) { this.items.push(new Button(opts.name, this, { ...opts, type: 'submit' })); return this; } textField(opts) { this.items.push(new TextField(opts.name, this, opts)); return this; } textArea(opts) { this.items.push(new TextArea(opts.name, this, opts)); return this; } subForm(opts) { this.items.push(new SubForm(opts.name, this, opts)); return this; } subFormArray(opts) { this.items.push(new SubFormArray(opts.name, this, opts)); return this; } fileInput(opts) { this.items.push(new FileInput(opts.label || opts.name, this, opts)); return this; } get lastItem() { return this.items[this.items.length - 1]; } get value() { return this.items.reduce((obj, { id, value }) => { if (value !== undefined) { obj[id] = value; } return obj; }, {}); } }