Kampagnen-Kacheln: gegliederte Texte, Geschenke mit Preis, aufklappbar
Filipe, mit einem Bildschirmfoto des Regelblocks: "man soll die titel
in den texten besser erkennen und sehen was zu was passt. ich will
auch dass man sieht welche geschenke bei dem event zaehlen und so.
ich will alle informationen die moeglich sind wenn man den link
hochlaedt. ... auch wenn man teilt soll es einfach perfekt sein. man
soll alle infos sehen die man braucht. die kacheln von den events
soll auch nicht so lang sein, die soll man aufklappen koennen. genau
wie eine trennung fuer heute, letzte woche letzten monat und so."
DER FEHLER LAG NICHT IM TEXT, SONDERN IN SEINER ANZEIGE. Im Feld
stand die ganze Zeit eine Gliederung -- Hinweise mit "* ", eine
Ueberschrift mit Untertitel hinter einem Gedankenstrich, Absaetze
ohne Zeichen, Aufzaehlungen mit "- ". Die Kachel hat daraus mit
punkteAusText() EINE flache Liste gemacht: jede Zeile derselbe
Strich, alle gleich gross.
gliederung() liest die Gliederung, die schon dasteht, statt
den Text umzuschreiben. Die beiden Kampagnen, die
heute in der Datenbank liegen, sehen dadurch
sofort richtig aus -- ohne Umstellung.
Geschenke kommen aus der gelesenen LISTE, nicht aus dem
Text, und stehen OHNE Aufklappen auf der Kachel.
Aufklappen alles Uebrige hinter einem Druck: gemessen 555 px
weniger je Kachel bei Gipfelstuermer.
Gruppen je Spalte laeuft / kommt / vorbei, Vergangenes
nach diese Woche, dieser Monat, aelter.
NEU GELESEN (stand in allen vier gespeicherten Seiten und wurde nie
angesehen): die Rangliste mit ihren Gruppen ("Superstars" bis
"5. Liga", bei Glow Up "Team Glow"/"Team Shine"), die Beschreibung je
Missionsgruppe, der Steckbrief (Kurznummer, Markt, Sprache, Zone),
der zweite Bildbaustein, und Ueberschriften INNERHALB der Klapptexte
-- "WELCHE LIGA BIN ICH?" hat jetzt sechs eingerueckte Unterpunkte
statt zwoelf gleichrangiger Zeilen.
EVENT_TEXT_MAX 6000 -> 20000. Der Regeltext von Gipfelstuermer ist
7679 Zeichen lang; es fielen bisher jedes Mal rund 1600 Zeichen
echter Inhalt weg. Die Zahl steht jetzt an EINER Stelle.
TEILEN: Was die KAMPAGNE sagt, geht hinaus (Aufgaben, Geschenke,
Regeln) -- wer WIR sind, nicht (Name, Rolle, Haus, Kampagnennummer,
Steckbrief). Und keine Hinweiszeile: "Die Preise konnten nicht
gelesen werden -- bitte nachtragen" ist eine Notiz an DogFather und
hat auf einer Seite, die er in Discord postet, nichts zu suchen.
BERICHTIGT, WEIL NACHGEMESSEN:
- Number(null) ist 0 und 0 ist endlich -- "Feuerwerk" bekam an drei
Stellen "0 Coins" angeschrieben, also eine falsche Preisangabe.
- Ein Kommentar im Leser behauptete, der Wertungszeitraum weiche
vom Kampagnenzeitraum ab. Nachgemessen ist er in allen drei
Seiten mit Rangliste auf die Millisekunde gleich; ich hatte zwei
verschiedene Kampagnen verglichen.
- bild-kampagne.mjs verlangte "jede Kachel traegt den Ton ihrer
Seite" und war damit seit dem 07.10. rot, weil an dem Tag bewusst
das Gegenteil entschieden wurde (Zustandston, Seitenkante). Nicht
aufgefallen, weil nach dem Lauf nur die Zahl der MESSUNGEN notiert
wurde, nicht die der FEHLER.
- .kv-seite > .eintrag-karte wird .kv-seite .eintrag-karte: Die
Karten haengen durch die Gruppen eine Ebene tiefer. Das waere der
fuenfte Direktkind-Selektor gewesen, der nach einem Umbau still
ausfaellt -- diesmal vorher gesehen.
GEPRUEFT: 186 (lesen, +58), 148 (Route/Teilen, +25), 158 (Kachel,
+64), 67 (Agentur, +5), 67 Messungen (Bild, +14), dazu struktur,
css-klassen, zeichen, deutsche-texte, tippziele, lesbarkeit und
haus-trennung (107, unveraendert). Sechs Gegenproben: alle sechs
Sabotagen werden bemerkt, alle Dateien byte-gleich wiederhergestellt.
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
+570
-9
@@ -98,11 +98,19 @@ const tag = (v) => tagLokal(v);
|
||||
der Agentur. Die Pruefung braucht beide Seiten gefuellt -- sonst
|
||||
misst sie eine Trennung, bei der eine Haelfte leer ist, und
|
||||
„zwei nebeneinander" waere dann zu Recht rot. */
|
||||
function evt(titel, von, bis, auf, reg, kampagneId = null) {
|
||||
/* `daten` ist der Auszug, den der Leser beim Einlesen ablegt
|
||||
(07.10.2026). Daraus baut der Server die Geschenke mit
|
||||
Coinpreis, den Steckbrief und die Beschreibung je
|
||||
Missionsgruppe. Ohne ihn waeren diese drei Dinge hier gar
|
||||
nicht pruefbar -- und ein Feld, das keine Pruefung ansieht,
|
||||
ist ein Feld, das beim naechsten Umbau still ausfaellt. */
|
||||
function evt(titel, von, bis, auf, reg, kampagneId = null, daten = null) {
|
||||
d.prepare("INSERT INTO eintraege (titel, text, bereich, art, status, datum, event_ende,"
|
||||
+ " event_aufgaben, event_regeln, dringlichkeit, erstellt, erstellt_von, kampagne_id)"
|
||||
+ " VALUES (?,?,'agentur','kampagne','offen',?,?,?,?,'mittel',?,?,?)")
|
||||
.run(titel, "Beschreibung zum Test.", von, bis, auf, reg, jetzt, idDogi, kampagneId);
|
||||
+ " event_aufgaben, event_regeln, dringlichkeit, erstellt, erstellt_von, kampagne_id,"
|
||||
+ " kampagne_daten)"
|
||||
+ " VALUES (?,?,'agentur','kampagne','offen',?,?,?,?,'mittel',?,?,?,?)")
|
||||
.run(titel, "Beschreibung zum Test.", von, bis, auf, reg, jetzt, idDogi, kampagneId,
|
||||
daten === null ? null : JSON.stringify(daten));
|
||||
return d.prepare("SELECT last_insert_rowid() AS id").get().id;
|
||||
}
|
||||
/* Die drei Zustaende, die eventStand kennt -- jeder einzeln, nicht als
|
||||
@@ -116,6 +124,66 @@ const kommend = evt("November Challenge", tag(20), tag(45),
|
||||
"· 30 Live-Stunden", "· Nur eigene Konten");
|
||||
const vorbei = evt("September Rückblick", tag(-40), tag(-12),
|
||||
"· 20 Live-Stunden", "· Nur eigene Konten");
|
||||
|
||||
/* ==== EIN EVENT MIT ECHTER GLIEDERUNG (07.10.2026) ==========
|
||||
|
||||
Der Regeltext ist ZEICHENGLEICH mit dem, was am 07.10.2026
|
||||
wirklich in der Datenbank steht (Eintrag 89, „LIVE Glow Up")
|
||||
-- nur gekuerzt. Erfundene Testdaten haetten hier genau das
|
||||
verdeckt, worum es geht: Die Hinweise mit `* ` davor, die
|
||||
Ueberschrift mit Untertitel hinter einem Gedankenstrich, der
|
||||
Absatz ohne Zeichen und die Aufzaehlung mit `· `. Jede dieser
|
||||
vier Zeilensorten sah vorher gleich aus.
|
||||
|
||||
ZWEI GESCHENKE, UND EINES OHNE PREIS. Das ist die Gegenprobe
|
||||
zu einem Fehler, der am 07.10.2026 beim ersten Lauf wirklich
|
||||
auftrat: `Number(null)` ist 0, und 0 ist endlich -- „Feuerwerk"
|
||||
bekam dadurch „0 Coins" angeschrieben, also eine falsche
|
||||
Preisangabe. Mit nur einem Geschenk MIT Preis waere das nie
|
||||
aufgefallen.
|
||||
|
||||
ES LAEUFT UND KOMMT VON TIKTOK: Damit liegt es links in der
|
||||
Gruppe „Laeuft gerade", die offen steht -- sonst waere alles
|
||||
darin zugeklappt und nicht messbar. */
|
||||
const struktText = [
|
||||
"* Diese Kampagne hat keinen Einleitungstext — der Inhalt steht in den Klapptexten.",
|
||||
"* Diese Kampagne hat keine Preisliste auf der Seite.",
|
||||
"",
|
||||
"SAMMLE DEIN FEUERWERK — Erhalte doppelte Punkte für die Rangliste",
|
||||
"· Feuerwerk (Sammle Feuerwerk in deinem LIVE!)",
|
||||
"· Ahorn-Welt — 12000 Coins",
|
||||
"",
|
||||
"INFOS ZUR KAMPAGNE",
|
||||
"LIVE Glow Up ist eine exklusive 4-wöchige Wachstum Challenge.",
|
||||
"Wofür brauche ich das?",
|
||||
"Damit du stärkere LIVE-Gewohnheiten aufbaust.",
|
||||
"",
|
||||
"### Superstars",
|
||||
"Du kannst teilnehmen, wenn du eine Einladung hast.",
|
||||
"",
|
||||
"KAMPAGNENZEITPLAN",
|
||||
"· Woche 1: 5. - 11.10.",
|
||||
"",
|
||||
"TEILNAHME",
|
||||
"Länder: DE, CH, AT, LI, LU",
|
||||
].join("\n");
|
||||
const strukt = evt("Glow Up Struktur", tag(-2), tag(20),
|
||||
"Tägliche Mission\nWöchentliche Mission", struktText,
|
||||
"7690927903777262344", {
|
||||
geschenke: [
|
||||
{ id: "1", name: "Feuerwerk", preis: null, hinweis: "Sammle Feuerwerk in deinem LIVE!" },
|
||||
{ id: "2", name: "Ahorn-Welt", preis: 12000 },
|
||||
],
|
||||
aufgabenGruppen: [
|
||||
{ titel: "Tägliche Mission", beschreibung: "Erfülle sie jeden Tag neu.",
|
||||
von_tag: "2026-10-05", bis_tag: "2026-10-11" },
|
||||
],
|
||||
steckbrief: {
|
||||
nummer: "7690927903777262344", kurznummer: "1139900164",
|
||||
region: "EU-TTP2", sprache: "de-DE", verbund: null,
|
||||
zeitzone: "Europe/Berlin", anmeldung_ab: null, ergebnis_bis: null,
|
||||
},
|
||||
});
|
||||
/* Ein gewoehnlicher Eintrag auf demselben Brett: Er darf sich NICHT
|
||||
mitverwandeln. Ohne ihn wuerde "nur Events sind betroffen" hier gar
|
||||
nicht geprueft. */
|
||||
@@ -249,8 +317,102 @@ melde("\n=== 1. Die Punkte kommen als Liste vom Server ===");
|
||||
`mit Leerzeichen getippt -> gleich sauber: ${JSON.stringify(p[2]?.text)}`);
|
||||
ok(p.every((x) => /^[0-9a-f]{16}$/.test(x.schluessel || "")) && p.length > 0,
|
||||
"jeder Punkt hat einen Schluessel (16 Hexzeichen)");
|
||||
ok((e?.event_regelpunkte || []).length === 2,
|
||||
`2 Regelpunkte (${(e?.event_regelpunkte || []).length})`);
|
||||
/* GEGLIEDERT STATT FLACH (07.10.2026). Hier stand
|
||||
`event_regelpunkte` -- eine Liste gleichrangiger Zeilen. Der
|
||||
Regeltext dieses Events hat keine Ueberschrift, also ist es
|
||||
EIN Abschnitt ohne Titel mit zwei Punkten. Genau das wird
|
||||
gemessen: nicht „es kommt irgendetwas", sondern die Form. */
|
||||
const ab = e?.event_regelabschnitte || [];
|
||||
ok(ab.length === 1 && ab[0].titel === null && ab[0].zeilen.length === 2,
|
||||
`ein Abschnitt ohne Titel mit 2 Zeilen: ${JSON.stringify(ab)}`);
|
||||
ok(ab[0]?.zeilen.every((z) => z.art === "punkt"),
|
||||
"beide Zeilen sind Punkte, keine Absaetze");
|
||||
/* DER ROHTEXT KOMMT WEITERHIN MIT -- er ist der dritte Ausgang,
|
||||
wenn die Gliederung einmal ausfaellt. */
|
||||
ok(typeof e?.event_regeln === "string" && e.event_regeln.includes("eigenen Konto"),
|
||||
"der Rohtext steht als Rueckfall weiterhin in der Antwort");
|
||||
|
||||
/* ---- Das gegliederte Event: Geschenke, Steckbrief, Gruppen -- */
|
||||
const s = (daten.eintraege || []).find((x) => x.titel === "Glow Up Struktur");
|
||||
ok(!!s, "das gegliederte Event ist auf dem Brett");
|
||||
const sab = s?.event_regelabschnitte || [];
|
||||
const titel = sab.map((a) => a.titel);
|
||||
ok(titel.includes("SAMMLE DEIN FEUERWERK") && titel.includes("INFOS ZUR KAMPAGNE")
|
||||
&& titel.includes("KAMPAGNENZEITPLAN") && titel.includes("TEILNAHME"),
|
||||
`die vier Ueberschriften sind erkannt: ${JSON.stringify(titel)}`);
|
||||
const feuer = sab.find((a) => a.titel === "SAMMLE DEIN FEUERWERK");
|
||||
ok(feuer?.unter === "Erhalte doppelte Punkte für die Rangliste",
|
||||
`der Untertitel steht getrennt: ${JSON.stringify(feuer?.unter)}`);
|
||||
ok(feuer?.art === "geschenke", `der Abschnitt ist als Geschenke erkannt (${feuer?.art})`);
|
||||
|
||||
/* DIE GEGENPROBE ZUM 0-COINS-FEHLER. `preis: null` darf NICHT
|
||||
als 0 herauskommen -- „0 Coins" ist eine Preisangabe, und
|
||||
zwar eine falsche. */
|
||||
const gaben = (feuer?.zeilen || []).filter((z) => z.art === "geschenk");
|
||||
ok(gaben.length === 2, `zwei Geschenke (${gaben.length})`);
|
||||
const ohne = gaben.find((z) => z.text === "Feuerwerk");
|
||||
const mit = gaben.find((z) => z.text === "Ahorn-Welt");
|
||||
ok(ohne && (ohne.coins === null || ohne.coins === undefined),
|
||||
`ein Geschenk ohne Preis hat KEINEN Preis, nicht 0: ${JSON.stringify(ohne)}`);
|
||||
ok(mit?.coins === 12000, `und eines mit Preis hat ihn: ${JSON.stringify(mit?.coins)}`);
|
||||
ok(ohne?.zusatz === "Sammle Feuerwerk in deinem LIVE!",
|
||||
`der Hinweis aus der Geschenkliste kommt mit: ${JSON.stringify(ohne?.zusatz)}`);
|
||||
|
||||
/* Die Unterstufe aus einem fremden Text. */
|
||||
const supers = sab.find((a) => a.titel === "Superstars");
|
||||
ok(supers?.stufe === 3, `eine Unterueberschrift ist Stufe 3 (${supers?.stufe})`);
|
||||
ok(sab.find((a) => a.titel === "INFOS ZUR KAMPAGNE")?.stufe === 2,
|
||||
"und ein eigener Abschnitt Stufe 2");
|
||||
|
||||
/* Die Frage mit Antwort darunter. */
|
||||
const infos = sab.find((a) => a.titel === "INFOS ZUR KAMPAGNE");
|
||||
ok((infos?.zeilen || []).some((z) => z.art === "frage" && z.text === "Wofür brauche ich das?"),
|
||||
`die Frage mit Antwort darunter ist erkannt: ${JSON.stringify(infos?.zeilen)}`);
|
||||
|
||||
/* GEGENPROBE: Eine Zeile aus nichts als Laendercodes waere
|
||||
gross geschrieben und wuerde zur Ueberschrift. `regelnText`
|
||||
schreibt deshalb „Länder: ..." -- und genau das muss ein
|
||||
ABSATZ bleiben, kein Titel. */
|
||||
const teil = sab.find((a) => a.titel === "TEILNAHME");
|
||||
ok((teil?.zeilen || []).some((z) => z.art === "text" && z.text.startsWith("Länder:")),
|
||||
`„Länder: DE, CH, ..." bleibt ein Absatz: ${JSON.stringify(teil?.zeilen)}`);
|
||||
ok(!titel.includes("DE, CH, AT, LI, LU"),
|
||||
"und wird nicht zur Ueberschrift");
|
||||
|
||||
/* Die Hinweise stehen in einem eigenen Abschnitt ohne Titel --
|
||||
nicht zwischen den Regeln. Das war der Mangel im
|
||||
Bildschirmfoto. */
|
||||
const hin = sab.find((a) => a.art === "hinweise");
|
||||
ok(hin && hin.titel === null && hin.zeilen.length === 2
|
||||
&& hin.zeilen.every((z) => z.art === "hinweis"),
|
||||
`die zwei Hinweise stehen fuer sich: ${JSON.stringify(hin)}`);
|
||||
|
||||
/* Steckbrief und Aufgabenbeschreibung. */
|
||||
ok(s?.event_steckbrief?.kurznummer === "1139900164",
|
||||
`der Steckbrief kommt mit: ${JSON.stringify(s?.event_steckbrief)}`);
|
||||
ok(s?.event_steckbrief?.verbund === undefined,
|
||||
"ein leeres Feld faellt weg, statt als Leerstelle zu erscheinen");
|
||||
const tagMission = (s?.event_punkte || []).find((x) => x.text === "Tägliche Mission");
|
||||
ok(tagMission?.beschreibung === "Erfülle sie jeden Tag neu.",
|
||||
`die Beschreibung haengt an der Aufgabe: ${JSON.stringify(tagMission)}`);
|
||||
ok(tagMission?.von_tag === "2026-10-05" && tagMission?.bis_tag === "2026-10-11",
|
||||
"und ihr Zeitraum dazu");
|
||||
const woche = (s?.event_punkte || []).find((x) => x.text === "Wöchentliche Mission");
|
||||
ok(woche && woche.beschreibung === undefined,
|
||||
"eine Aufgabe ohne Gruppe bekommt kein leeres Feld");
|
||||
|
||||
/* GEGENPROBE: Die drei Events OHNE Kampagnendaten bekommen
|
||||
weder Geschenke noch Steckbrief. Ohne sie waere unbelegt,
|
||||
dass die Felder aus `kampagne_daten` kommen und nicht
|
||||
irgendwo erfunden werden. */
|
||||
ok(e?.event_steckbrief === undefined,
|
||||
"ein Event ohne Kampagnendaten hat keinen Steckbrief");
|
||||
ok(!(e?.event_regelabschnitte || []).some((a) => a.art === "geschenke"),
|
||||
"und keinen Geschenkabschnitt");
|
||||
ok(e?.kampagne_daten === undefined,
|
||||
"die Rohspalte selbst geht NICHT an die Oberflaeche");
|
||||
ok(s?.kampagne_daten === undefined,
|
||||
"auch nicht beim Event, das sie hat");
|
||||
ok(e?.event_geschafft === 0, `noch nichts abgehakt (${e?.event_geschafft})`);
|
||||
|
||||
/* GEGENPROBE: Ein Eintrag, der KEIN Event ist, bekommt keine Punkte.
|
||||
@@ -443,8 +605,16 @@ async function alsRolle(rolle, code, breite = 1280) {
|
||||
{
|
||||
const { ctx, seite } = await alsRolle("admin", "CODE-DOGI-0001", 1280);
|
||||
|
||||
/* VIER SEIT DEM 07.10.2026: dazu kam „Glow Up Struktur" mit
|
||||
echter Gliederung. Die Zahl steht hier als Bedingung und
|
||||
nicht nur im Meldetext -- ein stiller Rueckgang waere sonst
|
||||
unsichtbar (CLAUDE.md, 28.08.2026).
|
||||
|
||||
ZUGEKLAPPTE GRUPPEN ZAEHLEN MIT: „Vorbei" steht von sich aus
|
||||
zu, aber `hidden` entfernt ein Element nicht aus dem Baum.
|
||||
Waere das anders, muesste hier erst aufgeklappt werden. */
|
||||
const karten = await seite.$$('.eintrag-karte[data-eventkarte="ja"]');
|
||||
ok(karten.length === 3, `3 Eventkarten (${karten.length}) -- die Schulung ist keine`);
|
||||
ok(karten.length === 4, `4 Eventkarten (${karten.length}) -- die Schulung ist keine`);
|
||||
|
||||
/* GEGENPROBE: Die Schulung bleibt eine gewoehnliche Karte. Ohne sie
|
||||
waere "nur Events sind umgebaut" unbelegt. */
|
||||
@@ -844,6 +1014,362 @@ async function alsRolle(rolle, code, breite = 1280) {
|
||||
await ctx.close();
|
||||
}
|
||||
|
||||
/* =======================================================================
|
||||
4b. SIEHT MAN DIE GLIEDERUNG? (07.10.2026)
|
||||
|
||||
Das ist der Abschnitt, der Filipes Bildschirmfoto beantwortet. Und
|
||||
zwar MESSEND: „es gibt ein h5" beweist nichts -- ein h5, das
|
||||
genauso aussieht wie der Absatz darunter, ist genau der Zustand,
|
||||
der beanstandet wurde. Gemessen werden deshalb die berechneten
|
||||
Werte und ihr UNTERSCHIED.
|
||||
|
||||
EIN GRUENER HAKEN, DER NICHTS MISST, IST DAS SCHLIMMERE VON ZWEIEN
|
||||
(CLAUDE.md, 01.09.2026): Jede Bedingung hier enthaelt die Zahl der
|
||||
tatsaechlich untersuchten Dinge, und zu jeder Aussage „so sieht es
|
||||
aus" gehoert eine, die „und so NICHT" sagt.
|
||||
======================================================================= */
|
||||
melde("\n=== 4b. Die Gliederung auf dem Bildschirm ===");
|
||||
{
|
||||
const { ctx, seite } = await alsRolle("admin", "CODE-DOGI-0001", 1280);
|
||||
|
||||
/* ---- Die Kachel ist zu, und das ist der Zweck --------------- */
|
||||
const zuerst = await seite.evaluate(() => {
|
||||
const k = [...document.querySelectorAll('.eintrag-karte[data-eventkarte="ja"]')]
|
||||
.find((x) => x.textContent.includes("Glow Up Struktur"));
|
||||
if (!k) return { fehlt: true };
|
||||
const mehr = k.querySelector(".ev-mehr__inhalt");
|
||||
const knopf = k.querySelector(".ev-mehr__knopf");
|
||||
return {
|
||||
hoeheZu: Math.round(k.getBoundingClientRect().height),
|
||||
verborgen: !!mehr?.hidden,
|
||||
gedrueckt: knopf?.getAttribute("aria-expanded"),
|
||||
zahl: k.querySelector(".ev-mehr__zahl")?.textContent.trim() || null,
|
||||
wort: k.querySelector(".ev-mehr__wort")?.textContent.trim() || null,
|
||||
/* Was TROTZ zugeklapptem Kasten dasteht. */
|
||||
gaben: [...k.querySelectorAll(".ev-block--gaben .ev-gabe")].map((g) => ({
|
||||
name: g.querySelector(".ev-gabe__name")?.textContent.trim(),
|
||||
coins: g.querySelector(".ev-gabe__coins")?.textContent.trim() || null,
|
||||
zusatz: g.querySelector(".ev-gabe__zusatz")?.textContent.trim() || null,
|
||||
})),
|
||||
hinweise: [...k.querySelectorAll(".ev-hinweise .ev-hinweis")]
|
||||
.map((h) => h.textContent.trim()),
|
||||
/* Die Hinweise duerfen NICHT in der Abschnittsliste stehen --
|
||||
genau das war der Mangel. */
|
||||
hinweisInRegeln: k.querySelectorAll(".ev-abschnitte .ev-hinweis").length,
|
||||
zusatz: k.querySelector(".ev-punkt__zusatz")?.textContent.trim() || null,
|
||||
};
|
||||
});
|
||||
melde(" -- zu: " + JSON.stringify(zuerst));
|
||||
ok(!zuerst.fehlt, "die gegliederte Kachel steht auf dem Brett");
|
||||
ok(zuerst.verborgen === true && zuerst.gedrueckt === "false",
|
||||
`der Infokasten ist von sich aus zu (hidden=${zuerst.verborgen}, `
|
||||
+ `aria-expanded=${zuerst.gedrueckt})`);
|
||||
ok(zuerst.wort === "Alle Infos" && /Abschnitt/.test(zuerst.zahl || ""),
|
||||
`und der Knopf sagt, was dahinter steht: "${zuerst.wort} / ${zuerst.zahl}"`);
|
||||
|
||||
/* ---- Die Geschenke stehen OHNE Aufklappen da ---------------- */
|
||||
ok(zuerst.gaben.length === 2,
|
||||
`zwei Geschenke sind sofort sichtbar (${zuerst.gaben.length})`);
|
||||
const ahorn = zuerst.gaben.find((g) => g.name === "Ahorn-Welt");
|
||||
const feuer = zuerst.gaben.find((g) => g.name === "Feuerwerk");
|
||||
ok(/12\.000/.test(ahorn?.coins || "") && /Coins/.test(ahorn?.coins || ""),
|
||||
`der Coinpreis steht mit Tausenderpunkt da: ${JSON.stringify(ahorn?.coins)}`);
|
||||
/* DIE GEGENPROBE ZUM 0-COINS-FEHLER, diesmal auf dem Bildschirm:
|
||||
Ein Kampagnengeschenk ohne Preis darf KEINE Preisplakette
|
||||
bekommen. „0 Coins" waere eine falsche Preisangabe. */
|
||||
ok(feuer && feuer.coins === null,
|
||||
`ein Geschenk ohne Preis zeigt keinen Preis: ${JSON.stringify(feuer)}`);
|
||||
ok(feuer?.zusatz === "Sammle Feuerwerk in deinem LIVE!",
|
||||
`stattdessen steht da, wie man es bekommt: ${JSON.stringify(feuer?.zusatz)}`);
|
||||
|
||||
/* ---- Die Hinweise stehen fuer sich ------------------------- */
|
||||
ok(zuerst.hinweise.length === 2,
|
||||
`die zwei Hinweise stehen sichtbar in ihrem eigenen Kasten (${zuerst.hinweise.length})`);
|
||||
ok(zuerst.hinweisInRegeln === 0,
|
||||
`und KEINER zwischen den Regeln (${zuerst.hinweisInRegeln}) -- das war der Mangel`);
|
||||
|
||||
/* ---- Die Beschreibung haengt unter der Aufgabe -------------- */
|
||||
ok(/Erfülle sie jeden Tag neu/.test(zuerst.zusatz || "")
|
||||
&& /05\.10\.2026/.test(zuerst.zusatz || ""),
|
||||
`unter der Aufgabe stehen Beschreibung und Zeitraum: ${JSON.stringify(zuerst.zusatz)}`);
|
||||
|
||||
/* ---- Aufklappen: wird die Kachel laenger? ------------------- */
|
||||
/* DIE RICHTIGE KACHEL (berichtigt 07.10.2026).
|
||||
|
||||
Hier stand `.eintrag-karte[data-eventkarte="ja"] .ev-mehr__knopf`
|
||||
-- das traf die ERSTE Eventkarte („Oktober Event"), nicht die
|
||||
gegliederte. Gemessen wurde danach eine Kachel, deren Kasten
|
||||
weiterhin zu war: „spart 0 px", „0 px eingerueckt",
|
||||
„Untertitel null". Drei rote Zeilen, kein Schaden am Code.
|
||||
|
||||
Das ist die Sorte Fehlalarm, die Vertrauen kostet (CLAUDE.md,
|
||||
26.09.2026) -- deshalb wird die Kachel ueber ihren TITEL
|
||||
gesucht, nicht ueber ihre Position. */
|
||||
const knopfNr = await seite.evaluate(() => {
|
||||
const alle = [...document.querySelectorAll('.eintrag-karte[data-eventkarte="ja"]')];
|
||||
const i = alle.findIndex((x) => x.textContent.includes("Glow Up Struktur"));
|
||||
return i;
|
||||
});
|
||||
ok(knopfNr >= 0, `die gegliederte Kachel ist Karte Nr. ${knopfNr}`);
|
||||
await seite.evaluate(() => {
|
||||
const k = [...document.querySelectorAll('.eintrag-karte[data-eventkarte="ja"]')]
|
||||
.find((x) => x.textContent.includes("Glow Up Struktur"));
|
||||
k.querySelector(".ev-mehr__knopf").click();
|
||||
});
|
||||
await seite.waitForTimeout(300);
|
||||
const danach = await seite.evaluate(() => {
|
||||
const k = [...document.querySelectorAll('.eintrag-karte[data-eventkarte="ja"]')]
|
||||
.find((x) => x.textContent.includes("Glow Up Struktur"));
|
||||
const mehr = k.querySelector(".ev-mehr__inhalt");
|
||||
const lies = (w) => {
|
||||
const s = getComputedStyle(w);
|
||||
return {
|
||||
groesse: Math.round(parseFloat(s.fontSize) * 100) / 100,
|
||||
gewicht: Number(s.fontWeight),
|
||||
sperrung: s.letterSpacing,
|
||||
gross: s.textTransform,
|
||||
farbe: s.color,
|
||||
text: w.textContent.trim().slice(0, 40),
|
||||
};
|
||||
};
|
||||
const k2 = k.querySelector('.ev-abschnitt[data-stufe="2"] > .ev-abschnitt__titel');
|
||||
const k3 = k.querySelector('.ev-abschnitt[data-stufe="3"] > .ev-abschnitt__titel');
|
||||
const abs = k.querySelector(".ev-abschnitt .ev-absatz");
|
||||
const frage = k.querySelector(".ev-abschnitt .ev-frage");
|
||||
return {
|
||||
hoeheAuf: Math.round(k.getBoundingClientRect().height),
|
||||
verborgen: !!mehr?.hidden,
|
||||
titel: [...k.querySelectorAll(".ev-abschnitt__titel")].map((h) => h.textContent.trim()),
|
||||
stufe2: k2 ? lies(k2) : null,
|
||||
stufe3: k3 ? lies(k3) : null,
|
||||
absatz: abs ? lies(abs) : null,
|
||||
frage: frage ? lies(frage) : null,
|
||||
/* DER UNTERTITEL DES GESCHENKABSCHNITTS STEHT IM
|
||||
GESCHENKBLOCK (berichtigt 07.10.2026).
|
||||
|
||||
Hier stand `.ev-abschnitt__unter`. „SAMMLE DEIN FEUERWERK
|
||||
— Erhalte doppelte Punkte" ist aber genau der Abschnitt,
|
||||
der aus den Regeln HERAUSGENOMMEN und nach oben gezogen
|
||||
wird (damit die Geschenke ohne Aufklappen sichtbar sind).
|
||||
Sein Untertitel heisst dort `.ev-gaben__unter`. Die
|
||||
Pruefung suchte ihn an der Stelle, an der er absichtlich
|
||||
nicht mehr steht.
|
||||
|
||||
BEIDE WERDEN JETZT GEMESSEN: `unter` fuer einen
|
||||
gewoehnlichen Abschnitt (es gibt hier keinen mit
|
||||
Untertitel, also null -- das ist in Ordnung) und
|
||||
`gabenWoher`/`gabenUnter` fuer den, um den es geht. */
|
||||
unter: k.querySelector(".ev-gaben__unter")?.textContent.trim() || null,
|
||||
gabenWoher: (() => {
|
||||
const p = k.querySelector(".ev-gaben__woher");
|
||||
if (!p) return null;
|
||||
const u = p.querySelector(".ev-gaben__unter");
|
||||
const ganz = p.textContent.trim();
|
||||
return u ? ganz.slice(0, ganz.length - u.textContent.trim().length).trim() : ganz;
|
||||
})(),
|
||||
/* DIE EINRUECKUNG WIRD AM TEXT GEMESSEN, NICHT AM KASTEN
|
||||
(berichtigt 07.10.2026).
|
||||
|
||||
Hier stand der Abstand der beiden ABSCHNITTE. Der ist 0,
|
||||
und das ist richtig: Beide sind volle Kinder derselben
|
||||
Spalte, die Einrueckung entsteht durch `padding-left` --
|
||||
sie verschiebt den INHALT, nicht das Rechteck. Gemessen
|
||||
kam „0 px eingerueckt" heraus, obwohl der Text sichtbar
|
||||
eingerueckt war.
|
||||
|
||||
Was man sehen soll, ist der Text. Also wird der gemessen. */
|
||||
einzug: (() => {
|
||||
const h3 = k.querySelector('.ev-abschnitt[data-stufe="3"] > .ev-abschnitt__titel');
|
||||
const h2 = k.querySelector('.ev-abschnitt[data-stufe="2"] > .ev-abschnitt__titel');
|
||||
return h3 && h2
|
||||
? Math.round(h3.getBoundingClientRect().x - h2.getBoundingClientRect().x)
|
||||
: null;
|
||||
})(),
|
||||
steck: [...k.querySelectorAll(".ev-steck__name")].map((x) => x.textContent.trim()),
|
||||
steckWerte: [...k.querySelectorAll(".ev-steck__wert")].map((x) => x.textContent.trim()),
|
||||
};
|
||||
});
|
||||
melde(" -- auf: " + JSON.stringify(danach).slice(0, 700));
|
||||
ok(danach.verborgen === false,
|
||||
"ein Druck macht den Infokasten auf");
|
||||
/* DAS IST DIE ANTWORT AUF „die kacheln sollen nicht so lang sein":
|
||||
nicht „sie ist kurz", sondern „sie ist MESSBAR kuerzer als mit
|
||||
allem offen". Eine Kachel, die zugeklappt genauso hoch ist, hat
|
||||
nichts gespart. */
|
||||
ok(danach.hoeheAuf > zuerst.hoeheZu + 80,
|
||||
`zugeklappt spart die Kachel ${danach.hoeheAuf - zuerst.hoeheZu} px `
|
||||
+ `(${zuerst.hoeheZu} statt ${danach.hoeheAuf})`);
|
||||
|
||||
/* ---- Und jetzt: SIEHT man die Ueberschrift? ----------------- */
|
||||
ok(danach.titel.length >= 4,
|
||||
`${danach.titel.length} Ueberschriften stehen da: ${JSON.stringify(danach.titel.slice(0, 6))}`);
|
||||
ok(!!danach.stufe2 && !!danach.absatz,
|
||||
"Ueberschrift und Absatz sind beide da (sonst misst der Vergleich nichts)");
|
||||
/* DREI UNTERSCHIEDE, NICHT EINER. Ein einziger (etwa nur die
|
||||
Farbe) wuerde bei einem anderen Farbschema wieder verschwinden. */
|
||||
const u2 = danach.stufe2 || {};
|
||||
const ua = danach.absatz || {};
|
||||
const unterschiede = [
|
||||
["Gewicht", u2.gewicht, ua.gewicht],
|
||||
["Sperrung", u2.sperrung, ua.sperrung],
|
||||
["Grossschreibung", u2.gross, ua.gross],
|
||||
["Farbe", u2.farbe, ua.farbe],
|
||||
].filter(([, a, b]) => a !== b);
|
||||
ok(unterschiede.length >= 3,
|
||||
`die Ueberschrift unterscheidet sich in ${unterschiede.length} von 4 Merkmalen `
|
||||
+ `vom Absatz: ${JSON.stringify(unterschiede)}`);
|
||||
ok(u2.gewicht >= 700 && ua.gewicht < 700,
|
||||
`sie ist fett, der Absatz nicht (${u2.gewicht} gegen ${ua.gewicht})`);
|
||||
ok(u2.gross === "uppercase" && ua.gross === "none",
|
||||
`sie steht in Grossbuchstaben, der Absatz nicht (${u2.gross} / ${ua.gross})`);
|
||||
|
||||
/* Die Unterstufe sieht anders aus als die Oberstufe UND anders
|
||||
als ein Absatz -- sonst waere die zweite Stufe keine. */
|
||||
ok(!!danach.stufe3, "eine Unterueberschrift ist da");
|
||||
const u3 = danach.stufe3 || {};
|
||||
ok(u3.gross === "none" && u3.gewicht >= 600,
|
||||
`die Unterstufe ist halbfett und NICHT in Grossbuchstaben `
|
||||
+ `(${u3.gewicht}, ${u3.gross})`);
|
||||
ok(u3.gewicht > ua.gewicht,
|
||||
`aber immer noch kraeftiger als ein Absatz (${u3.gewicht} gegen ${ua.gewicht})`);
|
||||
ok(danach.einzug >= 8,
|
||||
`und sie ist ${danach.einzug} px eingerueckt (Grenze 8)`);
|
||||
|
||||
/* Der Untertitel hinter dem Gedankenstrich steht getrennt -- und
|
||||
die Ueberschrift der Kampagne bleibt erhalten. „Sammle dein
|
||||
Feuerwerk" sagt, WARUM diese Geschenke zaehlen; ein selbst
|
||||
erfundenes „Geschenke" daneben haette das verschluckt. */
|
||||
ok(danach.gabenWoher === "SAMMLE DEIN FEUERWERK",
|
||||
`die Ueberschrift der Kampagne steht ueber den Geschenken: `
|
||||
+ `${JSON.stringify(danach.gabenWoher)}`);
|
||||
ok(danach.unter === "Erhalte doppelte Punkte für die Rangliste",
|
||||
`der Untertitel steht als eigene Zeile: ${JSON.stringify(danach.unter)}`);
|
||||
|
||||
/* Die Frage ist kraeftiger als der Absatz unter ihr. */
|
||||
ok(!!danach.frage && danach.frage.gewicht > ua.gewicht,
|
||||
`eine Frage mit Antwort darunter steht kraeftiger da `
|
||||
+ `(${danach.frage?.gewicht} gegen ${ua.gewicht}): ${JSON.stringify(danach.frage?.text)}`);
|
||||
|
||||
/* Der Steckbrief -- deutsche Namen, keine Rohfelder. */
|
||||
ok(danach.steck.includes("Kurznummer") && danach.steck.includes("Markt"),
|
||||
`der Steckbrief nennt die Felder auf Deutsch: ${JSON.stringify(danach.steck)}`);
|
||||
ok(danach.steckWerte.includes("1139900164"),
|
||||
`und zeigt die Werte: ${JSON.stringify(danach.steckWerte)}`);
|
||||
ok(!danach.steck.some((n) => /_|activity|flag/i.test(n)),
|
||||
"kein Rohfeldname steht auf der Kachel");
|
||||
|
||||
/* ---- Die eigene Wahl haelt das Neuladen aus ---------------- */
|
||||
await seite.reload({ waitUntil: "networkidle" });
|
||||
await seite.waitForSelector(".ev-mehr__knopf", { timeout: 15000 });
|
||||
await seite.waitForTimeout(600);
|
||||
const nachher = await seite.evaluate(() => {
|
||||
const k = [...document.querySelectorAll('.eintrag-karte[data-eventkarte="ja"]')]
|
||||
.find((x) => x.textContent.includes("Glow Up Struktur"));
|
||||
return { verborgen: !!k?.querySelector(".ev-mehr__inhalt")?.hidden };
|
||||
});
|
||||
/* WARUM DAS WICHTIG IST: Das Brett baut sich bei jeder
|
||||
Aktualisierung neu auf. Eine Kachel, die dabei zuklappt,
|
||||
waehrend man liest, ist aergerlicher als eine lange. */
|
||||
ok(nachher.verborgen === false,
|
||||
"aufgeklappt bleibt aufgeklappt, auch nach dem Neuladen");
|
||||
|
||||
/* ---- Die Gruppen der Spalten ------------------------------- */
|
||||
const gruppen = await seite.evaluate(() => {
|
||||
const seiten = [...document.querySelectorAll(".kv-seite")].map((s) => ({
|
||||
seite: s.dataset.seite,
|
||||
gruppen: [...s.querySelectorAll(".ev-gruppe__kopf")].map((g) => ({
|
||||
name: g.dataset.gruppe,
|
||||
wort: g.querySelector(".ev-gruppe__wort")?.textContent.trim(),
|
||||
zahl: g.querySelector(".ev-gruppe__zahl")?.textContent.trim(),
|
||||
zu: g.nextElementSibling?.hidden === true,
|
||||
})),
|
||||
}));
|
||||
return { seiten };
|
||||
});
|
||||
melde(" -- Gruppen: " + JSON.stringify(gruppen));
|
||||
const alleGruppen = gruppen.seiten.flatMap((s) => s.gruppen);
|
||||
ok(alleGruppen.length >= 3,
|
||||
`${alleGruppen.length} Gruppen stehen in den Spalten`);
|
||||
const laeuft = alleGruppen.filter((g) => g.name === "laeuft");
|
||||
const vorbei = alleGruppen.filter((g) => g.name.startsWith("vorbei"));
|
||||
ok(laeuft.length >= 1 && laeuft.every((g) => !g.zu),
|
||||
`„Laeuft gerade" steht offen (${laeuft.length})`);
|
||||
ok(vorbei.length >= 1 && vorbei.every((g) => g.zu),
|
||||
`und Vergangenes zu (${vorbei.length}: `
|
||||
+ `${vorbei.map((g) => g.wort).join(", ")})`);
|
||||
/* KEINE LEERE GRUPPE. Fuenf Ueberschriften ueber nichts waeren
|
||||
schlimmer als eine lange Spalte. */
|
||||
ok(alleGruppen.every((g) => Number(g.zahl) > 0),
|
||||
`jede Gruppe hat Eintraege: ${JSON.stringify(alleGruppen.map((g) => g.zahl))}`);
|
||||
/* UND DIE SUMME STIMMT: Keine Karte faellt zwischen zwei Gruppen
|
||||
durch. Ohne diese Zeile waere „es gibt Gruppen" vereinbar damit,
|
||||
dass ein Event in keiner davon auftaucht. */
|
||||
const summe = alleGruppen.reduce((s, g) => s + Number(g.zahl), 0);
|
||||
ok(summe === 4, `alle 4 Events stehen in genau einer Gruppe (Summe ${summe})`);
|
||||
|
||||
/* GEGENPROBE: Links und rechts teilen sich den Zustand NICHT.
|
||||
Dieser Fehler war bei den Zeitstufen schon einmal da.
|
||||
|
||||
ERST DRUECKEN, DANN NACHSEHEN (berichtigt 07.10.2026). Vorher
|
||||
stand hier `... || merker.length === 0` -- und weil nie
|
||||
jemand eine Gruppe angefasst hatte, war die Liste leer und
|
||||
die Zeile gruen, ohne etwas gemessen zu haben. Genau die
|
||||
Sorte Haken, die immer bestaetigt (CLAUDE.md, 01.09.2026).
|
||||
|
||||
Jetzt wird eine Gruppe LINKS zugeklappt und danach geprueft,
|
||||
dass (1) ein Merker entstanden ist, (2) er die Seite nennt
|
||||
und (3) die gleichnamige Gruppe RECHTS davon unberuehrt ist. */
|
||||
const vorher = await seite.evaluate(() => {
|
||||
const links = document.querySelector('.kv-seite[data-seite="tiktok"] .ev-gruppe__kopf');
|
||||
const name = links?.dataset.gruppe;
|
||||
const rechts = [...document.querySelectorAll('.kv-seite[data-seite="agentur"] .ev-gruppe__kopf')]
|
||||
.find((g) => g.dataset.gruppe === name);
|
||||
links?.click();
|
||||
return {
|
||||
name,
|
||||
linksZu: links?.nextElementSibling?.hidden === true,
|
||||
rechtsDa: !!rechts,
|
||||
rechtsZu: rechts ? rechts.nextElementSibling?.hidden === true : null,
|
||||
};
|
||||
});
|
||||
const merker = await seite.evaluate(() => Object.keys(localStorage)
|
||||
.filter((s) => s.startsWith("abschnitt:agentur:")));
|
||||
melde(" -- nach dem Druck: " + JSON.stringify({ ...vorher, merker }));
|
||||
ok(merker.length > 0 && merker.every((s) => /:(tiktok|agentur):/.test(s)),
|
||||
`der Merker nennt die Seite: ${JSON.stringify(merker)}`);
|
||||
/* DIESE ZEILE WAR SELBST FALSCH (berichtigt 07.10.2026).
|
||||
|
||||
Hier stand `!s.includes(":agentur:")`. Der Merker heisst aber
|
||||
`abschnitt:agentur:tiktok:laeuft` -- und „agentur" darin ist der
|
||||
BRETTNAME, nicht die Seite. Die Zeile war damit nie erfuellbar.
|
||||
Zwei Dinge heissen gleich und sind verschieden; genau dieser
|
||||
Fehler stand am 07.10.2026 schon einmal im Projekt (das Feld
|
||||
„Gilt für" nennt das HAUS, nicht das Brett).
|
||||
|
||||
Gemessen wird jetzt die Form des Schluessels GANZ: genau einer,
|
||||
und er nennt die angefasste Seite. Das ist die Aussage, auf die
|
||||
es ankommt -- der Zustand ist je Seite abgelegt, also kann ein
|
||||
Druck links rechts nichts bewirken. */
|
||||
ok(merker.length === 1 && merker[0] === `abschnitt:agentur:tiktok:${vorher.name}`,
|
||||
`genau ein Merker, fuer die angefasste Seite: ${JSON.stringify(merker)}`);
|
||||
|
||||
/* UND DIE ANDERE SEITE STEHT NOCH SO DA WIE VORHER. Gemessen an
|
||||
der Gruppe, die es dort gibt -- „Kommt noch" war offen und muss
|
||||
offen bleiben, obwohl links gerade zugeklappt wurde. */
|
||||
const andereSeite = await seite.evaluate(() => {
|
||||
const g = [...document.querySelectorAll('.kv-seite[data-seite="agentur"] .ev-gruppe__kopf')]
|
||||
.map((x) => ({ name: x.dataset.gruppe, zu: x.nextElementSibling?.hidden === true }));
|
||||
return g;
|
||||
});
|
||||
const kommt = andereSeite.find((g) => g.name === "kommt");
|
||||
ok(!!kommt && kommt.zu === false,
|
||||
`rechts ist nichts mitgeklappt: ${JSON.stringify(andereSeite)}`);
|
||||
ok(vorher.linksZu === true,
|
||||
`die angefasste Gruppe links ist zu (${vorher.name})`);
|
||||
|
||||
await ctx.close();
|
||||
}
|
||||
|
||||
melde("\n=== 5. Abhaken im Browser, mit Neuladen ===");
|
||||
{
|
||||
const { ctx, seite } = await alsRolle("creator", "CODE-CREA-0001", 1280);
|
||||
@@ -1037,11 +1563,42 @@ melde("\n=== 7. Auf dem Handy (412 px) ===");
|
||||
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. */
|
||||
/* GEMESSEN WIRD, WAS MAN SIEHT (berichtigt 07.10.2026).
|
||||
|
||||
Hier standen ALLE Eventkarten. Seit die Spalten nach Zustand
|
||||
und Alter gegliedert sind, steht „Vorbei — aelter" von sich
|
||||
aus zugeklappt -- und eine Karte in einem `hidden`-Kasten hat
|
||||
ein Rechteck von 0x0 an Position 0,0. Gemessen kam
|
||||
„379, 379, 379, 379, 0 px" heraus, und die Pruefung meldete
|
||||
eine zu schmale Karte, obwohl keine zu schmal war.
|
||||
|
||||
ZWEI SCHAEDEN, NICHT EINER: Die Paarprobe daneben haette bei
|
||||
ZWEI zugeklappten Karten „zwei auf gleicher Hoehe" gemeldet --
|
||||
beide liegen auf y=0. Das waere ein Fehlalarm, der erst
|
||||
auftritt, wenn ein zweites Event vorbeigelaufen ist, also
|
||||
irgendwann von selbst. Solche Fehlalarme kosten das Vertrauen
|
||||
in den ganzen Satz (CLAUDE.md, 26.09.2026).
|
||||
|
||||
UND DAS VERSCHWINDEN WIRD SELBST GEPRUEFT: Eine unsichtbare
|
||||
Karte darf nur deshalb unsichtbar sein, weil ihre Gruppe zu
|
||||
ist. Ohne diese zweite Haelfte haette „wir messen nur die
|
||||
sichtbaren" genau den Fall weggeschaut, in dem eine Karte
|
||||
wirklich fehlt. */
|
||||
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) }; });
|
||||
const alle = [...document.querySelectorAll('.eintrag-karte[data-eventkarte="ja"]')]
|
||||
.map((x) => {
|
||||
const r = x.getBoundingClientRect();
|
||||
const gruppe = x.closest(".ev-gruppe__inhalt");
|
||||
return {
|
||||
x: Math.round(r.x), y: Math.round(r.y), b: Math.round(r.width),
|
||||
sichtbar: r.width > 0 && r.height > 0,
|
||||
inZu: !!(gruppe && gruppe.hidden),
|
||||
};
|
||||
});
|
||||
const k = alle.filter((a) => a.sichtbar);
|
||||
return {
|
||||
karten: k,
|
||||
versteckt: alle.filter((a) => !a.sichtbar),
|
||||
/* 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,
|
||||
@@ -1051,6 +1608,10 @@ melde("\n=== 7. Auf dem Handy (412 px) ===");
|
||||
`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.versteckt.every((a) => a.inZu),
|
||||
`was man nicht sieht, steckt in einer zugeklappten Gruppe `
|
||||
+ `(${schmal.versteckt.length} verborgen, davon `
|
||||
+ `${schmal.versteckt.filter((a) => a.inZu).length} erklaert)`);
|
||||
ok(schmal.quer <= 1,
|
||||
`die Seite laesst sich nicht seitlich schieben (${schmal.quer} px)`);
|
||||
/* UND WENN DOCH, DANN WELCHES ELEMENT? Eine Zahl allein schickt
|
||||
|
||||
Reference in New Issue
Block a user