# iOS Safari Userscripts — cs.rin.ru [English](#english) | [Deutsch](#deutsch) --- ## English A single userscript that rebuilds the phpBB3 pages of `cs.rin.ru` into a mobile layout for Safari on iOS. It replaces the original table layout entirely: the existing page content is hidden and a freshly built DOM is appended to `
`. `rin-mobile.user.js` matches `*://cs.rin.ru/forum/*` and picks its view from the page type: | Page | View | |---|---| | `viewforum.php`, `index.php`, forum root | Topic and forum list as cards | | `search.php` | The query form restyled, or — for a submitted search in "Posts" mode — its hits as cards | | `viewtopic.php` | Thread as a post stream with a fixed bottom navigation bar | | `ucp.php?mode=login` | Login form, restyled in place; on the same URL after a successful submit, the resulting information page instead | | anything else | Untouched — no styles are injected | ### Screenshots | Forum list, with the sections above the topics collapsed | Thread, with the in-topic search bar revealed | |---|---| |
|
|
| **Search form, top: quick links and forum picker** | **Search form, bottom: options and buttons** |
|
|
|
### What it does
The original page is hidden and a mobile layout is built from the same data,
one view per page type:
- **Lists as cards.** Forum and topic rows become cards with title, description,
counts and last post; category headers become section headings.
- **Section strips.** Forums, announcements, stickies and topics are separated
by a header carrying the section name and its card count. Announcements and
stickies start collapsed — they repeat above the topics on *every* page of a
forum. Tapping a header toggles its section, and the state is remembered per
section across forums.
- **Fixed page bar.** First / previous / next / last and a page indicator.
Tapping the indicator opens a sheet with a number field and every page of the
forum or thread, not just the handful phpBB renders.
- **Fixed breadcrumb bar** with a login pill showing the account name. Without
it there is no way back out of a thread, since the original page is hidden.
- **Search from anywhere.** With a session, a magnifier sits next to the pill:
it opens `search.php`, or inside a thread reveals a bar that searches the
topic.
- **Readable posts.** Avatar, author, rank and timestamp above the message;
signatures fold into a collapsed box.
- **Forms are moved, not rebuilt.** Login, search and the page after a
successful login reuse the original elements, so hidden fields and the plain
server-side POST stay intact. The search form starts on Main Forum with
subforums off, and the board rules on the login page fold away.
- **Search hits as cards** in "Posts" display mode, each with a link straight to
the post. "Topics" mode falls through to the regular list view.
The script's own labels are German; anything taken from the board keeps its
original wording — `FOREN` in the first screenshot is the script's name for a
group the board does not label, while `STICKIES` and `TOPICS` are the board's
own words.
It runs at `document-start` and injects a mobile viewport meta tag. A `DEBUG`
flag in the source, off by default, adds a green diagnostic overlay showing the
version, the chosen view and how many rows were converted.
### Installation on iOS
1. Install a userscript manager for Safari on iOS (for example *Userscripts*)
and enable it under *Settings → Safari → Extensions*.
2. Add `rin-mobile.user.js` to the manager's script directory.
3. Grant the extension permission for `cs.rin.ru`.
---
### Development
The script is developed on Windows in Chrome or Edge with Tampermonkey.
`dev/rin-mobile.dev.user.js` is a loader: it contains nothing but a metadata
block that pulls in the real script from disk via `@require`. Editing
`rin-mobile.user.js` and reloading the page is enough — no reinstall in
Tampermonkey.
#### ⚠️ Path adjustment required
The loader in `dev/` references the script by **absolute path**:
```js
// @require file:///C:/Projekte/ios_safari_userscripts/rin-mobile.user.js
```
This path is hardcoded and only valid on the machine it was written for. After
cloning the repository or moving the project folder, adjust the `@require` line
in `dev/rin-mobile.dev.user.js` to your own location.
Use forward slashes and the `file:///` prefix, including the drive letter —
`file:///D:/projects/ios_safari_userscripts/rin-mobile.user.js`. A `@require`
that cannot be resolved causes Tampermonkey to skip the script **entirely and
without an error message on the page**, which looks exactly like the script not
being installed at all.
#### Tampermonkey setup
Three settings are required; missing the first one is the most common cause of
"nothing happens":
1. `chrome://extensions` → Tampermonkey → enable **Allow user scripts**.
On older Chrome versions, enable **Developer mode** at the top right
instead. Without this, Manifest V3 blocks all injection.
2. Same page → enable **Allow access to file URLs**, so `@require file://`
can be resolved.
3. Tampermonkey dashboard → *Settings* → *Externals* → set the update interval
to **always**, otherwise the loader keeps serving a cached copy of the
script.
Then open the loader once via `file:///.../dev/rin-mobile.dev.user.js` —
Tampermonkey intercepts `.user.js` URLs and offers to install it.
Do not run the loader and the plain script side by side. If both are enabled in
Tampermonkey, the code executes twice on the same page, producing duplicate
cards and two debug overlays.
#### Test fixtures
Layout work happens on the live site, with the loader active in Chrome. The
saved pages under `dev/` serve a different purpose: `cs.rin.ru` requires a
login, and its markup is the only source for what the script has to cope with,
so the pages that matter are kept as snapshots — as a reference to read, and as
input for a throwaway jsdom harness when a change needs to be checked against
several pages at once.
1. Open the page while logged in, then in DevTools right-click `` →
*Copy outerHTML*.
2. Save it under the page's own name — `dev/viewtopic.php`, `dev/viewforum.php`,
`dev/index.php`, `dev/ucp.php`, `dev/search.php`.
The loader deliberately matches `cs.rin.ru` only, so these files are not meant
to be opened in the browser. Serving them locally would take `@include` rules
for `localhost`, and those match on page names common enough (`index.php`,
anything containing `search`) that the script would inject its stylesheet into
unrelated local projects.
A snapshot saved while logged out contains `span.link_removed` placeholders
instead of links, and may use different markup for author names than the
logged-in view — worth knowing before puzzling over a fixture that behaves
differently from the real page.
#### Device emulation
DevTools → *Device Toolbar* (`Ctrl+Shift+M`) → *Edit…* → add a custom device
with **430 × 932** and DPR **3** for an iPhone 15 Pro Max, device type *Mobile*,
and an iOS Safari user agent string.
#### What desktop emulation cannot show
Chrome uses Blink, iOS Safari uses WebKit. These points have to be verified on
the device:
- `env(safe-area-inset-bottom)` in `.rm-nav` — always `0` in the emulator, so
the clearance for the home indicator is untested.
- A bottom `position: fixed` bar together with Safari's collapsing toolbar.
- `width: 100vw` — on the desktop the scrollbar counts towards it and creates
phantom overflow, so the debug overlay reports different numbers than iOS.
- `-webkit-text-size-adjust` and Safari's automatic font scaling.
- `-webkit-backdrop-filter` renders in Chrome, but looks different.
For higher fidelity without an iPhone, Playwright ships a real WebKit build for
Windows (`npx playwright install webkit`).
#### Troubleshooting
If nothing happens at all, separate the two possible causes before reading any
code. Check the loader's *Externals* tab in the Tampermonkey dashboard: an
empty or failed entry means the `@require` path is wrong. If the entry is
there and the script still does nothing, set `DEBUG = true` in
`rin-mobile.user.js` — the green overlay appears on every page the script
touches, so its absence means the script never ran, while an overlay reporting
`ansicht=keine` means it ran but the URL matched no view.
If Tampermonkey keeps serving a stale copy despite the update interval, open
the loader's *Externals* tab and trigger an update on the `@require` entry by
hand, or disable and re-enable the loader — both discard the cached copy.
### Repository layout
```
rin-mobile.user.js all views: lists, thread, login, search
CLAUDE.md notes for working on the script
dev/
rin-mobile.dev.user.js loader, @require with absolute path
*.php saved pages, markup reference, not in git
docs/
Screenshot_mobile_*.png the screenshots above
```
---
## Deutsch
Ein Userscript, das die phpBB3-Seiten von `cs.rin.ru` für Safari auf iOS in eine
mobile Ansicht umbaut. Es ersetzt das ursprüngliche Tabellenlayout vollständig:
der vorhandene Seiteninhalt wird ausgeblendet und ein neu gebautes DOM an
`` gehängt.
`rin-mobile.user.js` greift auf `*://cs.rin.ru/forum/*` und wählt die Ansicht
anhand des Seitentyps:
| Seite | Ansicht |
|---|---|
| `viewforum.php`, `index.php`, Forumwurzel | Themen- und Forenliste als Karten |
| `search.php` | Das Suchformular umgestylt oder — bei abgeschickter Suche im Modus „Posts" — die Treffer als Karten |
| `viewtopic.php` | Thread als Beitragsstrom mit fixierter Navigationsleiste |
| `ucp.php?mode=login` | Login-Formular, an Ort und Stelle umgestylt; auf derselben URL nach erfolgreichem Absenden stattdessen die Informationsseite |
| alles andere | Unverändert — es werden keine Stile injiziert |
### Screenshots
| Forenliste, die Abschnitte über den Themen zugeklappt | Thread, mit eingeblendeter Suchleiste |
|---|---|
|
|
|
| **Suchformular, oben: Schnellzugriffe und Forenwähler** | **Suchformular, unten: Optionen und Schaltflächen** |
|
|
|
### Was das Script liefert
Die Originalseite wird ausgeblendet und aus denselben Daten eine mobile Ansicht
gebaut, je eine pro Seitentyp:
- **Listen als Karten.** Foren- und Themenzeilen werden zu Karten mit Titel,
Beschreibung, Zahlen und letztem Beitrag, Kategoriezeilen zu
Zwischenüberschriften.
- **Gruppenköpfe.** Foren, Ankündigungen, Stickies und Themen trennt jeweils ein
Kopf mit dem Namen des Abschnitts und der Zahl seiner Karten. Ankündigungen
und Stickies starten zugeklappt — sie stehen auf *jeder* Seite eines Forums
über den Themen. Ein Tipp auf den Kopf klappt seinen Abschnitt um, der Zustand
gilt je Abschnitt über alle Foren hinweg.
- **Fixierte Seitenleiste.** Erste / vorherige / nächste / letzte Seite und eine
Positionsanzeige. Ein Tipp darauf öffnet ein Sheet mit Zahlenfeld und allen
Seiten des Forums oder Threads, nicht nur der Handvoll, die phpBB rendert.
- **Fixierte Brotkrumenleiste** mit einer Login-Pille, die den Kontonamen zeigt.
Ohne sie führt aus einem Thread kein Weg zurück, weil die Originalseite
ausgeblendet ist.
- **Suche von überall.** Besteht eine Sitzung, sitzt neben der Pille eine Lupe:
sie öffnet `search.php` oder blendet innerhalb eines Threads eine Leiste ein,
die das Thema durchsucht.
- **Lesbare Beiträge.** Avatar, Autor, Rang und Zeitstempel über dem Text,
Signaturen wandern in einen zugeklappten Kasten.
- **Formulare werden verschoben, nicht nachgebaut.** Login, Suche und die Seite
nach erfolgreichem Login übernehmen die Original-Elemente, damit versteckte
Felder und der schlichte serverseitige POST erhalten bleiben. Das Suchformular
startet auf Main Forum ohne Unterforen, die Forenregeln im Login klappen weg.
- **Suchtreffer als Karten** im Anzeigemodus „Posts", jeder mit einem Link
direkt zum Beitrag. Der Modus „Topics" läuft durch die gewöhnliche
Listenansicht.
Die Beschriftungen des Scripts sind deutsch, alles aus dem Forum Übernommene
behält seinen Wortlaut — `FOREN` im ersten Screenshot ist die Bezeichnung des
Scripts für eine Gruppe, die die Seite selbst nicht beschriftet, `STICKIES` und
`TOPICS` sind ihre eigenen Worte.
Das Script läuft bei `document-start` und setzt ein mobiles Viewport-Meta-Tag.
Ein `DEBUG`-Flag im Quelltext, standardmäßig aus, legt ein grünes
Diagnose-Overlay über die Seite: Version, gewählte Ansicht und Zahl der
umgewandelten Zeilen.
### Installation unter iOS
1. Einen Userscript-Manager für Safari unter iOS installieren (zum Beispiel
*Userscripts*) und unter *Einstellungen → Safari → Erweiterungen* aktivieren.
2. `rin-mobile.user.js` in das Script-Verzeichnis des Managers legen.
3. Der Erweiterung die Berechtigung für `cs.rin.ru` erteilen.
---
### Entwicklung
Entwickelt wird unter Windows in Chrome oder Edge mit Tampermonkey.
`dev/rin-mobile.dev.user.js` ist ein Loader: er enthält nur einen
Metadatenblock, der das eigentliche Script per `@require` von der Platte
einbindet. Es genügt, `rin-mobile.user.js` zu bearbeiten und die Seite neu zu
laden — keine Neuinstallation in Tampermonkey nötig.
#### ⚠️ Pfadanpassung erforderlich
Der Loader in `dev/` verweist mit einem **absoluten Pfad** auf das Script:
```js
// @require file:///C:/Projekte/ios_safari_userscripts/rin-mobile.user.js
```
Dieser Pfad ist fest eingetragen und gilt nur auf dem Rechner, für den er
geschrieben wurde. Nach dem Klonen des Repositories oder dem Verschieben des
Projektordners muss die `@require`-Zeile in `dev/rin-mobile.dev.user.js` auf den
eigenen Ablageort angepasst werden.
Dabei Schrägstriche und das Präfix `file:///` inklusive Laufwerksbuchstaben
verwenden — `file:///D:/projekte/ios_safari_userscripts/rin-mobile.user.js`.
Ein `@require`, das nicht aufgelöst werden kann, führt dazu, dass Tampermonkey
das Script **komplett und ohne Fehlermeldung auf der Seite** überspringt. Das
sieht exakt so aus, als wäre gar kein Script installiert.
#### Tampermonkey einrichten
Drei Einstellungen sind nötig; die erste ist die mit Abstand häufigste Ursache
für „es passiert überhaupt nichts":
1. `chrome://extensions` → Tampermonkey → **Nutzerskripte zulassen**
aktivieren. Bei älteren Chrome-Versionen stattdessen den
**Entwicklermodus** oben rechts einschalten. Ohne das blockiert Manifest V3
jede Injektion.
2. Auf derselben Seite → **Zugriff auf Datei-URLs zulassen** aktivieren, damit
`@require file://` aufgelöst werden kann.
3. Tampermonkey-Dashboard → *Einstellungen* → *Externals* → Update-Intervall auf
**immer** stellen, sonst liefert der Loader weiterhin eine zwischen
gespeicherte Fassung des Scripts aus.
Danach den Loader einmal über `file:///.../dev/rin-mobile.dev.user.js` öffnen —
Tampermonkey fängt `.user.js`-URLs ab und bietet die Installation an.
Den Loader nicht parallel zum unveränderten Script betreiben. Sind beide in
Tampermonkey aktiv, läuft der Code doppelt auf derselben Seite, mit doppelten
Karten und zwei Debug-Overlays als Folge.
#### Testfixtures
Die Layoutarbeit findet auf der echten Seite statt, mit dem Loader aktiv in
Chrome. Die gespeicherten Seiten unter `dev/` dienen etwas anderem: `cs.rin.ru`
verlangt einen Login, und sein Markup ist die einzige Quelle dafür, womit das
Script zurechtkommen muss. Die relevanten Seiten liegen deshalb als Mitschnitt
vor — zum Nachlesen und als Eingabe für ein Wegwerf-Harness mit jsdom, wenn
eine Änderung gegen mehrere Seiten auf einmal zu prüfen ist.
1. Die Seite eingeloggt öffnen, in den DevTools mit der rechten Maustaste auf
`` → *Copy outerHTML*.
2. Unter dem Namen der Seite ablegen — `dev/viewtopic.php`,
`dev/viewforum.php`, `dev/index.php`, `dev/ucp.php`, `dev/search.php`.
Der Loader greift bewusst nur auf `cs.rin.ru`, diese Dateien sind also nicht
zum Öffnen im Browser gedacht. Sie lokal auszuliefern verlangte
`@include`-Regeln für `localhost`, und die passen auf Seitennamen, die dort
häufig genug vorkommen (`index.php`, alles mit „search" darin), dass das Script
sein Stylesheet in fremde lokale Projekte injizieren würde.
Ein ausgeloggt gespeicherter Mitschnitt enthält statt der Links
`span.link_removed`-Platzhalter und kann Autorennamen anders auszeichnen als
die eingeloggte Ansicht — gut zu wissen, bevor man über eine Fixture rätselt,
die sich anders verhält als die echte Seite.
#### Geräte-Emulation
DevTools → *Device Toolbar* (`Strg+Umschalt+M`) → *Edit…* → eigenes Gerät mit
**430 × 932** und DPR **3** für ein iPhone 15 Pro Max anlegen, Gerätetyp
*Mobile*, dazu einen iOS-Safari-User-Agent eintragen.
#### Was die Desktop-Emulation nicht zeigt
Chrome verwendet Blink, iOS Safari verwendet WebKit. Diese Punkte müssen am
Gerät geprüft werden:
- `env(safe-area-inset-bottom)` in `.rm-nav` — im Emulator immer `0`, die
Freihaltung für den Home-Indicator bleibt also ungetestet.
- Eine unten fixierte Leiste zusammen mit Safaris ein- und ausfahrender
Toolbar.
- `width: 100vw` — auf dem Desktop zählt die Scrollbar mit und erzeugt
Phantom-Overflow, das Debug-Overlay meldet dort andere Zahlen als unter iOS.
- `-webkit-text-size-adjust` und Safaris automatische Schriftvergrößerung.
- `-webkit-backdrop-filter` rendert in Chrome, sieht aber anders aus.
Für höhere Treue ohne iPhone bringt Playwright einen echten WebKit-Build für
Windows mit (`npx playwright install webkit`).
#### Fehlersuche
Passiert überhaupt nichts, zuerst die beiden möglichen Ursachen trennen, bevor
Code gelesen wird. Im Tampermonkey-Dashboard den Tab *Externals* des Loaders
prüfen: ein leerer oder fehlgeschlagener Eintrag bedeutet, dass der
`@require`-Pfad falsch ist. Ist der Eintrag da und trotzdem passiert nichts, in
`rin-mobile.user.js` `DEBUG = true` setzen — das grüne Overlay erscheint auf
jeder Seite, die das Script anfasst. Bleibt es aus, lief das Script gar nicht;
meldet es `ansicht=keine`, lief es, aber die URL passte auf keine Ansicht.
Liefert Tampermonkey trotz Update-Intervall weiterhin einen veralteten Stand
aus, im Tab *Externals* des Loaders den `@require`-Eintrag von Hand
aktualisieren oder den Loader einmal deaktivieren und wieder aktivieren —
beides verwirft die zwischengespeicherte Fassung.
### Aufbau des Repositories
```
rin-mobile.user.js alle Ansichten: Listen, Thread, Login, Suche
CLAUDE.md Notizen zur Arbeit am Script
dev/
rin-mobile.dev.user.js Loader, @require mit absolutem Pfad
*.php gespeicherte Seiten, Markup-Vorlage, nicht in git
docs/
Screenshot_mobile_*.png die Screenshots oben
```