Am Handy wird aus einer Kalenderpille ein Punkt

GEMESSEN, was dort wirklich stand:

    Fenster   Zelle   Pille   Platz fuer Text
     360 px   42 px   32 px   16 px  ->  1-2 Buchstaben
     390 px   46 px   36 px   20 px  ->  2-3 Buchstaben
     412 px   49 px   39 px   23 px  ->  3 Buchstaben
     768 px   95 px   85 px   69 px  ->  lesbar

"Content-Ideen sammeln" wurde zu "C…" -- eine Zeile, die Hoehe kostet
und nichts sagt. Drei Termine an einem Tag waren drei solche Zeilen.

JETZT: ein Punkt je Termin, nebeneinander. Man sieht, DASS an dem Tag
etwas ist und wie viel, und tippt den Tag an, um zu lesen, was. Der
Tagesdialog dafuer steht seit jeher, ist lesbar und hat 44-px-Zeilen;
er war nur schwer zu finden, solange das Raster so tat, als koenne man
dort lesen.

  - Zeitraum: bleibt ein durchgehender Balken. Ihn auch zu Punkten zu
    machen naehme genau das weg, wofuer er am 21.09. gebaut wurde.
  - Anlass (Feiertag u. a.): ein ECKIGES Zeichen, damit man es vom
    runden Termin unterscheidet. "DE…" fuer "Tag der Deutschen
    Einheit" sagt genauso wenig.
  - Erledigtes: hohl statt voll -- sonst saehe ein abgehakter Termin
    aus wie ein offener, und der Kalender loege.
  - Die Punkte sind NICHT einzeln antippbar (pointer-events: none).
    Ein 8-px-Link waere ein Nadeloehr; so faellt jeder Tipp auf die
    Zelle. Am Rechner bleibt die Pille ein Link.

DREI DINGE, DIE ERST DAS BILDSCHIRMFOTO GEZEIGT HAT:

(1) Die Zahlen sagten 8 x 8 -- und der Titel lief trotzdem quer ueber
    die Nachbarzellen. Ursache: start.css traegt eine Sammelregel
    `body.start .k-pille { font-size: .75rem }`, um ein Element
    spezifischer als `.k-tag .k-pille` (0,2,1 gegen 0,2,0). Sie
    gewinnt, egal welche Datei spaeter laedt. Aufgeklaert hat es die
    Frage an den Browser, WELCHE Regeln auf das Element passen.

(2) `.k-tag` traegt `container-type: inline-size` und ist damit der
    Behaelter fuer ihre KINDER. Eine Regel fuer `.k-tag` SELBST in
    `@container` wird gegen den naechsten Behaelter darueber geprueft
    und greift nie. Die Zelle blieb eine Flex-Spalte, jeder Punkt bekam
    eine eigene Zeile. Jetzt fragt die Zelle das Raster -- ein
    benannter Behaelter, Schwelle gerechnet: 46 + 8 + 7 x 60 = 474.

(3) Die Kinder der Pille (Uhrzeit, Wiederholzeichen) haben eine eigene
    Schriftgroesse und hielten den Punkt auf 26 px Hoehe. Ein 8 x 26
    grosser "Punkt" ist ein Strich.

pruef-kalender: 141/0 -- vorher 135 ok und 6 FEHL.

Die sechs waren KEIN Fehler am Kalender, und nur einer davon war neu:

  - Vier kamen von Screen 11 (Termin von-bis): Ein Eintrag ueber fuenf
    Tage setzt fuenf Marken, und die Pruefung zaehlte Marken statt
    Eintraege. Sie hatte am 17.09. schon gelernt, ihre Erwartung
    abzuleiten -- veraltet war diesmal nicht die Erwartung, sondern
    das, was gemessen wurde. Gezaehlt wird jetzt ueber den VERWEIS
    (`zeigen=eintrag-N`), der an jedem Tag derselbe ist. Der `title`
    ginge nicht: Er endet mit "(Tag 3 von 5)".
  - Zwei waren meine: Die Pruefung las die Farbe aus der linken Kante
    -- die faellt beim Punkt weg, also meldete sie "1 Farbe" statt 5.
    Gelesen wird jetzt `--pfarbe`, die Quelle selbst.

