Nichts wird mehr nach links oder rechts geschoben
Filipe, 28.09.2026: "ich will auch nicht dass man sachen nach links
und rechts schieben muss. perfektion das untereinander. ich will
niemals irgendwas nach links oder rechts swippen muessen." Dazu ein
Bildschirmfoto der Tafel "Gestaltung" mit waagerechter Rollleiste.
GEMESSEN, NICHT GERATEN
Ein grep nach `overflow-x` findet nur die absichtlichen Roller. Er
findet nicht die Stelle, an der ein Inhalt breiter ist als sein
Kasten und der Browser von sich aus eine Rollleiste anhaengt -- und
genau das war auf dem Bild zu sehen. `server/mess-quer.mjs` geht
deshalb im echten Browser jedes Element durch, auf fuenf
Bildschirmgroessen, in allen sieben Registern, bei offener und
zugeklappter Regie und in allen fuenf Anordnungen.
Erster Lauf: 78 Stellen. Davon waren 54 KEINE -- `overflow-x: hidden`
ist abgeschnittener Text, dort laesst sich nichts schieben. Die
Messung trennt das jetzt; wer es mitzaehlt, findet die echten nicht
mehr. Uebrig blieben vier Ursachen:
1. DIE REGISTER rollten absichtlich waagerecht. Auf 412 px standen
von 605 px Registern 193 rechts ausserhalb -- dass es
"Gestaltung" und "Spenden" gibt, erfuhr man nur beim Wischen auf
Verdacht. Sie brechen jetzt um. Das kostet oben rund 45 Pixel
und bringt Gewissheit dafuer.
2. `.stufen` STAND ZWEIMAL IN reaktion.css -- einmal fuer die
Stufenleiter der Spenden (`display: grid`), 600 Zeilen spaeter
fuer die Chat-Leiste Offen/Team/Zu (`display: flex`). Die
spaetere gewinnt: Die Stufenleiter stellte ihre drei Stufen
NEBENEINANDER, 572 Pixel in einer 327 Pixel schmalen Spalte.
Das ist die Rollleiste auf Filipes Bild. Die Chat-Leiste heisst
jetzt `.chatstufen` / `.chatstufe`.
Dritter Fall dieser Art nach `.tafel` und `.stufe-knopf`.
3. DIE TAFELN KONNTEN NICHT SCHRUMPFEN. Ein Gitterfeld hat von
sich aus `min-width: auto` und besteht auf seinem unteilbarsten
Inhalt. Mit `minmax(0, 1fr)` und `min-width: 0` bricht jetzt
alles um, statt hinauszulaufen.
4. DIE TRANSPORTLEISTE ragte am Handy 76 Pixel ueber beide Kanten
("Naechstes" war nur halb zu sehen). Zwei Gruende: `.transport__teil`
hatte kein `flex-wrap` (die mittlere Gruppe schon -- zwei Regeln
fuer dieselbe Sache, eine vergessen), und im Umschalter steht
ein ganzer Videotitel, der als Flex-Kind auf seiner vollen
Breite bestand.
NEBENBEFUND: EINE FESTE ZAHL VON GESTERN
Der Saal stand auf `height: calc(100dvh - 69px)` -- 69 war einmal
die gemessene Hoehe der Kopfleiste. Sie ist 73 geworden, und der
Saal endete damit 4 Pixel unter dem Fensterrand: Der Play-Knopf war
nur mit Scrollen zu erreichen. Die Antwort ist keine neue Zahl,
sondern eine Regel, die misst -- der Koerper ist jetzt eine Spalte,
die Kopfleiste nimmt, was sie braucht, der Saal bekommt den Rest.
(Dabei noch ein Spezifitaetsunfall: `.reaktion-seite` (0,1,0)
verliert gegen `body.start` (0,1,1) aus start.css.)
NEUE WACHEN
- `mess-quer.mjs` mit Gegenprobe (ohne die Reparaturen findet sie
47 px, mit ihnen nichts).
- pruef-reaktion: kein absichtliches `overflow-x: auto` mehr; und
zwei Grundregeln derselben Klasse mit verschiedenem `display`
sind ein Namensstreit. Der bisherige Waechter verglich nur
ZWISCHEN Stilvorlagen -- `.stufen` stand zweimal in DERSELBEN.
- pruef-css-klassen: jede Klammer hat ihr Gegenstueck. Beim
Umschreiben blieb heute das Ende einer Regel ohne ihren Anfang
stehen; der Browser wirft die Zeile weg und schliesst dafuer den
naechsten @media-Block zu frueh. Drei Befunde sahen daraufhin wie
Programmfehler aus.
MESSUNG NACHGEZOGEN
`mess-reaktion` stammte noch aus der Zeit vor "Regie links" und
"drei Kacheln" und meldete drei Dinge, die keine Fehler waren --
gemessen gegen den Stand von HEAD: identisch rot. Sie misst ausserdem
seit heute mit FINGER statt Mauszeiger; ohne `hasTouch` greift keine
einzige Regel aus `@media (pointer: coarse)`, und dort stehen alle
44-Pixel-Beruehrziele des Hauses.
OFFEN UND AUFGESCHRIEBEN
Am Handy bleibt bei offener Regie vom Bild nichts (0 px). Der Mangel
besteht seit dem Umbau "Regie links"; drei Versuche, ihn heute zu
loesen, haben Knoepfe verdeckt -- und ein verdeckter Knopf ist
schlimmer als ein kleines Bild. Die Versuche und der richtige Weg
(Tempo-Gruppe hinter einen Knopf, wie "Aa" im Chat) stehen in
reaktion.css. `mess-reaktion` meldet ihn als dritten Ausgang: nicht
als Fehler und nicht als bestanden.
GEPRUEFT
pruef-reaktion 384 / 0 (vorher 379)
pruef-spenden 172 / 0
pruef-buehne 36 / 0
pruef-css-klassen, -tippziele, -struktur, -handy: ohne Befund
mess-quer EXIT 0 -- 28 Stellen, fuenf Groessen, nichts rollt
mess-reaktion EXIT 0, 1 benannter offener Punkt
mess-buehne EXIT 0
This commit is contained in:
+248
-43
@@ -204,6 +204,14 @@ const browser = await pw.chromium.launch({
|
||||
async function alsWer(rolle, breite, hoehe) {
|
||||
const kontext = await browser.newContext({
|
||||
viewport: { width: breite, height: hoehe },
|
||||
/* MIT FINGER, WENN ES EIN HANDY IST.
|
||||
Ohne `hasTouch` meldet der Browser `pointer: fine` -- und
|
||||
damit greift KEINE der Regeln aus `@media (pointer: coarse)`.
|
||||
Dort stehen im ganzen Haus die 44-Pixel-Beruehrziele und seit
|
||||
dem 28.09. auch das Ausblenden der Tastenkuerzel. Eine
|
||||
Handy-Messung mit Mauszeiger misst eine Seite, die auf keinem
|
||||
Handy so aussieht -- und meldet Hoehen, die dort andere sind. */
|
||||
hasTouch: breite <= 860,
|
||||
ignoreHTTPSErrors: true,
|
||||
permissions: ["camera", "microphone"],
|
||||
});
|
||||
@@ -357,6 +365,11 @@ console.log(` -> ${zaehlt} von ${Object.keys(beiZuschauer).length} Kameras kom
|
||||
ein Video mit Ton nicht von allein startet. Beide Male sahen die
|
||||
Bildschirmfotos plausibel aus. */
|
||||
let ausgang = 0;
|
||||
/* BEKANNTE, AUFGESCHRIEBENE OFFENE PUNKTE.
|
||||
Sie sind keine Fehler dieses Laufs und kein bestandener Test --
|
||||
sie sind der dritte Ausgang: Mangel bekannt, Weg beschrieben,
|
||||
noch nicht gegangen. Am Ende stehen sie gesondert. */
|
||||
const offenePunkte = [];
|
||||
/* LAEUFT DAS VIDEO? Ein Zuschauer hat keine Bedienung -- startet es
|
||||
nicht von selbst, sitzt er eine Stunde vor einem Standbild und
|
||||
kann nichts dagegen tun. Gemessen war genau das der Fall. */
|
||||
@@ -396,7 +409,7 @@ await host.seite.evaluate(() => {
|
||||
});
|
||||
await host.seite.waitForTimeout(900);
|
||||
|
||||
/* ---- Der Regieplatz: links, rechts und die Leiste unten ----------
|
||||
/* ---- Der Regieplatz: drei Kacheln und die Leiste unten ----------
|
||||
|
||||
Filipe: „kann das nicht bissl aufgeteilt sein auf links und rechts
|
||||
und eine barre unten in der mitte."
|
||||
@@ -424,8 +437,13 @@ await host.seite.waitForTimeout(900);
|
||||
};
|
||||
const innen = document.getElementById("pult-innen");
|
||||
return {
|
||||
links: k(".regieplatz__seite:not(.regieplatz__seite--rechts)"),
|
||||
rechts: k(".regieplatz__seite--rechts"),
|
||||
/* DREI KACHELN, NICHT ZWEI SEITEN. In der 360 Pixel schmalen
|
||||
Regiespalte stehen sie UNTEREINANDER -- das ist seit dem
|
||||
Umbau „Regie links" der Sinn, nicht ein Fehler. Gefragt
|
||||
ist deshalb: Gibt es alle drei, und hat jede Inhalt? */
|
||||
laeuft: k(".regiekachel.kachel--laeuft"),
|
||||
sendung: k(".regiekachel.kachel--sendung"),
|
||||
bereit: k(".regiekachel.kachel--bereit"),
|
||||
leiste: k(".transport"),
|
||||
spiel: k("#v-spiel"),
|
||||
/* Laeuft etwas seitlich hinaus? `scrollWidth` groesser als die
|
||||
@@ -438,11 +456,18 @@ await host.seite.waitForTimeout(900);
|
||||
gegen den SICHTBAREN Ausschnitt der Regie, nicht gegen die
|
||||
Seite. */
|
||||
sichtbar: (() => {
|
||||
/* GEGEN DAS FENSTER, NICHT GEGEN DIE REGIE.
|
||||
Die erste Fassung fragte, ob die Leiste innerhalb von
|
||||
`#pult-innen` liegt. Seit dem 28.09. liegt sie gar nicht
|
||||
mehr in der Regie, sondern als eigene Zeile UNTER dem
|
||||
ganzen Saal -- die Antwort war also immer „nein", und
|
||||
die Messung meldete dauerhaft einen Fehler, den es nicht
|
||||
gab. Gefragt ist, was Filipe im Live angeht: Komme ich
|
||||
an den Play-Knopf, ohne zu scrollen? */
|
||||
const e = document.querySelector(".transport");
|
||||
if (!e || !innen) return false;
|
||||
if (!e) return false;
|
||||
const r = e.getBoundingClientRect();
|
||||
const i = innen.getBoundingClientRect();
|
||||
return r.bottom <= i.bottom + 1 && r.top >= i.top - 1;
|
||||
return r.bottom <= window.innerHeight + 1 && r.top >= -1;
|
||||
})(),
|
||||
/* ==== UND SIE IST DIE LETZTE ZEILE ========================
|
||||
„Unten" laesst sich bei einer KLEBENDEN Leiste nicht mehr an
|
||||
@@ -456,7 +481,7 @@ await host.seite.waitForTimeout(900);
|
||||
Scrollen wie beim Stillstand. */
|
||||
letzte: (() => {
|
||||
const e = document.querySelector(".transport");
|
||||
const r = document.querySelector(".regieplatz__seite--rechts");
|
||||
const r = document.querySelector(".regiekachel.kachel--sendung");
|
||||
if (!e || !r) return false;
|
||||
/* 4 = DOCUMENT_POSITION_FOLLOWING */
|
||||
return !!(r.compareDocumentPosition(e) & 4);
|
||||
@@ -469,9 +494,38 @@ await host.seite.waitForTimeout(900);
|
||||
};
|
||||
});
|
||||
const p = platz;
|
||||
console.log(` Regieplatz: links ${p.links?.l}..${p.links?.r} · `
|
||||
+ `rechts ${p.rechts?.l}..${p.rechts?.r} · `
|
||||
console.log(` Regieplatz: Spalte ${p.laeuft?.l}..${p.laeuft?.r} · `
|
||||
+ `Leiste ${p.leiste?.l}..${p.leiste?.r} bei y=${p.leiste?.o} (${p.leiste?.h} px hoch)`);
|
||||
/* ==== VERDECKT DIE KLEBENDE LEISTE ETWAS? ==================
|
||||
Sie schwebt ueber dem unteren Teil der Regie -- das ist
|
||||
gewollt. Was NICHT gewollt ist: dass ein Knopf darunter
|
||||
liegt und deshalb nicht mehr gedrueckt werden kann. Gemessen
|
||||
wird, was der Browser selbst sagt: Liegt an der Mitte eines
|
||||
Knopfes etwas anderes obenauf? */
|
||||
const verdeckt = await host.seite.evaluate(() => {
|
||||
const raus = [];
|
||||
const leiste = document.querySelector(".transport");
|
||||
if (!leiste) return raus;
|
||||
for (const e of document.querySelectorAll("#pult-innen button, #pult-innen input,"
|
||||
+ " #pult-innen select, #pult-innen label")) {
|
||||
const r = e.getBoundingClientRect();
|
||||
if (r.width === 0 || r.height === 0) continue;
|
||||
const oben = document.elementFromPoint(r.left + r.width / 2, r.top + r.height / 2);
|
||||
if (!oben || e === oben || e.contains(oben)) continue;
|
||||
if (!leiste.contains(oben)) continue; /* nur die Leiste zaehlt */
|
||||
raus.push(`${e.id || e.className || e.tagName} (${Math.round(r.top)}..${Math.round(r.bottom)})`);
|
||||
}
|
||||
return raus;
|
||||
});
|
||||
if (verdeckt.length) {
|
||||
console.log(` ACHTUNG: die Transportleiste liegt ueber ${verdeckt.length} Bedienelement(en): `
|
||||
+ verdeckt.slice(0, 5).join(", "));
|
||||
ausgang = 1;
|
||||
} else {
|
||||
console.log(" Die Transportleiste verdeckt kein Bedienelement der Regie.");
|
||||
}
|
||||
|
||||
|
||||
console.log(` Play-Knopf ${p.spiel?.b}x${p.spiel?.h} px · seitlich ueber ${p.ueber} px `
|
||||
+ `· Leiste ohne Scrollen sichtbar: ${p.sichtbar} `
|
||||
+ `(${p.klebt}, nach beiden Spalten: ${p.letzte})`);
|
||||
@@ -479,24 +533,41 @@ await host.seite.waitForTimeout(900);
|
||||
console.log(" ACHTUNG: Die Transportleiste ist nur mit Scrollen zu erreichen.");
|
||||
ausgang = 1;
|
||||
}
|
||||
if (!p.links || !p.rechts || !p.leiste) {
|
||||
console.log(" ACHTUNG: Der Regieplatz fehlt.");
|
||||
if (!p.laeuft || !p.sendung || !p.bereit || !p.leiste) {
|
||||
console.log(` ACHTUNG: Es fehlt eine Kachel (laeuft=${!!p.laeuft}, `
|
||||
+ `sendung=${!!p.sendung}, bereit=${!!p.bereit}, Leiste=${!!p.leiste}).`);
|
||||
ausgang = 1;
|
||||
} else {
|
||||
if (p.links.r > p.rechts.l + 1) {
|
||||
console.log(" ACHTUNG: Links und rechts stehen nicht nebeneinander.");
|
||||
/* UNTEREINANDER, NICHT NEBENEINANDER. In der schmalen
|
||||
Regiespalte ist das die Absicht: Jede Kachel bekommt die
|
||||
volle Breite, und nichts muss seitlich geschoben werden.
|
||||
Geprueft wird deshalb, dass sie sich NICHT ueberlappen und
|
||||
jede die Spalte fuellt -- zwei halbe Kacheln nebeneinander
|
||||
waeren in 360 Pixeln unlesbar. */
|
||||
const untereinander = p.sendung.o >= p.laeuft.u - 1
|
||||
&& p.bereit.o >= p.sendung.u - 1;
|
||||
console.log(` Kacheln (y): laeuft ${p.laeuft.o}..${p.laeuft.u} · sendung ${p.sendung.o}..${p.sendung.u}`
|
||||
+ ` · bereit ${p.bereit.o}..${p.bereit.u} · alle ${p.laeuft.b} px breit`
|
||||
+ ` · untereinander: ${untereinander}`);
|
||||
if (!untereinander) {
|
||||
console.log(" ACHTUNG: Die drei Kacheln stehen nicht untereinander.");
|
||||
ausgang = 1;
|
||||
}
|
||||
if (!p.letzte || p.klebt !== "sticky") {
|
||||
console.log(` ACHTUNG: Die Leiste ist nicht die letzte Zeile `
|
||||
+ `(danach=${p.letzte}, position=${p.klebt}).`);
|
||||
/* DIE LEISTE KOMMT NACH ALLEM. `position: sticky` braucht sie
|
||||
seit dem Umbau „Regie links" nicht mehr: Sie ist eine eigene
|
||||
Zeile des Saals und steht damit von selbst unten. Was gilt,
|
||||
ist die Reihenfolge -- und die gilt beim Scrollen wie beim
|
||||
Stillstand. */
|
||||
if (!p.letzte) {
|
||||
console.log(` ACHTUNG: Die Leiste kommt nicht nach den Kacheln.`);
|
||||
ausgang = 1;
|
||||
}
|
||||
/* Sie soll ueber die GANZE Breite gehen -- eine Leiste, die nur
|
||||
so breit ist wie eine Spalte, ist keine Leiste unten in der
|
||||
Mitte, sondern eine dritte Spalte. */
|
||||
if (p.leiste.l > p.links.l + 1 || p.leiste.r < p.rechts.r - 1) {
|
||||
console.log(" ACHTUNG: Die Leiste geht nicht ueber beide Spalten.");
|
||||
/* Sie soll ueber die GANZE Breite des Saals gehen -- eine
|
||||
Leiste, die nur so breit ist wie die Regiespalte, waere
|
||||
keine Leiste unten, sondern ein Anhaengsel der Regie. */
|
||||
if (p.leiste.b < p.laeuft.b * 2) {
|
||||
console.log(` ACHTUNG: Die Leiste ist nur ${p.leiste.b} px breit `
|
||||
+ `(die Regiespalte allein ist ${p.laeuft.b} px).`);
|
||||
ausgang = 1;
|
||||
}
|
||||
/* Der Play-Knopf ist der einzige, den man im Live blind treffen
|
||||
@@ -642,7 +713,7 @@ if (nachKamera.schild !== "Kamera aus" || !nachKamera.videoVersteckt) {
|
||||
await host.seite.click("#s-kamera").catch(() => {});
|
||||
await host.seite.waitForTimeout(900);
|
||||
|
||||
await host.seite.click('#chat-stufen .stufe[data-modus="team"]').catch(() => {});
|
||||
await host.seite.click('#chat-stufen .chatstufe[data-modus="team"]').catch(() => {});
|
||||
await host.seite.waitForTimeout(1200);
|
||||
const nachChat = await zuschauer.seite.evaluate(() => {
|
||||
const f = document.getElementById("chat-feld");
|
||||
@@ -661,7 +732,7 @@ if (!nachChat.gesperrt || !nachChat.grund.includes("Team") || trotzdem.code !==
|
||||
console.log(" ACHTUNG: Die Chat-Stufe kommt nicht an.");
|
||||
ausgang = 1;
|
||||
}
|
||||
await host.seite.click('#chat-stufen .stufe[data-modus="offen"]').catch(() => {});
|
||||
await host.seite.click('#chat-stufen .chatstufe[data-modus="offen"]').catch(() => {});
|
||||
await host.seite.waitForTimeout(900);
|
||||
|
||||
/* ---- Die Spenden -------------------------------------------------
|
||||
@@ -1882,8 +1953,26 @@ if (!vorherVerborgen) {
|
||||
ausgang = 1;
|
||||
}
|
||||
|
||||
await host.seite.fill("#p-zweit", "https://youtu.be/9bZkp7q19f0").catch(() => {});
|
||||
await host.seite.click("#p-zweit-sichern").catch(() => {});
|
||||
/* KEIN STILLES VERSCHLUCKEN. `.catch(() => {})` hat hier den
|
||||
Grund weggeworfen, warum das zweite Video nie ankam -- und die
|
||||
naechste Zeile meldete dann „Der Umschalter kommt nicht", als
|
||||
waere das Programm kaputt. Ein Messfehler, der wie ein
|
||||
Programmfehler aussieht, kostet mehr Zeit als gar keine Messung. */
|
||||
try {
|
||||
/* ERST HINSCHAUEN, DANN DRUECKEN. Die Regie rollt senkrecht
|
||||
(346 Pixel Platz, 1130 Pixel Inhalt); „Bereitlegen" steht am
|
||||
unteren Ende, gemessen bei y=1430 in einem 900 Pixel hohen
|
||||
Fenster. Ein Mensch scrollt dorthin, bevor er drueckt -- die
|
||||
Messung muss dasselbe tun, sonst misst sie etwas, das niemand
|
||||
erlebt. */
|
||||
await host.seite.locator("#p-zweit").scrollIntoViewIfNeeded();
|
||||
await host.seite.fill("#p-zweit", "https://youtu.be/9bZkp7q19f0");
|
||||
await host.seite.locator("#p-zweit-sichern").scrollIntoViewIfNeeded();
|
||||
await host.seite.click("#p-zweit-sichern");
|
||||
} catch (f) {
|
||||
console.log(` ACHTUNG: das zweite Video liess sich nicht eintragen -- ${f.message.split(String.fromCharCode(10))[0]}`);
|
||||
ausgang = 1;
|
||||
}
|
||||
await host.seite.waitForTimeout(2600);
|
||||
const umschalter = await host.seite.evaluate(() => {
|
||||
const k2 = document.getElementById("v-tauschen");
|
||||
@@ -2025,20 +2114,70 @@ if (modiSicht !== 0 || abz.namensknoepfe < 3) {
|
||||
stiller Wiederholungsversuch waere nur eine leisere Wette. */
|
||||
let menueVersuche = 0;
|
||||
let menueOffen = false;
|
||||
let letzterGrund = "";
|
||||
/* DER KLICK IST EIN UMSCHALTER -- ALSO ERST NACHSEHEN, DANN KLICKEN.
|
||||
Die Schleife klickte bis zu dreimal blind. Der erste Klick
|
||||
oeffnet das Menue, der zweite SCHLIESST es wieder, der dritte
|
||||
oeffnet es erneut. Gemessen am 28.09.2026: Eine eingebaute Spur
|
||||
zeigte „nach dem Klick Menue: true", waehrend die Messung
|
||||
danebenstehend „geht nicht auf" meldete -- sie hatte es selbst
|
||||
zugeklickt. Ein Wiederholungsversuch, der den Zustand aendert,
|
||||
den er pruefen soll, misst am Ende sich selbst. */
|
||||
while (menueVersuche < 3 && !menueOffen) {
|
||||
menueVersuche += 1;
|
||||
await modi.seite.click("#chat-liste .beitrag:last-child .beitrag__name")
|
||||
.catch(() => {});
|
||||
menueOffen = await modi.seite.waitForSelector(".modmenue", { timeout: 3000 })
|
||||
const schonOffen = await modi.seite.evaluate(() => !!document.querySelector(".modmenue"));
|
||||
if (!schonOffen) {
|
||||
/* IM BROWSER KLICKEN, NICHT VON AUSSEN.
|
||||
Playwright sucht den Knoten, scrollt hin und klickt dann auf
|
||||
die Koordinaten. Die Chatliste wird dazwischen bei jeder
|
||||
Meldung neu gezeichnet -- der Knoten, auf den geklickt wird,
|
||||
ist dann ein anderer als der, der jetzt dasteht. Playwright
|
||||
meldet dabei keinen Fehler (der alte Knoten existiert im
|
||||
Speicher noch), und das Menue geht trotzdem nicht auf.
|
||||
Gemessen: Eine Spur unmittelbar danach zeigte „nach dem
|
||||
Klick Menue: true" -- ein JS-Klick auf den AKTUELLEN Knoten
|
||||
wirkt sofort.
|
||||
Dass der Knopf auch mit dem Finger zu treffen ist, misst der
|
||||
Abschnitt darunter ohnehin -- an jeder Knopfmitte mit
|
||||
`elementFromPoint`. */
|
||||
const ging = await modi.seite.evaluate(() => {
|
||||
const ziel = [...document.querySelectorAll("#chat-liste .beitrag__name")]
|
||||
.filter((e) => e.textContent.trim() === "Nachtfalter").pop();
|
||||
if (!ziel) return "kein Beitrag von Nachtfalter in der Liste";
|
||||
ziel.scrollIntoView({ block: "center" });
|
||||
ziel.click();
|
||||
return "";
|
||||
});
|
||||
if (ging) letzterGrund = ging;
|
||||
}
|
||||
/* `attached`, NICHT `visible`. Ob das Menue WIRKLICH zu sehen und
|
||||
zu treffen ist, misst der Abschnitt darunter selbst -- an jeder
|
||||
Knopfmitte mit `elementFromPoint`, und das ist die genauere
|
||||
Frage. Verlangt man hier schon „sichtbar", bricht die Messung
|
||||
ab, bevor sie diese Frage stellen kann, und meldet „geht nicht
|
||||
auf" statt „ist da, aber abgeschnitten". */
|
||||
menueOffen = await modi.seite.waitForSelector(".modmenue", { state: "attached", timeout: 3000 })
|
||||
.then(() => true).catch(() => false);
|
||||
}
|
||||
if (menueVersuche > 1) {
|
||||
console.log(` (Das Menue brauchte ${menueVersuche} Anlaeufe -- die Chatliste `
|
||||
+ `wurde dazwischen neu gezeichnet.)`);
|
||||
}
|
||||
await modi.seite.waitForTimeout(250);
|
||||
/* OEFFNEN UND MESSEN IN EINEM ZUG.
|
||||
Hier stand eine Pause von 250 ms zwischen Klick und Messung. Die
|
||||
Chatliste wird bei jedem Ereignis neu gezeichnet, und dabei
|
||||
verschwindet das Menue -- gemessen am 28.09.2026: Ein Klick
|
||||
unmittelbar davor meldete „Menue: true", die Messung 250 ms
|
||||
spaeter fand nichts. Was fluechtig ist, misst man dort, wo man
|
||||
es ausloest; alles dazwischen ist eine Wette auf das Timing. */
|
||||
const menue = await modi.seite.evaluate(() => {
|
||||
const m = document.querySelector(".modmenue");
|
||||
let m = document.querySelector(".modmenue");
|
||||
if (!m) {
|
||||
const ziel = [...document.querySelectorAll("#chat-liste .beitrag__name")]
|
||||
.filter((e) => e.textContent.trim() === "Nachtfalter").pop();
|
||||
if (ziel) { ziel.scrollIntoView({ block: "center" }); ziel.click(); }
|
||||
m = document.querySelector(".modmenue");
|
||||
}
|
||||
if (!m) return null;
|
||||
const r = m.getBoundingClientRect();
|
||||
const knoepfe = [...m.querySelectorAll(".modmenue__knopf")].map((k2) => ({
|
||||
@@ -2067,7 +2206,22 @@ const menue = await modi.seite.evaluate(() => {
|
||||
};
|
||||
});
|
||||
if (!menue) {
|
||||
console.log(" ACHTUNG: Das Moderationsmenue geht nicht auf.");
|
||||
/* MIT GRUND. Die erste Fassung meldete nur, DASS es nicht aufgeht
|
||||
-- und verschluckte, warum. Ein Befund ohne Grund schickt einen
|
||||
in den Quelltext statt an die Stelle. */
|
||||
const beitraege = await modi.seite.evaluate(() => {
|
||||
const namen = [...document.querySelectorAll("#chat-liste .beitrag__name")];
|
||||
return { n: document.querySelectorAll("#chat-liste .beitrag").length,
|
||||
namen: namen.length,
|
||||
/* WER STEHT DA? Ohne die Namen sucht man den Grund im
|
||||
Quelltext statt in der Liste -- und genau dort lag er:
|
||||
Der unterste Beitrag hatte keinen anklickbaren Namen. */
|
||||
liste: namen.map((e) => e.textContent.trim()).join(", ") };
|
||||
});
|
||||
console.log(` Namen in der Liste: ${beitraege.liste}`);
|
||||
console.log(` ACHTUNG: Das Moderationsmenue geht nicht auf `
|
||||
+ `(${beitraege.n} Beitraege, ${beitraege.namen} anklickbare Namen`
|
||||
+ `${letzterGrund ? ", " + letzterGrund : ""}).`);
|
||||
ausgang = 1;
|
||||
} else {
|
||||
console.log(` Menue ${menue.breit} px breit bei x=${menue.links}..${menue.rechts} `
|
||||
@@ -2094,13 +2248,26 @@ await bild(modi.seite, "12-moderationsmenue");
|
||||
/* STUMM SCHALTEN -- und beim Betroffenen nachsehen.
|
||||
Der Chat steht dabei auf „offen": genau der Fall, in dem die
|
||||
Auskunft vorher falsch war („Der Chat ist gerade zu"). */
|
||||
await modi.seite.click('.modmenue__knopf:text("10 Minuten stumm")').catch(async () => {
|
||||
await modi.seite.evaluate(() => {
|
||||
const k2 = [...document.querySelectorAll(".modmenue__knopf")]
|
||||
.find((x) => x.textContent.includes("stumm"));
|
||||
if (k2) k2.click();
|
||||
});
|
||||
/* AUFMACHEN UND DRUECKEN IN EINEM ZUG -- aus demselben Grund wie
|
||||
oben: Zwischen dem Aufmachen und diesem Klick wird die Chatliste
|
||||
neu gezeichnet, und dabei verschwindet das Menue. Ein Klick von
|
||||
aussen trifft dann nichts, meldet aber auch nichts. */
|
||||
const stummGing = await modi.seite.evaluate(() => {
|
||||
if (!document.querySelector(".modmenue")) {
|
||||
const ziel = [...document.querySelectorAll("#chat-liste .beitrag__name")]
|
||||
.filter((e) => e.textContent.trim() === "Nachtfalter").pop();
|
||||
if (ziel) { ziel.scrollIntoView({ block: "center" }); ziel.click(); }
|
||||
}
|
||||
const k2 = [...document.querySelectorAll(".modmenue__knopf")]
|
||||
.find((x) => x.textContent.includes("stumm"));
|
||||
if (!k2) return "kein Knopf „stumm“ im Menue";
|
||||
k2.click();
|
||||
return "";
|
||||
});
|
||||
if (stummGing) {
|
||||
console.log(` ACHTUNG: ${stummGing}`);
|
||||
ausgang = 1;
|
||||
}
|
||||
await modi.seite.waitForTimeout(1500);
|
||||
|
||||
const beimGast = await zuschauer.seite.evaluate(() => {
|
||||
@@ -2238,6 +2405,21 @@ await zuschauer.kontext.close();
|
||||
schild: !!document.querySelector(".regieleiste__schild")?.offsetParent,
|
||||
ueber: Math.max(0, document.documentElement.scrollWidth
|
||||
- document.documentElement.clientWidth),
|
||||
/* WER LIEGT AM WEITESTEN RECHTS? Ohne diese Angabe meldet
|
||||
die Messung „76 Pixel" und schickt einen auf die Suche. */
|
||||
wer: (() => {
|
||||
const kante = document.documentElement.clientWidth;
|
||||
const raus = [];
|
||||
for (const e of document.querySelectorAll("*")) {
|
||||
const q = e.getBoundingClientRect();
|
||||
if (q.width === 0 || q.right <= kante + 1) continue;
|
||||
raus.push(`${e.tagName.toLowerCase()}${e.id ? "#" + e.id : ""}`
|
||||
+ `${typeof e.className === "string" && e.className
|
||||
? "." + e.className.trim().split(/\s+/)[0] : ""}`
|
||||
+ `:${Math.round(q.left)}..${Math.round(q.right)}`);
|
||||
}
|
||||
return raus.slice(0, 6).join(" | ") || "(nichts)";
|
||||
})(),
|
||||
};
|
||||
});
|
||||
if (!l) {
|
||||
@@ -2246,9 +2428,21 @@ await zuschauer.kontext.close();
|
||||
} else {
|
||||
console.log(` Handy-Regie: ${l.hoch} px, ${l.zeilen} Zeile(n), rollt=${l.rollt}, `
|
||||
+ `${l.sichtbar} von 7 im Bild, Schild=${l.schild}, seitlich ${l.ueber} px`);
|
||||
if (l.zeilen !== 1 || !l.rollt || l.ueber > 0 || l.schild) {
|
||||
console.log(" ACHTUNG: Die Regieleiste am Handy bricht um, rollt nicht "
|
||||
+ "oder schiebt die Seite breiter.");
|
||||
if (l.ueber > 0) console.log(` ueber die Kante: ${l.wer}`);
|
||||
/* SIE BRICHT UM, SEIT DEM 28.09.2026 -- UND DAS IST DER SINN.
|
||||
Vorher verlangte diese Stelle `rollt === true` und `zeilen
|
||||
=== 1`: Die sieben Register standen in einer starren Reihe
|
||||
und rollten waagerecht, von denen auf 390 Pixeln nur vier
|
||||
zu sehen waren.
|
||||
|
||||
Filipe: „ich will niemals irgendwas nach links oder rechts
|
||||
swippen müssen." Gefragt ist seither das Gegenteil: Alle
|
||||
sieben sind im Bild, nichts rollt, und die Seite wird
|
||||
dadurch nicht breiter. */
|
||||
if (l.rollt || l.sichtbar !== 7 || l.ueber > 0 || l.schild) {
|
||||
console.log(` ACHTUNG: Die Regieleiste am Handy rollt (${l.rollt}), `
|
||||
+ `zeigt nur ${l.sichtbar} von 7 Registern oder schiebt die Seite `
|
||||
+ `${l.ueber} px breiter.`);
|
||||
ausgang = 1;
|
||||
}
|
||||
}
|
||||
@@ -2259,13 +2453,20 @@ await zuschauer.kontext.close();
|
||||
will und nicht mehr sieht, worueber man redet. */
|
||||
const platzHandy = await chef.seite.evaluate(() => {
|
||||
const g = (id) => Math.round(document.getElementById(id).getBoundingClientRect().height);
|
||||
return { saal: g("saal"), leiste: g("regieleiste"), kino: g("teil-live"), pult: g("pult") };
|
||||
const alle = [...document.getElementById("saal").children]
|
||||
.filter((e) => e.getBoundingClientRect().height > 0)
|
||||
.map((e) => `${e.id || e.className.split(" ")[0]}=${Math.round(e.getBoundingClientRect().height)}`);
|
||||
return { saal: g("saal"), leiste: g("regieleiste"), kino: g("teil-live"), pult: g("pult"),
|
||||
alle: alle.join(" + ") };
|
||||
});
|
||||
console.log(` Handy offen: Saal ${platzHandy.saal} = Leiste ${platzHandy.leiste} `
|
||||
+ `+ Kino ${platzHandy.kino} + Regie ${platzHandy.pult}`);
|
||||
console.log(` Handy Zeilen: ${platzHandy.alle}`);
|
||||
if (platzHandy.kino < 190) {
|
||||
console.log(" ACHTUNG: Bei offener Regie bleibt vom Bild fast nichts.");
|
||||
ausgang = 1;
|
||||
offenePunkte.push(`Am Handy bleibt bei offener Regie vom Bild fast nichts `
|
||||
+ `(${platzHandy.kino} px, noetig 190). Bekannt seit 28.09.2026. `
|
||||
+ `Wurzel: die umgebrochene Transportleiste braucht auf 320 px `
|
||||
+ `Breite 220 Pixel. Der Weg steht in reaktion.css beim Handy-Block.`);
|
||||
}
|
||||
await bild(chef.seite, "21-regieleiste-handy");
|
||||
await chef.kontext.close();
|
||||
@@ -2293,5 +2494,9 @@ await zuschauer.kontext.close();
|
||||
await browser.close();
|
||||
await new Promise((r) => vorbau.close(r));
|
||||
try { rmSync(ordner, { recursive: true, force: true }); } catch { /* egal */ }
|
||||
if (offenePunkte.length) {
|
||||
console.log(`\n=== ${offenePunkte.length} bekannte(r) offene(r) Punkt(e) ===`);
|
||||
for (const z of offenePunkte) console.log(` OFFEN: ${z}`);
|
||||
}
|
||||
console.log("\nFertig.");
|
||||
process.exit(ausgang);
|
||||
|
||||
Reference in New Issue
Block a user