Sie befinden sich hier: start » de » Interne Dokumentation » DokuWiki-Erweiterungen (WvdS) » FluentUI (Design-System-Bibliothek) » FluentUI: Komponenten-Referenzen » FluentUI: Vertical Grid (Property Grid) — Demo-Übersicht » Vertical Grid: Grundlagen

Vertical Grid: Grundlagen

Zurück: Demo-Übersicht


1. Übersicht und Zweck

Status: vollständig [Live] — Grundraster, Gruppen/Sektionen, Readonly-Modus, Validierungszustand und required-Kennzeichnung sind umgesetzt (Quelle: lib/plugins/wkfluentui/helper/widgets.php, Methode propertyGrid()).

propertyGrid() stellt ein Objekt als zweispaltiges Label/Wert-Raster dar — Attribute als Zeilen, nicht als Spalten (Gegenstück zu dataGrid(), das viele Objekte als Zeilen zeigt). Zielgruppe: jedes Formular oder jeder Eigenschaften-Inspektor, der Label+Control-Paare braucht, ohne eine eigene Formular-Grid-CSS zu bauen.

2. Voraussetzungen

  • DokuWiki mit aktiviertem Plugin wkfluentui.
  • helper_plugin_wkfluentui_widgets geladen über plugin_load('helper', 'wkfluentui_widgets').
  • Controls (controlHtml) liefert der Aufrufer selbst — propertyGrid() rendert kein einziges Eingabefeld, nur den Rahmen darum (s. Eingabefelder für passende Control-Bausteine).

3. Konzepte

Zwei Rollen, ein Baustein: Formular-Raster (Eingabefelder mit Label-Spalte) und Eigenschaften-Inspektor (kontextsensitive Anzeige des ausgewählten Objekts, typisch in der Auxbar) nutzen dieselbe Methode — der Unterschied liegt nur in $opts['mode'] (Abschnitt 7).

