Upload PDFs to the library, link them from any link target, show them in a viewer
PDFs go through the same upload field as images, are checked by their content and kept unchanged in their own table. Every link field can pick one, and a page that links a PDF opens it in a dialog with the browser's own viewer; touch devices and browsers without a viewer get a new tab instead. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
04927b9563
commit
e8a9dcdf5c
20 files changed
+667
-30
No files matched your search
+13
-1
@@ -1,5 +1,17 @@
|
||||
# Projektstatus
|
||||
|
||||
## PDFs in der Mediathek, als Linkziel und im Betrachter (22.09.2026)
|
||||
|
||||
**Anlass:** Umut: „kann man aktuell PDFs hochladen und als Button verlinken? … und ein Inline PDF Viewer wie Bild-Popup“, danach: „ja setz um, einfacher Browser-Betrachter“.
|
||||
|
||||
- **Hochladen:** Das Upload-Feld der Mediathek nimmt jetzt neben JPEG, PNG und WebP auch PDFs bis 20 MB an. Ob eine Datei ein PDF ist, entscheidet ihr Inhalt (`%PDF-` in den ersten 1024 Bytes), nicht die Endung. Die PDFs stehen in einer eigenen Tabelle `document` (Migration `20260917000100`) und nicht in `media`. Jede Bildauswahl erwartet dort Varianten mit Breite und Höhe. Die Datei liegt unverändert als `<id>.pdf` im Medienordner und geht deshalb mit jeder Sicherung mit. Die Mediathek zeigt die PDFs unter den Bildern, mit Titel und Archivieren.
|
||||
- **Ausliefern:** `/media/<id>.pdf` kommt mit `Content-Type: application/pdf`, `nosniff`, `inline` und dem Titel als Dateinamen, `X-Robots-Tag: noindex` und `frame-ancestors 'self'`: Einbetten darf es nur die eigene Website. Archivierte PDFs bleiben erreichbar, wie Bilder.
|
||||
- **Verlinken:** Jedes Linkziel (Button, Bild, Symbolkarte, CTA, Symbol) hat den Knopf „PDF aus Mediathek wählen“ mit einer Liste, Suche und Hochladen direkt im Dialog. Ins Feld kommt die Adresse `/media/<id>.pdf`, ein gewöhnlicher lokaler Pfad, also ohne neue Schemaversion.
|
||||
- **Betrachter:** `public/assets/lightbox.js` (dieselbe Datei wie der Bildbetrachter, damit eine Seite kein Skript mehr lädt) zeigt ein verlinktes PDF in einem `<dialog>` mit `<iframe>` und nutzt dafür den PDF-Betrachter des Browsers, dazu Herunterladen, „Im neuen Tab“ und Schließen. Wo der Browser keinen eingebauten Betrachter hat (`navigator.pdfViewerEnabled`) oder das Gerät ein Touchgerät ist, öffnet sich das PDF im neuen Tab: Android-Chrome hat keinen Betrachter, iOS-Safari zeigt im Rahmen nur die erste Seite. Ist „In neuem Tab öffnen“ gesetzt oder das Skript nicht geladen, bleibt es ein normaler Link. Skript und `frame-src 'self'` kommen nur auf Seiten, deren Dokumente (auch Kopf, Fuß, Sektionen und Fließtext) auf ein PDF der Mediathek zeigen.
|
||||
- **Grenzen:** Hochgeladene PDFs sind über ihre Adresse öffentlich. Kein PDF.js, also sieht der Betrachter je nach Browser anders aus. Chrome zeigt im Kopf des Betrachters die Kennung aus der Adresse, nicht den Titel. PDFs werden nicht gelöscht, nur archiviert.
|
||||
|
||||
**Geprüft:** zwei neue Tests (`CmsTest::testAPdfFromTheLibraryIsALinkTargetAndOpensInTheViewer`, `EditorSecurityTest::testPdfsGoThroughTheMediaUploadAndTheEditorPicker`: Ablehnung von Nicht-PDFs, Kopfzeilen, 404, Skript und Richtlinie nur mit PDF-Link, Formular-Upload, API mit Token, Archiv). Im Browser mit der Pilotkopie: Klick auf den Button öffnet das zweiseitige PDF im Popup, Schließen gibt den Fokus an den Button zurück, bei 375 px mit Touch öffnet es einen neuen Tab. Der Auswahldialog im Editor ist nur per Syntaxprüfung geprüft, nicht im Browser. Dafür wäre eine Anmeldung nötig.
|
||||
|
||||
## Siebte Installation: Landingpage „KANTARCI Immobilien – Mietanfrage“ (18.09.2026)
|
||||
|
||||
**Anlass:** Umut: „neues Projekt wir brauchen eine einfache landingpage nach gleichem prinzip. einfache landingpage impressum und datenschutz notwendig? baus ein“ – dazu das Paket `KANTARCI-Immobilien-Landingpage.zip` (Next.js/Vinext für Cloudflare mit D1-Datenbank: Kopf, dunkler Hero, Werteleiste, Mietanfrage, Fuß, ein Banner als einziges Bild). Später: „Formular gefällt mir noch nicht kannst du ein multipage formular machen ggfls mit icon checkbox“ und die Anbieterdaten (Geschäftsführer Ridvan Kantarci, Ooser Hauptstr. 51, 76532 Baden-Baden, info@kantarci-immo.de).
|
||||
@@ -1071,7 +1083,7 @@ Erster Commit angelegt (`82b0782`); das Projekt hat damit einen Rückfallpunkt.
|
||||
## Bekannte Einschränkungen
|
||||
|
||||
- Gestaltung über geprüfte Tokens, keine beliebigen Pixelwerte, eigenen Schriften oder freien Farben. Noch keine Inline-Textbearbeitung, Formulare, dynamischen Menüs, Plugin-/Themeverwaltung oder WordPress-Import. Abschnittsvorlagen sind lokale Blockrezepte, keine globale Templateverwaltung.
|
||||
- Mediathek derzeit für statische Bilder: keine Videos/PDFs/SVGs, Lightbox/Slideshow, freie Bildzuschnitte, Ordner, Paginierung oder physische Löschung. Bild-URLs sind öffentlich; Archivieren schützt keine vertraulichen Dateien. Originale werden durch optimierte Varianten ersetzt. Einblendungen starten beim Laden, nicht beim Scrollen.
|
||||
- Mediathek derzeit für statische Bilder und PDFs (seit 22.09.2026): keine Videos/SVGs, Lightbox/Slideshow, freie Bildzuschnitte, Ordner, Paginierung oder physische Löschung. Bild-URLs sind öffentlich; Archivieren schützt keine vertraulichen Dateien. Originale werden durch optimierte Varianten ersetzt. Einblendungen starten beim Laden, nicht beim Scrollen.
|
||||
- Sektionen bieten die vorhandenen Farb-/Breitentokens geräteübergreifend. Benutzerverwaltung und Passwortänderung sind noch nicht als Browseroberfläche verfügbar.
|
||||
- **Der Aufgabenplan ist von Anfragen abhängig.** Ohne Besucher und ohne geöffnetes Backend läuft nichts; minutengenau ist nur ein echter Cronjob oder der URL-Cronjob des Hosters. Unter Apache mit mod_php belegt eine laufende Aufgabe einen PHP-Prozess, nachdem die Seite beim Besucher ist (dort gibt es kein `fastcgi_finish_request()`) – deshalb sind die Grenzen je Seitenaufruf klein (2 Aufgaben, 20 Sekunden) und der Auslöser abschaltbar. Die Sicherung ist die schwerste Aufgabe und läuft trotzdem mit: eine tägliche Sicherung ist mehr wert als keine. **Nicht geprüft:** das Verhalten unter mod_php und unter echter Last – hier lief alles gegen den eingebauten PHP-Server.
|
||||
- **Offene redaktionelle Feststellung:** `/grundlagen` trägt einen im Editor gesetzten Textblock in `#d08080` auf hellem Grund – 2,75:1, unter der AA-Schwelle. Die Farbe wurde **nicht** verändert, weil sie eine Nutzerentscheidung ist; die Prüfung nennt sie bei jedem Lauf, und die Kontrastwarnung im Editor meldet sie ebenfalls.
|
||||
|
||||
Reference in new issue
Block a user