From b941080694d47bebe371d9233410eeda561b9710 Mon Sep 17 00:00:00 2001 From: Claudian Date: Fri, 4 Sep 2026 19:18:02 +0200 Subject: [PATCH] Die Namensliste ging beim Scrollen zu FILIPE, mit Bildschirmfoto der Personenauswahl: "wenn ich da scollen will geht das immer zu" Er hatte recht, und es war eine einzige Zeile in workspace/assets/js/wahl.js: addEventListener('scroll', schliessen, true); Das dritte Argument bedeutet "in der Einfangphase lauschen" -- und damit auf JEDES Scroll-Ereignis im ganzen Dokument, auch auf das in der Liste selbst. Wer die Namensliste herunterrollen wollte, schloss sie im selben Moment. Bei acht Eintraegen faellt das kaum auf; beim ganzen Manager- und Scout-Team ist die Liste unbedienbar. Zumachen MUSS sie trotzdem, wenn die Seite scrollt: Sie haengt an position:fixed und schwaemme sonst neben ihrem Knopf davon. Deshalb wird jetzt unterschieden, WO gescrollt wurde -- ein Scroll-Ereignis der Seite hat document als Ziel, das ist nicht in der Liste enthalten, also schliesst sie wie bisher. Dazu overscroll-behavior: contain in gate.css. Ohne das reicht der Browser das Rollen am Listenende an die Seite weiter, die Seite bewegt sich -- und daran schliesst die Liste zu Recht. Der Fehler waere zur Haelfte zurueck gewesen. GEPRUEFT im echten Browser am echten wahl.js und gate.css (pruef-wahl-scrollen.mjs, 7 Pruefungen), und zwar BEIDE Haelften der Zusage: Liste scrollt -> bleibt offen, Seite scrollt -> geht zu. Eine Reparatur, die nur die eine Richtung sichert, waere die naechste Ueberraschung. Gegenprobe: alte Zeile testweise eingesetzt -> 2 Pruefungen fallen durch. Reparatur -> alle 7 gruen. Die Pruefung hat sich beim Bauen DREIMAL geweigert, etwas zu bestaetigen, das sie nicht gemessen hatte -- "die Liste ist gar nicht laenger als ihr Fenster", "scrollTop = 0". Jedes Mal lag es an meinem Aufbau (zu hohes Fenster, fehlende Stylesheets, Mausrad ohne Wirkung), nie an der Reparatur. Gruen gemeldet haette sie es nie. Der Versionsstempel muss mit: Cloudflare haelt JS und CSS vier Stunden im Browser fest. Ohne neue Adresse saehe Filipe die Reparatur bis zu vier Stunden lang nicht. HINWEIS ZUM COMMIT: In diesem Verzeichnis lag zum Zeitpunkt der Arbeit fremde, uncommittete Arbeit -- vier Server-Dateien (heute 16:41-16:53 geaendert), sieben neue Pruefdateien, ~110 Bildschirmfotos, eine Fokusring-Korrektur in gate.css und eine Beschriftung in profil.html. Nichts davon ist hier drin. Bereitgestellt wurde ausdruecklich nach Pfad, und die beiden Dateien mit gemischtem Inhalt (gate.css, profil.html) wurden dafuer aus HEAD geholt und nur um den eigenen Anteil ergaenzt. Die fremde Arbeit steht unveraendert im Arbeitsstand. --- pruef-wahl-scrollen.mjs | 143 ++++++++++++++++++++++++++++++++++ workspace/assets/css/gate.css | 4 + workspace/assets/js/wahl.js | 21 ++++- workspace/aufgaben.html | 14 ++-- workspace/automation.html | 16 ++-- workspace/bereich.html | 24 +++--- workspace/calls.html | 18 ++--- workspace/content.html | 20 ++--- workspace/dateien.html | 16 ++-- workspace/index.html | 4 +- workspace/kalender.html | 16 ++-- workspace/personen.html | 16 ++-- workspace/report.html | 18 ++--- workspace/scouting.html | 16 ++-- workspace/start.html | 12 +-- workspace/startcheck.html | 18 ++--- workspace/steckbrief.html | 16 ++-- workspace/uebersicht.html | 12 +-- workspace/wissen.html | 16 ++-- 19 files changed, 293 insertions(+), 127 deletions(-) create mode 100644 pruef-wahl-scrollen.mjs diff --git a/pruef-wahl-scrollen.mjs b/pruef-wahl-scrollen.mjs new file mode 100644 index 00000000..acce694e --- /dev/null +++ b/pruef-wahl-scrollen.mjs @@ -0,0 +1,143 @@ +/* =================================================================== + pruef-wahl-scrollen.mjs — die Namensliste bleibt beim Scrollen offen. + + ANLASS (Filipe, 04.09.2026, mit Bildschirmfoto der Personenauswahl): + "wenn ich da scollen will geht das immer zu" + + Er hatte recht, und die Ursache war eine einzige Stelle in + assets/js/wahl.js: + + addEventListener('scroll', schliessen, true); + + Das dritte Argument bedeutet "in der Einfangphase lauschen" -- und + damit auf JEDES Scroll-Ereignis im ganzen Dokument, auch auf das in + der Liste selbst. Wer die Namensliste herunterrollen wollte, schloss + sie im selben Moment. Bei acht Eintraegen faellt das kaum auf; beim + ganzen Manager- und Scout-Team ist die Liste unbedienbar. + + Zumachen MUSS sie trotzdem, wenn die Seite scrollt: Sie haengt an + position:fixed und schwaemme sonst neben ihrem Knopf davon. Deshalb + pruefen hier beide Haelften -- eine Reparatur, die nur die eine + Richtung sichert, waere die naechste Ueberraschung: + + scrollt die LISTE -> bleibt offen + scrollt die SEITE -> geht zu + + Geprueft wird im echten Browser am ECHTEN wahl.js und gate.css, nicht + an einer Nachbildung. Eine Nachbildung haette genau die Zeile nicht + gehabt, um die es geht. + + Aufruf: node pruef-wahl-scrollen.mjs + =================================================================== */ +import { chromium } from "playwright"; +import { readFileSync } from "node:fs"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; + +const HIER = dirname(fileURLToPath(import.meta.url)); +const JS = join(HIER, "workspace", "assets", "js", "wahl.js"); +/* ALLE Stylesheets, die eine Arbeitsplatz-Seite laedt -- nicht nur gate.css. + Beim ersten Lauf war nur gate.css eingebunden: Die Eintraege bekamen dadurch + weder Schriftgroesse noch Innenabstand, 30 Namen waren zusammen 243 Pixel hoch, + und die Liste konnte gar nicht scrollen. Die Pruefung hat das gemeldet, statt + gruen zu behaupten, sie haette das Scrollen geprueft. */ +const CSS_DATEIEN = ["gate.css", "start.css", "aufgaben.css"] + .map((n) => join(HIER, "workspace", "assets", "css", n)); + +let gut = 0; +const schlecht = []; +const pruefe = (name, bedingung, zusatz = "") => { + if (bedingung) { gut++; console.log(" ok " + name); } + else { schlecht.push(name); console.log(" FEHLER " + name + (zusatz ? " — " + zusatz : "")); } +}; + +/* Genug Eintraege, damit die Liste ueberhaupt scrollen KANN -- mit fuenf + Namen gaebe es nichts zu rollen, und die Pruefung waere gruen, ohne + etwas gemessen zu haben. Die Namen sind die aus Filipes Bild. */ +const NAMEN = [ + "Dogfather (admin)", "VanVan (admin)", "Cigdem (manager)", "Drouwn (manager)", + "Schulle (manager)", "BananaStift (scout)", "Patrick (scout)", "Tili (scout)", + ...Array.from({ length: 22 }, (_, i) => `Weitere Person ${i + 9} (scout)`), +]; + +const browser = await chromium.launch(); +/* Ein NIEDRIGES Fenster, wie auf Filipes Bildschirmfoto. Beim ersten Lauf stand hier + 700 Pixel Hoehe -- da passte die ganze Liste hinein, es gab nichts zu scrollen, und + "bleibt beim Scrollen offen" waere eine leere Aussage gewesen. Die Pruefung hat das + selbst gemeldet, statt gruen zu behaupten, was sie nicht gemessen hatte. */ +const seite = await browser.newPage({ viewport: { width: 1280, height: 420 } }); + +/* Die Seite ist absichtlich hoch: Ohne Scrollweg liesse sich die zweite + Haelfte ("die Seite scrollt -> Liste geht zu") gar nicht pruefen. */ +await seite.setContent(` + +
+ +
+ `); +for (const datei of CSS_DATEIEN) await seite.addStyleTag({ content: readFileSync(datei, "utf8") }); +await seite.addScriptTag({ content: readFileSync(JS, "utf8") }); +await seite.waitForTimeout(150); + +console.log("\n--- Die Liste laesst sich ueberhaupt oeffnen ---"); +const knopf = seite.locator(".wahl2__knopf").first(); +pruefe("Das Auswahlfeld wurde eingepackt", await knopf.count() > 0); +await knopf.click(); +await seite.waitForTimeout(120); +const liste = seite.locator(".wahl2__liste").first(); +pruefe("Die Liste ist offen", await liste.count() > 0); + +/* DIE LISTE MUSS SCROLLEN KOENNEN, sonst ist alles Weitere wertlos: Eine Liste, die + gar nicht rollt, bleibt beim Scrollen selbstverstaendlich offen. + + Die Hoehe wird hier ausdruecklich klein gesetzt, statt sie aus dem Seitenaufbau + entstehen zu lassen. Grund: Geaendert wurde die JavaScript-Logik (welches Scrollen + schliesst die Liste), nicht die Gestaltung. Ein Aufbau, der erst die echte + Schriftgroesse, Zeilenhoehe und Fensterhoehe nachbaut, prueft am Ende die + Stylesheets -- und beim ersten Versuch genau daran vorbei: 30 Namen waren + zusammen 243 Pixel hoch, es gab nichts zu rollen, und die Pruefung hat das + gemeldet, statt gruen zu behaupten, sie haette gescrollt. + + Wie gross die Liste im Betrieb wird, entscheidet gate.css (max-height aus dem + Platz unter dem Knopf) -- das ist eine andere Frage als diese hier. */ +await liste.evaluate((el) => { el.style.maxHeight = "150px"; }); +await seite.waitForTimeout(80); +const scrollbar = await liste.evaluate((el) => el.scrollHeight > el.clientHeight + 4); +pruefe("Und sie ist laenger als ihr Fenster — es gibt wirklich etwas zu scrollen", scrollbar); + +console.log("\n--- DER FALL: in der Liste scrollen ---"); +/* Gerollt wird ueber scrollTop, nicht ueber das Mausrad. Grund: Beim ersten Versuch + stand hier hover() + mouse.wheel() -- die Liste blieb offen, aber scrollTop war 0. + Das Rad hatte gar nichts bewegt, es war also nie ein Scroll-Ereignis unterwegs, und + "bleibt offen" haette nichts bewiesen. Eine Zuweisung an scrollTop loest dasselbe + Ereignis aus wie das Rad, nur zuverlaessig. */ +await liste.evaluate((el) => { el.scrollTop = 60; }); +await seite.waitForTimeout(200); +pruefe("Die Liste ist nach dem Scrollen NOCH OFFEN", await seite.locator(".wahl2__liste").count() > 0); +const versatz = await seite.locator(".wahl2__liste").first() + .evaluate((el) => el.scrollTop).catch(() => 0); +pruefe("Und sie ist wirklich gerollt — nicht nur stehen geblieben", versatz > 0, `scrollTop = ${versatz}`); + +console.log("\n--- GEGENPROBE: die SEITE scrollen ---"); +/* Die andere Haelfte der Zusage. Ohne sie waere "bleibt offen" auch mit + einem ersatzlos entfernten Zuhoerer gruen -- und die Liste stuende beim + Scrollen der Seite irgendwo im Nichts. */ +await seite.mouse.move(20, 20); +await seite.mouse.wheel(0, 400); +await seite.waitForTimeout(200); +pruefe("Beim Scrollen der Seite geht sie zu", await seite.locator(".wahl2__liste").count() === 0); + +console.log("\n--- Und danach laesst sie sich wieder oeffnen ---"); +await seite.evaluate(() => window.scrollTo(0, 0)); +await seite.waitForTimeout(100); +await seite.locator(".wahl2__knopf").first().click(); +await seite.waitForTimeout(120); +pruefe("Erneutes Oeffnen geht", await seite.locator(".wahl2__liste").count() > 0); + +await browser.close(); + +console.log(""); +console.log("=".repeat(60)); +if (schlecht.length === 0) console.log(`Alle ${gut} Pruefungen bestanden.`); +else { console.log(`${gut} bestanden, ${schlecht.length} fehlgeschlagen:`); schlecht.forEach((s) => console.log(" - " + s)); } +process.exit(schlecht.length ? 1 : 0); diff --git a/workspace/assets/css/gate.css b/workspace/assets/css/gate.css index a56b8cc6..ee15d3a6 100644 --- a/workspace/assets/css/gate.css +++ b/workspace/assets/css/gate.css @@ -774,6 +774,10 @@ body.suche-offen { overflow: hidden; } position: fixed; z-index: 90; min-width: 180px; max-width: min(420px, calc(100vw - 24px)); overflow-y: auto; padding: 5px; + /* Am Ende der Liste NICHT weiterrollen: Ohne das gibt der Browser das Scrollen an + die Seite weiter (Scroll-Verkettung), die Seite bewegt sich -- und genau daran + schliesst die Liste zu Recht. Damit waere der Fehler von oben zur Haelfte zurueck. */ + overscroll-behavior: contain; background: #0d1420; border: 1px solid rgba(63, 189, 245, .3); border-radius: 11px; diff --git a/workspace/assets/js/wahl.js b/workspace/assets/js/wahl.js index 3ca81b6c..7cde6ef4 100644 --- a/workspace/assets/js/wahl.js +++ b/workspace/assets/js/wahl.js @@ -338,7 +338,26 @@ schliessen(); }); addEventListener('resize', schliessen); - addEventListener('scroll', schliessen, true); + + /* SCROLLEN IN DER LISTE DARF SIE NICHT SCHLIESSEN (04.09.2026, von Filipe gemeldet: + "wenn ich da scollen will geht das immer zu"). + + Hier stand `addEventListener('scroll', schliessen, true)`. Das dritte Argument + bedeutet: in der EINFANGPHASE lauschen -- und damit auf JEDES Scrollen im ganzen + Dokument, auch auf das in der Liste selbst. Wer die Namensliste herunterrollen + wollte, schloss sie damit im selben Moment. Bei acht Eintraegen faellt das kaum + auf, beim ganzen Team ist die Liste unbedienbar. + + Zumachen muss sie trotzdem, wenn die SEITE scrollt: Sie haengt position:fixed am + Knopf und schwaemme sonst davon. Deshalb wird jetzt unterschieden, WO gescrollt + wurde. Ein Scroll-Ereignis der Seite hat document als Ziel -- das ist nicht in der + Liste enthalten, also schliesst sie wie bisher. */ + addEventListener('scroll', (e) => { + if (!aktiv) return; + const ziel = e.target; + if (ziel instanceof Node && aktiv.liste?.contains(ziel)) return; + schliessen(); + }, true); /* Ein Formular-reset() leert das