Neun neue Zusicherungen, darunter die, die beim Bauen gefehlt hat:
"nichts ragt ueber den Rand seiner Zelle hinaus". Groesse allein
genuegt nicht -- die Pille war bereits 8 x 8 und trug trotzdem Text.
Gegenprobe: Raster auf 1200 px aufziehen, Titel muss zurueckkommen.

Nachbarn gruen: pruef-tippziele 11/0 (sieht die 11 neuen Regeln, zaehlt
den Punkt richtig nicht als Tippziel), pruef-css-klassen 30/0,
pruef-zeitraum 16/0, pruef-terminregel 35/0.
This commit is contained in:
2026-09-21 17:01:54 +02:00
parent bfbe6feafe
commit 432e533c86
39 changed files with 844 additions and 514 deletions
+168 -6
View File
@@ -197,7 +197,27 @@ const lesen = (seite) => seite.evaluate(() => ({
/* Eintraege */
pillen: [...document.querySelectorAll(".k-pille")].map((p) => ({
text: p.textContent,
farbe: getComputedStyle(p).borderLeftColor,
/* DIE KENNUNG IST DER TITEL-TEXT, nicht der sichtbare Text: Bei
einem Zeitraum steht im sichtbaren Text "Tag 3/5 ..." und er ist
abgeschnitten.
DER `title` GEHT AUCH NICHT: Er endet bei einem Zeitraum mit
"(Tag 3 von 5)" und ist damit an jedem Tag ein anderer -- der
erste Versuch zaehlte deshalb weiter 14 statt 10.
Der VERWEIS bleibt gleich: `bereich.html?b=live&zeigen=eintrag-7`
zeigt an jedem der fuenf Tage auf denselben Eintrag. Wo es
keinen gibt (Fristen, Calls), tut es der Titel -- die sind immer
eintaegig. */
kennung: p.getAttribute("href") || p.title || p.textContent,
spanne: p.dataset.spanne || null,
/* DIE FARBE KOMMT AUS `--pfarbe`, NICHT AUS DER LINKEN KANTE.
Die Kante ist eine Darstellung und faellt weg, wo die Pille ein
Punkt ist (Handy) -- dann meldete diese Pruefung "1 Farbe" und
sah aus wie ein Befund am Kalender. Die Eigenschaft dagegen
steht auf jeder Pille, in jeder Ansicht. */
farbe: p.style.getPropertyValue("--pfarbe").trim()
|| getComputedStyle(p).borderLeftColor,
brett: p.querySelector(".k-pille__brett")?.textContent || null,
zugesagt: !!p.querySelector('.k-pille__zusage'),
})),
@@ -258,9 +278,22 @@ for (const [breite, wie] of [[1440, "Computer"], [390, "Handy"]]) {
ok(r.heuteZellen === 1, `genau ein Tag ist "heute" (${r.heuteZellen})`);
ok(r.fremdZellen > 0, `die Nachbarmonatstage sind erkennbar (${r.fremdZellen})`);
/* ---- Eintraege im Raster ---- */
ok(r.pillen.length === ERWARTET.pillen,
`alle ${ERWARTET.pillen} Einträge stehen im Raster (${r.pillen.length})`);
/* ---- Eintraege im Raster ----
EIN EINTRAG, NICHT EINE MARKE (berichtigt 21.09.2026).
Seit ein Termin von-bis ueber die ganze Spanne markiert wird
(Filipes Wunsch vom 21.09.), setzt ein Eintrag ueber fuenf Tage
auch FUENF Marken ins Raster. Diese Zeile zaehlte Marken und
meldete deshalb 14 statt 10 -- ohne dass am Kalender etwas kaputt
war. Dieselbe Falle wie eine feste Zahl, nur eine Ebene tiefer:
nicht die Erwartung war veraltet, sondern das, was gemessen wurde.
`kennung` ist fuer alle Tage desselben Eintrags gleich. */
const eintraege = (liste) => new Set(liste.map((x) => x.kennung)).size;
ok(eintraege(r.pillen) === ERWARTET.pillen,
`alle ${ERWARTET.pillen} Einträge stehen im Raster `
+ `(${eintraege(r.pillen)} Einträge in ${r.pillen.length} Marken)`);
ok(r.pillen.some((p) => p.text.includes("Wochen-Call")), "der Call ist dabei");
ok(r.pillen.some((p) => p.text.includes("Thumbnail bauen")), "die Frist aus den Aufgaben auch");
/* Jede Art traegt ihre eigene Farbe. Zwei Calls, ein Termin, ein
@@ -291,8 +324,9 @@ for (const [breite, wie] of [[1440, "Computer"], [390, "Handy"]]) {
await seite.click('.k-chip:has-text("Call")');
await seite.waitForTimeout(250);
const nachFilter = await lesen(seite);
ok(nachFilter.pillen.length === ERWARTET.ohneCalls,
`Calls ausgeschaltet: ${ERWARTET.ohneCalls} Einträge übrig (${nachFilter.pillen.length})`);
ok(eintraege(nachFilter.pillen) === ERWARTET.ohneCalls,
`Calls ausgeschaltet: ${ERWARTET.ohneCalls} Einträge übrig `
+ `(${eintraege(nachFilter.pillen)})`);
ok(new RegExp(`· ${ERWARTET.ohneCalls} Einträge`).test(nachFilter.unter),
`und die Kopfzeile zählt neu ("${nachFilter.unter}")`);
await seite.click('.k-chip:has-text("Call")');
@@ -704,6 +738,134 @@ console.log("\n=== Die gerechneten Tage");
}
}
/* =======================================================================
AM HANDY WIRD AUS EINER PILLE EIN PUNKT
=======================================================================
Eine Monatszelle ist am Handy 42-49 px breit. Abzueglich Zellen- und
Pillenrand bleiben 16-23 px fuer Text -- anderthalb Buchstaben und
drei Punkte. "Content-Ideen sammeln" wurde zu "C…".
Seit dem 21.09.2026 wird daraus ein Punkt: Man sieht, DASS an dem
Tag etwas ist und wie viel, und tippt den Tag an, um zu lesen, was.
Ein Zeitraum bleibt ein durchgehender Balken -- sonst ginge genau
das verloren, wofuer er gebaut wurde.
WAS HIER GEMESSEN WIRD, und warum gerade das: Die Groesse allein
genuegt NICHT. Beim Bauen war die Pille bereits 8 x 8 gross und trug
trotzdem ihren Titel quer ueber die Nachbarzellen -- weil eine
Sammelregel aus start.css die Schriftgroesse zurueckholte. Die
Zahlen sagten "alles gut", das Bildschirmfoto sagte das Gegenteil.
Deshalb wird hier beides gefragt: die Groesse UND ob irgendetwas
ueber den Rand der Zelle hinausragt.
======================================================================= */
console.log("\n=== Am Handy wird aus einer Pille ein Punkt");
{
const kPunkt = await browser.newContext({ viewport: { width: 390, height: 1100 } });
const sPunkt = await anmelden(kPunkt, "admin", "CODE-DOGI-0001");
try {
await sPunkt.goto(BASIS + "/workspace/kalender.html", { waitUntil: "networkidle" });
await sPunkt.waitForTimeout(900);
const lage = await sPunkt.evaluate(() => {
const raster = document.querySelector(".k-raster");
if (!raster) return null;
const zellen = [...document.querySelectorAll(".k-tag")];
const pillen = [...document.querySelectorAll(".k-tag .k-pille")];
const punkte = pillen.filter((p) => !p.dataset.spanne);
const balken = pillen.filter((p) => p.dataset.spanne);
/* RAGT IRGENDETWAS UEBER SEINE ZELLE HINAUS? Das ist die Frage,
an der es beim Bauen haengengeblieben ist. Zwei Pixel Luft --
Raender und Rundungen. */
const raus = [];
for (const z of zellen) {
const rz = z.getBoundingClientRect();
for (const e of z.querySelectorAll("*")) {
const r = e.getBoundingClientRect();
if (r.width < 1) continue;
if (r.right > rz.right + 2) {
raus.push(`${e.className}: ${Math.round(r.right - rz.right)}px ueber den Rand`);
}
}
}
const masse = (liste) => liste.map((p) => {
const r = p.getBoundingClientRect();
return { b: Math.round(r.width), h: Math.round(r.height),
zeiger: getComputedStyle(p).pointerEvents,
schrift: getComputedStyle(p).fontSize };
});
return {
raster: Math.round(raster.getBoundingClientRect().width),
zelle: zellen[0] ? Math.round(zellen[0].getBoundingClientRect().width) : 0,
punkte: masse(punkte), balken: masse(balken),
raus: raus.slice(0, 5),
/* Die Zelle muss antippbar bleiben -- der Punkt ist es nicht,
also muss es jemand sein. */
zelleKnopf: zellen.filter((z) => z.getAttribute("role") === "button").length,
zellen: zellen.length,
};
});
ok(!!lage, "das Monatsraster steht am Handy");
if (lage) {
console.log(` Raster ${lage.raster}px, Zelle ${lage.zelle}px, `
+ `${lage.punkte.length} Punkte, ${lage.balken.length} Balken`);
/* DIE ZAHL GEHOERT IN DIE BEDINGUNG: Ohne Eintraege waere unten
alles gruen und nichts geprueft. */
ok(lage.punkte.length > 0,
`es gibt ueberhaupt Eintraege zu messen (${lage.punkte.length})`);
ok(lage.punkte.every((p) => p.b <= 12 && p.h <= 12),
`jeder Termin ist ein Punkt (${lage.punkte.map((p) => p.b + "x" + p.h).join(", ")})`);
ok(lage.punkte.every((p) => p.schrift === "0px"),
`und traegt keinen Text mehr (${[...new Set(lage.punkte.map((p) => p.schrift))].join(", ")})`);
ok(lage.punkte.every((p) => p.zeiger === "none"),
"ein 8-px-Punkt ist nicht einzeln antippbar -- der Tipp gehoert der Zelle");
ok(lage.zelleKnopf === lage.zellen,
`und jede Zelle IST antippbar (${lage.zelleKnopf} von ${lage.zellen})`);
/* DER EIGENTLICHE BEFUND VON DAMALS. */
ok(lage.raus.length === 0, lage.raus.length === 0
? "nichts ragt ueber den Rand seiner Zelle hinaus"
: `ragt hinaus: ${lage.raus.join(" | ")}`);
/* Ein Zeitraum bleibt ein Balken -- breiter als ein Punkt. */
if (lage.balken.length) {
ok(lage.balken.every((b) => b.b > 12),
`ein Zeitraum bleibt ein durchgehender Balken (${lage.balken.map((b) => b.b + "px").join(", ")})`);
}
}
/* GEGENPROBE: Das Raster breiter machen, bis die Abfrage nicht mehr
greift -- dann muessen die Punkte wieder zu Pillen mit Text
werden. Ohne das waere oben nur bewiesen, dass es IRGENDEINE
Regel gibt, nicht dass sie an der Breite haengt. */
const gegen = await sPunkt.evaluate(() => {
const raster = document.querySelector(".k-raster");
if (!raster) return null;
const vorher = raster.style.width;
raster.style.width = "1200px";
/* Layout erzwingen, sonst misst man den Stand von davor. */
void raster.offsetWidth;
const p = document.querySelector(".k-tag .k-pille");
const st = p ? getComputedStyle(p) : null;
const aus = st ? { schrift: st.fontSize, zeiger: st.pointerEvents,
breite: Math.round(p.getBoundingClientRect().width) } : null;
raster.style.width = vorher;
return aus;
});
ok(gegen && gegen.schrift !== "0px" && gegen.zeiger === "auto",
`bei breitem Raster steht der Titel wieder da `
+ `(${gegen ? gegen.schrift + ", " + gegen.breite + "px, " + gegen.zeiger : "nicht messbar"})`);
} finally {
await kPunkt.close();
}
}
await browser.close();
/* Der Testordner bleibt manchmal gesperrt, weil der Server im selben
Prozess noch auf der Datenbank sitzt. Das ist kein Prüfergebnis --