1 import {EditorUiContext, EditorUiElement, EditorContainerUiElement} from "./core";
2 import {el} from "../../helpers";
4 export interface EditorFormFieldDefinition {
7 type: 'text' | 'select' | 'textarea';
10 export interface EditorSelectFormFieldDefinition extends EditorFormFieldDefinition {
12 valuesByLabel: Record<string, string>
15 export interface EditorFormDefinition {
17 action: (formData: FormData, context: EditorUiContext) => boolean;
18 fields: EditorFormFieldDefinition[];
21 export class EditorFormField extends EditorUiElement {
22 protected definition: EditorFormFieldDefinition;
24 constructor(definition: EditorFormFieldDefinition) {
26 this.definition = definition;
29 setValue(value: string) {
30 const input = this.getDOMElement().querySelector('input,select,textarea') as HTMLInputElement;
35 return this.definition.name;
38 protected buildDOM(): HTMLElement {
39 const id = `editor-form-field-${this.definition.name}-${Date.now()}`;
40 let input: HTMLElement;
42 if (this.definition.type === 'select') {
43 const options = (this.definition as EditorSelectFormFieldDefinition).valuesByLabel
44 const labels = Object.keys(options);
45 const optionElems = labels.map(label => el('option', {value: options[label]}, [label]));
46 input = el('select', {id, name: this.definition.name, class: 'editor-form-field-input'}, optionElems);
47 } else if (this.definition.type === 'textarea') {
48 input = el('textarea', {id, name: this.definition.name, class: 'editor-form-field-input'});
50 input = el('input', {id, name: this.definition.name, class: 'editor-form-field-input'});
53 return el('div', {class: 'editor-form-field-wrapper'}, [
54 el('label', {class: 'editor-form-field-label', for: id}, [this.trans(this.definition.label)]),
60 export class EditorForm extends EditorContainerUiElement {
61 protected definition: EditorFormDefinition;
62 protected onCancel: null|(() => void) = null;
64 constructor(definition: EditorFormDefinition) {
65 super(definition.fields.map(fieldDefinition => new EditorFormField(fieldDefinition)));
66 this.definition = definition;
69 setValues(values: Record<string, string>) {
70 for (const name of Object.keys(values)) {
71 const field = this.getFieldByName(name);
73 field.setValue(values[name]);
78 setOnCancel(callback: () => void) {
79 this.onCancel = callback;
82 protected getFieldByName(name: string): EditorFormField|null {
83 for (const child of this.children as EditorFormField[]) {
84 if (child.getName() === name) {
92 protected buildDOM(): HTMLElement {
93 const cancelButton = el('button', {type: 'button', class: 'editor-form-action-secondary'}, [this.trans('Cancel')]);
94 const form = el('form', {}, [
95 ...this.children.map(child => child.getDOMElement()),
96 el('div', {class: 'editor-form-actions'}, [
98 el('button', {type: 'submit', class: 'editor-form-action-primary'}, [this.trans(this.definition.submitText)]),
102 form.addEventListener('submit', (event) => {
103 event.preventDefault();
104 const formData = new FormData(form as HTMLFormElement);
105 this.definition.action(formData, this.getContext());
108 cancelButton.addEventListener('click', (event) => {