Chat: Fotos und PDFs schicken, Gespraeche wegraeumen
Filipe, mit Bildschirmfoto: "man muss die chats auch geloescht bekommen!!! am besten waere es auch wenn man da auch im chat pdfs schicken koennte. pdfs und fotos." Zwei Entscheidungen vorher abgestimmt, weil sie den Bau bestimmen: Geloescht wird NUR BEI MIR. Schicken duerfen ALLE im Gespraech, auch Creator -- anders als in der Dateiablage, wo etwas in einem Bereich landet, den mehrere sehen. Hier bekommt es genau der, mit dem man ohnehin gerade spricht. --- ANHAENGE --- Drei Wege zur selben Sache, weil Leute unterschiedlich arbeiten: die Bueroklammer, Hineinziehen und Einfuegen mit Strg+V (der Weg fuer einen Screenshot -- der liegt in der Zwischenablage und nirgends als Datei). Alle drei laufen durch dieselbe Funktion; drei Fassungen waeren drei Gelegenheiten, dass eine die Pruefung vergisst. Ein Foto wird GEZEIGT, ein PDF wird als Karte ANGEBOTEN. Das ist kein Schoenheitsunterschied: Ein Bild erkennt man in einer Zehntelsekunde, ein PDF muss man ohnehin oeffnen -- eine Vorschau davon waere ein grauer Kasten, der so tut, als koennte man etwas lesen. DIE SICHERHEIT STEHT IN dateiErkennen(). Dateiname und Content-Type kommen vom Absender und sind frei erfunden; der Typ wird deshalb aus den ersten Bytes bestimmt (PNG/GIF/WebP/JPEG/PDF, mit Breite und Hoehe im selben Durchgang). SVG steht absichtlich NICHT in der Liste -- das ist XML, das Skripte enthalten darf, ein als Bild getarntes Programm. Ausgeliefert wird spaeter genau der ERKANNTE Typ, nie der eingeschickte, dazu nosniff und "default-src 'none'; sandbox". Auf der Platte bekommt jede Datei einen erzeugten Zufallsnamen, in einem Ordner ausserhalb des Repos. Zuruecknehmen loescht die Datei wirklich -- sonst waere sie im Verlauf weg und ueber die Adresse noch da, also nur der Anschein einer Ruecknahme. --- WEGRAEUMEN --- Zwei Spalten in chat_teilnehmer statt einer, wegen eines Randfalls: Bei einem Gespraech ohne jede Nachricht waere die Grenze 0 -- und 0 heisst sonst "nie geloescht". geloescht_am unterscheidet die beiden. Die Grenze wirkt in der Liste, im Verlauf, in der Vorschau, in der SUCHE, bei den Anhaengen und in der Ungelesen-Zahl. Die Suche ist die Stelle, an der so etwas typischerweise durchrutscht: aus der Liste weg, ueber die Suche noch da. --- DER FUND: 323 PIXEL --- Ein Bild ist spaeter fertig als der Rest der Seite. Beim Oeffnen springt der Verlauf ans Ende, dann kommt das Foto an und schiebt alles darunter weg -- man steht ploetzlich mittendrin, ohne etwas angeklickt zu haben. Das width/height-Attribut am <img>, wie man es ueberall liest, hilft hier NICHT: Es gibt nur das Seitenverhaeltnis. Damit daraus eine Hoehe wird, muss die Breite feststehen -- bei "width: auto" und einem nicht geladenen Bild ist sie 0. Der Platz wird jetzt am KASTEN reserviert (aspect-ratio + max-width aus den gemessenen Massen). Und die Pruefung dazu hatte denselben Fehler wie das Auge: Sie mass in einem Fenster, in dem das Bild laengst im Zwischenspeicher lag, und meldete tadellose 0 px. Sie misst jetzt in einem FRISCHEN Browser -- der Fall, um den es geht, ist der erste. --- SICHERUNG --- chat-anhaenge/ ist im selben Zug in tools/sicherung-holen.sh eingetragen, nicht spaeter, wenn es auffaellt: Genau so ist die Luecke bei den Profilbildern entstanden. tools/wiederherstellung-proben.mjs bestaetigt: "der Server benutzt 4 Datenordner", keiner fehlt. --- Pruefung --- server/pruef-chat-anhaenge.mjs, neu, 60 Pruefungen, alle gruen. Abschnitt 3 versucht ausdruecklich, hereinzukommen: HTML als bild.png, SVG als foto.png, SVG als svg, eine Textdatei, ein PNG-Kopf ohne Inhalt -- alle fuenf mit 415 abgewiesen, ein echtes JPEG danach mit 201 angenommen (sonst bewiese der Block nur, dass gar nichts durchkommt). 13 MB geben 413 mit lesbarem Text, nicht 500. Konsolenfehler werden nach ZEITPUNKT getrennt, nicht nach Statusnummer: Was waehrend eines absichtlichen Versuchs entsteht, ist gewollt. Nach Nummer zu filtern waere bequem und wuerde ab morgen echte 404 mit verschlucken. Ausserdem gruen: pruef-chat, pruef-chat-optik, pruef-chat-ausbau, pruef-css-klassen. Angesehen bei 1440 px und bei 390 px. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
+42
-10
@@ -14,17 +14,17 @@
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609091211" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609091211" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609091251" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609091251" />
|
||||
<!-- aufgaben.css bringt die Dialog- und Formularstile mit (.dialog,
|
||||
.neu__zeile, .dialog__knoepfe). Sie stehen dort seit dem
|
||||
Aufgabenbrett; sie hierher zu kopieren hiesse, sie an zwei Stellen
|
||||
zu pflegen. Dieselbe Lösung nutzen kalender.html und content.html.
|
||||
Gemeldet von pruef-css-klassen.mjs, bevor jemand einen ungestylten
|
||||
Dialog zu sehen bekam. -->
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091211" />
|
||||
<link rel="stylesheet" href="assets/css/chat.css?v=202609091211" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609091211" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091251" />
|
||||
<link rel="stylesheet" href="assets/css/chat.css?v=202609091251" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609091251" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -112,6 +112,18 @@
|
||||
<h2 class="chat__titel" id="verlauf-titel">Wähle ein Gespräch</h2>
|
||||
<p class="chat__unter" id="verlauf-unter"></p>
|
||||
</div>
|
||||
<!-- GESPRÄCH WEGRÄUMEN (09.09.2026).
|
||||
Filipe: "man muss die chats auch gelöscht bekommen!!!"
|
||||
Es verschwindet nur bei DIR -- das Gegenüber behält seinen
|
||||
Verlauf. Der Knopf steht erst da, wenn auch ein Gespräch
|
||||
offen ist; sonst wäre er ein Angebot ohne Gegenstand. -->
|
||||
<button type="button" class="chat__weg" id="gespraech-weg" hidden
|
||||
aria-label="Dieses Gespräch wegräumen"
|
||||
title="Gespräch wegräumen – nur bei dir">
|
||||
<svg viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M5 7h14M10 7V5h4v2M6.5 7l.8 12h9.4l.8-12M10 10.5v5.5M14 10.5v5.5" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- aria-live="polite": Ein Vorleseprogramm sagt neue Nachrichten
|
||||
@@ -121,6 +133,13 @@
|
||||
mitten im Satz weggerissen. Jetzt bleibt er stehen, und hier
|
||||
steht, wie viel unten wartet. -->
|
||||
<button type="button" class="chat__zum-neuesten" id="zum-neuesten" hidden></button>
|
||||
<!-- HINEINZIEHEN (09.09.2026). Erscheint nur, solange wirklich
|
||||
etwas über dem Fenster hängt. Eine dauerhaft sichtbare
|
||||
Ablagefläche wäre jeden Tag im Weg für den Fall, dass man
|
||||
sie vielleicht braucht. -->
|
||||
<div class="chat__ablage" id="ablage" hidden aria-hidden="true">
|
||||
<span>Loslassen – Foto oder PDF schicken</span>
|
||||
</div>
|
||||
<div class="chat__verlauf" id="verlauf" role="log" aria-live="polite" aria-relevant="additions">
|
||||
<p class="chat__leer" id="verlauf-leer">
|
||||
Links ein Gespräch auswählen – oder mit <strong>Neu</strong> eines anfangen.
|
||||
@@ -160,6 +179,19 @@
|
||||
nicht, sonst käme man nie zu einer zweiten Zeile.
|
||||
Die Tastenbelegung steht jetzt im title -- sie ist ein
|
||||
Hinweis für Wiederkehrer, keine Aufforderung. -->
|
||||
<!-- ANHANG (09.09.2026): "pdfs und fotos".
|
||||
Das Feld selbst bleibt unsichtbar -- ein Datei-Auswahlfeld
|
||||
sieht in jedem Browser anders aus und lässt sich nicht
|
||||
gestalten. Bedient wird es über die Büroklammer daneben. -->
|
||||
<input type="file" id="anhang-feld" class="chat__anhang-feld"
|
||||
accept="image/png,image/jpeg,image/webp,image/gif,application/pdf"
|
||||
tabindex="-1" aria-hidden="true" />
|
||||
<button type="button" class="chat__anhang" id="anhang-auf"
|
||||
aria-label="Foto oder PDF anhängen" title="Foto oder PDF anhängen">
|
||||
<svg viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M20 11.5 12.3 19.2a4.4 4.4 0 0 1-6.2-6.2l7.9-7.9a2.9 2.9 0 0 1 4.1 4.1l-7.9 7.9a1.5 1.5 0 0 1-2.1-2.1l7.2-7.2" />
|
||||
</svg>
|
||||
</button>
|
||||
<textarea id="text" rows="1" maxlength="4000"
|
||||
placeholder="Nachricht schreiben …"
|
||||
title="Enter schickt ab, Umschalt+Enter macht eine neue Zeile"></textarea>
|
||||
@@ -215,10 +247,10 @@
|
||||
</form>
|
||||
</dialog>
|
||||
|
||||
<script src="assets/js/bereiche.js?v=202609091211"></script>
|
||||
<script src="assets/js/wahl.js?v=202609091211" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609091211"></script>
|
||||
<script src="assets/js/glocke.js?v=202609091211"></script>
|
||||
<script src="assets/js/chat.js?v=202609091211"></script>
|
||||
<script src="assets/js/bereiche.js?v=202609091251"></script>
|
||||
<script src="assets/js/wahl.js?v=202609091251" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609091251"></script>
|
||||
<script src="assets/js/glocke.js?v=202609091251"></script>
|
||||
<script src="assets/js/chat.js?v=202609091251"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user