feat(workflow): Workflow-Buttons in die Standard-Button-Leiste der Form integrieren

Die Workflow-Buttons ("Nächster Kontakt", "Speichern und weiter") standen
bisher in einer eigenen Zeile über der Standard-Leiste (Zurücksetzen,
Abbrechen, Speichern). Das Form-Widget erhält dafür das neue optionale
Attribut extrabuttons, dessen Buttons rechts neben "Speichern" in die
Leiste eingereiht werden — sie profitieren damit auch vom Sticky-Verhalten
der Leiste.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
gg committed 2026-09-24 19:24:50 +02:00
1 parent 4d8febcc3f
commit 32afb35840
2 files changed
+45 -30

No files matched your search

+32 -30
View File
@@ -583,6 +583,37 @@ export const TagesWorkflowMaske: m.ClosureComponent = () => {
formDirty = dirty formDirty = dirty
origOnDirtyChange(dirty) origOnDirtyChange(dirty)
} }
// Workflow-Buttons nicht als eigene Zeile über der Standard-
// Leiste, sondern in diese eingereiht (extrabuttons der Form):
// "Nächster Kontakt" und "Speichern und weiter" erscheinen
// rechts neben "Speichern", "Speichern und weiter" ganz rechts
// als Primäraktion des Workflows.
formAttrs.extrabuttons = [
m("button.w3-button.w3-theme.w3-right.w3-mobile", {
type: "button",
onclick: () => {
weiterNachSpeichern = true
if (formRef && typeof formRef.requestSubmit === "function") {
formRef.requestSubmit()
}
}
},
m("i.material-icons", {style: {verticalAlign: 'middle', marginRight: '4px'}}, "skip_next"),
"Speichern und weiter"),
m("button.w3-button.w3-theme-l2.w3-right.w3-mobile", {
type: "button",
style: {'margin-right': '4px'},
onclick: () => {
if (formDirty &&
!window.confirm("Es gibt ungespeicherte Eingaben. Ohne Speichern zum nächsten Kontakt wechseln?")) {
return
}
naechsterKontakt()
}
},
m("i.material-icons", {style: {verticalAlign: 'middle', marginRight: '4px'}}, "arrow_forward"),
"Nächster Kontakt")
]
// Tag-Optionen und Farb-Map für die Mehrfachauswahl. // Tag-Optionen und Farb-Map für die Mehrfachauswahl.
const tagOptionen: iSelectOption[] = tagListe.map((t: iTag) => { const tagOptionen: iSelectOption[] = tagListe.map((t: iTag) => {
@@ -723,36 +754,7 @@ export const TagesWorkflowMaske: m.ClosureComponent = () => {
oninput: (e: Event) => { oninput: (e: Event) => {
wiedervorlageDatum = (e.target as HTMLInputElement).value wiedervorlageDatum = (e.target as HTMLInputElement).value
} }
} as iInput)), } as iInput))
// ---- Workflow-Navigation ----
// "Speichern" und "Abbrechen" (= Zurück zur Liste)
// liefert der Form-Standard-Button-Bereich.
m("div.w3-bar.w3-padding-16",
m("button.w3-button.w3-theme.w3-right", {
type: "button",
onclick: () => {
weiterNachSpeichern = true
if (formRef && typeof formRef.requestSubmit === "function") {
formRef.requestSubmit()
}
}
},
m("i.material-icons", {style: {verticalAlign: 'middle', marginRight: '4px'}}, "skip_next"),
"Speichern und weiter"),
m("button.w3-button.w3-theme-l2.w3-right", {
type: "button",
style: {'margin-right': '4px'},
onclick: () => {
if (formDirty &&
!window.confirm("Es gibt ungespeicherte Eingaben. Ohne Speichern zum nächsten Kontakt wechseln?")) {
return
}
naechsterKontakt()
}
},
m("i.material-icons", {style: {verticalAlign: 'middle', marginRight: '4px'}}, "arrow_forward"),
"Nächster Kontakt")
)
]) ])
) )
) )
+13
View File
@@ -19,6 +19,14 @@ export interface iForm {
* der Form synchron zu halten und so den Navigations-Guard * der Form synchron zu halten und so den Navigations-Guard
* (dirtyguard.ts) zu speisen. */ * (dirtyguard.ts) zu speisen. */
onDirtyChange?: (dirty: boolean) => void onDirtyChange?: (dirty: boolean) => void
/** Zusätzliche Buttons, die in die Standard-Button-Leiste der Form
* eingereiht werden. Sie werden im DOM vor den Standard-Buttons
* gesetzt und floaten daher (mit w3-right) rechts außen — die
* Standard-Buttons (Zurücksetzen, Abbrechen, Speichern) behalten
* ihre gewohnte Position. Die Buttons sind selbst als m(...) zu
* übergeben; die aufrufende Maske ist für Styling und Callbacks
* verantwortlich. */
extrabuttons?: m.Child[]
} }
export const Form:m.ClosureComponent<iForm> = (vnode) => { export const Form:m.ClosureComponent<iForm> = (vnode) => {
@@ -103,6 +111,11 @@ export const Form:m.ClosureComponent<iForm> = (vnode) => {
: {} : {}
}, },
[ [
// Zusätzliche Buttons der Maske zuerst ins DOM:
// mit w3-right landen sie optisch rechts außen,
// die Standard-Buttons bleiben links davon in
// ihrer gewohnten Reihenfolge.
...(vnode.attrs.extrabuttons || []),
m("button.w3-button.w3-theme.w3-right.w3-mobile", {style: {margin: '0px 0px 2px 4px'}, type: "submit"}, "Speichern"), m("button.w3-button.w3-theme.w3-right.w3-mobile", {style: {margin: '0px 0px 2px 4px'}, type: "submit"}, "Speichern"),
m("button.w3-button.w3-theme.w3-right.w3-mobile", {style: {margin: '0px 0px 2px 4px'}, onclick: cancel, type: "button"}, "Abbrechen"), m("button.w3-button.w3-theme.w3-right.w3-mobile", {style: {margin: '0px 0px 2px 4px'}, onclick: cancel, type: "button"}, "Abbrechen"),
m("button.w3-button.w3-theme.w3-right.w3-mobile", {onclick: reset, type: "button"}, "Zurücksetzen") m("button.w3-button.w3-theme.w3-right.w3-mobile", {onclick: reset, type: "button"}, "Zurücksetzen")