# CLAUDE.md
Ein Userscript, das die phpBB-Seiten von `cs.rin.ru` fuer Safari auf iOS in eine
mobile Ansicht umbaut. Kein Build, keine Abhaengigkeiten, kein `package.json` —
die `.user.js`-Datei ist das Produkt.
| Datei | Greift auf | Zweck |
|---|---|---|
| `rin-mobile.user.js` | `*://cs.rin.ru/forum/*` | Beide Ansichten, Weiche nach Seitentyp |
| `dev/rin-mobile.dev.user.js` | zusaetzlich `localhost:*` | Loader, bindet per `@require file:///` das echte Script ein |
| `dev/viewtopic.php` | — | Fixture: gespeicherter Thread, 1114 Seiten |
Das Fixture ist ueber `.gitignore` (`dev/*.php`) ausgeschlossen. Nach einem
frischen Klon ist es nicht da und muss nach der Anleitung in der README neu
gespeichert werden — die Seite verlangt einen Login.
## Aufbau
Ein IIFE, streng der Reihe nach:
1. `DEBUG`-Flag und `log`-Array
2. Weiche: `view` ist `'thread'`, `'liste'` oder `''` — abgeleitet aus
`location.pathname + location.search`
3. Nur bei gesetztem `view`: Viewport-Meta (idempotent ueber `[data-rm]`) und
der komplette Style-Block als Template-Literal
4. `replaceBody(root)` blendet alle bisherigen `body`-Kinder aus und haengt die
neue Ansicht an
5. `buildList()` beziehungsweise `buildThread()` lesen das Original-DOM und
bauen ein `div.rm-root`; beide haengen zum Schluss ueber `addCrumbs()` die
fixierte Brotkrumenleiste an
6. `run()` waehlt die Ansicht und haengt bei `DEBUG` das gruene Overlay an
7. Start ueber `DOMContentLoaded`, falls `readyState === 'loading'`
Auf Seiten ausserhalb der Weiche (`posting.php`, Profile, …) passiert nichts,
insbesondere wird kein Stylesheet injiziert.
## Fallen, die nicht aus dem Code hervorgehen
**Beide Ansichten teilen sich einen Klassennamensraum.** Das war der Grund fuer
die Zusammenlegung: als getrennte Scripts matchte `rin-mobile` auch
`viewtopic.php` und injizierte dort sein Stylesheet, obwohl es nichts baute.
Gleich benannte Regeln kollidierten mit identischer Spezifitaet, und die
Ladereihenfolge der Userscripts entschied ueber das Layout.
- Geteilt: `.rm-root`, `.rm-hidden`, `.rm-dbg`, die globale `img`-Regel
- Unterschiede zwischen den Ansichten ueber einen Modifier am Root loesen,
nicht ueber zwei Regeln mit demselben Selektor. `.rm-root.rm-thread` haelt
so die 64px hinter der fixierten Leiste frei.
- Namen sind ansichtsspezifisch zu halten: `.rm-jump`/`.rm-pages` gehoeren der
Liste, `.rm-goto`/`.rm-grid` dem Thread-Sheet.
- `.rm-av` braucht `!important` auf Breite und Hoehe, sonst gewinnt die globale
`img { height:auto !important }`-Regel gegen die Avatarmasse.
**Was nach `body` soll, muss nach `replaceBody()` angehaengt werden.**
Die Funktion markiert *alle* vorhandenen `body`-Kinder mit `.rm-hidden`. Das
Sheet wird deshalb erst beim ersten Antippen gebaut — das loest das Problem
nebenbei mit.
**Die Brotkrumenleiste ist fixiert, nicht sticky.** `.rm-root` traegt
`overflow:hidden` und wuerde damit zum Scrollport einer `position:sticky`
-Leiste, in dem nie gescrollt wird — sie klebte nie. Fixierte Nachfahren
klammert das `overflow` dagegen nicht, weil der Root keinen Containing Block
aufspannt. Die Freihaltung oben haengt an `body.rm-crumbed`, damit ohne
Brotkrumen im Markup kein leerer Streifen bleibt.
**`Page X of Y` steht als `Page 1 of 1114`
im Markup.** Ein Grep im Roh-HTML nach `Page 1 of` findet nichts, die Regex auf
`txt(document.body)` greift trotzdem. Nicht vorschnell fuer kaputt halten.
**`per_page` kommt aus der `jumpto()`-Funktion der Seite**
(`var per_page = '15';`). Nur damit lassen sich Seiten-URLs als
`start = (Seite - 1) * per_page` selbst bauen. Die gerenderten Seitenlinks
taugen nicht als Quelle — phpBB zeigt bei 1114 Seiten nur `1, 2, 3, 4, 5 … 1114`.
Ohne `per_page` degradiert die Leiste auf erste Seite plus die
Original-Zurueck/Weiter-Links, das Sheet verschwindet.
**`postRow()` steigt bewusst mehrere `tr` hoch.** Der Beitragstext liegt in
einer verschachtelten Tabelle, `closest('tr')` trifft die innere Zeile ohne
Autor- und Profilspalte.
**`DEBUG` steht auf `true`** und muss vor dem Ausliefern auf `false`. Die
Versionsnummer steht doppelt: im `@version`-Header und im Text des
Debug-Overlays.
## Testen
Es gibt keine Testsuite. Bewaehrt hat sich ein Wegwerf-Harness mit jsdom im
Scratchpad (nicht im Repo ablegen — das Projekt soll abhaengigkeitsfrei
bleiben):
```js
const dom = new JSDOM(html, { url: 'https://cs.rin.ru/forum/viewtopic.php?f=10&t=68689&start=45' });
```
Drei Stolpersteine dabei:
- JSDOM parst asynchron fertig. Nach `eval(src)` rund 60 ms warten, sonst hat
das Script noch auf `DOMContentLoaded` gewartet und nichts gebaut.
- `location.href` ist in JSDOM nicht ueberschreibbar. Fuer Navigationstests im
eingelesenen Quelltext `location.href = u;` durch einen Hook ersetzen.
- `requestAnimationFrame` und `scrollIntoView` fehlen und muessen gestubbt
werden.
Sinnvolle Faelle: erste Seite, zweite Seite, Mitte, letzte Seite, dazu die
Degradation ohne `per_page` und ein Thread ohne Paginierung. Fixture-Eckdaten:
`f=10&t=68689`, `per_page = 15`, 1114 Seiten, letzte Seite `start=16695`.
Fuer die Weiche und die Listenansicht genuegt eine handgeschriebene Tabelle mit
`a.topictitle`-Zeilen. Zu pruefen ist dabei auch eine Seite ausserhalb der
Weiche wie `posting.php`: dort darf weder eine Ansicht gebaut noch ein
`