Tabs als fortschreitende Verbesserung (Dokumentschema v7)

Auf Entscheidung von Umut werden Tabs jetzt mit JavaScript umgesetzt.
Die Regel "der Seiteninhalt braucht kein Browser-JavaScript" bleibt
dabei eingehalten: der Server liefert eine Ankerliste und alle Panels
mit eigenen Überschriften, versteckt nichts, und ohne Skript ist
jeder Inhalt lesbar und über die Tastatur erreichbar.

public/assets/tabs.js ergänzt tablist/tab/tabpanel, Auswahl per
Pfeiltasten, Home und Ende sowie aria-selected und wählt bei einem
passenden Sprungziel das zugehörige Panel.

Die strenge Richtlinie bleibt Voreinstellung: öffentliche Seiten
senden weiterhin script-src 'none'. Nur eine Seite mit Tab-Block
sendet script-src 'self' und bindet die eine externe Datei ein;
Inline-Skript ist nie erlaubt.

Geprüft: 109 PHP-Tests / 395 Assertions unter PHP 8.2.12 und 8.4.22,
14 JavaScript-Modelltests, Lint/Format/Container. Das Skript selbst
wurde nicht ausgeführt: Tastaturbedienung und ARIA-Verhalten sind
ohne Browserlauf ungeprüft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
kantarciandClaude Opus 5 committed 2026-09-12 11:41:36 +02:00
1 parent 8600384f1a
commit c6ec00a906
17 files changed
+279 -26

No files matched your search

+23
View File
@@ -211,3 +211,26 @@ test('v6 containers accept only their own children and an accordion starts with
history.undo(); history.undo(); history.undo();
assert.deepEqual(history.document, fixture());
});
test('a new tab group starts with two tabs and accepts nothing but tabs', () => {
const history = new EditorHistory(fixture());
const id = history.change(doc => insertBlock(doc, 'tabs', 's2'));
const group = locate(history.document.blocks, id).block;
assert.equal(history.document.schemaVersion, 7);
// One tab is not a tab group, and the enhancement needs at least two to do anything.
assert.equal(group.children.length, 2);
assert.deepEqual(group.children.map(c => c.type), ['tabitem', 'tabitem']);
assert.notEqual(group.children[0].id, group.children[1].id);
assert.deepEqual(group.children[0].props, { title: 'Neuer Tab' });
assert.equal(canContain(group, { type: 'tabitem' }), true);
assert.equal(canContain(group, { type: 'text' }), false);
assert.equal(canContain({ type: 'section', children: [] }, { type: 'tabitem' }), false);
assert.equal(canContain({ type: 'accordion', children: [] }, { type: 'tabitem' }), false);
// A tab itself holds ordinary content.
assert.equal(canContain(group.children[0], { type: 'text' }), true);
history.undo();
assert.deepEqual(history.document, fixture());
});