Textblöcke dürfen ab v12 Auszeichnung tragen: fett, kursiv, unterstrichen, durchgestrichen, Code, hervorgehoben, hoch- und tiefgestellt, Absätze, Listen und Links. Die Entscheidung, was erlaubt ist, fällt auf dem Server beim Speichern - nicht im Editor und nicht beim Rendern. Was in der Datenbank landet, ist damit schon sicher, also kann kein Renderer das Filtern vergessen, und eine manipulierte Anfrage speichert nichts, was der Editor nicht anbietet. Nicht erlaubte Elemente werden ausgepackt, nicht gelöscht: der Text bleibt, nur die Auszeichnung geht. script, style, iframe und Verwandte verschwinden samt Inhalt, weil Auspacken ihren Code als Text sichtbar machen würde. Attribute fallen weg außer href an a, und auch das nur nach Adressprüfung. Ausgegeben wird formatierter Text nur ab v12, dann in einem div statt einem p, weil die Positivliste Absätze und Listen enthält. Ältere Dokumente behalten Klartextsemantik und werden weiter maskiert. Eine Inkonsistenz nebenbei behoben: ein Text mit einem < behielt echte Zeilenumbrüche, während alles andere <br> benutzte. Geprüft: 182 PHP-Tests / 685 Assertions unter PHP 8.2.12 und 8.4.22, darunter dreizehn Fälle durch den Filter mit acht Angriffen, dazu Editortest mit axe und öffentliche Browserprüfung. Die Werkzeugleiste selbst ist nicht bedient und nicht mit einem Screenreader geprüft. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
51 lines
3.0 KiB
Twig
51 lines
3.0 KiB
Twig
<!doctype html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>{{ heading }}{% if result.page > 1 %} · Seite {{ result.page }}{% endif %} · Beiträge</title>
|
|
<meta name="description" content="{{ term ? 'Beiträge zu ' ~ term.name : 'Alle Beiträge' }}.">
|
|
<link rel="canonical" href="{{ canonical }}">
|
|
{% if result.page > 1 %}<link rel="prev" href="{{ base }}{{ result.page > 2 ? '?seite=' ~ (result.page - 1) : '' }}">{% endif %}
|
|
{% if result.page < result.pages %}<link rel="next" href="{{ base }}?seite={{ result.page + 1 }}">{% endif %}
|
|
<link rel="alternate" type="application/rss+xml" title="Beiträge" href="/feed.xml">
|
|
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
|
|
<link rel="stylesheet" href="/assets/site.css">
|
|
<link rel="stylesheet" href="/assets/design.css">
|
|
</head>
|
|
<body class="kant">
|
|
<a class="skip-link" href="#main">Zum Inhalt springen</a>
|
|
{% if areas.header|default(null) %}
|
|
<header class="site-header">
|
|
{% for block in areas.header.blocks %}{% include 'blocks/block.html.twig' with {block: block, postLists: {}, forms: {}, breadcrumbs: [], navigation: navigation|default({}), sections: sections|default({}), richText: true} only %}{% endfor %}
|
|
</header>
|
|
{% endif %}
|
|
<main id="main" tabindex="-1">
|
|
<section class="block-section tone-mint width-normal">
|
|
<div class="shell section-inner">
|
|
{% if term %}<p class="post-terms-label">{{ term.kind == 'category' ? 'Kategorie' : 'Schlagwort' }}</p>{% endif %}
|
|
<h1>{{ heading }}</h1>
|
|
<p class="block-text">{{ result.total }} {{ result.total == 1 ? 'Beitrag' : 'Beiträge' }}{% if result.pages > 1 %} · Seite {{ result.page }} von {{ result.pages }}{% endif %}</p>
|
|
</div>
|
|
</section>
|
|
<section class="block-section tone-paper width-normal">
|
|
<div class="shell section-inner">
|
|
{% include 'blocks/post-list.html.twig' with {posts: result.posts} only %}
|
|
{% if result.pages > 1 %}
|
|
<nav class="pagination" aria-label="Seiten">
|
|
{% if result.page > 1 %}<a rel="prev" href="{{ base }}{{ result.page > 2 ? '?seite=' ~ (result.page - 1) : '' }}">← Neuere</a>{% endif %}
|
|
<span>Seite {{ result.page }} von {{ result.pages }}</span>
|
|
{% if result.page < result.pages %}<a rel="next" href="{{ base }}?seite={{ result.page + 1 }}">Ältere →</a>{% endif %}
|
|
</nav>
|
|
{% endif %}
|
|
</div>
|
|
</section>
|
|
</main>
|
|
{% if areas.footer|default(null) %}
|
|
<footer class="site-footer">
|
|
{% for block in areas.footer.blocks %}{% include 'blocks/block.html.twig' with {block: block, postLists: {}, forms: {}, breadcrumbs: [], navigation: navigation|default({}), sections: sections|default({}), richText: true} only %}{% endfor %}
|
|
</footer>
|
|
{% endif %}
|
|
</body>
|
|
</html>
|