Files
rin-mobile-userscript/rin-mobile.user.js
T
Andre 46a1ed8d07 fix: resolve author and avatar detection in thread view
The forum nests each post body inside its own table, so ascending to the
nearest enclosing row stopped within that inner table rather than at the
actual post row. The author and profile columns were never in scope, and
every post silently degraded to the placeholder name and the generated
initial avatar instead of the real ones.

Author lookup additionally keyed on a profile link attribute this forum
does not emit at all, so even a correct row would have yielded nothing.
Both conditions failed quietly, which made the result look like a styling
problem rather than a broken DOM traversal.
2026-08-02 13:44:54 +02:00

237 lines
8.2 KiB
JavaScript

// ==UserScript==
// @name RIN Mobile
// @description Mobile Karten-Ansicht fuer cs.rin.ru
// @version 1.4
// @match *://cs.rin.ru/forum/*
// @run-at document-start
// ==/UserScript==
(function () {
'use strict';
var DEBUG = true;
var log = [];
function h() { return document.head || document.documentElement; }
if (!document.querySelector('meta[name="viewport"][data-rm]')) {
var m = document.createElement('meta');
m.name = 'viewport';
m.content = 'width=device-width, initial-scale=1, viewport-fit=cover';
m.setAttribute('data-rm', '1');
h().appendChild(m);
}
var st = document.createElement('style');
st.textContent = `
html, body { max-width:100% !important; overflow-x:hidden !important;
margin:0 !important; padding:0 !important; }
body { font-size:16px !important;
-webkit-text-size-adjust:100% !important; }
img { max-width:100% !important; height:auto !important; }
.rm-dbg { background:#222; color:#0f0; font:12px/1.45 monospace;
padding:8px 10px; white-space:pre-wrap;
border-bottom:2px solid #0f0; }
.rm-root { box-sizing:border-box !important;
display:block !important;
width:100vw !important; max-width:100vw !important;
margin:0 !important; padding:0 !important;
overflow:hidden !important; }
.rm-card { box-sizing:border-box !important;
display:block !important;
width:100% !important; max-width:100% !important;
margin:0 !important;
padding:14px 14px 15px !important;
border-bottom:1px solid rgba(128,128,128,.28) !important; }
.rm-card:active { background:rgba(128,128,128,.14); }
.rm-main { box-sizing:border-box !important;
display:block !important;
width:100% !important; max-width:100% !important;
text-decoration:none !important; color:inherit !important;
font-size:20px !important; font-weight:600 !important;
line-height:1.32 !important;
white-space:normal !important;
word-break:normal !important;
overflow-wrap:break-word !important;
hyphens:none !important; }
.rm-badge { display:inline; font-size:11px; font-weight:700;
text-transform:uppercase; letter-spacing:.04em;
padding:2px 6px; margin-right:6px; border-radius:4px;
background:rgba(200,60,60,.18); color:#e06a6a;
white-space:nowrap; vertical-align:2px; }
.rm-meta { margin-top:8px; font-size:13px; opacity:.7;
overflow-wrap:break-word; }
.rm-meta span + span::before { content:" · "; opacity:.55; }
.rm-foot { margin-top:5px; display:flex; align-items:center;
justify-content:space-between; gap:10px; }
.rm-last { font-size:13px; opacity:.55; min-width:0;
overflow-wrap:break-word; }
.rm-jump { flex:none; font-size:12px; padding:5px 10px;
border:1px solid rgba(128,128,128,.4); border-radius:99px;
text-decoration:none !important; color:inherit !important;
white-space:nowrap; }
.rm-pages { padding:14px; display:flex; flex-wrap:wrap; gap:8px; }
.rm-pages a { padding:6px 11px; border-radius:8px;
border:1px solid rgba(128,128,128,.35);
text-decoration:none !important; color:inherit !important; }
.rm-hidden { display:none !important; }
`;
h().appendChild(st);
function txt(el) { return (el.textContent || '').replace(/\s+/g, ' ').trim(); }
function breakable(s) {
return s.replace(/([|\/\\,;:>\]\)])/g, '$1\u200B');
}
function convert(tr) {
var titleA = tr.querySelector('a.topictitle') ||
tr.querySelector('a[href*="viewtopic.php"]');
if (!titleA) return null;
var titleCell = titleA.closest('td');
var nums = [], author = '', last = '', jump = null;
Array.prototype.forEach.call(tr.children, function (td) {
if (td === titleCell) return;
var t = txt(td);
if (/^\d+$/.test(t)) { nums.push(t); return; }
var pa = td.querySelector('a[href*="profile.php"],a[href*="memberlist.php"]');
if (pa && t.length < 40 && !/\d{4}/.test(t)) { author = t; return; }
if (t) {
last = t;
jump = td.querySelector('a[href*="#p"]') ||
td.querySelector('a[href*="viewtopic.php"]');
}
});
var card = document.createElement('div');
card.className = 'rm-card';
var main = document.createElement('a');
main.className = 'rm-main';
main.href = titleA.href;
var raw = txt(titleA);
var badge = (raw.match(/^\[([^\]]{1,20})\]/) || [])[1];
if (badge) {
var b = document.createElement('span');
b.className = 'rm-badge';
b.textContent = badge;
main.appendChild(b);
raw = raw.replace(/^\[[^\]]{1,20}\]\s*/, '');
}
main.appendChild(document.createTextNode(breakable(raw)));
card.appendChild(main);
var meta = document.createElement('div');
meta.className = 'rm-meta';
function add(s) {
var e = document.createElement('span');
e.textContent = s;
meta.appendChild(e);
}
if (author) add(author);
if (nums[0]) add(nums[0] + ' Antworten');
if (nums[1]) add(nums[1] + ' Views');
if (meta.children.length) card.appendChild(meta);
var foot = document.createElement('div');
foot.className = 'rm-foot';
var l = document.createElement('div');
l.className = 'rm-last';
l.textContent = last;
foot.appendChild(l);
if (jump) {
var j = document.createElement('a');
j.className = 'rm-jump';
j.href = jump.href;
j.textContent = 'Neueste ↓';
foot.appendChild(j);
}
card.appendChild(foot);
return card;
}
function build() {
var onList = /viewforum\.php|search\.php/
.test(location.pathname + location.search) ||
location.pathname === '/forum/';
log.push('listenseite=' + onList);
if (!onList) return;
var links = document.querySelectorAll(
'a.topictitle,a[href*="viewtopic.php"]');
log.push('themenlinks=' + links.length);
if (!links.length) return;
var root = document.createElement('div');
root.className = 'rm-root';
var rows = [], tables = new Set();
links.forEach(function (a) {
var tr = a.closest('tr');
if (!tr || tr.dataset.rm) return;
var tbl = tr.closest('table');
if (!tbl) return;
tr.dataset.rm = '1';
rows.push(tr);
tables.add(tbl);
});
var built = 0;
rows.forEach(function (tr) {
try {
var c = convert(tr);
if (c) { root.appendChild(c); built++; }
} catch (e) { log.push('convert: ' + e.message); }
});
log.push('karten=' + built);
if (!built) return;
var seen = {}, pages = document.createElement('div');
pages.className = 'rm-pages';
document.querySelectorAll('a[href*="start="]').forEach(function (a) {
var t = txt(a);
if (!t || t.length > 4 || seen[t]) return;
seen[t] = 1;
var n = document.createElement('a');
n.href = a.href;
n.textContent = t;
pages.appendChild(n);
});
if (pages.children.length) root.appendChild(pages);
// Originalinhalt ausblenden, Liste als direktes body-Kind einhaengen
Array.prototype.forEach.call(document.body.children, function (el) {
if (el !== root) el.classList.add('rm-hidden');
});
document.body.appendChild(root);
if (DEBUG) {
var c0 = root.querySelector('.rm-card');
log.push('fenster=' + window.innerWidth +
' body=' + document.body.scrollWidth +
' karte=' + (c0 ? Math.round(c0.getBoundingClientRect().width) : '?'));
}
}
function run() {
try { build(); } catch (e) { log.push('build: ' + e.message); }
if (DEBUG) {
var d = document.createElement('div');
d.className = 'rm-dbg';
d.textContent = 'RIN Mobile v1.4\n' + log.join('\n');
document.body.insertBefore(d, document.body.firstChild);
}
}
if (document.readyState === 'loading')
document.addEventListener('DOMContentLoaded', run);
else
run();
})();