Modelle: startdatum (Projekt), datum und wiedervorlage_datum (CallLog) von String(20) auf Date umgestellt. columns2dict serialisiert diese nun über isoformat() als yyyy-MM-dd. Die String-Normalisierung in columns2dict wurde entfernt, da sie nicht mehr benötigt wird. Migration V01.08: Normalisiert bestehende String-Datumswerte (z.B. '2026-08-3') auf ISO-Format yyyy-MM-dd mittels printf/substr, da SQLite's date() einstellige Komponenten nicht erkennt. Leere Strings werden zu NULL. V01.07 ist Platzhalter für die fehlgeschlagene V01.06. Client: toDateInputValue normalisiert ebenfalls String-Datumswerte als Fallback für Route-Params (Neuanlage). Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
139 lines
5.1 KiB
TypeScript
139 lines
5.1 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
|
|
}
|
|
/**
|
|
* 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.
|
|
*/
|
|
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
|
|
}
|
|
|
|
|
|
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
|
|
} |