Sie befinden sich hier: start » de » Interne Dokumentation » DokuWiki-Erweiterungen (WvdS) » FluentUI (Design-System-Bibliothek) » FluentUI: Komponenten-Referenzen » FluentUI: Editoren und Code-Darstellung

FluentUI: Editoren und Code-Darstellung

1. Übersicht und Zweck

Status: gemischt — fünf Bausteine [Live] (je eigener Träger, darunter codeEditor() und htmlSplitEditor()) plus die Editor-/Markup-Umschaltung (WYSIWYG-Umschaltung, bewusst außerhalb dieser Seite geführt — Träger wvdsmd), je Abschnitt vermerkt.

Diese Seite ordnet fünf verschiedene Editor-/Code-Darstellungs-Bausteine ein und verlinkt die jeweilige Quelle der Wahrheit — sie ersetzt keine Plugin-Doku. Zielgruppe: jeder Entwickler, der entscheiden muss, welcher Baustein für „Code zeigen„ vs. „Code bearbeiten“ vs. „Wiki-Inhalt bearbeiten„ der richtige ist (Abschnitt 5).

2. Voraussetzungen

  • Für codeEditor() und htmlSplitEditor(): DokuWiki mit aktiviertem Plugin wkfluentui und helper_plugin_wkfluentui_widgets geladen.
  • Für GeSHi: keine — Core-Funktion, immer verfügbar.
  • Für den Markdown-Editor: Plugin wvdsmd aktiviert, Seite trägt den Markdown-Marker (Autodetect).

3. Konzepte

Gemeinsames Muster aller fünf Bausteine: progressive Erweiterung über einer funktionsfähigen Textarea — dieselbe Konvention wie bei den JS-Erweiterungen der Helper-API (kein zweiter Code-Pfad, Markup bleibt das Speicherformat).

