Files
gg 675d7775c1 feat: oninput-Callback zum Input-Widget hinzugefügt
Ermöglicht ein Live-Binding der Eingabewerte, damit Eingaben bei einem
Redraw (z.B. durch interaktive Elemente außerhalb des Inputs) nicht
verloren gehen.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-09-19 14:07:30 +02:00

144 lines
5.4 KiB
TypeScript

import m from "mithril"
/**
* Der Vnode der Komponente 'Input' akzeptiert die folgenden Parameter:
* @property {string} name - Der Name des Feldes
* @property {any} value - der darzustellende Wert
* @property {string} type (optional) - der Type des Input Felds. Möglich sind alle Type des HTML-Elements 'Input'
* @property {string|number} width (optional) - die Breite des Input Felds. Möglich sind alle Längeneinheiten, die bom Width-Attribut möglich sind
* @property {number} min (optional) -
* @property {number} max (optional) -
* @property {number} step (optional) -
* @property {boolean} autofocus (optional) -
*/
export interface iInput {
name: string
value: any
type?: string
width?: string
min?: number
max?: number
step?: number
autofocus?: boolean
readonly?: boolean
required?:boolean
onchanged?: Function
oninput?: Function
}
/**
* Diese Komponente stellt ein Html-Input Element dar. Der darzustellende Wert wird einfach mit dem Attribut
* 'value' übergeben. Der eingegebene Wert muss dann später explizit aus Value abgefragt werden. Es findet also kein
* sutomatisches Binding statt. Über den oninput-Callback kann jedoch ein Live-Binding realisiert werden,
* damit Eingaben bei einem Redraw (z.B. durch interaktive Elemente außerhalb des Inputs) nicht verloren gehen.
*/
export const Input:m.Component<iInput> = {
onupdate: (vnode) => {
if (vnode.attrs.autofocus != undefined && vnode.attrs.autofocus == true) {
let e: HTMLElement = vnode.dom as HTMLElement
e.focus()
}
},
view: (vnode) => {
let attributes = {}
let width:number|string = '100%'
attributes['name'] = vnode.attrs.name
attributes['type'] = vnode.attrs.type == undefined ? 'text' : vnode.attrs.type
if (attributes['type'] == 'number') {
if (vnode.attrs.min != undefined) {
attributes['min'] = vnode.attrs.min
}
if (vnode.attrs.max != undefined) {
attributes['max'] = vnode.attrs.max
}
if (vnode.attrs.step != undefined) {
attributes['step'] = vnode.attrs.step
}
}
if (attributes['type'] == 'date') {
attributes['value'] = toDateInputValue(vnode.attrs.value)
}
else {
attributes['value'] = vnode.attrs.value
}
if (vnode.attrs.required != undefined && vnode.attrs.required == true) {
attributes['required'] = vnode.attrs.required
}
if (vnode.attrs.readonly != undefined && vnode.attrs.readonly == true) {
attributes['readonly'] = "true"
}
if (vnode.attrs.width != undefined) {
width = vnode.attrs.width
}
attributes['style'] = {'margin-bottom': '5px', 'width': width}
if (vnode.attrs.onchanged != undefined) {
attributes['onchange'] = vnode.attrs.onchanged
}
if (vnode.attrs.oninput != undefined) {
attributes['oninput'] = vnode.attrs.oninput
}
return m("input.w3-input.w3-border", attributes)
}
}
export interface iTextarea {
name: string
value: any
cols?: number
rows?: number
autofocus?: boolean
readonly?: boolean
}
/**
* Diese Komponente stellt ein Html-Textarea Element dar. Der darzustellende Wert wird einfach mit dem Attribut
* 'value' übergeben. Der eingegebene Wert muss dann später explizit aus Value abgefragt werden. Es findet also kein
* automatisches Binding statt.
*/
export const Textarea:m.Component<iTextarea> = {
onupdate: (vnode) => {
if (vnode.attrs.autofocus != undefined && vnode.attrs.autofocus == true) {
let e: HTMLElement = vnode.dom as HTMLElement
e.focus()
}
},
view: (vnode) => {
let attributes = {}
attributes['name'] = vnode.attrs.name
attributes['value'] = vnode.attrs.value
if (vnode.attrs.cols != undefined) {
attributes['cols'] = vnode.attrs.cols
}
if (vnode.attrs.rows != undefined) {
attributes['rows'] = vnode.attrs.rows
}
if (vnode.attrs.readonly != undefined && vnode.attrs.readonly == true) {
attributes['readonly'] = vnode.attrs.readonly
}
attributes['style'] = {'margin-bottom': '5px', "width": '100%'}
return m("textarea.w3-input.w3-border.w3-mobile", attributes)
}
}
export function toDateInputValue(date: Date|string): string {
let result: string = null
if (typeof date === "string") {
// String-Datumswerte (aus der DB) auf das vom HTML-Date-Input
// geforderte Format yyyy-MM-dd normalisieren (führende Nullen).
if (date === "") {
result = ""
} else {
const parts = date.split("-")
if (parts.length === 3) {
result = [parts[0], parts[1].padStart(2, "0"), parts[2].padStart(2, "0")].join("-")
} else {
result = date
}
}
} else if (date instanceof Date && date != null) {
result = [date.getFullYear(), (date.getMonth() + 1).toString().padStart(2, "0"), date.getDate().toString().padStart(2, "0")].join("-")
}
return result
}