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