Baustein Was es ist Verwendung Träger / Quelle der Wahrheit Status
GeSHi (Code-Rendering) Syntax-Highlighting beim Rendern — kein Editor, keine eigene API <code sql>…</code>/<file> im Wiki-Text und Fenced-Code-Blöcke (```lang) in Markdown-Embeds ({{md>…}} / <markdown>); Sprachkennung = GeSHi-Sprachname DokuWiki-Core (inc/parser/xhtml.php → vendored GeSHi); Optik über --wk-wiki-code-*-Tokens umgesetzt (Core)
Quellcode-Editor CodeMirror, progressiv über einer normalen <textarea> — ohne JavaScript bleibt die Textarea voll funktionsfähig jedes Admin-Modul über codeEditor() (Erstkonsument: SQL-Workbench in wksqliteds) gemeinsame Kopie unter wkfluentui/cm/ + Widget codeEditor() (Vertrag: Abschnitt 6/7 unten) umgesetzt
Geteilter HTML-Editor Quelltext und bearbeitbare gerenderte Vorschau nebeneinander; die Quelle bleibt maßgeblich, die Vorschau schreibt neu formatiert zurück Admin-Flächen, die HTML-Fragmente pflegen (Erstkonsument: Snippet-Verwaltung in wksnippet) Widget htmlSplitEditor() + scripts/htmlsplit.js, Vorschau in einem Sandbox-iframe (Vertrag: Abschnitt 8/9 unten) umgesetzt
DokuWiki-Standard-Editor Cores Seiten-Editor: Toolbar (Fett/Link/…) + Textarea + Vorschau, Draft-/Lock-Fluss jede Wiki-Seite, do=edit DokuWiki-Core umgesetzt (Core)
Markdown-Editor vendored EasyMDE ersetzt die Textarea auf Markdown-Seiten; Marker-Zeile unsichtbar, DokuWiki-Save/Draft-Fluss unverändert; No-JS-Fallback = Textarea Seiten mit Markdown-Marker (Autodetect) Plugin wvdsmd — Quelle der Wahrheit: Markdown (wvdsmd) umgesetzt

4. Erste Schritte

Minimalbeispiel: CodeMirror-Editor über eine bestehende SQL-Textarea aktivieren.

/** @var helper_plugin_wkfluentui_widgets $widgets */
$widgets = plugin_load('helper', 'wkfluentui_widgets');
?>
<textarea id="sql-input" name="sql"></textarea>
<?php echo $widgets->codeEditor('sql-input', 'sql'); ?>

Falsch: codeEditor() auf eine Textarea zeigen lassen, die zum Zeitpunkt des Aufrufs noch nicht im DOM steht (z. B. Aufruf vor dem <textarea>-Tag). Das Aktivierungs-Markup verweist per id auf ein Element, das existieren muss — die Reihenfolge im Beispiel oben (Textarea zuerst) ist verbindlich.

5. Verwendung: Leitfaden „welcher Baustein wofür"

Bedarf Baustein
Code im Inhalt zeigen <code lang> (GeSHi) — nie einen Editor einbetten
Code/SQL im Admin-Modul bearbeiten codeEditor() (ein Aufruf neben der Textarea, kein plugin-lokales Vendoring nötig)
HTML-Fragment mit Sichtprüfung bearbeiten htmlSplitEditor() (umschließt dieselbe Textarea; enthält codeEditor() für die Quellseite)
Wiki-Inhalt bearbeiten Core-Editor; Markdown-Seiten automatisch via wvdsmd
Kein Nachbau von Monaco/VS-Code-Editoren bewusste Grenze wie bei der Layout-Mechanik (layout)

6. API-Referenz: codeEditor()

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 codeEditor(string $textareaId, string $language, array $opts = []): string

Zusammenfassung: Liefert das <script>-freie Aktivierungs-Markup (data-wk-code-editor-Attribute) für eine bestehende, benannte Textarea; scripts/codeeditor.js (progressive Erweiterung) ersetzt sie beim Laden durch eine CodeMirror-Instanz.

Rückgabewert: string — Aktivierungs-Markup. Leerer String bei unbekannter $language-Kennung oder leerer $textareaId — die Textarea bleibt in beiden Fällen unangetastet eine gewöhnliche Textarea, kein Fehler.

7. Parameter, Optionen und Zustände

Parameter Typ Pflicht Beschreibung
$textareaId string Ja id der bestehenden Ziel-Textarea
$language string Ja eine von sql|php|css|javascript|markdown|html; jede andere Kennung liefert den leeren String
$opts['submitId'] string Nein id des Submit-Buttons, den Strg+Enter klickt — der Editor synchronisiert vorher in die Textarea

Instanz-Zugriff (Client): wkCodeEditor.get(textareaId)null, solange/falls CodeMirror nicht geladen hat; zur Klick-Zeit auflösen, nicht beim Seitenaufbau. Event wk-codeeditor-ready feuert zusätzlich an der Textarea.

Lazy-Load: Vendor-Assets laden nur auf Seiten mit mindestens einem Aktivierungs-Marker nach — kein site-weiter Payload-Anstieg.

Vendoring (begründete Spez-Korrektur): die gemeinsame CodeMirror-Kopie (5.65.16 + Modi sql/php/css/javascript/markdown/htmlmixed samt Abhängigkeiten clike/xml/htmlmixed, MIT-Lizenzdatei) liegt unter wkfluentui/cm/nicht im ursprünglich skizzierten vendor/cm/, weil DokuWikis Web-Schicht direkten Zugriff auf vendor/-Verzeichnisse verweigert (auf dieser Instanz empirisch verifiziert, 404).

Fehlerverhalten:

Bedingung Verhalten
unbekannte $language-Kennung Rückgabe leerer String, Textarea bleibt unangetastet
leere $textareaId Rückgabe leerer String
Ziel-Textarea existiert nicht im DOM kein PHP-Fehler (das Widget prüft das DOM nicht); scripts/codeeditor.js findet beim Laden kein Ziel und aktiviert nichts — stille clientseitige Degradation

8. API-Referenz: htmlSplitEditor()

Metadatum Wert
Sprache PHP
Namespace helper_plugin_wkfluentui_widgets
Datei lib/plugins/wkfluentui/helper/widgets.php
Träger der Interaktion lib/plugins/wkfluentui/scripts/htmlsplit.js
Sichtbarkeit public
Stabilität stabil (Tier 1)
public function htmlSplitEditor(string $textareaHtml, string $textareaId, array $opts = []): string

Zusammenfassung: Umschließt die fertige, vom Aufrufer erzeugte Textarea mit einem geteilten Editor: links der Quelltext (CodeMirror, Sprache html — derselbe Baustein wie in Abschnitt 6), rechts die gerenderte Vorschau. Die Vorschau ist bearbeitbar; was dort geändert wird, landet neu formatiert in der Quelle.

Warum der Aufrufer die Textarea behält: Diese Bibliothek hat bewusst kein nacktes Textarea-Widget — Name, Größe, Pflichtfeld-Status und Label eines Formularfelds gehören zum Bildschirm, nicht zum Entwurfssystem. Das Widget bekommt deshalb fertiges, vom Aufrufer escaptes Markup und legt nur die Umgebung darum. Folge: der abgeschickte POST ist mit und ohne diesen Baustein identisch.

Parameter Typ Pflicht Beschreibung
$textareaHtml string Ja vollständiges <textarea …>-Markup des Aufrufers, von diesem escapt
$textareaId string Ja deren id; leer ⇒ $textareaHtml wird unverändert zurückgegeben
$opts['mode'] string Nein Startansicht source|split|preview (Standard split); eine zuvor gespeicherte Benutzeransicht gewinnt
$opts['editable'] bool Nein false ⇒ Vorschau nur lesbar, Formatiergruppe entfällt vollständig (Standard true)
$opts['storageKey'] string Nein Namensraum der gespeicherten Ansicht (wk-htmlsplit:<storageKey> in localStorage); leer ⇒ Ansicht wird nicht gemerkt
$opts['submitId'] string Nein id des Speichern-Knopfs — an codeEditor() weitergegeben, also Strg+Enter
$opts['lang'] string Nein Inhaltssprache der Vorschau (Standard $conf['lang'])

Ohne JavaScript: die Werkzeugleiste trägt serverseitig hidden (ihre Ansichts- und Formatierknöpfe wären sonst tote Bedienelemente), die Vorschaufläche ist leer und hidden. Übrig bleibt genau die Textarea des Aufrufers. Alle Knöpfe des Bausteins sind type=„button“, und das Adressfeld der Verknüpfung trägt kein name — es kann also nichts mitgeschickt werden.

Vorschau als Sandbox-iframe: sandbox=„allow-same-origin“, ohne allow-scripts (beide zusammen sind die dokumentierte Sandbox-Ausnahme und damit keine Absicherung). Das ist notwendig, weil gepflegte HTML-Fragmente <style> und <script> enthalten dürfen: inline gerendert würde ein <style> die Admin-Seite ringsum umstylen. Verifiziert auf dieser Instanz — das <script> eines Fragments läuft weder im Rahmen noch im Elterndokument, sein <style> wirkt innerhalb des Rahmens und die Admin-Seite bleibt messbar unverändert. Die Stylesheets der Wirtsseite werden in das Vorschaudokument kopiert, damit die Vorschau die echte Kaskade zeigt und nicht eine handgepflegte Näherung.

Platzhalter-Chips: Plugin-Platzhalter ({{wk:lang>…}}, {{wk:image>…}}) sind kein HTML. In der Vorschau werden sie zu je einem unteilbaren, nicht bearbeitbaren Chip, der das Token wörtlich trägt und wörtlich zurückgeschrieben wird — sonst zerlegt ein einzelner Tastendruck ein Token, oder die Textkodierung macht aus dem < in {{wk:lang>de:< 24 Stunden}} ein <, womit das Muster des konsumierenden Plugins nicht mehr passt. Die Chips entstehen aus dem Quelltext, nicht aus dem geparsten Baum: nur dort existieren die Rohbytes noch, nur dort ist ein Platzhalter, der selbst Markup enthält (…Industrie-<br/>erfahrung…), ein zusammenhängendes Token, und nur dort ist Text- von Attributposition unterscheidbar. Platzhalter in Attributwerten bleiben unangetastet.

Speicherweg: Die Textarea ist und bleibt das Formularfeld. Eine Vorschau-Änderung, die beim Klick auf Speichern noch in ihrer Entprellzeit steckt, wird in der Capture-Phase am document nachgezogen — vor dem Übertrag von CodeMirror in die Textarea, der am Formular selbst hängt. Ohne diese Reihenfolge gehen die letzten Tastendrücke der Vorschau beim Speichern verloren, und zwar stumm.

Erstkonsument: Snippet-Verwaltung (wksnippet, do=admin&page=wksnippet&edit=<key>).

9. Rundlauf: was eine Vorschau-Bearbeitung an der Quelle ändert

Eine Bearbeitung in der Vorschau bedeutet, dass der Browser das Markup neu serialisiert. Das ist verlustbehaftet und deshalb hier beziffert statt beschwiegen. Wer nur links im Quelltext arbeitet, löst nichts davon aus.

Gemessen über alle 55 Snippet-Dateien dieser Instanz (Quelle → Vorschau → Bearbeitung → Quelle):

Ergebnis Dateien
Dokument parst gleich (Elemente, Attribute, Text) 55 / 55
Platzhalter byteweise identisch (430 Stück) 55 / 55
<script>-/<style>-Inhalte byteweise identisch 55 / 55
Datei als Ganzes byteweise identisch 28 / 55
Unterschied ausschließlich in der Einrückung 23 / 55
Unterschied darüber hinaus 4 / 55

Die vier Abweichungen sind darstellungsneutral: Zeichenreferenzen für druckbare Zeichen werden zum Zeichen selbst ( → Häkchen, » → Guillemet), und der Schrägstrich eines leeren Elements entfällt (<br/><br>).

Rücknahme: Das Zurückschreiben ist eine CodeMirror-Änderung — ein einzelnes Strg+Z im Quelltextfeld nimmt die komplette Neuformatierung zurück. Die Werkzeugleiste sagt das auch dort, wo es passiert.

Einrückung: vier Leerzeichen, und ein Element, dessen Kinder alle inline sind, bleibt einzeilig, solange die Zeile 110 Zeichen nicht überschreitet. Inhalte von <script>, <style>, <pre> und <textarea> werden nie umgebrochen oder neu eingerückt — dort ändert Einrücken die Bedeutung, nicht das Aussehen.

10. Vollständige Beispiele: Editor ↔ Markup-Umschaltung [Live]

Träger wvdsmd (Vollausbau 2026-07-14) — Quelle: lib/plugins/wvdsmd/script.js.

Auf Markdown-Seiten trägt die EasyMDE-Toolbar einen Umschalter zwischen Editor-Ansicht (EasyMDE mit Format-Toolbar und Vorschau) und Markup-Ansicht (die rohe Textarea inklusive sichtbarer Marker-Zeile — identisch zum No-JS-Zustand). Der Wechsel ist jederzeit in beide Richtungen möglich und wirkt sofort, ohne Speichern; die zuletzt gewählte Ansicht wird pro Benutzer gemerkt (localStorage, wk-editor-view:<login>); jeder Wechsel wird über eine aria-live-Region angesagt. Eigenschaften:

  1. Markup bleibt Speicherformat (Markdown) — beide Ansichten editieren dieselbe zugrunde liegende Textarea, es gibt keine Rückserialisierung und damit konstruktionsbedingt verlustfreie Wechsel (byte-gleicher Quelltext, im Verifikationslauf nachgewiesen).
  2. No-JS-Fallback bleibt die rohe Textarea; der Umschalter existiert nur in der JS-erweiterten Ansicht.
  3. DokuWiki-Syntax-Seiten behalten den Core-Editor mit seiner Syntax-Toolbar und dem „Vorschau“-Button — dort gibt es nur eine Bearbeitungsansicht, ein Umschalter wäre bedeutungslos.

Vertiefung — konkrete Toolbar-Befehle: zwei Unterseiten dokumentieren, welche DokuWiki-Syntax/Markdown-Tokens die Editor-Toolbars einfügen (EasyMDE für Markdown, Core-Toolbar für DokuWiki-Syntax), nach dem Kategorienschema der DevExpress-ASPxHtmlEditor-Demo-Suite (https://demos.devexpress.com/ASPxHTMLEditorDemos/Default.aspx), aber auf das tatsächliche Ziel-Format dieser Bibliothek übertragen statt generischer HTML-Tags:

11. Einschränkungen und Randfälle

  • GeSHi bestimmt die Sprachliste; unbekannte Kennungen rendern als Klartext (kein Fehler). In Markdown-Embeds gilt dasselbe: wvdsdwmds ParsedownRenderer hebt Fenced-Blöcke mit bekannter Sprachkennung über DokuWikis GeSHi-Pfad hervor (p_xhtml_cached_geshi()); Blöcke ohne/mit unbekannter Kennung bleiben Parsedown-Roh-<pre> — degradiert, nie verloren. Engine-Kennung parsedown-1.7.4-geshi1 invalidiert Alt-Caches.
  • CodeMirror/EasyMDE sind vendored (offline, keine CDN-Abhängigkeit) — Updates sind bewusste, versionierte Plugin-Änderungen.
  • Editor-Flächen liegen im Content-Panel und folgen dem Panel-Füll-Rezept aus datagrid (Zutaten 1–3 gelten identisch für Editoren).
  • Kein Nachbau von Monaco/VS-Code-Editoren (Abschnitt 5).

12. Accessibility und Kompatibilität

  • Vollständiger Überblick: Accessibility (konsolidiert, nicht hier dupliziert).
  • Ohne JavaScript bleibt jeder Baustein eine gewöhnliche, vollständig zugängliche Textarea.
  • CodeMirror/EasyMDE sind vendored — Browserkompatibilität folgt den jeweiligen Vendor-Release-Notes (nicht separat in dieser Bibliothek getestet).

13. Troubleshooting

Symptom: codeEditor() rendert nichts (leerer String), obwohl Textarea und Sprache korrekt aussehen.

Ursache: $language enthält eine Kennung außerhalb von sql/php/css/javascript/markdown/html (Groß-/Kleinschreibung beachten — die Prüfung ist exakt, keine Normalisierung).

Lösung: Kennung gegen die exakte Liste in Abschnitt 7 prüfen.


Symptom: Markdown-Fenced-Code-Block wird nicht hervorgehoben.

Ursache: unbekannte oder fehlende Sprachkennung nach den drei Backticks, oder der Cache trägt noch die alte Engine-Kennung.

Lösung: Sprachkennung gegen GeSHis Liste prüfen; bei Verdacht auf veralteten Cache: Engine-Kennung parsedown-1.7.4-geshi1 erzwingt Invalidierung.


Symptom: Beim geteilten HTML-Editor fehlt die Werkzeugleiste, oder die Vorschau bleibt leer, obwohl das Markup im Quelltext steht.

Ursache: Der ausgelieferte Skript-Bund ist veraltet. lib/exe/js.php bündelt die Dateien aus scripts/ über /* DOKUWIKI:include */ und stützt seinen Zwischenspeicher nicht auf deren Änderungszeit — eine Änderung an scripts/htmlsplit.js allein erneuert den Bund also nicht, und der Browser hält zusätzlich seine eigene Kopie unter unveränderter tseed-Kennung.

Lösung: script.js des Plugins anfassen (touch) und im Browser hart neu laden (Strg+Umschalt+R). Gilt für jede Änderung an einer eingebundenen Skriptdatei, nicht nur für diesen Baustein.

14. Verwandte Themen

de/wiki/dwe/wkfluentui/component/editors/start.txt · Zuletzt geändert: von 0.0.0.0