diff --git a/server/pruef-fingermass.mjs b/server/pruef-fingermass.mjs new file mode 100644 index 00000000..223420b6 --- /dev/null +++ b/server/pruef-fingermass.mjs @@ -0,0 +1,151 @@ +/* ===================================================================== + pruef-fingermass.mjs — Wer am Handy misst, braucht einen Finger + + WAS HIER SCHIEFGING (29.09.2026 gemessen): + In chat.css stand neben den 44-Pixel-Knoepfen der Nachrichten- + fusszeile eine Rechnung: „Fuenf mal 44 plus vier Abstaende sind + 236 px — eine Blase hat auf 412 px innen 251 px. Die Reihe bleibt + damit einzeilig." Sie vergisst die Uhrzeit (57 px), und 236 + 57 + sind 293. Gemessen waren es drei Zeilen, 96 Pixel hoch, unter + JEDER einzelnen Nachricht. + + WARUM DAS VIER TAGE UNBEMERKT BLIEB: Die Regel ist nie gelaufen. + `page.setViewportSize({ width: 412 })` aendert nur die Groesse. + `hasTouch` gehoert zum KONTEXT und laesst sich danach nicht mehr + setzen — ohne ihn meldet der Browser `pointer: fine`, und KEINE + einzige Regel aus `@media (pointer: coarse)` greift. Dort stehen + im ganzen Haus die 44-Pixel-Beruehrziele. + + Eine Messung mit Mauszeiger auf 412 Pixeln vermisst also eine + Seite, die es auf keinem Telefon gibt — und meldet dabei „in + Ordnung". Das ist die dritte Sorte falscher Haken: nicht + uebersprungen, nicht rot, sondern gruen und wertlos. + + WAS DIESE PRUEFUNG SICHERT: Dass die Zahl solcher Messungen nur + noch SINKT. Sie meldet nicht 18 Fehler auf einmal — eine Warnung, + die immer kommt, wird weggeklickt und nimmt den echten Fund mit. + Sie haelt eine Grundlinie und schlaegt an, sobald eine NEUE + dazukommt. + + UND SIE SCHLAEGT AUCH AN, WENN DIE ZAHL SINKT. Wer eine Messung + repariert und die Grundlinie stehen laesst, deckt damit Platz fuer + die naechste Suende. Das kostet eine Zeile und haelt die Wache + scharf. + ===================================================================== */ + +import { readdirSync, readFileSync } from "node:fs"; +import { join } from "node:path"; + +let ok_ = 0, fehl = 0; +const ok = (b, text) => { if (b) { ok_++; console.log(" ok " + text); } + else { fehl++; console.log(" FEHL " + text); } }; + +const ORDNER = new URL(".", import.meta.url).pathname.replace(/^\/([A-Za-z]:)/, "$1"); + +/* GRUNDLINIE, gemessen am 29.09.2026. Diese Zahl darf nur kleiner + werden. Wird sie kleiner, gehoert sie hier angepasst — die + Pruefung sagt es dann selbst. + + EIN GREP HATTE 18 GEZAEHLT. Zwei davon waren Zahlen in + Kommentaren („gemessen bei 412 px"), keine Fenster. Deshalb liest + diese Pruefung nur die Stelle, die ein Fenster AUFMACHT, und + blendet Kommentare vorher aus. Die erste Zahl, die eine Wache + liefert, ist selten die richtige — auch hier war die genauere + Lesart um zwei kleiner. */ +const GRUNDLINIE = 16; + +/* Ab wann ist ein Fenster ein Telefon? 860 ist die Grenze, die im + Haus schon in mess-reaktion und mess-chat-optik steht. Darueber + hat ein Geraet mit hoher Wahrscheinlichkeit einen Zeiger. */ +const SCHMAL = /(?:width|breite)\s*[:=]\s*(\d{3})\b/g; +const MISST = /getBoundingClientRect|offsetWidth|offsetHeight|clientWidth|clientHeight|scrollWidth|scrollHeight|boundingBox/; + +/* NUR DIE STELLE, DIE EIN FENSTER AUFMACHT — nicht jede Zahl im + Text. `width: 412` in einem Kommentar ueber eine Messung von + gestern ist keine Messung. */ +const fensterBreiten = (text) => { + const raus = []; + const ohneKommentar = text.replace(/\/\*[\s\S]*?\*\//g, " ").replace(/^\s*\/\/.*$/gm, " "); + for (const m of ohneKommentar.matchAll(/(?:newContext|setViewportSize|viewport)\s*[({][^)}]{0,200}/g)) { + for (const z of m[0].matchAll(SCHMAL)) raus.push(Number(z[1])); + } + return raus; +}; + +export const fingerlos = (text) => { + const breiten = fensterBreiten(text); + if (!breiten.some((b) => b <= 860)) return false; + if (/hasTouch/.test(text)) return false; + return MISST.test(text); +}; + +console.log("\n=== 1. Wer misst am Telefon ohne Finger? ==="); +const dateien = readdirSync(ORDNER) + .filter((n) => /^(pruef|mess)-.*\.mjs$/.test(n) && n !== "pruef-fingermass.mjs"); + +/* DRITTER AUSGANG: Findet sie nichts zum Ansehen, ist das kein + „alles in Ordnung", sondern „konnte nicht nachsehen". */ +if (dateien.length < 50) { + console.log(` FEHL Nur ${dateien.length} Pruefdateien gefunden — der Ordner stimmt nicht.`); + console.log(" Erwartet werden ueber 150 in " + ORDNER); + process.exit(2); +} + +const funde = []; +let mitFinger = 0, amTelefon = 0; +for (const name of dateien) { + const text = readFileSync(join(ORDNER, name), "utf8"); + const breiten = fensterBreiten(text); + if (!breiten.some((b) => b <= 860)) continue; + amTelefon++; + if (/hasTouch/.test(text)) { mitFinger++; continue; } + if (MISST.test(text)) funde.push(name); +} + +console.log(` ${amTelefon} Dateien oeffnen ein Telefonformat, ${mitFinger} davon mit Finger.`); +if (funde.length) console.log(" ohne Finger und mit Massband: " + funde.join(", ")); + +ok(amTelefon > 20, `${amTelefon} Dateien messen am Telefon — die Suche findet ueberhaupt etwas`); + +if (funde.length > GRUNDLINIE) { + ok(false, `${funde.length} Messungen ohne Finger — das sind ${funde.length - GRUNDLINIE} MEHR ` + + `als die Grundlinie ${GRUNDLINIE}. Neu dazugekommen ist eine Messung, die auf ` + + "412 px eine Seite vermisst, die es auf keinem Telefon gibt. `hasTouch: true` " + + "gehoert in den newContext-Aufruf — setViewportSize kann es nicht nachtragen."); +} else if (funde.length < GRUNDLINIE) { + ok(false, `Nur noch ${funde.length} Messungen ohne Finger — die Grundlinie steht auf ` + + `${GRUNDLINIE}. Bitte in pruef-fingermass.mjs auf ${funde.length} senken, sonst deckt ` + + "sie Platz fuer die naechste."); +} else { + ok(true, `${funde.length} Messungen ohne Finger — unveraendert zur Grundlinie ${GRUNDLINIE}`); +} + +console.log("\n=== 2. Gegenprobe: kann sie auch NICHT IN ORDNUNG sagen? ==="); +const faelle = [ + ["der Fall vom 29.09. (schmal, misst, kein Finger)", + 'const s = await b.newContext({ viewport: { width: 412, height: 900 } });\n' + + 'el.getBoundingClientRect()', true], + ["mit Finger", + 'const s = await b.newContext({ viewport: { width: 412, height: 900 }, hasTouch: true });\n' + + 'el.getBoundingClientRect()', false], + ["nur ein Laptopfenster", + 'const s = await b.newContext({ viewport: { width: 1280, height: 900 } });\n' + + 'el.getBoundingClientRect()', false], + ["schmal, misst aber nichts", + 'const s = await b.newContext({ viewport: { width: 390, height: 844 } });\n' + + 'await p.textContent("h1")', false], + ["eine Breite, die nur im Kommentar steht", + '/* gemessen bei width: 412 -- drei Zeilen */\n' + + 'const s = await b.newContext({ viewport: { width: 1440, height: 900 } });\n' + + 'el.getBoundingClientRect()', false], + ["setViewportSize statt newContext — kann hasTouch gar nicht setzen", + 'await p.setViewportSize({ width: 390, height: 844 });\nel.offsetWidth', true], +]; +const daneben = faelle.filter(([, text, soll]) => fingerlos(text) !== soll).map(([n]) => n); +ok(daneben.length === 0, + daneben.length ? `Gegenprobe daneben bei: ${daneben.join(", ")}` + : `Gegenprobe: alle ${faelle.length} Faelle richtig eingeordnet`); + +console.log(`\n${ok_} Pruefungen, ${fehl} Fehler`); +console.log(fehl ? "NICHT IN ORDNUNG\n" : "ALLES IN ORDNUNG\n"); +process.exit(fehl ? 1 : 0); diff --git a/server/pruef-ueberlappung.mjs b/server/pruef-ueberlappung.mjs index 8148f3f3..195d0607 100644 --- a/server/pruef-ueberlappung.mjs +++ b/server/pruef-ueberlappung.mjs @@ -49,10 +49,20 @@ const SEITEN = ["start.html", "kalender.html", "aufgaben.html", "calls.html", "c 1280 = kleinster Laptop. Keine davon ist geraten. */ const BREITEN = [320, 412, 768, 1280]; +/* MIT FINGER, NICHT MIT MAUSZEIGER (29.09.2026). + `viewport` allein macht aus einem Browser kein Telefon. `hasTouch` + gehoert zum KONTEXT und laesst sich spaeter nicht mehr setzen; + ohne ihn meldet der Browser `pointer: fine`, und KEINE Regel aus + `@media (pointer: coarse)` greift. Dort stehen im ganzen Haus die + 44-Pixel-Beruehrziele -- also genau die Groessen, deren + Ueberlappung diese Pruefung sucht. Sie hat bis heute eine Seite + vermessen, die es auf keinem Handy gibt. + Oberhalb von 860 px bleibt es beim Zeiger: Ein Laptop hat keinen. */ const b = await chromium.launch(); let funde = 0, geprueft = 0; for (const breite of BREITEN) { - const sitz = await b.newContext({ viewport: { width: breite, height: 900 } }); + const sitz = await b.newContext({ + viewport: { width: breite, height: 900 }, hasTouch: breite <= 860 }); await sitz.addCookies(kekse); const p = await sitz.newPage(); for (const seite of SEITEN) { @@ -120,7 +130,7 @@ for (const breite of BREITEN) { Seiten. Wer "Meine Sicht" antippte, landete im Chat. Aufgefallen ist das durch Hinsehen -- gemessen hatte es niemand. */ { - const sitz = await b.newContext({ viewport: { width: 412, height: 900 } }); + const sitz = await b.newContext({ viewport: { width: 412, height: 900 }, hasTouch: true }); await sitz.addCookies(kekse); const p = await sitz.newPage(); await p.goto(BASIS + "/workspace/start.html", { waitUntil: "networkidle" });