refactor: merge the two userscripts into one

The list script matched the whole forum, thread pages included, and injected its
stylesheet there before bailing out of its own build. Both stylesheets were
therefore live on every thread, and rules sharing a class name resolved by
userscript load order rather than by intent — a layout that could differ between
two machines with the same files installed. One of those clashes was already
costing the clearance behind the fixed bar.

A single script picks its view from the page type instead, which turns the
shared class namespace from a hazard into a plain fact of the file, resolved
with a modifier on the root element. Pages outside either view now stay
untouched, where before they still received a full stylesheet.

Two things the merge brought to light: the global image rule was overriding the
avatar dimensions, which only went unnoticed because square avatars happen to
scale to the same result, and a zero-width space had been sitting in the source
as a literal character rather than an escape.

Installations carrying the old thread script have to remove it; the remaining
one keeps its name and updates in place.

Claude-Session: https://claude.ai/code/session_0158owAAsXAfFiT3hGkQt1Xk
This commit is contained in:
Andre
2026-08-02 14:24:29 +02:00
parent bd4fc85d38
commit eff957ed07
6 changed files with 634 additions and 665 deletions
+45 -35
View File
@@ -1,54 +1,59 @@
# CLAUDE.md
Zwei eigenstaendige Userscripts, die die phpBB-Seiten von `cs.rin.ru` fuer
Safari auf iOS in eine mobile Ansicht umbauen. Kein Build, keine
Abhaengigkeiten, kein `package.json` — die `.user.js`-Dateien sind das Produkt.
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/*` | Themenlisten als Karten |
| `rin-thread.user.js` | `*://cs.rin.ru/forum/viewtopic.php*` | Thread als Beitragsstrom + Navigationsleiste |
| `dev/*.dev.user.js` | zusaetzlich `localhost:*` | Loader, binden per `@require file:///` die echten Scripts ein |
| `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.
## Gemeinsames Muster beider Scripts
## Aufbau
Beide sind nach demselben Schema gebaut, Aenderungen am einen sind oft auch am
anderen faellig:
Ein IIFE, streng der Reihe nach:
1. IIFE mit `'use strict'`, `DEBUG`-Flag und `log`-Array ganz oben
2. Viewport-Meta setzen (idempotent ueber `[data-rm]`)
3. Kompletter Style-Block als Template-Literal, **bedingungslos** injiziert
4. `build()` liest das Original-DOM, baut ein neues `div.rm-root`
5. Alle bisherigen `body`-Kinder bekommen `.rm-hidden`, dann wird `root`
angehaengt
6. `run()` haengt bei `DEBUG` das gruene Overlay oben an
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`
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 Stylesheets sind auf Threadseiten gleichzeitig aktiv.**
`rin-mobile` matcht `*://cs.rin.ru/forum/*`, also auch `viewtopic.php`. Sein
`build()` steigt dort zwar aus, der Style-Block wird aber vorher injiziert.
Gleich benannte Klassen kollidieren mit identischer Spezifitaet, entschieden
wird nach Ladereihenfolge der Userscripts — und die ist nicht garantiert.
**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.
- Nur bewusst geteilt: `.rm-root`, `.rm-hidden`, `.rm-dbg`
- **Offene Kollision:** `.rm-root` hat in `rin-mobile` `padding:0 !important`,
in `rin-thread` `padding:0 0 64px 0 !important`. Laedt `rin-mobile` spaeter,
faellt die Freihaltung hinter der fixierten Leiste weg. Noch nicht behoben.
- Neue Klassen im Thread-Script gegen `rin-mobile.user.js` gegenpruefen.
`.rm-goto` und `.rm-grid` heissen genau deshalb so — `.rm-jump` und
`.rm-pages` waren dort schon belegt.
- 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 der Ausblend-Schleife angehaengt werden.**
Die Schleife markiert *alle* vorhandenen `body`-Kinder mit `.rm-hidden`. Das
Sheet im Thread-Script wird deshalb erst beim ersten Antippen gebaut — das
loest das Problem nebenbei mit.
**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.
**`Page X of Y` steht als `Page <strong>1</strong> of <strong>1114</strong>`
im Markup.** Ein Grep im Roh-HTML nach `Page 1 of` findet nichts, die Regex auf
@@ -65,9 +70,9 @@ Original-Zurueck/Weiter-Links, das Sheet verschwindet.
einer verschachtelten Tabelle, `closest('tr')` trifft die innere Zeile ohne
Autor- und Profilspalte.
**`DEBUG` steht in beiden Dateien auf `true`** und muss vor dem Ausliefern in
beiden auf `false`. Die Versionsnummer steht ebenfalls doppelt: im
`@version`-Header und im Text des Debug-Overlays.
**`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
@@ -92,6 +97,11 @@ 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
`<style>` injiziert werden.
Am Geraet zu pruefen bleibt, was Blink nicht zeigt: `env(safe-area-inset-*)`,
fixierte Leisten gegen Safaris ein- und ausfahrende Toolbar,
`-webkit-backdrop-filter`, Schriftskalierung. Details und die