Die Verwaltung zeichnete sich endlos neu

Gemessen am laufenden Server: nach dem Scan lief eine Schleife mit zwei
Abrufen je Runde, sichtbar als vier dauernd drehende Spinner.

Der Weg dahin: verfolgen() lief bei jedem Aufbau der Mediathekenzeile, sah
den Zustand finished, meldete das über geaendert(), und geaendert() war
mediathekenNeuLaden — also neu zeichnen. Der Neuaufbau startete verfolgen()
erneut, das wieder finished sah. Dass der Lauf längst vorbei war, machte
keinen Unterschied; der Zustand bleibt im Speicher stehen.

Zwei Dinge dagegen. verfolgen() meldet nur noch, wenn es selbst einen Lauf
angestossen hat — beim Aufbau zeigt es den Stand an und schweigt. Und die
Verwaltung frischt über zaehlerAuffrischen() nur noch die Seitenleiste auf
statt die ganze Seite neu zu zeichnen.

Dazu zwei Befunde aus dem Plan, die sich beim Nachsehen als falsch
erwiesen: die Takte werden sehr wohl abbestellt, dafür gibt es seit je
einen MutationObserver, und das Dashboard tauscht seinen Inhalt erst nach
dem Abruf. Geblieben ist der Spinner in den Listen, der bei jedem
Auffrischen erschien — der kommt jetzt nur noch beim ersten Aufbau.

Dazu der Zwischenspeicher für Ansichten. Der Router hängt sie aus statt
sie zu zerstören; beim Zurückkommen stehen sie sofort wieder da, mitsamt
Bildlauf, offenem Reiter und gesetzten Filtern, und laden leise nach.
Gemessen: null Abrufe und 4 von 4 Kacheln beim Zurückkommen aus der
Verwaltung. Höchstens fünf Ansichten, Verfall nach fünf Minuten,
weggeworfen bei allem, was den Bestand ändert. Detailseite und Verwaltung
sind ausgenommen — beide zeigen Laufendes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-10-04 12:11:06 +02:00
co-authored by Claude Opus 5
parent 8b67a7ec88
commit 637e95fbb1
5 changed files with 212 additions and 21 deletions
+37 -7
View File
@@ -5,6 +5,7 @@ import {
} from './api';
import { icons, icon } from './icons';
import { einrichtung } from './views/setup';
import { einhaengen, ablegen, vergessen } from './ansichten';
import { anmeldung } from './views/login';
import { startseite } from './views/home';
import { mediathek } from './views/library';
@@ -76,6 +77,19 @@ export async function mediathekenNeuLaden(): Promise<void> {
zeichnen();
}
/** Frischt nur die Seitenleiste auf — ohne die Ansicht neu zu zeichnen.
*
* **Der Unterschied ist wichtiger, als er aussieht.** Die Verwaltung meldete
* nach jedem Scan „fertig" und liess neu zeichnen; der Neuaufbau startete die
* Verfolgung erneut, die sah wieder „fertig" und meldete wieder — eine
* Endlosschleife mit zwei Abrufen je Runde, die sich als vier dauernd
* drehende Spinner zeigte. Ein neuer Zählwert in der Seitenleiste braucht
* keinen Neuaufbau der Seite. */
export async function zaehlerAuffrischen(): Promise<void> {
mediatheken = await bibliotheken();
leisteBauen();
}
/* ---------- Kopfleiste ---------- */
function kopfleisteBauen(): void {
@@ -166,8 +180,10 @@ function zeichnen(): void {
b.classList.toggle('check', ziel === `#/${teile.slice(0, 2).join('/')}`);
});
// **Aushängen, nicht leeren.** `innerHTML = ''` zerstörte die Ansicht —
// mitsamt Bildlauf, offenem Reiter und gesetzten Filtern.
ablegen();
inhalt.innerHTML = '';
window.scrollTo(0, 0);
const oeffnen = (art: 'filme' | 'serien', id: string) => { location.hash = `#/${art}/${id}`; };
const alleZeigen = (b: Bibliothek) => { location.hash = `#/m/${b.id}`; };
@@ -176,20 +192,34 @@ function zeichnen(): void {
const kennung = teile[1];
if (art && kennung) {
inhalt.appendChild(detailseite(art, kennung, () => history.back()));
// **Die Detailseite wird nicht gemerkt.** Sie ist billig gebaut, und ein
// veralteter Sehfortschritt darauf wäre ärgerlicher als der Neuaufbau.
einhaengen(weg, inhalt, () => detailseite(art, kennung, () => history.back()));
} else if (teile[0] === 'm' && kennung) {
const b = mediatheken.find(x => x.id === kennung);
// Eine Mediathek, die es nicht mehr gibt — etwa, weil sie in einem
// anderen Fenster gelöscht wurde. Zurück auf Start ist hier richtiger
// als eine Fehlermeldung über eine Kennung, die niemand gelesen hat.
if (b) inhalt.appendChild(mediathek(b, serverName, teile[2] ?? 'mediathek', oeffnen));
else location.hash = '#/';
if (b) {
einhaengen(weg, inhalt,
() => mediathek(b, serverName, teile[2] ?? 'mediathek', oeffnen),
{ merken: true });
} else location.hash = '#/';
} else if (teile[0] === 'suche' && kennung) {
inhalt.appendChild(suchseite(decodeURIComponent(kennung), oeffnen));
einhaengen(weg, inhalt, () => suchseite(decodeURIComponent(kennung), oeffnen),
{ merken: true });
} else if (teile[0] === 'verwaltung' && istAdmin()) {
inhalt.appendChild(verwaltung(mediathekenNeuLaden));
// **Die Verwaltung auch nicht** — sie zeigt Laufendes. Ihr Takt hängt am
// Signal und hört auf, sobald man weggeht.
einhaengen(weg, inhalt, signal => verwaltung(() => {
// Gemerkte Ansichten wegwerfen: der Bestand hat sich geändert.
// Die Seitenleiste bekommt neue Zahlen — die Seite selbst bleibt.
vergessen();
void zaehlerAuffrischen();
}, signal));
} else {
inhalt.appendChild(startseite(mediatheken, oeffnen, alleZeigen));
einhaengen(weg, inhalt, () => startseite(mediatheken, oeffnen, alleZeigen),
{ merken: true });
}
inhalt.appendChild(hinweisleiste());