mirror of
https://github.com/Andre-Bzk/rin-mobile-userscript.git
synced 2026-11-15 09:33:08 +01:00
feat: optimize search.php for the mobile view
search.php had no mobile treatment: the query form rendered as an unstyled desktop table, and a submitted search fell back to the regular forum-listing view on the untested assumption that results looked like topic rows. The query form is now recognised by its forum-picker select, the one element the small "search this forum/topic" widgets embedded on other pages don't share — they reuse the same form action and keyword field name and would otherwise be picked up by mistake. Results in the "Posts" display mode the in-thread search bar produces turned out to carry post excerpts, not topic rows, and needed their own card layout instead of running through the list view, which would have misread the topic and profile links inside each hit. Submit/reset controls kept native iOS Safari chrome even under -webkit-appearance:none once restyled, clipping their labels — only visible on device, not in the emulator this project is developed against. Replacing them with real <button> elements (same name/value, so the submitted form data is unchanged) fixed it where the CSS-only attempt didn't; touch targets were sized up to match.
This commit is contained in:
@@ -13,6 +13,8 @@ die `.user.js`-Datei ist das Produkt.
|
|||||||
| `dev/index.php` | — | Fixture: Forumwurzel, zwei Kategorien mit Forenzeilen, keine Paginierung |
|
| `dev/index.php` | — | Fixture: Forumwurzel, zwei Kategorien mit Forenzeilen, keine Paginierung |
|
||||||
| `dev/ucp.php` | — | Fixture: Login-Formular (`mode=login`), nur ausgeloggter Zustand |
|
| `dev/ucp.php` | — | Fixture: Login-Formular (`mode=login`), nur ausgeloggter Zustand |
|
||||||
| `dev/after_login/ucp.php` | — | Fixture: dieselbe URL nach erfolgreichem Login, "Information"-Vorlage statt Formular |
|
| `dev/after_login/ucp.php` | — | Fixture: dieselbe URL nach erfolgreichem Login, "Information"-Vorlage statt Formular |
|
||||||
|
| `dev/search.php` | — | Fixture: Suchformular ohne Treffer, eingeloggt aufgenommen |
|
||||||
|
| `dev/search2.php` | — | Fixture: Suchtreffer im Modus "Posts" (15 von 1438 Treffern, `t=63042`, `per_page=15`, 96 Seiten) |
|
||||||
|
|
||||||
Die Fixtures sind ueber `.gitignore` (`dev/*.php`) ausgeschlossen. Nach einem
|
Die Fixtures sind ueber `.gitignore` (`dev/*.php`) ausgeschlossen. Nach einem
|
||||||
frischen Klon sind sie nicht da und muessen nach der Anleitung in der README neu
|
frischen Klon sind sie nicht da und muessen nach der Anleitung in der README neu
|
||||||
@@ -203,6 +205,90 @@ Original-Zurueck/Weiter-Links, das Sheet verschwindet.
|
|||||||
einer verschachtelten Tabelle, `closest('tr')` trifft die innere Zeile ohne
|
einer verschachtelten Tabelle, `closest('tr')` trifft die innere Zeile ohne
|
||||||
Autor- und Profilspalte.
|
Autor- und Profilspalte.
|
||||||
|
|
||||||
|
**Die Lupe und die Login-Pille haengen an einer gemeinsamen `margin-left:auto`
|
||||||
|
auf einem Wrapper (`.rm-auth-group`), nicht je an sich selbst.** Saesse die
|
||||||
|
Regel wie zuvor direkt auf `.rm-auth`, wuerde nur die Pille an den Rand
|
||||||
|
geschoben und die Lupe bliebe links davon kleben — mit sichtbarer Luecke
|
||||||
|
dazwischen statt „direkt links neben der Pille". Die Lupe existiert im Markup
|
||||||
|
ohnehin nur bei bestehender Sitzung; ausgeloggt bleibt der Wrapper mit der
|
||||||
|
Pille als einzigem Kind und verhaelt sich exakt wie vorher.
|
||||||
|
|
||||||
|
**`#topic-search` steht dreifach identisch im Thread-Markup** (Kopf, Fuss,
|
||||||
|
ueber der Beitragsliste), jedes Mal mit derselben, eigentlich unzulaessigen
|
||||||
|
`id`. `document.querySelector('#topic-search')` trifft einfach das erste und
|
||||||
|
verschiebt es unveraendert in die zweite Leiste — alle drei tragen dieselben
|
||||||
|
versteckten Felder (`t`, `sf`, `terms`), welches der drei benutzt wird, ist
|
||||||
|
gleichgueltig.
|
||||||
|
|
||||||
|
**`select[name="fid[]"]` ist der einzige verlaessliche Marker fuer das grosse
|
||||||
|
Suchformular auf `search.php`.** Sowohl `viewforum.php` als auch
|
||||||
|
`viewtopic.php` betten ein eigenes Mini-Suchformular ein (`#forum-search` /
|
||||||
|
`#topic-search`, „Search this forum…" / „Search this topic…"), beide mit
|
||||||
|
`action="./search.php"` und einem Feld `name="keywords"` — nach diesen Merkmalen
|
||||||
|
allein liesse sich das grosse Formular nicht von den kleinen unterscheiden.
|
||||||
|
Der mehrfach waehlbare Forenwaehler existiert dagegen nur im grossen Formular.
|
||||||
|
|
||||||
|
**Die Textfelder des Suchformulars tragen `style="width: 300px"` direkt im
|
||||||
|
Markup.** Eine externe Regel ohne `!important` sticht dagegen nicht, egal wie
|
||||||
|
spezifisch der Selektor ist — `buildSearchForm()` entfernt das
|
||||||
|
`style`-Attribut deshalb, statt gegen es anzuschreiben.
|
||||||
|
|
||||||
|
**Eine abgeschickte Suche liefert keine Themenliste, sondern einen ganz
|
||||||
|
anderen Aufbau.** Die anfaengliche Annahme, Trefferzeilen tragen dieselben
|
||||||
|
`topictitle`-Links wie eine Themenliste und laufen unveraendert durch
|
||||||
|
`buildList()`, stimmte nicht — zumindest nicht im Modus "Posts" (`sr=posts`),
|
||||||
|
der ueber die zweite Leiste im Thread entsteht, weil deren Formular kein `sr`
|
||||||
|
setzt. Jeder Treffer ist stattdessen ein Beitragsauszug: Autor, Zeitstempel,
|
||||||
|
Forum/Thema-Kontext, ein Stueck `postbody`. `buildSearchResults()` erkennt
|
||||||
|
diesen Modus an `p.topictitle` — als `<p>`, nicht als `<a>` wie das
|
||||||
|
gleichnamige Klassenpendant einer Themenzeile in `viewforum.php` — und baut
|
||||||
|
daraus eigene Karten (`buildHit()`), bevor `buildList()`s allgemeines
|
||||||
|
Zeileneinsammeln ueberhaupt anfaengt und die enthaltenen `viewtopic.php`-Links
|
||||||
|
falsch klassifizieren wuerde. Ungeprueft bleibt der Modus "Topics" (`sr=topics`,
|
||||||
|
Vorauswahl im grossen Suchformular) — dafuer liegt keine Fixture vor, dort
|
||||||
|
sehen Treffer laut phpBB-Doku tatsaechlich wie topictitle-Zeilen aus und
|
||||||
|
wuerden vermutlich durch den regulaeren Listenzweig laufen, das ist aber nicht
|
||||||
|
verifiziert.
|
||||||
|
|
||||||
|
**Ein Treffer im Modus "Posts" besteht aus drei `<tr>`, unterscheidbar nur an
|
||||||
|
der Position, nicht an einer Klasse.** Titelzeile (`p.topictitle`), Autor-
|
||||||
|
und Betreffzeile, dann Antworten/Views samt Beitragsauszug — alle drei
|
||||||
|
tragen row1/row2 wahllos, die einzige verlaessliche Zuordnung ist
|
||||||
|
`nextElementSibling` von der Titelzeile aus.
|
||||||
|
|
||||||
|
**Der Beitragsauszug haengt in `<td class="postbody">`, nicht in
|
||||||
|
`div`/`span.postbody` wie im echten Thread.** `buildHit()` verschiebt das
|
||||||
|
`<td>` trotzdem unveraendert per `appendChild()` in `.rm-body` — das ist reine
|
||||||
|
DOM-Manipulation, keine Neuparse, darum meckert der Browser nicht ueber ein
|
||||||
|
`<td>` ausserhalb einer Tabelle. Es rendert danach aber weiterhin als
|
||||||
|
`display:table-cell`, wenn `.rm-root.rm-hits .rm-body > td` das nicht
|
||||||
|
ausdruecklich auf `block` zwingt.
|
||||||
|
|
||||||
|
**"Replies: 5403" und "Views: 951837" stehen im Markup nur durch ein `<br />`
|
||||||
|
getrennt, ohne Leerzeichen.** `txt()` normalisiert Whitespace, erzeugt aber
|
||||||
|
keinen wo im Original-Markup keiner steht — `txt(meta)` liefert deshalb
|
||||||
|
`5403Views:951837` statt zwei getrennter Werte. `buildHit()` greift beide
|
||||||
|
Zahlen einzeln per Regex heraus und reicht sie an dieselbe `metaRow()` wie bei
|
||||||
|
Themenkarten weiter, die den Trenner per CSS (`::before`) selbst einfuegt.
|
||||||
|
|
||||||
|
**`input[type="submit"]`/`input[type="reset"]` setzen eigenes Padding und
|
||||||
|
Zentrierung in iOS Safari unzuverlaessig um — auch mit `-webkit-appearance:
|
||||||
|
none`.** Zuerst aufgefallen bei Suchen/Zuruecksetzen im Suchformular
|
||||||
|
nebeneinander, wo die feste Flex-Aufteilung die Verzerrung besonders sichtbar
|
||||||
|
machte: zu schmale Buttons, Text nicht mittig. `-webkit-appearance:none` plus
|
||||||
|
`box-sizing:border-box`/`line-height:normal` (erster Versuch) reichte laut
|
||||||
|
Test am Geraet nicht aus — das legt einen tieferen WebKit-Bug nahe, bei dem
|
||||||
|
`input[type=submit/reset]` die native Knopfoptik trotz `appearance:none` nicht
|
||||||
|
vollstaendig ablegt. Der tragfaehige Fix ist `inputToButton()`: die
|
||||||
|
Original-`<input>`-Elemente werden vor dem Verschieben durch echte
|
||||||
|
`<button type="submit/reset">` ersetzt (Name und Value wandern mit, am
|
||||||
|
uebermittelten Formularfeld aendert sich nichts) — `<button>` wird von WebKit
|
||||||
|
unter `appearance:none` zuverlaessig respektiert. Betrifft grundsaetzlich
|
||||||
|
jeden Submit-Button im Script: Suchformular, Login, Thread-Suchleiste nutzen
|
||||||
|
alle `inputToButton()`. Ungeprueft, ob `-webkit-appearance:none` allein bei
|
||||||
|
einer anderen iOS-Version genuegt haette — der Wechsel auf `<button>` umgeht
|
||||||
|
die Frage, statt sie zu beantworten.
|
||||||
|
|
||||||
**`DEBUG` steht auf `true`** und muss vor dem Ausliefern auf `false`. Die
|
**`DEBUG` steht auf `true`** und muss vor dem Ausliefern auf `false`. Die
|
||||||
Versionsnummer steht doppelt: im `@version`-Header und im Text des
|
Versionsnummer steht doppelt: im `@version`-Header und im Text des
|
||||||
Debug-Overlays.
|
Debug-Overlays.
|
||||||
@@ -267,6 +353,27 @@ Kategorien mit zusammen 16 Forenkarten, keine Paginierung. Zu pruefen ist
|
|||||||
zusaetzlich eine `ucp.php?mode=login&redirect=index.php`-URL — sie muss trotz
|
zusaetzlich eine `ucp.php?mode=login&redirect=index.php`-URL — sie muss trotz
|
||||||
des `index.php`-Substrings im Login-Zweig landen, nicht im Listen-Zweig.
|
des `index.php`-Substrings im Login-Zweig landen, nicht im Listen-Zweig.
|
||||||
|
|
||||||
|
Fuer das Suchformular genuegt `dev/search.php` unveraendert, URL
|
||||||
|
`search.php`: geprueft werden der Forenwaehler als Erkennungsmerkmal, das
|
||||||
|
verschobene Formular samt versteckter Felder (`t`, `sid`), die entfernten
|
||||||
|
inline-`style`-Attribute der Textfelder und die Schnellzugriffs-Chips aus
|
||||||
|
`p.searchbar`. Zu pruefen ist ausserdem `dev/viewforum.php` auf derselben
|
||||||
|
Weiche: dessen eingebettetes `#forum-search`-Mini-Formular teilt sich Aktion
|
||||||
|
und `keywords`-Feld mit dem grossen Suchformular und darf `buildSearchForm()`
|
||||||
|
nicht faelschlich auslösen, die Forenliste muss wie gewohnt Karten liefern.
|
||||||
|
|
||||||
|
Fuer Suchtreffer genuegt `dev/search2.php` unveraendert, URL beliebig (die
|
||||||
|
Erkennung haengt nicht an `location`, sondern an `p.topictitle` im Markup):
|
||||||
|
geprueft werden alle 15 Trefferkarten, die verschobene "Searched topic /
|
||||||
|
Search term used"-Zelle samt ihrer beiden Links, Autor und Zeitstempel pro
|
||||||
|
Treffer, die per Regex getrennten Antworten-/Views-Zahlen, der verschobene
|
||||||
|
`td.postbody`-Beitragsauszug und die Seitennavigation (`per_page=15`, 96
|
||||||
|
Seiten). Zu pruefen ist ausserdem, dass `dev/search.php` (das leere Formular)
|
||||||
|
weiterhin den Formular-Zweig trifft und nicht in die Treffer-Erkennung faellt,
|
||||||
|
und dass `dev/viewforum.php` weiterhin normale Karten liefert — beide haben
|
||||||
|
kein `p.topictitle`. Der Modus "Topics" (`sr=topics`) ist mangels Fixture
|
||||||
|
ungeprueft.
|
||||||
|
|
||||||
Am Geraet zu pruefen bleibt, was Blink nicht zeigt: `env(safe-area-inset-*)`,
|
Am Geraet zu pruefen bleibt, was Blink nicht zeigt: `env(safe-area-inset-*)`,
|
||||||
fixierte Leisten gegen Safaris ein- und ausfahrende Toolbar,
|
fixierte Leisten gegen Safaris ein- und ausfahrende Toolbar,
|
||||||
`-webkit-backdrop-filter`, Schriftskalierung. Details und die
|
`-webkit-backdrop-filter`, Schriftskalierung. Details und die
|
||||||
|
|||||||
@@ -72,6 +72,14 @@ account name accordingly. The name is parsed from the link text with a
|
|||||||
if it ever fails to match — a different language, a different bracket style —
|
if it ever fails to match — a different language, a different bracket style —
|
||||||
the pill still shows "Logout", just without a name, rather than breaking.
|
the pill still shows "Logout", just without a name, rather than breaking.
|
||||||
|
|
||||||
|
Once a session exists, the login pill also carries a magnifier button
|
||||||
|
directly to its left, so it does not compete with the breadcrumb trail for
|
||||||
|
space and only shows up where cs.rin.ru's own search is actually reachable.
|
||||||
|
Outside a thread it links straight to `search.php`; inside one it instead
|
||||||
|
reveals a second bar under the crumbs with a search field, reusing the
|
||||||
|
original "Search this topic…" form in place rather than rebuilding it, so the
|
||||||
|
hidden topic-id and scope fields stay intact.
|
||||||
|
|
||||||
The login form itself is not rebuilt from scratch: the original `<form>`
|
The login form itself is not rebuilt from scratch: the original `<form>`
|
||||||
element is moved into the new layout and restyled, table rows collapsed to a
|
element is moved into the new layout and restyled, table rows collapsed to a
|
||||||
vertical stack. Reusing the element rather than reconstructing it keeps the
|
vertical stack. Reusing the element rather than reconstructing it keeps the
|
||||||
@@ -87,6 +95,25 @@ header followed by a message cell), not by its wording, and restyles it the
|
|||||||
same way as the form: the original cell — message and link included — is
|
same way as the form: the original cell — message and link included — is
|
||||||
reused in place rather than rebuilt.
|
reused in place rather than rebuilt.
|
||||||
|
|
||||||
|
`search.php` gets its own treatment when it shows the query form rather than
|
||||||
|
results. It is recognised by its forum picker — a `select[name="fid[]"]`
|
||||||
|
multi-select that only exists on this form, not on the small "Search this
|
||||||
|
forum…" / "Search this topic…" widgets embedded elsewhere — and then moved
|
||||||
|
into the new layout the same way the login form is: table rows collapsed to a
|
||||||
|
vertical stack, radio groups and selects restyled for touch, and the quick
|
||||||
|
links above it ("View new posts", "View your posts", …) turned into a row of
|
||||||
|
chips.
|
||||||
|
|
||||||
|
A submitted search lands back on `search.php`, now with results — which, in
|
||||||
|
the "Posts" display mode the in-thread search bar produces, look nothing like
|
||||||
|
a topic list: each hit is a post excerpt with its own author, timestamp, and
|
||||||
|
forum/topic context. Recognised by a `p.topictitle` marker unique to this
|
||||||
|
mode, these get their own cards, built before the regular list view's row
|
||||||
|
scanning would otherwise misread the topic and profile links inside them. The
|
||||||
|
"Topics" display mode is not handled specially — no fixture shows what it
|
||||||
|
looks like, so it still falls through to the regular list view, which may or
|
||||||
|
may not render it sensibly.
|
||||||
|
|
||||||
The script runs at `document-start`, injects a mobile viewport meta tag, and
|
The script runs at `document-start`, injects a mobile viewport meta tag, and
|
||||||
carries a `DEBUG` flag. While `DEBUG` is `true`, a green diagnostic overlay is
|
carries a `DEBUG` flag. While `DEBUG` is `true`, a green diagnostic overlay is
|
||||||
prepended to the page showing which view was chosen and how many rows were
|
prepended to the page showing which view was chosen and how many rows were
|
||||||
@@ -291,6 +318,15 @@ gegen das Markup einer echten eingeloggten Sitzung bestätigt ist; greift es
|
|||||||
einmal nicht — andere Sprache, andere Klammerform — bleibt die Pille bei
|
einmal nicht — andere Sprache, andere Klammerform — bleibt die Pille bei
|
||||||
„Logout" stehen, nur ohne Namen, statt zu reißen.
|
„Logout" stehen, nur ohne Namen, statt zu reißen.
|
||||||
|
|
||||||
|
Besteht eine Sitzung, trägt die Login-Pille zusätzlich einen Lupen-Button
|
||||||
|
direkt links neben sich, damit er nicht mit der Brotkrumenleiste um Platz
|
||||||
|
konkurriert, und erscheint nur dort, wo cs.rins eigene Suche überhaupt
|
||||||
|
erreichbar ist. Außerhalb eines Threads führt er direkt zu `search.php`;
|
||||||
|
innerhalb eines Threads blendet er stattdessen eine zweite Leiste unter den
|
||||||
|
Brotkrumen mit einem Suchfeld ein — das ist das Original-Formular „Search this
|
||||||
|
topic…", unverändert an Ort und Stelle wiederverwendet statt neu gebaut, damit
|
||||||
|
die versteckten Felder für Themen-Id und Suchbereich erhalten bleiben.
|
||||||
|
|
||||||
Das Login-Formular selbst wird nicht neu gebaut: das Original-`<form>`-Element
|
Das Login-Formular selbst wird nicht neu gebaut: das Original-`<form>`-Element
|
||||||
wandert unverändert in das neue Layout und wird umgestylt, Tabellenzeilen
|
wandert unverändert in das neue Layout und wird umgestylt, Tabellenzeilen
|
||||||
werden zu einer senkrechten Abfolge zusammengeklappt. Die Wiederverwendung
|
werden zu einer senkrechten Abfolge zusammengeklappt. Die Wiederverwendung
|
||||||
@@ -308,6 +344,26 @@ Nachrichtenzelle), und stylt sie wie das Formular um: die Original-Zelle —
|
|||||||
Nachricht und Link inklusive — wandert unverändert an ihren Platz statt neu
|
Nachricht und Link inklusive — wandert unverändert an ihren Platz statt neu
|
||||||
gebaut zu werden.
|
gebaut zu werden.
|
||||||
|
|
||||||
|
`search.php` bekommt eine eigene Behandlung, wenn es das Suchformular statt
|
||||||
|
Treffern zeigt. Erkannt wird das am Forenwähler — einem Mehrfachauswahlfeld
|
||||||
|
`select[name="fid[]"]`, das es nur in diesem Formular gibt, nicht in den
|
||||||
|
kleinen „Search this forum…" / „Search this topic…"-Widgets an anderer
|
||||||
|
Stelle — und dann wie das Login-Formular in das neue Layout verschoben:
|
||||||
|
Tabellenzeilen zu einer senkrechten Abfolge zusammengeklappt, Radio-Gruppen
|
||||||
|
und Auswahlfelder für Touch umgestylt, die Schnellzugriffe darüber („View new
|
||||||
|
posts", „View your posts", …) zu einer Reihe aus Chips.
|
||||||
|
|
||||||
|
Eine abgeschickte Suche landet wieder auf `search.php`, diesmal mit Treffern —
|
||||||
|
die im Anzeigemodus „Posts", den die Suchleiste im Thread erzeugt, aber
|
||||||
|
überhaupt nicht wie eine Themenliste aussehen: jeder Treffer ist ein
|
||||||
|
Beitragsauszug mit eigenem Autor, Zeitstempel und Forum-/Thema-Kontext.
|
||||||
|
Erkannt an einem Merkmal (`p.topictitle`), das es nur in diesem Modus gibt,
|
||||||
|
bekommen sie eigene Karten, gebaut bevor das Zeileneinsammeln der gewöhnlichen
|
||||||
|
Listenansicht die enthaltenen Themen- und Profillinks falsch deuten würde.
|
||||||
|
Der Anzeigemodus „Topics" bekommt keine eigene Behandlung — keine Fixture
|
||||||
|
zeigt, wie er aussieht, er läuft also weiterhin durch die gewöhnliche
|
||||||
|
Listenansicht, was passend sein kann oder auch nicht.
|
||||||
|
|
||||||
Das Script läuft bei `document-start`, setzt ein mobiles Viewport-Meta-Tag und
|
Das Script läuft bei `document-start`, setzt ein mobiles Viewport-Meta-Tag und
|
||||||
hat ein `DEBUG`-Flag. Solange `DEBUG` auf `true` steht, wird ein grünes
|
hat ein `DEBUG`-Flag. Solange `DEBUG` auf `true` steht, wird ein grünes
|
||||||
Diagnose-Overlay über die Seite gelegt, das zeigt, welche Ansicht gewählt wurde
|
Diagnose-Overlay über die Seite gelegt, das zeigt, welche Ansicht gewählt wurde
|
||||||
|
|||||||
+308
-8
@@ -1,7 +1,7 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name RIN Mobile
|
// @name RIN Mobile
|
||||||
// @description Mobile Ansicht fuer cs.rin.ru: Themenlisten als Karten, Threads als Beitragsstrom
|
// @description Mobile Ansicht fuer cs.rin.ru: Themenlisten als Karten, Threads als Beitragsstrom
|
||||||
// @version 3.9
|
// @version 3.13
|
||||||
// @match *://cs.rin.ru/forum/*
|
// @match *://cs.rin.ru/forum/*
|
||||||
// @run-at document-start
|
// @run-at document-start
|
||||||
// ==/UserScript==
|
// ==/UserScript==
|
||||||
@@ -17,6 +17,23 @@
|
|||||||
function txt(el) { return (el ? el.textContent || '' : '')
|
function txt(el) { return (el ? el.textContent || '' : '')
|
||||||
.replace(/\s+/g, ' ').trim(); }
|
.replace(/\s+/g, ' ').trim(); }
|
||||||
|
|
||||||
|
// input[type=submit]/[type=reset] behalten in iOS Safari trotz
|
||||||
|
// -webkit-appearance:none teils ihre native Knopfoptik und setzen eigenes
|
||||||
|
// Padding und Zentrierung nur unzuverlaessig um — ein echtes <button> wird
|
||||||
|
// unter appearance:none dagegen zuverlaessig respektiert. name und value
|
||||||
|
// wandern mit, damit sich am uebermittelten Formularfeld nichts aendert.
|
||||||
|
function inputToButton(input) {
|
||||||
|
if (!input) return null;
|
||||||
|
var btn = document.createElement('button');
|
||||||
|
btn.type = input.type;
|
||||||
|
if (input.name) btn.name = input.name;
|
||||||
|
if (input.hasAttribute('value')) btn.value = input.value;
|
||||||
|
btn.className = input.className;
|
||||||
|
btn.textContent = input.value;
|
||||||
|
input.replaceWith(btn);
|
||||||
|
return btn;
|
||||||
|
}
|
||||||
|
|
||||||
// Der Seitentyp entscheidet, welche Ansicht gebaut wird. Beide Ansichten
|
// Der Seitentyp entscheidet, welche Ansicht gebaut wird. Beide Ansichten
|
||||||
// liegen in einem Script, weil sie sich Grundstile und Klassennamen teilen.
|
// liegen in einem Script, weil sie sich Grundstile und Klassennamen teilen.
|
||||||
// Als getrennte Scripts waren auf Threadseiten beide Stylesheets aktiv und
|
// Als getrennte Scripts waren auf Threadseiten beide Stylesheets aktiv und
|
||||||
@@ -131,8 +148,12 @@
|
|||||||
font-size:16px; padding:9px 12px; border-radius:10px;
|
font-size:16px; padding:9px 12px; border-radius:10px;
|
||||||
color:#eee; background:rgba(120,120,120,.18);
|
color:#eee; background:rgba(120,120,120,.18);
|
||||||
border:1px solid rgba(160,160,160,.35); }
|
border:1px solid rgba(160,160,160,.35); }
|
||||||
.rm-search-bar input[type="submit"] {
|
.rm-search-bar button[type="submit"] {
|
||||||
flex:none; font-size:14px; font-weight:650; padding:9px 16px;
|
-webkit-appearance:none; appearance:none;
|
||||||
|
display:flex; align-items:center; justify-content:center;
|
||||||
|
box-sizing:border-box; line-height:normal; text-align:center;
|
||||||
|
flex:none; min-height:44px; font-size:14px; font-weight:650;
|
||||||
|
padding:12px 16px;
|
||||||
border-radius:10px; color:#fff; border:0;
|
border-radius:10px; color:#fff; border:0;
|
||||||
background:rgba(120,170,255,.85); }
|
background:rgba(120,170,255,.85); }
|
||||||
|
|
||||||
@@ -297,10 +318,104 @@
|
|||||||
text-decoration:none !important; color:inherit !important; }
|
text-decoration:none !important; color:inherit !important; }
|
||||||
.rm-login form input[type="checkbox"] { width:18px; height:18px;
|
.rm-login form input[type="checkbox"] { width:18px; height:18px;
|
||||||
vertical-align:middle; margin-right:8px; }
|
vertical-align:middle; margin-right:8px; }
|
||||||
.rm-login form input[type="submit"] {
|
.rm-login form button[type="submit"] {
|
||||||
width:100%; font-size:16px; font-weight:650; padding:13px;
|
-webkit-appearance:none; appearance:none;
|
||||||
margin-top:20px; border-radius:10px; color:#fff; border:0;
|
display:flex; align-items:center; justify-content:center;
|
||||||
|
box-sizing:border-box; line-height:normal; text-align:center;
|
||||||
|
width:100%; min-height:48px; font-size:16px; font-weight:650;
|
||||||
|
padding:16px 13px; margin-top:20px; border-radius:10px; color:#fff;
|
||||||
|
border:0; background:rgba(120,170,255,.85); }
|
||||||
|
|
||||||
|
/* === Suchformular (search.php ohne Treffer) === */
|
||||||
|
|
||||||
|
.rm-search-shortcuts { display:flex; flex-wrap:wrap; gap:8px;
|
||||||
|
padding:0 14px 16px; }
|
||||||
|
.rm-search-shortcuts a { font-size:13px; padding:6px 12px; border-radius:99px;
|
||||||
|
border:1px solid rgba(128,128,128,.4);
|
||||||
|
text-decoration:none !important; color:inherit !important; }
|
||||||
|
|
||||||
|
/* Derselbe Tabelle-zu-Block-Trick wie bei .rm-login form, eigener Name
|
||||||
|
statt Wiederverwendung: das Formular hier ist ein anderes und hat
|
||||||
|
andere Feldtypen (radio, select statt checkbox). */
|
||||||
|
.rm-searchform form { display:block;
|
||||||
|
padding:4px 14px calc(80px + env(safe-area-inset-bottom)); }
|
||||||
|
.rm-searchform form table, .rm-searchform form tbody,
|
||||||
|
.rm-searchform form tr, .rm-searchform form td {
|
||||||
|
display:block !important; width:100% !important; }
|
||||||
|
.rm-searchform form td { padding:0 !important; }
|
||||||
|
/* Bleibt sichtbar statt wie beim Login versteckt: die beiden th-Zeilen
|
||||||
|
("Search query", "Search options") sind hier Abschnittstrenner, keine
|
||||||
|
Formular-Kopfzelle ohne eigenen Inhalt. */
|
||||||
|
.rm-searchform form th { display:block !important; padding:16px 0 4px;
|
||||||
|
font-size:12px; font-weight:700;
|
||||||
|
text-transform:uppercase; letter-spacing:.06em;
|
||||||
|
opacity:.55; }
|
||||||
|
.rm-searchform form b.genmed { display:block; margin:14px 0 4px;
|
||||||
|
font-size:14px; font-weight:650; }
|
||||||
|
.rm-searchform form span.gensmall { display:block; margin-bottom:6px;
|
||||||
|
font-size:12px; opacity:.6; }
|
||||||
|
.rm-searchform form input[type="text"] {
|
||||||
|
box-sizing:border-box; width:100%; font-size:16px; padding:11px 12px;
|
||||||
|
border-radius:10px; color:#eee; background:rgba(120,120,120,.18);
|
||||||
|
border:1px solid rgba(160,160,160,.35); }
|
||||||
|
.rm-searchform form select {
|
||||||
|
box-sizing:border-box; width:100%; font-size:16px; padding:9px 12px;
|
||||||
|
margin-top:4px; border-radius:10px; color:#eee;
|
||||||
|
background:rgba(120,120,120,.18); border:1px solid rgba(160,160,160,.35); }
|
||||||
|
.rm-searchform form select[multiple] { font-size:15px; padding:4px; }
|
||||||
|
.rm-searchform form input[type="radio"] { width:18px; height:18px;
|
||||||
|
vertical-align:middle; margin-right:6px; }
|
||||||
|
/* Einzige Zeile ohne Block-Stapelung: Suchen/Zuruecksetzen sollen
|
||||||
|
nebeneinander stehen, nicht wie der Rest des Formulars untereinander. */
|
||||||
|
.rm-searchform form td.cat { display:flex !important; gap:10px;
|
||||||
|
padding-top:10px !important; }
|
||||||
|
/* input[type=submit]/[type=reset] behalten in iOS Safari trotz
|
||||||
|
-webkit-appearance:none teils die native Knopfoptik und setzen Padding,
|
||||||
|
Rahmen und Zentrierung nur unzuverlaessig um — deshalb echte <button>
|
||||||
|
statt der Original-<input>-Elemente, siehe inputToButton(). */
|
||||||
|
.rm-searchform form button[type="submit"],
|
||||||
|
.rm-searchform form button[type="reset"] {
|
||||||
|
-webkit-appearance:none; appearance:none;
|
||||||
|
display:flex; align-items:center; justify-content:center;
|
||||||
|
box-sizing:border-box; line-height:normal; text-align:center;
|
||||||
|
min-height:48px; font-size:16px; font-weight:650;
|
||||||
|
padding:16px 13px; border-radius:10px;
|
||||||
|
border:0; }
|
||||||
|
.rm-searchform form button[type="submit"] { flex:1; color:#fff;
|
||||||
background:rgba(120,170,255,.85); }
|
background:rgba(120,170,255,.85); }
|
||||||
|
.rm-searchform form button[type="reset"] { flex:none; color:#eee;
|
||||||
|
background:rgba(120,120,120,.18);
|
||||||
|
border:1px solid rgba(160,160,160,.45) !important; }
|
||||||
|
|
||||||
|
/* === Suchtreffer (search.php mit Ergebnissen, Modus "Posts") === */
|
||||||
|
|
||||||
|
.rm-hits-info { padding:0 14px 14px; font-size:13px; opacity:.75;
|
||||||
|
overflow-wrap:break-word; }
|
||||||
|
.rm-hits-info a { color:inherit !important; }
|
||||||
|
|
||||||
|
.rm-hit { box-sizing:border-box !important; display:block !important;
|
||||||
|
width:100% !important; padding:14px !important;
|
||||||
|
border-top:1px solid rgba(128,128,128,.25) !important; }
|
||||||
|
.rm-hit-ctx { display:block; margin-bottom:8px; font-size:12px;
|
||||||
|
font-weight:650; text-transform:uppercase; letter-spacing:.03em;
|
||||||
|
opacity:.6; text-decoration:none !important;
|
||||||
|
color:inherit !important; overflow-wrap:break-word; }
|
||||||
|
.rm-hit-head { display:flex; align-items:baseline; justify-content:space-between;
|
||||||
|
gap:8px; }
|
||||||
|
.rm-hit-user { font-size:14px; font-weight:650; }
|
||||||
|
.rm-hit-when { flex:none; font-size:12px; opacity:.55; }
|
||||||
|
/* Wiederverwendet: dieselbe .rm-meta-Regel aus der Themenliste, gleiche
|
||||||
|
"X Antworten · Y Views"-Optik. */
|
||||||
|
.rm-hit .rm-meta { margin-top:4px; }
|
||||||
|
/* .rm-body wird 1:1 vom Thread uebernommen (gleiches Beitragsmarkup),
|
||||||
|
nur der verschobene Container ist hier ein td statt div/span und
|
||||||
|
braucht die Umstellung auf Block, die .rm-body selbst nicht mitbringt. */
|
||||||
|
.rm-root.rm-hits .rm-body { margin-top:8px; }
|
||||||
|
.rm-root.rm-hits .rm-body > td { display:block !important; padding:0 !important; }
|
||||||
|
.rm-hit-go { display:inline-block; margin-top:10px; font-size:12px;
|
||||||
|
padding:5px 10px; border:1px solid rgba(128,128,128,.4);
|
||||||
|
border-radius:99px; text-decoration:none !important;
|
||||||
|
color:inherit !important; }
|
||||||
|
|
||||||
/* === Seitennavigation, beide Ansichten === */
|
/* === Seitennavigation, beide Ansichten === */
|
||||||
|
|
||||||
@@ -1005,7 +1120,190 @@
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// search.php ohne Treffer zeigt nur das Suchformular — keine topictitle-
|
||||||
|
// oder forumlink-Zeilen, an denen buildList() sonst seine Karten festmacht.
|
||||||
|
// Erkannt wird das Formular am Forenwaehler select[name="fid[]"]: der
|
||||||
|
// steckt nur im grossen Suchformular, nicht in den kleinen "Search this
|
||||||
|
// forum/topic..."-Formularen auf Foren- und Themenseiten, die denselben
|
||||||
|
// Formularnamen "keywords" verwenden wuerden und sonst faelschlich
|
||||||
|
// getroffen werden koennten.
|
||||||
|
function buildSearchForm() {
|
||||||
|
var picker = document.querySelector('select[name="fid[]"]');
|
||||||
|
var form = picker && picker.closest('form');
|
||||||
|
if (!form) return false;
|
||||||
|
|
||||||
|
var root = document.createElement('div');
|
||||||
|
root.className = 'rm-root rm-searchform';
|
||||||
|
|
||||||
|
var title = document.createElement('div');
|
||||||
|
title.className = 'rm-login-title';
|
||||||
|
title.textContent = 'Suche';
|
||||||
|
root.appendChild(title);
|
||||||
|
|
||||||
|
// Schnellzugriffe (View new posts, View your posts, ...) stehen als
|
||||||
|
// eigene Linkliste ausserhalb des Formulars und würden sonst mit dem Rest
|
||||||
|
// der Originalseite verschwinden.
|
||||||
|
var quick = document.querySelector('p.searchbar');
|
||||||
|
if (quick) {
|
||||||
|
var links = quick.querySelectorAll('a');
|
||||||
|
if (links.length) {
|
||||||
|
var chips = document.createElement('div');
|
||||||
|
chips.className = 'rm-search-shortcuts';
|
||||||
|
links.forEach(function (a) {
|
||||||
|
var c = document.createElement('a');
|
||||||
|
c.href = a.href;
|
||||||
|
c.textContent = txt(a);
|
||||||
|
chips.appendChild(c);
|
||||||
|
});
|
||||||
|
root.appendChild(chips);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Die Textfelder tragen ein inline style="width: 300px", das jede externe
|
||||||
|
// Breitenregel ohne !important sticht.
|
||||||
|
form.querySelectorAll('input[type="text"]').forEach(function (inp) {
|
||||||
|
inp.removeAttribute('style');
|
||||||
|
});
|
||||||
|
|
||||||
|
form.querySelectorAll('input[type="submit"], input[type="reset"]')
|
||||||
|
.forEach(inputToButton);
|
||||||
|
|
||||||
|
root.appendChild(form);
|
||||||
|
replaceBody(root);
|
||||||
|
addCrumbs();
|
||||||
|
log.push('suche=formular');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eine Suche im Modus "Posts" (Standard beim Suchen ueber die zweite Leiste
|
||||||
|
// im Thread, da deren Formular kein sr setzt) liefert etwas ganz anderes
|
||||||
|
// als eine Themenliste: pro Treffer Autor, Zeitstempel und ein Auszug aus
|
||||||
|
// dem Beitrag selbst, keine topictitle-/forumlink-Zeilen. buildList() wuerde
|
||||||
|
// die darin enthaltenen viewtopic.php-Links trotzdem einsammeln und an
|
||||||
|
// rowKind() falsch klassifizieren, ohne diese eigene Behandlung davor.
|
||||||
|
// Erkannt wird der Treffer-Modus an p.topictitle — als <p>, nicht als <a>
|
||||||
|
// wie das gleichnamige forumlink-Gegenstueck einer Themenzeile.
|
||||||
|
function buildSearchResults() {
|
||||||
|
var hits = document.querySelectorAll('p.topictitle');
|
||||||
|
if (!hits.length) return false;
|
||||||
|
|
||||||
|
var root = document.createElement('div');
|
||||||
|
root.className = 'rm-root rm-hits';
|
||||||
|
|
||||||
|
var summary = document.querySelector('span.titles');
|
||||||
|
var title = document.createElement('div');
|
||||||
|
title.className = 'rm-login-title';
|
||||||
|
title.textContent = summary ? txt(summary) : 'Suchergebnisse';
|
||||||
|
root.appendChild(title);
|
||||||
|
|
||||||
|
// "Searched topic: ... / Search term used: ..." traegt funktionierende
|
||||||
|
// Links (erneute Suche, Sprung zum Thema) und wird deshalb wie das
|
||||||
|
// Formular selbst uebernommen statt aus dem Text nachgebaut.
|
||||||
|
var form = hits[0].closest('form');
|
||||||
|
var infoCell = form && form.querySelector('td.genmed');
|
||||||
|
if (infoCell) {
|
||||||
|
infoCell.classList.add('rm-hits-info');
|
||||||
|
root.appendChild(infoCell);
|
||||||
|
}
|
||||||
|
|
||||||
|
var built = 0;
|
||||||
|
hits.forEach(function (p) {
|
||||||
|
try {
|
||||||
|
var card = buildHit(p);
|
||||||
|
if (card) { root.appendChild(card); built++; }
|
||||||
|
} catch (e) { log.push('treffer: ' + e.message); }
|
||||||
|
});
|
||||||
|
log.push('treffer=' + built);
|
||||||
|
if (!built) return false;
|
||||||
|
|
||||||
|
// Muss vor replaceBody() laufen: pageState() liest das Original-DOM.
|
||||||
|
var pg = pageState();
|
||||||
|
if (pg.total > 1) pageNav(root, pg);
|
||||||
|
|
||||||
|
replaceBody(root);
|
||||||
|
addCrumbs();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ein Treffer besteht aus drei aufeinanderfolgenden <tr> derselben Tabelle:
|
||||||
|
// Titelzeile (Forum/Thema), Autor- und Betreffzeile, Antworten/Views samt
|
||||||
|
// Beitragsauszug. Die Zuordnung laeuft ueber nextElementSibling statt ueber
|
||||||
|
// Klassen, weil alle drei row1/row2-Zeilen sonst gleich aussehen.
|
||||||
|
function buildHit(p) {
|
||||||
|
var titleRow = p.closest('tr');
|
||||||
|
var infoRow = titleRow && titleRow.nextElementSibling;
|
||||||
|
var bodyRow = infoRow && infoRow.nextElementSibling;
|
||||||
|
|
||||||
|
var forumA = p.querySelector('a[href*="viewforum.php"]');
|
||||||
|
var topicA = p.querySelector('a[href*="viewtopic.php"]');
|
||||||
|
if (!topicA) return null;
|
||||||
|
|
||||||
|
var el = document.createElement('div');
|
||||||
|
el.className = 'rm-hit';
|
||||||
|
|
||||||
|
var ctx = document.createElement('a');
|
||||||
|
ctx.className = 'rm-hit-ctx';
|
||||||
|
ctx.href = topicA.href;
|
||||||
|
ctx.textContent = breakable((forumA ? txt(forumA) + ' › ' : '') + txt(topicA));
|
||||||
|
el.appendChild(ctx);
|
||||||
|
|
||||||
|
var author = '', posted = '', subjectA = null;
|
||||||
|
if (infoRow) {
|
||||||
|
var ua = infoRow.querySelector('.postauthor');
|
||||||
|
author = ua ? txt(ua) : '';
|
||||||
|
subjectA = infoRow.querySelector('a[href*="viewtopic.php"]');
|
||||||
|
var pm = txt(infoRow).match(/Posted:\s*(.+)$/i);
|
||||||
|
if (pm) posted = pm[1].trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
var head = document.createElement('div');
|
||||||
|
head.className = 'rm-hit-head';
|
||||||
|
var who = document.createElement('span');
|
||||||
|
who.className = 'rm-hit-user';
|
||||||
|
who.textContent = author || 'Gast';
|
||||||
|
head.appendChild(who);
|
||||||
|
if (posted) {
|
||||||
|
var when = document.createElement('span');
|
||||||
|
when.className = 'rm-hit-when';
|
||||||
|
when.textContent = posted;
|
||||||
|
head.appendChild(when);
|
||||||
|
}
|
||||||
|
el.appendChild(head);
|
||||||
|
|
||||||
|
if (bodyRow) {
|
||||||
|
// txt() haengt "Replies:" und "Views:" ohne Trennzeichen aneinander,
|
||||||
|
// weil das <br /> dazwischen keinen Leerraum hinterlaesst — deshalb
|
||||||
|
// einzeln herausgegriffen und ueber dieselbe metaRow() wie bei
|
||||||
|
// Themenkarten mit " · " verbunden.
|
||||||
|
var metaTxt = txt(bodyRow.querySelector('.postdetails'));
|
||||||
|
var reM = metaTxt.match(/Replies:\s*([\d.,]+)/i);
|
||||||
|
var viM = metaTxt.match(/Views:\s*([\d.,]+)/i);
|
||||||
|
var metaEl = metaRow([reM ? reM[1] + ' Antworten' : '',
|
||||||
|
viM ? viM[1] + ' Views' : '']);
|
||||||
|
if (metaEl) el.appendChild(metaEl);
|
||||||
|
|
||||||
|
var pb = bodyRow.querySelector('.postbody');
|
||||||
|
if (pb) {
|
||||||
|
var wrap = document.createElement('div');
|
||||||
|
wrap.className = 'rm-body';
|
||||||
|
wrap.appendChild(pb);
|
||||||
|
el.appendChild(wrap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var jump = document.createElement('a');
|
||||||
|
jump.className = 'rm-hit-go';
|
||||||
|
jump.href = (subjectA || topicA).href;
|
||||||
|
jump.textContent = 'Zum Beitrag ↓';
|
||||||
|
el.appendChild(jump);
|
||||||
|
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
|
||||||
function buildList() {
|
function buildList() {
|
||||||
|
if (buildSearchForm()) return;
|
||||||
|
if (buildSearchResults()) return;
|
||||||
|
|
||||||
// Dokumentreihenfolge entscheidet: in einer Forenzeile steht der Forenname
|
// Dokumentreihenfolge entscheidet: in einer Forenzeile steht der Forenname
|
||||||
// vor dem Link auf den letzten Beitrag. Ohne diese Reihenfolge faellt die
|
// vor dem Link auf den letzten Beitrag. Ohne diese Reihenfolge faellt die
|
||||||
// Zeile als Thema an, der Forenname verschwindet und nur die Beschreibung
|
// Zeile als Thema an, der Forenname verschwindet und nur die Beschreibung
|
||||||
@@ -1113,7 +1411,7 @@
|
|||||||
inp.placeholder = 'In diesem Thema suchen';
|
inp.placeholder = 'In diesem Thema suchen';
|
||||||
}
|
}
|
||||||
var submit = form.querySelector('input[type="submit"]');
|
var submit = form.querySelector('input[type="submit"]');
|
||||||
if (submit) submit.value = 'Suchen';
|
if (submit) { submit.value = 'Suchen'; inputToButton(submit); }
|
||||||
|
|
||||||
var bar = document.createElement('div');
|
var bar = document.createElement('div');
|
||||||
bar.className = 'rm-search-bar';
|
bar.className = 'rm-search-bar';
|
||||||
@@ -1334,6 +1632,8 @@
|
|||||||
if (!td.children.length && !txt(td)) td.classList.add('rm-hidden');
|
if (!td.children.length && !txt(td)) td.classList.add('rm-hidden');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
inputToButton(form.querySelector('input[type="submit"]'));
|
||||||
|
|
||||||
root.appendChild(form);
|
root.appendChild(form);
|
||||||
replaceBody(root);
|
replaceBody(root);
|
||||||
addCrumbs();
|
addCrumbs();
|
||||||
@@ -1387,7 +1687,7 @@
|
|||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
var d = document.createElement('div');
|
var d = document.createElement('div');
|
||||||
d.className = 'rm-dbg';
|
d.className = 'rm-dbg';
|
||||||
d.textContent = 'RIN Mobile v3.9\n' + log.join('\n');
|
d.textContent = 'RIN Mobile v3.13\n' + log.join('\n');
|
||||||
document.body.insertBefore(d, document.body.firstChild);
|
document.body.insertBefore(d, document.body.firstChild);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user