From c5e3ab1c44a8ee49e0ef840ff62d0883f46e69af Mon Sep 17 00:00:00 2001 From: Dogfather Date: Mon, 5 Oct 2026 22:41:18 +0200 Subject: [PATCH] Zwei Meldungen aus dem Support: Auswahlmenues und die Stelle im Chat DIENE: "Beim Kalender laesst sich die Art noch nicht einstellen, das Menue ploppt nur ganz kurz auf und verschwindet direkt wieder. Das selbe bei den Wiederholungen." In wahl.js stand `addEventListener('resize', schliessen)`. Auf dem Rechner ist das harmlos -- dort aendert sich die Fenstergroesse nur, wenn jemand sie aendert. Auf einem Handy aendert sie sich BEIM BEDIENEN: Die Adressleiste faehrt beim kleinsten Scrollen ein und aus, die Tastatur kommt und geht, und jedes Mal feuert `resize`. Die Liste ging auf, der Browser meldete eine neue Hoehe, und sie war wieder zu. Es ist derselbe Fehler wie am 04.09. beim Scrollen ("wenn ich da scollen will geht das immer zu"), nur eine Zeile tiefer: Ein Ereignis, das beim BEDIENEN entsteht, wird als Grund zum Abbrechen genommen. Jetzt wird die Liste neu ausgerichtet statt geschlossen -- `stelle()` kann das ohnehin, und nach einer Groessenaenderung muss sie es sowieso. pruef-suchfeld 8 -> 15, an Dienes genauem Fall: Kalenderformular, beide Felder, echte Groessenaenderung dazwischen. Gemessen wird nicht nur "offen", sondern auch "sitzt noch am Knopf" (6 px) -- offen, aber verrutscht waere nur die halbe Antwort. Gegenprobe: mit der alten Zeile 4 Fehler. ---------------------------------------------------------------------- MISS: "Wenn ich auf den Chat gehen, komme ich zuerst auf die erste neue Nachricht, aber kurze Zeit spaeter springt er auf die zuletzt geschrieben Nachricht." In chat.js stand `unten = true; neuUnten = 0;` AUSSERHALB von `if (!sanft)` -- es lief also bei jedem Nachladen, auch beim sanften, das staendig passiert (Strom verbindet, jemand heftet etwas an, eine Nachricht kommt). Solange die Neu-Linie steht, faellt das nicht auf: Der Zweig darueber springt dorthin und kehrt zurueck, bevor `unten` gelesen wird. Die zweite Haelfte ist `wache` -- sie loescht den Sprung-Merker beim ersten FINGERTIPP auf den Verlauf, und das ist richtig so. Ab da ist der Weg frei, und das naechste sanfte Nachladen findet `unten === true` vor und reisst die Ansicht ans Ende. Genau ihre "kurze Zeit spaeter". Ein sanftes Nachladen ist kein Oeffnen. Wo jemand steht, weiss ab jetzt allein der Scroll-Horcher -- und der misst es, statt es anzunehmen. DREI FEHLVERSUCHE BIS ZUR MESSUNG, und sie gehoeren ins Protokoll: Erst sechs Sekunden Nichtstun, dann ein Fingertipp auf Koordinaten, dann ein Verbindungsabriss -- alle drei waren mit dem ALTEN Code gruen. Eine Pruefung, die den Fehler nicht herstellt, misst nichts, und ich haette sie beinahe als Beweis genommen. Was fehlte: Der Griff muss den Verlauf WIRKLICH treffen (Koordinaten gehen daneben), und es braucht einen echten sanften Nachlauf -- hier das Anheften, das ein `pin`-Ereignis an alle im Raum schickt. Erst damit flippt die Gegenprobe: ohne Korrektur 500 -> 7054 px und `amEnde: true`, mit Korrektur bleibt es bei 500. pruef-chat-neu-stelle 62 -> 69. Unterwegs wieder entfernt: ein Merker `schonGesprungen`, den ich zuerst eingebaut hatte. Nach der echten Korrektur ist er unerreichbar, und ich konnte ihn mit keiner Messung zum Greifen bringen. Ein Zweig, den nichts erreicht, sieht beim Lesen aus wie ein Fall, den es gibt. Gegengemessen: pruef-chat 80, pruef-chat-optik 84, pruef-freie-namen 32 -- 0 Fehler. Co-Authored-By: Claude Opus 5 --- server/pruef-chat-neu-stelle.mjs | 155 +++++++++++++++++++++++++++++++ server/pruef-suchfeld.mjs | 90 ++++++++++++++++++ workspace/anruf-probe.html | 10 +- workspace/app.webmanifest | 8 +- workspace/assets/js/chat.js | 29 +++++- workspace/assets/js/wahl.js | 27 +++++- workspace/aufgaben.html | 38 ++++---- workspace/automation.html | 32 +++---- workspace/befinden.html | 34 +++---- workspace/bereich.html | 44 ++++----- workspace/bewerben.html | 38 ++++---- workspace/bewerbungen.html | 36 +++---- workspace/buehne.html | 6 +- workspace/calls.html | 34 +++---- workspace/chat.html | 40 ++++---- workspace/content.html | 34 +++---- workspace/crew-index.html | 12 +-- workspace/crew.webmanifest | 8 +- workspace/dateien.html | 34 +++---- workspace/entwicklung.html | 36 +++---- workspace/hilfe.html | 30 +++--- workspace/index.html | 10 +- workspace/kalender.html | 34 +++---- workspace/leistung.html | 32 +++---- workspace/manager-ziele.html | 28 +++--- workspace/material.html | 32 +++---- workspace/notizen.html | 28 +++--- workspace/personen.html | 32 +++---- workspace/profil.html | 36 +++---- workspace/reaktion.html | 38 ++++---- workspace/rechte.html | 34 +++---- workspace/report.html | 36 +++---- workspace/scouting.html | 32 +++---- workspace/start.html | 32 +++---- workspace/startcheck.html | 34 +++---- workspace/steckbrief.html | 36 +++---- workspace/support.html | 28 +++--- workspace/tafel.html | 6 +- workspace/talente.html | 36 +++---- workspace/team.html | 32 +++---- workspace/teamlage.html | 34 +++---- workspace/teilen.html | 30 +++--- workspace/treff-moderation.html | 32 +++---- workspace/treff-regeln.html | 32 +++---- workspace/uebersicht.html | 32 +++---- workspace/unsere-seiten.html | 30 +++--- workspace/unterstuetzen.html | 32 +++---- workspace/werdegang.html | 32 +++---- workspace/willkommen.html | 30 +++--- workspace/wissen.html | 34 +++---- 50 files changed, 981 insertions(+), 688 deletions(-) diff --git a/server/pruef-chat-neu-stelle.mjs b/server/pruef-chat-neu-stelle.mjs index f58945e9..8d680061 100644 --- a/server/pruef-chat-neu-stelle.mjs +++ b/server/pruef-chat-neu-stelle.mjs @@ -368,6 +368,161 @@ melde("=== 2. Gegenproben (jede MUSS anschlagen) ==="); + "-- die Messung kann also auch nein sagen"); } +/* ===================================================================== + DIE STELLE HAELT AUCH, WENN DIE LINIE VERSCHWINDET (05.10.2026) + + Miss: "Wenn ich auf den Chat gehen, komme ich zuerst auf die erste + neue Nachricht, aber kurze Zeit spaeter springt er auf die zuletzt + geschrieben Nachricht." + + Die Pruefungen oben messen den Zustand nach 2,2 Sekunden -- und der + war immer richtig. Ihr Fehler passiert DANACH: Beim Oeffnen meldet + die Seite "gelesen bis hier". Beim naechsten sanften Nachladen + steht die letzte Nachricht schon in `gelesen_bis`, die Linie + entsteht nicht mehr, und dieselbe Bedingung bedeutete ploetzlich + das Gegenteil -- nicht "das Neue ist jetzt gelesen", sondern + "nichts Neues, also ans Ende". + + Deshalb wird hier ZWEIMAL gemessen: einmal wie oben, und einmal + nach weiteren sechs Sekunden, in denen niemand etwas anfasst. Eine + Messung, die nur den ersten Moment ansieht, haette diesen Fehler + nie gefunden -- sie hat ihn wochenlang nicht gefunden. + ===================================================================== */ +melde(""); +melde("=== 4. Ein sanftes Nachladen reisst niemanden ans Ende ==="); +{ + const person = LEUTE[0]; + const keks = await anmelden(person.host, person.rolle, person.code); + const kPartner = await anmelden(person.partnerHost, person.partnerRolle, person.partnerCode); + const gr = await roh(person.host, keks, "/workspace/api/chat/gruppe", "POST", + { name: `${person.wer} Miss-Fall`, mit: [person.partner] }); + const raumId = gr.json().raum_id; + + let letzteAlte = 0; + for (let i = 1; i <= 20; i++) { + const a = await roh(person.partnerHost, kPartner, + `/workspace/api/chat/raeume/${raumId}/nachrichten`, "POST", + { text: `Alte Nachricht ${i} -- lange genug, damit sie auf einem Handy umbricht.` }); + letzteAlte = a.json().nachricht?.id || a.json().id || letzteAlte; + } + await roh(person.host, keks, `/workspace/api/chat/raeume/${raumId}/gelesen`, + "PUT", { bis: letzteAlte }); + for (let i = 1; i <= 12; i++) { + await roh(person.partnerHost, kPartner, + `/workspace/api/chat/raeume/${raumId}/nachrichten`, "POST", + { text: `NEUE Nachricht ${i} -- auch diese ist lang genug zum Umbrechen.` }); + } + + const kontext = await browser.newContext({ + viewport: { width: 390, height: 844 }, + deviceScaleFactor: 2, isMobile: true, hasTouch: true, + }); + await kontext.addCookies(keks.split("; ").map((k) => { + const [x, ...r] = k.split("="); + return { name: x, value: r.join("="), domain: person.host, path: "/" }; + })); + const seite = await kontext.newPage(); + const konsole = []; + seite.on("pageerror", (e) => konsole.push("Absturz: " + e.message.slice(0, 120))); + await seite.goto(`https://${person.host}:${HP}/workspace/chat.html?raum=${raumId}`, + { waitUntil: "networkidle" }); + + const messen = () => seite.evaluate(() => { + const v = document.getElementById("verlauf"); + if (!v) return { da: false }; + const l = v.querySelector(".chat-neu"); + return { + da: true, + stelle: Math.round(v.scrollTop), + amEnde: v.scrollHeight - v.scrollTop - v.clientHeight < 40, + linieDa: !!l, + }; + }); + + await seite.waitForTimeout(2200); + const erst = await messen(); + ok(erst.da && erst.linieDa && !erst.amEnde, + `beim Oeffnen steht sie an der neuen Stelle (Linie ${erst.linieDa}, am Ende ${erst.amEnde})`); + + /* ==== DER FINGERTIPP IST DER AUSLOESER ======================== + + Der erste Anlauf liess die Seite einfach sechs Sekunden in Ruhe + -- und war mit dem ALTEN Code genauso gruen. Die Messung hat + Miss' Fall gar nicht hergestellt. + + Es fehlte das, was ein Mensch beim Lesen zwangslaeufig tut: Er + tippt einmal auf den Verlauf. `wache` nimmt das (zu Recht) als + "er hat die Stelle gesehen" und loescht den Sprung-Merker. Erst + DANACH ist der Weg zu `if (unten)` frei -- und `unten` stand bei + jedem sanften Nachladen wieder auf true. + + Getippt wird an den linken Rand, nicht auf eine Nachricht: Es + geht um die Beruehrung, nicht um einen Knopf. */ + /* Der Griff muss den Verlauf WIRKLICH treffen -- ein Tipp auf + Koordinaten kann danebengehen, und dann bleibt der Merker + stehen (gemessen: die Ansicht sprang danach zur Linie zurueck, + nicht ans Ende, weil `wache` nie lief). */ + await seite.locator("#verlauf").dispatchEvent("touchstart"); + await seite.waitForTimeout(400); + + /* ==== UND JETZT NACH OBEN LESEN =============================== + + Hier wird der Defekt selbst gemessen statt Miss' Ablauf geraten + -- drei Versuche, ihn nachzustellen, waren mit dem ALTEN Code + gruen, und eine Pruefung, die den Fehler nicht herstellt, misst + nichts. + + Der Defekt ist eine Zeile: Beim Laden eines Raums wurde `unten` + auf true gesetzt, und zwar auch beim SANFTEN Nachladen. Wer also + irgendwo im Verlauf steht und dessen Strom neu verbindet, wird + ans Ende gerissen -- unabhaengig davon, wie er dorthin kam. + + Das ist allgemeiner als Miss' Fall und schliesst ihn ein. */ + await seite.evaluate(() => { document.getElementById("verlauf").scrollTop = 500; }); + await seite.waitForTimeout(400); + const obenGelesen = await messen(); + ok(obenGelesen.stelle <= 600 && !obenGelesen.amEnde, + `sie liest weiter oben (${obenGelesen.stelle} px, am Ende ${obenGelesen.amEnde})`); + + /* ==== UND DER ZWEITE AUSLOESER: EIN SANFTER NACHLAUF =========== + + Auch mit dem Fingertipp blieb die Messung mit dem alten Code + gruen -- es fehlte das, was `unten` ueberhaupt wieder auf true + setzt: ein erneutes Laden des Raums. Das passiert nicht von + selbst, sondern wenn der Ereignisstrom neu verbindet. + + Erst versucht mit einem Verbindungsabriss (offline/online) -- der + loeste in dieser Umgebung keinen aus, und die Messung blieb + gruen, ohne etwas hergestellt zu haben. Jetzt heftet jemand + anderes eine Nachricht an: Das schickt ein `pin`-Ereignis an + alle im Raum, und die Seite laedt sanft nach. Im "Rudel" mit zehn + Leuten ist das Alltag. */ + const angeheftet = await roh(person.host, keks, + `/workspace/api/chat/nachrichten/${letzteAlte}/anheften`, "PUT", { an: true }); + ok(angeheftet.status === 200, + `jemand heftet etwas an -- das loest den sanften Nachlauf aus (${angeheftet.status})`); + + /* Und jetzt sechs Sekunden nichts weiter tun -- genau das, was Miss + beschreibt: Sie liest, und "kurze Zeit spaeter" springt es. */ + await seite.waitForTimeout(6000); + const spaeter = await messen(); + + ok(spaeter.amEnde === false, + `nach dem Nachladen steht sie nicht am Ende (amEnde ${spaeter.amEnde})`); + /* Die eigentliche Zahl: Die Bildlaufposition darf sich nicht + nennenswert bewegt haben. "Nicht am Ende" allein koennte auch + heissen, dass sie irgendwohin anders gesprungen ist. */ + ok(Math.abs(spaeter.stelle - obenGelesen.stelle) <= 60, + `und zwar da, wo sie gelesen hat (${obenGelesen.stelle} -> ${spaeter.stelle} px)`); + /* Dass die Linie inzwischen WEG sein darf, ist kein Fehler -- + gelesen ist gelesen. Nur springen darf es deswegen nicht. */ + melde(` (die Linie ist jetzt ${spaeter.linieDa ? "noch da" : "weg -- gelesen"},` + + " das ist in Ordnung)"); + ok(konsole.length === 0, `keine Abstuerze (${konsole.join(" | ") || "keine"})`); + + await kontext.close(); +} + await browser.close(); vorbau.close(); diff --git a/server/pruef-suchfeld.mjs b/server/pruef-suchfeld.mjs index 559e7de8..72ceb21c 100644 --- a/server/pruef-suchfeld.mjs +++ b/server/pruef-suchfeld.mjs @@ -189,6 +189,96 @@ try { ok(konsole.length === 0, konsole.length ? konsole[0] : "keine Abstuerze"); await seite.screenshot({ path: "pruef-suchfeld.png", fullPage: false }); await kontext.close(); + +/* ===================================================================== + EINE GROESSENAENDERUNG DARF DIE LISTE NICHT SCHLIESSEN (05.10.2026) + + Diene: "Beim Kalender laesst sich die Art noch nicht einstellen, das + Menue ploppt nur ganz kurz auf und verschwindet direkt wieder. Das + selbe bei den Wiederholungen." + + Auf dem Rechner faellt das nie auf: Dort aendert sich die + Fenstergroesse nur, wenn jemand sie aendert. Auf einem Handy aendert + sie sich beim Bedienen -- Adressleiste, Tastatur -- und `resize` + feuerte `schliessen()`. + + Gemessen wird an GENAU IHREM Fall: Kalenderformular, die beiden + Auswahlfelder "Art" und "Wiederholung", und eine echte + Groessenaenderung dazwischen. Die Liste muss offen bleiben UND + danach an ihrem Knopf sitzen -- offen, aber verrutscht waere nur + die andere Haelfte. + ===================================================================== */ +{ + const kontext = await browser.newContext({ + viewport: { width: 390, height: 844 }, hasTouch: true, isMobile: true, + }); + const seite = await kontext.newPage(); + await seite.goto(BASIS + "/workspace/", { waitUntil: "domcontentloaded" }); + await seite.click('.rolle[data-rolle="admin"]'); + await seite.fill("#code", "CODE-DOGI-0001"); + await seite.click("button[type=submit]"); + await seite.waitForURL("**/start.html", { timeout: 15000 }); + await seite.goto(BASIS + "/workspace/kalender.html", { waitUntil: "networkidle" }); + await seite.waitForTimeout(1200); + await seite.evaluate(() => document.getElementById("neu-oeffnen")?.click()); + await seite.waitForTimeout(600); + + for (const [feldId, wie] of [["f-art", "Art"], ["f-takt", "Wiederholung"]]) { + const auf = await seite.evaluate((id) => { + const k = document.getElementById(id)?.closest(".wahl2")?.querySelector(".wahl2__knopf"); + if (!k) return "kein Knopf"; + k.click(); + return !!document.querySelector(".wahl2__liste"); + }, feldId); + ok(auf === true, `${wie}: die Liste geht auf (${auf})`); + + /* Die Groessenaenderung, die auf dem Handy beim Bedienen entsteht: + Die Adressleiste faehrt ein, das Fenster wird hoeher. */ + await seite.setViewportSize({ width: 390, height: 788 }); + await seite.waitForTimeout(350); + + const danach = await seite.evaluate(() => { + const l = document.querySelector(".wahl2__liste"); + if (!l) return { offen: false }; + const k = document.querySelector(".wahl2__knopf[aria-expanded='true']") + || document.querySelector(".wahl2 .wahl2__knopf"); + const lr = l.getBoundingClientRect(); + const kr = k ? k.getBoundingClientRect() : null; + return { + offen: true, + /* Sitzt sie noch an ihrem Knopf? Mehr als 40 px Abstand waere + "offen, aber verrutscht" -- und das ist kein Erfolg. */ + abstand: kr ? Math.round(Math.min(Math.abs(lr.top - kr.bottom), + Math.abs(lr.bottom - kr.top))) : null, + imBild: lr.top >= 0 && lr.bottom <= innerHeight + 1, + }; + }); + ok(danach.offen === true, + `${wie}: sie bleibt nach der Groessenaenderung offen (${danach.offen})`); + ok(danach.offen && danach.abstand !== null && danach.abstand <= 40, + `${wie}: und sitzt weiter an ihrem Knopf (${danach.abstand} px Abstand)`); + + await seite.setViewportSize({ width: 390, height: 844 }); + await seite.keyboard.press("Escape"); + await seite.waitForTimeout(250); + } + + /* GEGENPROBE: Escape schliesst sie weiterhin. Sonst haette ich aus + "schliesst zu frueh" ein "schliesst nie" gemacht -- und das waere + schlimmer, weil man dann gar nicht mehr herauskommt. */ + await seite.evaluate(() => document.getElementById("f-art") + ?.closest(".wahl2")?.querySelector(".wahl2__knopf")?.click()); + await seite.waitForTimeout(300); + const vorEsc = await seite.evaluate(() => !!document.querySelector(".wahl2__liste")); + await seite.keyboard.press("Escape"); + await seite.waitForTimeout(300); + const nachEsc = await seite.evaluate(() => !!document.querySelector(".wahl2__liste")); + ok(vorEsc && !nachEsc, + `Gegenprobe: Escape schliesst sie weiterhin (offen ${vorEsc} -> ${nachEsc})`); + + await kontext.close(); +} + } finally { await browser.close(); try { rmSync(ordner, { recursive: true, force: true }); } catch { /* egal */ } diff --git a/workspace/anruf-probe.html b/workspace/anruf-probe.html index be00c96e..4ef33eb5 100644 --- a/workspace/anruf-probe.html +++ b/workspace/anruf-probe.html @@ -16,8 +16,8 @@ verdeckt. Gefunden hat es pruef-struktur. Richtig sind `gate.css` (die Farbwerte des Hauses) und `haus.css`. --> - - + + - +