diff --git a/server/pruef-eventkarte.mjs b/server/pruef-eventkarte.mjs index 314904a9..5b38422f 100644 --- a/server/pruef-eventkarte.mjs +++ b/server/pruef-eventkarte.mjs @@ -471,6 +471,252 @@ async function alsRolle(rolle, code, breite = 1280) { }); melde(" -- gemessen: " + JSON.stringify(masse)); + /* ==== NUR MESSEN (07.10.2026): Breite, Ton und tote Regeln ==== */ + const lage = await seite.evaluate(() => { + const k = [...document.querySelectorAll('.eintrag-karte[data-eventkarte="ja"]')]; + const erste = k[0], zweite = k[1]; + const s = getComputedStyle(erste); + const liste = document.getElementById("liste"); + return { + kartenBreite: Math.round(erste.getBoundingClientRect().width), + listenBreite: Math.round(liste.getBoundingClientRect().width), + nebeneinander: zweite + ? Math.abs(erste.getBoundingClientRect().top - zweite.getBoundingClientRect().top) < 5 : null, + ton: s.getPropertyValue("--ton").trim() || "(nicht gesetzt)", + randLinks: s.borderLeftWidth, randOben: s.borderTopWidth, + radius: s.borderTopLeftRadius, + anzeige: getComputedStyle(liste).display, + /* Wo haengt die Karte wirklich? Im 4000-Zeilen-Modul stehen drei + Formen (Kanalspalten, Abschnitte nach Art, Zeitstrahl) -- die + Antwort aus dem Quelltext zu raten waere Raten. */ + eltern: (() => { + const weg = []; let n = erste.parentElement; + for (let i = 0; i < 4 && n; i++, n = n.parentElement) { + weg.push((n.tagName + "." + (n.className || "")).trim() + + (n.id ? "#" + n.id : "") + ":" + getComputedStyle(n).display); + } + return weg; + })(), + geschwister: erste.parentElement + ? [...erste.parentElement.children].map((c) => c.tagName + "." + (c.className || "").split(" ")[0]) + : [], + reihen: [...liste.children].map((c) => { + const r = c.getBoundingClientRect(); + return { + event: c.dataset.eventkarte === "ja", + titel: (c.querySelector(".eintrag-titel")?.textContent || "?").slice(0, 18), + x: Math.round(r.x), y: Math.round(r.y), b: Math.round(r.width), + }; + }), + }; + }); + melde(" -- Lage: " + JSON.stringify(lage)); + + /* ===== ZWEI NEBENEINANDER (07.10.2026) ============================ + + Filipe: „die soll aber auch garnicht so breit sein. es sollen immer + zwei neben einander stehen können." + + Gemessen VOR dem Umbau: 1160 px breit, eine je Reihe. */ + const events = lage.reihen.filter((r) => r.event); + const andere = lage.reihen.filter((r) => !r.event); + ok(events.length >= 2 && events.every((r) => r.b < lage.listenBreite * 0.55), + `jede Eventkarte ist hoechstens halb so breit wie die Liste ` + + `(${events.map((r) => r.b).join(", ")} von ${lage.listenBreite} px)`); + /* DASS SIE SCHMAL SIND, HEISST NOCH NICHT, DASS ZWEI NEBENEINANDER + STEHEN -- sie koennten auch untereinander in einer halben Spalte + haengen. Gemessen wird deshalb ein PAAR: zwei Karten, gleiche + Hoehe, verschiedene Seite. */ + const paar = events.some((a, i) => events.slice(i + 1) + .some((b2) => Math.abs(a.y - b2.y) < 5 && Math.abs(a.x - b2.x) > 100)); + ok(paar, `zwei Eventkarten stehen wirklich nebeneinander ` + + `(${events.map((r) => `${r.titel}@${r.x}/${r.y}`).join(" ")})`); + /* GEGENPROBE: Was KEIN Event ist, bleibt ueber die ganze Breite -- + sonst waere „die Liste ist jetzt zweispaltig" ein Umbau aller acht + Bereiche und nicht der Eventkarten. */ + ok(andere.length > 0 && andere.every((r) => r.b > lage.listenBreite * 0.95), + `die Nicht-Event-Karte behaelt die volle Breite (${andere.map((r) => r.b).join(", ")} px)`); + + /* ===== DIE KARTE SAGT, OB DAS EVENT LAEUFT ======================== */ + const toene = await seite.evaluate(() => { + const raus = {}; + for (const k of document.querySelectorAll('.eintrag-karte[data-eventkarte="ja"]')) { + raus[k.dataset.event] = getComputedStyle(k).getPropertyValue("--ton").trim(); + } + return raus; + }); + /* ==== NUR MESSEN: Wie sieht eine Karte OHNE Banner aus? ==== + Im Quelltext steht „OHNE BANNER GIBT ES TROTZDEM EINE BUEHNE -- + dann aus Farbe". Auf dem Bild vom 07.10.2026 war davon nichts zu + sehen: Die Karte ohne Bild fing direkt mit dem Titel an. */ + const buehnenLage = await seite.evaluate(() => { + const raus = []; + for (const k of document.querySelectorAll('.eintrag-karte[data-eventkarte="ja"]')) { + const b = k.querySelector(".ev-buehne"); + raus.push({ + titel: (k.querySelector(".eintrag-titel")?.textContent || "?").slice(0, 16), + mitbild: b?.dataset.mitbild || "nein", + buehneHoehe: b ? Math.round(b.getBoundingClientRect().height) : 0, + buehneGrund: b ? getComputedStyle(b).backgroundImage.slice(0, 30) : "-", + marke: (() => { const m = k.querySelector(".marke-art"); if (!m) return null; + const r = m.getBoundingClientRect(); const st = getComputedStyle(m); + return { text: m.textContent.trim(), b: Math.round(r.width), h: Math.round(r.height), + farbe: st.color, grund: st.backgroundColor, sicht: st.visibility, deck: st.opacity, + yImKarton: Math.round(r.top - k.getBoundingClientRect().top), + xImKarton: Math.round(r.left - k.getBoundingClientRect().left) }; })(), + }); + } + return raus; + }); + melde(" -- Buehnen: " + JSON.stringify(buehnenLage)); + + /* ===== NICHTS DARF AUS DER KARTE HERAUSLAUFEN (07.10.2026) ======== + + Die Karte traegt ein `clip-path` -- was oben herausragt, ist nicht + verschoben, sondern WEG. Genau das ist am 07.10.2026 passiert, als + die Karten halb so breit wurden: Das Etikett „Agentur-Events" sass + auf der Karte „September Rueckblick" bei y = -28 px. + + WARUM DIE ALTE MESSUNG ES NICHT FAND: Sie fragte nach Farbe, + Groesse, Sichtbarkeit und Deckkraft -- und bekam auf alles die + richtige Antwort. Nach der LAGE hatte sie nie gefragt. Ein Element + kann vollstaendig „sichtbar" sein und trotzdem ausserhalb des + Bildes liegen. + + Deshalb jetzt fuer JEDES Stueck jeder Eventkarte, nicht nur fuer + das Etikett: Die naechste Sache, die oben herausfaellt, ist + bestimmt eine andere. */ + const ueberstand = await seite.evaluate(() => { + const raus = []; + for (const k of document.querySelectorAll('.eintrag-karte[data-eventkarte="ja"]')) { + const kr = k.getBoundingClientRect(); + for (const t of k.querySelectorAll("*")) { + const r = t.getBoundingClientRect(); + if (r.width === 0 && r.height === 0) continue; + if (r.top < kr.top - 1 || r.left < kr.left - 1 || r.right > kr.right + 1) { + raus.push(`${(k.querySelector(".eintrag-titel")?.textContent || "?").slice(0, 14)}: ` + + `${(t.className || t.tagName).toString().split(" ")[0]} ` + + `oben ${Math.round(r.top - kr.top)}px / links ${Math.round(r.left - kr.left)}px`); + } + } + } + return raus; + }); + const geprueftTeile = await seite.evaluate(() => + [...document.querySelectorAll('.eintrag-karte[data-eventkarte="ja"] *')].length); + /* DIE ZAHL STEHT IN DER BEDINGUNG: "nichts ragt heraus" waere auf + einer leeren Liste ebenfalls wahr. */ + ok(geprueftTeile > 30 && ueberstand.length === 0, + `keines der ${geprueftTeile} Teile ragt aus seiner Karte heraus (${ueberstand.slice(0, 2).join(" | ") || "keins"})`); + + /* ===== UND DIE BUEHNE DARF NICHT GEQUETSCHT WERDEN ================ + + Dieselbe Sache eine Ebene tiefer: Die Buehne ist ein Flex-Element + der Karte und darf deshalb schrumpfen. Tut sie das, laeuft ihr + Inhalt unten heraus -- im Bildschirmfoto vom 07.10.2026 lag der + Zeitbalken auf dem Satz „Beschreibung zum Test." darunter. + + Gemessen wird der Inhalt gegen den Kasten, nicht das Aussehen: + `scrollHeight > clientHeight` heisst „es passt nicht hinein", egal + ob man es sieht oder nicht. */ + const gequetscht = await seite.evaluate(() => + [...document.querySelectorAll('.eintrag-karte[data-eventkarte="ja"] .ev-buehne')] + .map((b) => ({ + titel: (b.closest(".eintrag-karte").querySelector(".eintrag-titel")?.textContent || "?").slice(0, 14), + innen: b.scrollHeight, kasten: b.clientHeight, + stil: (() => { + const st = getComputedStyle(b); + return { h: st.height, maxH: st.maxHeight, minH: st.minHeight, + flex: st.flex, ar: st.aspectRatio, pad: st.paddingTop + "/" + st.paddingBottom }; + })(), + kinder: [...b.children].map((c) => + (c.className || c.tagName).toString().split(" ")[0] + ":" + + Math.round(c.getBoundingClientRect().height)), + }))); + melde(" -- Buehnen-Inhalt: " + JSON.stringify(gequetscht)); + ok(gequetscht.length >= 3 && gequetscht.every((b) => b.innen <= b.kasten + 1), + `der Inhalt passt in jede der ${gequetscht.length} Buehnen ` + + `(${gequetscht.map((b) => `${b.titel} ${b.innen}/${b.kasten}`).join(", ")})`); + + const tonListe = Object.values(toene); + ok(tonListe.length >= 3 && new Set(tonListe).size === tonListe.length, + `jeder Zustand traegt einen eigenen Ton (${JSON.stringify(toene)})`); + + /* Zum PAAR scrollen, nicht einfach den Bildschirm fotografieren: Oben + stehen Kopf, Filter und die Vorschlaege -- auf einem Bild davon + waere von den zwei Karten nebeneinander nichts zu sehen. */ + await seite.evaluate(() => { + const k = [...document.querySelectorAll('.eintrag-karte[data-eventkarte="ja"]')]; + const paar = k.find((a, i) => k.slice(i + 1).some((b2) => + Math.abs(a.getBoundingClientRect().top - b2.getBoundingClientRect().top) < 5)); + (paar || k[0]).scrollIntoView({ block: "start", behavior: "instant" }); + window.scrollBy(0, -24); + }); + await seite.waitForTimeout(400); + await seite.screenshot({ path: "server/pruef-eventkarte-raster.png", fullPage: false }); + + /* ===== „BANNER GANZ" ZEIGT ES IN DER MITTE (07.10.2026) =========== + + Filipe: „wenn man auf banner anzeigen drückt soll das banner schön + in der mitte sein." + + Vorher oeffnete der Knopf die DATEI in einem neuen Tab -- also die + eingebaute Bildanzeige des Browsers: Bild oben links, Rest schwarz. + Jetzt die Bildschau des Hauses, die genau dafuer schon existierte + und hier nur nie angeschlossen war. */ + const vorherAdresse = seite.url(); + const bannerKnopf = await seite.$(".ev-buehne__ganz"); + ok(!!bannerKnopf, "die Karte mit Banner hat den Knopf „Banner ganz“"); + await bannerKnopf.click(); + /* AUF DAS BILD WARTEN, nicht auf eine Zahl: Vor dem Laden ist + `naturalWidth` null, und null mal null steht weder in der Mitte + noch sonst wo. */ + await seite.waitForFunction(() => { + const b = document.querySelector("dialog.bildschau .bildschau__bild"); + return b && b.naturalWidth > 0; + }, null, { timeout: 15000 }).catch(() => {}); + await seite.waitForTimeout(400); + + const schau = await seite.evaluate(() => { + const d = document.querySelector("dialog.bildschau"); + if (!d) return { da: false }; + const b = d.querySelector(".bildschau__bild"); + const r = b.getBoundingClientRect(); + return { + da: true, offen: d.open, + mitteX: Math.round(r.x + r.width / 2), mitteY: Math.round(r.y + r.height / 2), + fensterX: Math.round(window.innerWidth / 2), fensterY: Math.round(window.innerHeight / 2), + breite: Math.round(r.width), hoehe: Math.round(r.height), + grund: getComputedStyle(d.querySelector(".bildschau__grund")).backgroundImage.slice(0, 22), + }; + }); + melde(" -- Bildschau: " + JSON.stringify(schau)); + ok(schau.da && schau.offen, `die Bildschau geht auf (${schau.da ? "offen=" + schau.offen : "gar nicht da"})`); + /* IN DER MITTE, in Pixeln gemessen. Waagerecht genau, senkrecht mit + etwas mehr Spiel: Oben liegt die Leiste mit Namen und Knoepfen, + das Bild sitzt deshalb ein Stueck tiefer als die halbe Hoehe. */ + ok(schau.da && Math.abs(schau.mitteX - schau.fensterX) <= 8, + `das Banner steht waagerecht in der Mitte (${schau.mitteX} gegen ${schau.fensterX})`); + ok(schau.da && Math.abs(schau.mitteY - schau.fensterY) <= 60, + `und senkrecht ebenfalls (${schau.mitteY} gegen ${schau.fensterY})`); + ok(schau.da && schau.breite > 300 && schau.hoehe > 100, + `es ist wirklich gross (${schau.breite}x${schau.hoehe} px)`); + ok(schau.da && schau.grund.includes("gradient"), + `mit dem Hintergrund der Schau statt schwarzer Leere (${schau.grund}…)`); + /* GEGENPROBE ZUM ABFANGEN: Haette der Klick NICHT gegriffen, waere + der Browser zur Bilddatei gesprungen. Dass die Adresse dieselbe + ist, beweist, dass die Schau den Klick wirklich uebernommen hat -- + und nicht nur zufaellig irgendwo im Dokument liegt. */ + ok(seite.url() === vorherAdresse, + `die Seite ist dabei nicht weggesprungen (${seite.url() === vorherAdresse ? "dieselbe Adresse" : seite.url()})`); + + await seite.screenshot({ path: "server/pruef-eventkarte-schau.png", fullPage: false }); + await seite.keyboard.press("Escape"); + await seite.waitForTimeout(300); + const zu = await seite.evaluate(() => + !document.querySelector("dialog.bildschau")?.open); + ok(zu, "und Escape schliesst sie wieder"); + /* DIE ZAHLEN AUS DEM BEFUND, jede einzeln. */ ok(masse.titelInKarte < 180, `der Titel steht ${masse.titelInKarte} px unter der Kartenkante (vorher 638+, Grenze 180)`); @@ -758,6 +1004,30 @@ melde("\n=== 7. Auf dem Handy (412 px) ==="); melde(" -- gemessen: " + JSON.stringify(handy)); ok(handy.knopfHoehe >= 44, `das Beruehrziel ist ${handy.knopfHoehe} px hoch (Grenze 44)`); + + /* ===== AUF DEM HANDY STEHT WIEDER EINE JE REIHE (07.10.2026) ====== + + Die Gegenprobe zum Raster: Zwei Karten nebeneinander sind am + Rechner richtig und auf 412 px unbedienbar -- dort waere jede + 199 px breit. Dass die Regel UMSCHALTET, muss gemessen werden; + sonst beweist „zwei nebeneinander" am Rechner nur, dass es dort + passt, und nichts darueber, was auf dem Telefon passiert. */ + const schmal = await seite.evaluate(() => { + const k = [...document.querySelectorAll('.eintrag-karte[data-eventkarte="ja"]')] + .map((x) => { const r = x.getBoundingClientRect(); return { x: Math.round(r.x), y: Math.round(r.y), b: Math.round(r.width) }; }); + return { + karten: k, + /* Stehen zwei auf gleicher Hoehe? Dann waere nicht umgeschaltet. */ + paar: k.some((a, i) => k.slice(i + 1).some((b2) => Math.abs(a.y - b2.y) < 5)), + quer: document.documentElement.scrollWidth - document.documentElement.clientWidth, + }; + }); + ok(schmal.karten.length >= 2 && !schmal.paar, + `auf 412 px steht eine Karte je Reihe (${schmal.karten.map((a) => `${a.b}px@${a.y}`).join(", ")})`); + ok(schmal.karten.every((a) => a.b > 330), + `und sie ist breit genug zum Bedienen (${schmal.karten.map((a) => a.b).join(", ")} px)`); + ok(schmal.quer <= 1, + `die Seite laesst sich nicht seitlich schieben (${schmal.quer} px)`); /* UND WENN DOCH, DANN WELCHES ELEMENT? Eine Zahl allein schickt einen auf die Suche; der Schuldige steht im DOM und wird nur nicht genannt. (Projektgedaechtnis: eine Pruefung, die nicht sagen kann, diff --git a/workspace/anleitung.html b/workspace/anleitung.html index 4270a448..d2a66c7a 100644 --- a/workspace/anleitung.html +++ b/workspace/anleitung.html @@ -7,17 +7,17 @@ - - - - - + + + + + - - + + @@ -289,16 +289,16 @@ Und anleitung.js braucht es doppelt: Symbol, Farbe, Name und Adresse jeder Karte kommen von dort, nicht vom Server. --> - + - - - - - - + + + + + + diff --git a/workspace/anruf-probe.html b/workspace/anruf-probe.html index 317d0c52..e30196ab 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`. --> - - + + - +