Knopf nach oben, Bildbetrachter, Rechtszeile als Baustein (Schema v19)
Der Knopf "nach oben" ist ein Anker, kein Skript: er springt an den Seitenanfang, eingeblendet ueber eine Scroll-Zeitachse. Abschaltbar und vollstaendig einstellbar - Seite, Form, Groesse, Farben, Schwelle, Beschriftung. Bilder lassen sich vergroessern, je Bild waehlbar (nichts / vergroessern / Adresse), Galerien mit einem Schalter. Grundlage ist ein gewoehnlicher Verweis auf die grosse Fassung: ohne JavaScript oeffnet er das Bild, mit JavaScript einen dialog-Betrachter mit Blaettern, Escape und Pfeiltasten. Das Skript laedt nur, wo es etwas zu tun hat. Die Rechtszeile wird ein Baustein und steht damit im Fussbereich statt als heller Streifen darunter. Die eingebaute Leiste erscheint nur noch, wenn die Seite den Baustein nicht enthaelt. Dabei gefunden: zwei Stylesheet-Regeln griffen seit drei Veroeffentlichungen nicht mehr. Beim Entfernen alter Regeln waren Selektorreste stehen geblieben, und CSS nimmt dann die naechste Regel mit - betroffen waren der Einwilligungsdialog und die Rechtszeile. Ein Test prueft jetzt jede CSS-Datei auf abgebrochene Selektoren. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
74766f6684
commit
de1e66350b
13 files changed
+464
-18
No files matched your search
@@ -29,6 +29,8 @@ final class DocumentValidator
|
||||
public const ICON_SIZES = [12, 16, 20, 24, 32, 40, 48, 56, 64, 80, 96, 120, 160, 200, 240];
|
||||
/** Schema v18: die Navigation zwischen Beiträgen, vom Renderer gefüllt. */
|
||||
public const V18_TYPES = ['postnav'];
|
||||
/** Die Rechtszeile als Baustein: gestaltbar und dort, wo sie hingehoert. */
|
||||
public const V19_TYPES = ['legal'];
|
||||
/** Schema v15: a single icon, a progress bar and a slider that works without a script. */
|
||||
public const V15_TYPES = ['icon', 'progress', 'slider'];
|
||||
|
||||
@@ -40,7 +42,7 @@ final class DocumentValidator
|
||||
public function validate(array $document, bool $requireHeading = true): void
|
||||
{
|
||||
$schemaVersion = $document['schemaVersion'] ?? null;
|
||||
$this->require(in_array($schemaVersion, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18], true), 'Unsupported document schema.');
|
||||
$this->require(in_array($schemaVersion, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19], true), 'Unsupported document schema.');
|
||||
$this->text($document['title'] ?? null, 160);
|
||||
$this->text($document['description'] ?? null, 320);
|
||||
$this->require(is_array($document['blocks'] ?? null) && array_is_list($document['blocks']), 'Blocks must be a list.');
|
||||
@@ -68,7 +70,7 @@ final class DocumentValidator
|
||||
// page: a deactivated plugin must never make stored content unreadable. Nothing from
|
||||
// props is rendered for such a block, so unvalidated values never reach the output.
|
||||
$plugin = $schemaVersion >= 4 && is_string($type) && 1 === preg_match('/^[a-z][a-z0-9]{1,30}\.[a-z][a-z0-9-]{1,40}$/D', $type);
|
||||
$this->require(in_array($type, ['section', 'row', 'column', 'heading', 'text', 'image', 'button'], true) || ($schemaVersion >= 3 && 'gallery' === $type) || ($schemaVersion >= 5 && 'postlist' === $type) || ($schemaVersion >= 6 && in_array($type, self::V6_TYPES, true)) || ($schemaVersion >= 7 && in_array($type, self::V7_TYPES, true)) || ($schemaVersion >= 8 && in_array($type, self::V8_TYPES, true)) || ($schemaVersion >= 9 && in_array($type, self::V9_TYPES, true)) || ($schemaVersion >= 11 && in_array($type, self::V11_TYPES, true)) || ($schemaVersion >= 14 && in_array($type, self::V14_TYPES, true)) || ($schemaVersion >= 15 && in_array($type, self::V15_TYPES, true)) || ($schemaVersion >= 18 && in_array($type, self::V18_TYPES, true)) || $plugin, 'Unknown block type. Preserve source until its plugin is available.');
|
||||
$this->require(in_array($type, ['section', 'row', 'column', 'heading', 'text', 'image', 'button'], true) || ($schemaVersion >= 3 && 'gallery' === $type) || ($schemaVersion >= 5 && 'postlist' === $type) || ($schemaVersion >= 6 && in_array($type, self::V6_TYPES, true)) || ($schemaVersion >= 7 && in_array($type, self::V7_TYPES, true)) || ($schemaVersion >= 8 && in_array($type, self::V8_TYPES, true)) || ($schemaVersion >= 9 && in_array($type, self::V9_TYPES, true)) || ($schemaVersion >= 11 && in_array($type, self::V11_TYPES, true)) || ($schemaVersion >= 14 && in_array($type, self::V14_TYPES, true)) || ($schemaVersion >= 15 && in_array($type, self::V15_TYPES, true)) || ($schemaVersion >= 18 && in_array($type, self::V18_TYPES, true)) || ($schemaVersion >= 19 && in_array($type, self::V19_TYPES, true)) || $plugin, 'Unknown block type. Preserve source until its plugin is available.');
|
||||
// An accordion entry only ever renders inside an accordion; at the top level or anywhere
|
||||
// else it would produce a details element without its group.
|
||||
$this->require('accordionitem' !== $type || 'accordion' === $parentType, 'An accordion entry belongs into an accordion.');
|
||||
@@ -292,6 +294,10 @@ final class DocumentValidator
|
||||
// so a stored document can never redirect a submission or change what is asked.
|
||||
$this->require(is_string($props['form'] ?? null) && 1 === preg_match('/^[a-z0-9]+(?:-[a-z0-9]+)*$/D', $props['form']) && strlen($props['form']) <= 80, 'Invalid form address.');
|
||||
}
|
||||
if ('gallery' === $type && isset($props['lightbox'])) {
|
||||
$this->require($schemaVersion >= 19, 'Der Bildbetrachter braucht Schema v19.');
|
||||
$this->require(is_bool($props['lightbox']), 'Der Bildbetrachter ist an oder aus.');
|
||||
}
|
||||
if ('image' === $type) {
|
||||
$this->url($props['src'] ?? null);
|
||||
// Ein Bild darf verlinken. Klingt selbstverstaendlich, fehlte aber: ein Logo im
|
||||
@@ -300,6 +306,12 @@ final class DocumentValidator
|
||||
$this->require($schemaVersion >= 17, 'Ein verlinktes Bild braucht Schema v17.');
|
||||
$this->url($props['href']);
|
||||
}
|
||||
// Was ein Klick auf das Bild tut. Ohne Angabe: nichts - wie bisher.
|
||||
if (isset($props['click'])) {
|
||||
$this->require($schemaVersion >= 19, 'Die Klickwirkung eines Bildes braucht Schema v19.');
|
||||
$this->require(in_array($props['click'], ['keine', 'vergroessern', 'link'], true), 'Für den Klick sind „keine", „vergroessern" und „link" vorgesehen.');
|
||||
$this->require('link' !== $props['click'] || '' !== ($props['href'] ?? ''), 'Ein Bild, das auf eine Adresse zeigen soll, braucht eine.');
|
||||
}
|
||||
$this->require(is_bool($props['decorative'] ?? null), 'Image purpose is required.');
|
||||
$this->text($props['alt'] ?? null, 300, $props['decorative']);
|
||||
$this->require(!$props['decorative'] || '' === $props['alt'], 'Decorative images need empty alternative text.');
|
||||
|
||||
Reference in new issue
Block a user