Page MenuHomeSealhub

mountable.ts
No OneTemporary

mountable.ts

import Router from "@koa/router";
import { FormControl } from "../forms/controls/form-control";
import { Context } from "koa";
import { FlatTemplatable, tempstream } from "tempstream";
import { FormField } from "../forms/fields/field";
import { FormData, FormDataValue, FormMessage } from "../forms/form";
export type PageErrorMessage = { type: "access" | "internal"; message: string };
export type Fields = Record<string, FormField<unknown>>;
export abstract class Mountable<F extends Fields = Fields> {
fields: F;
constructor() {
if (!this.fields) this.fields = {} as F;
}
abstract controls: FormControl[];
abstract mount(router: Router, path: string): void;
abstract canAccess(
ctx: Context
): Promise<{ canAccess: boolean; message: string }>;
abstract renderError(
ctx: Context,
error: PageErrorMessage
): Promise<FlatTemplatable>;
abstract extractRawValues(ctx: Context): Record<string, FormDataValue>;
// this one is meant to be overwritten
async validateValues(
ctx: Context,
data: Record<string, FormDataValue>
): Promise<{ valid: boolean; error: string }> {
return {
valid: true,
error: "",
};
}
protected async validate(
ctx: Context,
values: Record<string, FormDataValue>
): Promise<{
valid: boolean;
field_errors: Partial<Record<keyof Fields, string>>;
form_messages: FormMessage[];
}> {
const field_errors = {} as Record<keyof Fields, string>;
let valid = true;
const form_messages = [] as FormMessage[];
await Promise.all(
Object.entries(values)
.filter(([fieldname]) => fieldname in this.fields)
.map(async ([key]: [keyof F, FormDataValue]) => {
const field = this.fields[key];
const { valid: fieldvalid, message: fieldmessage } =
await field.getValue(ctx, values);
if (!fieldvalid) {
valid = false;
field_errors[field.name] = fieldmessage;
}
})
);
const formValidationResult = await this.validateValues(ctx, values);
if (!formValidationResult.valid) {
form_messages.push({
type: "error",
text: formValidationResult.error,
});
valid = false;
}
return { valid, field_errors, form_messages };
}
init(): void {
for (const [name, field] of Object.entries(this.fields)) {
field.init(name);
}
}
public renderControls(
ctx: Context,
data: FormData<keyof Fields>
): FlatTemplatable {
return tempstream/* HTML */ `${this.controls.map((control) =>
control.render(ctx, data.raw_values, data.messages)
)}`;
}
public renderMessages(
_: Context,
data: FormData<keyof Fields>
): FlatTemplatable {
return tempstream/* HTML */ `<div class="form-messages">
${data.messages.map(
(message) =>
`<div class="form-message form-message--${message.type}">${message.text}</div>`
)}
</div>`;
}
}

File Metadata

Mime Type
text/x-java
Expires
Sun, Sep 21, 01:00 (1 d, 20 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
931830
Default Alt Text
mountable.ts (2 KB)

Event Timeline