Klartext vs. vertrauenswürdiges HTML: label wird per hsc() escaped; controlHtml ist bereits vom Aufrufer erzeugtes, vertrauenswürdiges HTML — dieselbe Konvention wie überall in dieser API (s. api → Abschnitt „Konzepte").

Rückwärtskompatibilität: propertyGrid($rows) ohne die später ergänzten Schlüssel (section/value/state/required) rendert byte-identisch zur ursprünglichen Ein-Parameter-Version.

4. Erste Schritte

/** @var helper_plugin_wkfluentui_widgets $widgets */
$widgets = plugin_load('helper', 'wkfluentui_widgets');
 
echo $widgets->propertyGrid([
    ['label' => 'Name', 'controlHtml' => '<input type="text" name="name" required>'],
    ['label' => 'Aktiv', 'controlHtml' => '<input type="checkbox" name="aktiv">'],
]);

Falsch: rohen Nutzereingabe-Text direkt als controlHtml übergeben ('controlHtml' => $_POST['x']). controlHtml wird ungeprüft ausgegeben — der Aufrufer trägt hier die volle XSS-Verantwortung (CWE-79).

5. Verwendung

Einsatz Muster
Formular im Drawer/Dialog drawer()/modal() als Hülle, propertyGrid() als Body — Referenz: „Connect to…„-Dialog und Table Designer (wksqliteds, 6 Aufrufstellen in dbadmin/*.php)
Eigenschaften-Inspektor in der Auxbar propertyGrid() mit reinen Anzeige-Zeilen (mode' ⇒ 'display') im .wk-shell-auxbar-Panel; aktualisiert per Click-to-Reload bzw. über das wk-selectionchange-Event des DataGrids (datagrid → Selection-API)
Nicht verwenden für viele gleichartige Objekte (→ dataGrid()) oder lange Fließtext-Dokumentation (→ normale Wiki-Seite)

6. API-Referenz

Metadatum Wert
Sprache PHP
Namespace helper_plugin_wkfluentui_widgets
Datei lib/plugins/wkfluentui/helper/widgets.php
Sichtbarkeit public
Stabilität stabil (Tier 1)
public function propertyGrid(array $rows, array $opts = []): string

Zusammenfassung: Rendert ein zweispaltiges Label/Control-Formularraster (CSS-Grid fit-content(22rem) minmax(0, 1fr)) aus Zeilen-Definitionen, optional gruppiert in kollabierbare Sektionen und/oder im Readonly-Anzeigemodus.

Die Beschriftungsspalte darf sich an ihren Inhalt anschmiegen, aber nicht von ihm bemessen werden. Bis zum 25.08.2026 stand hier max-content 1fr zusammen mit white-space: nowrap auf der Beschriftung. Wo eine Beschriftung ein ganzer Satz ist — und in dieser Suite ist sie das bei jeder Einstellung eines Pakets —, war max-content die Breite dieses Satzes, und die Steuerelementspalte wurde über den sichtbaren Bereich hinausgeschoben.

Am Bild gemessen, Konfigurationsbildschirm: bei einer Fensterbreite von 768 px lag die rechte Kante des Steuerelements bei 1402 px, bei 1280 px bei 1646 px. Der Inhaltsbereich scrollt nicht seitwärts — die Steuerelemente waren also nicht außerhalb des Bildes, sondern unerreichbar. Bei 390 px war auf dem gesamten Bildschirm kein einziges sichtbar.

fit-content(<länge>) ist max-content mit einer Decke: eine kurze Beschriftung bestimmt weiterhin ihre eigene Breite, eine lange hört bei der Decke auf und bricht um. Beides gehört zusammen — ohne white-space: normal schrumpft eine nicht umbrechende Beschriftung nicht, sie läuft aus ihrer Zelle heraus, und das Steuerelement ist eine Ebene tiefer genauso weg.

Rückgabewert: string — vollständiges HTML-Fragment (<div class="wk-property-grid">…</div>). Leerer String bei leerem $rows.

7. Parameter, Optionen und Zustände

$rows (je Zeile)

Schlüssel Typ Pflicht Bedeutung
label string Nein Label-Text (hsc()-escaped)
controlHtml string Nein vertrauenswürdiges HTML des Controls — Aufrufer-escaped
fullRow bool Nein Zeile spannt über beide Spalten (Hinweistexte, Trenner, breite Controls)
section string Nein gruppiert aufeinanderfolgende Zeilen als kollabierbare Sektion (Abschnitt „Gruppen/Sektionen“ unten); ein wiederholter Name nach anderen Zeilen beginnt bewusst eine neue Gruppe
value string Nein nur bei mode => 'display' und ohne controlHtml: hsc()-escapeter Anzeige-Wert
mono bool Nein Monospace für value
state 'error'|'warning' Nein 3px-Akzentbalken; reine Anzeige, der Server bleibt Validierungs-Autorität
stateText string Nein Meldungszeile unter dem Control bei aktivem state
required bool Nein rotes Sternchen + .a11y-Screenreader-Text am Label — setzt kein required-Attribut im Aufrufer-HTML (s. Fehlerverhalten)
controlId string Nein ID des Controls im controlHtml: Label erhält for="<controlId>", eine State-Meldungszeile die ID <controlId>__statetext; enthält controlHtml genau einen id="<controlId>"-Treffer ohne eigenes aria-describedby, injiziert das Widget die Verknüpfung — sonst bleibt das Aufrufer-HTML unangetastet und der Aufrufer setzt aria-describedby="<controlId>__statetext" selbst. Ohne controlId: Markup byte-identisch zur Vorversion

$opts

Schlüssel Typ Bedeutung
mode 'display' Readonly-Anzeigemodus, Container-Modifier –display
persistKey string Sektions-Offen-Zustand überlebt Reloads via scripts/propertygrid.js in localStorage unter wk-propertygrid:<persistKey>

Erzeugtes Markup (Klassen)

Klasse Rolle
.wk-property-grid Container — CSS-Grid fit-content(22rem) minmax(0, 1fr)
.wk-property-grid__section-body Sektionskörper — eigenes Raster mit denselben Spurdefinitionen (display: contents auf der Zeile heißt, dass jedes Raster seine Spuren selbst nennen muss)
.wk-property-grid--display Container-Modifier des Readonly-Anzeigemodus
.wk-property-grid__row eine Label/Control-Zeile
.wk-property-grid__row--full Zeile über beide Spalten (fullRow)
.wk-property-grid__row--error / …--warning Zeile mit Validierungszustand
.wk-property-grid__label Label-Zelle
.wk-property-grid__required rotes Sternchen am Label eines Pflichtfelds
.wk-property-grid__control Control-Zelle
.wk-property-grid__value (--mono) Anzeige-Wert im Display-Modus
.wk-property-grid__section <details open>-Sektionsgruppe
.wk-property-grid__section-body Zwei-Spalten-Raster innerhalb einer Sektion
.wk-property-grid__statetext Meldungszeile unter dem Control einer State-Zeile

Gruppen/Sektionen

Zeilen mit gleichem section-Wert werden unter einer Sektions-Kopfzeile (volle Breite, halbfett mit dünnem Trenner — Optik der Fieldset-Legenden aus _admin-forms.css) gruppiert; die Kopfzeile ist per Klick/Enter kollabierbar (<details>-basiert, ohne JavaScript funktionsfähig). Zeilen ohne section rendern vor der ersten Sektion. Referenz: DevExpress-VerticalGrid-Kategorien, ADS Table-Designer-Gruppen.

Readonly-Anzeigemodus

propertyGrid($rows, ['mode' => 'display']): Zeilen ohne controlHtml akzeptieren value (Abschnitt oben); der Container trägt .wk-property-grid--display (kein Eingabe-Chrome, Werte selektierbar, Zeilen-Hover über --wk-admin-hover). Das ist der Standard für den Eigenschaften-Inspektor — Formular-Optik nur, wo tatsächlich editiert wird.

Fehlerverhalten

Bedingung Verhalten
$rows leer Rückgabe leerer String, kein Fehler
required ⇒ true ohne required-Attribut im controlHtml kein automatischer Fix — das Widget rendert nur die visuelle/a11y-Kennzeichnung; native Browser-Validierung entsteht ausschließlich durch das required-Attribut im Aufrufer-HTML selbst (bewusste Trennung, keine implizite Attribut-Injektion in fremdes HTML)
value gesetzt, aber mode fehlt value wird ignoriert, controlHtml bzw. leere Zelle rendert stattdessen

8. Vollständige Beispiele

Formular mit zwei Sektionen, einer Pflichtfeld-Validierung und Persistenz des Sektions-Zustands:

echo $widgets->propertyGrid([
    ['section' => 'Verbindung', 'label' => 'Host', 'controlHtml' => '<input type="text" name="host" required>', 'required' => true],
    ['section' => 'Verbindung', 'label' => 'Port', 'controlHtml' => '<input type="number" name="port" value="3306">'],
    ['section' => 'Zugangsdaten', 'label' => 'Benutzer', 'controlHtml' => '<input type="text" name="user">'],
    ['section' => 'Zugangsdaten', 'label' => 'Passwort', 'controlHtml' => '<input type="password" name="pass">', 'state' => 'warning', 'stateText' => 'Wird verschlüsselt gespeichert.'],
], ['persistKey' => 'connect-dialog']);

9. Einschränkungen und Randfälle

  • Kein Nachbau des DevExpress-Mehr-Datensatz-Vergleichsmodus (mehrere Objekte als Spalten) — bei Bedarf eigenständige Initiative; bis dahin: ein propertyGrid() je Objekt nebeneinander.
  • Panel-Füll-Verhalten (Grid füllt Drawer/Auxbar, scrollt innen) — Details: Adaptivity.
  • aria-describedby zwischen stateText und Control entsteht nur mit gesetztem controlId-Zeilen-Schlüssel (s. Abschnitt 7) — Alt-Aufrufer ohne den Schlüssel rendern unverändert; Details: Accessibility.

10. Accessibility und Kompatibilität

  • Vollständiger Überblick: Accessibility (konsolidiert, nicht hier dupliziert).
  • Ohne JavaScript bleiben alle Sektionen offen bedienbar (native <details>-Semantik); nur die Persistenz des Offen-Zustands über Reloads entfällt.
  • Browserkompatibilität: keine Anforderungen über CSS-Grid-Grundunterstützung hinaus.

11. Troubleshooting

Symptom: Pflichtfeld zeigt kein rotes Sternchen trotz required ⇒ true.

Ursache: required in der Zeilen-Definition und required als HTML-Attribut im controlHtml sind zwei getrennte Dinge — nur ersteres steuert das Sternchen.

Lösung: 'required' => true in der Zeile setzen und das required-Attribut selbst im controlHtml ergänzen, wenn native Browser-Validierung gewünscht ist.


Symptom: Sektions-Offen-Zustand geht bei jedem Seitenaufruf verloren.

Ursache: $opts['persistKey'] fehlt.

Lösung: einen über Seitenaufrufe stabilen, pro Formular eindeutigen persistKey setzen.

12. Verwandte Themen

de/wiki/dwe/wkfluentui/component/property-grid/basics.txt · Zuletzt geändert: von rollout