Ein Klick, der nichts tat, und niemand sagte warum
Eine Serienkachel kannte der Server als Titel nicht: „als gesehen markieren" lief in eine 404, und weil das Kontextmenü die Ablehnung verschluckte, geschah sichtbar gar nichts. Dasselbe beim Favoriten. UserItemState bekommt eine Serienkennung, das Häkchen zieht alle Folgen mit, und was wirft, erscheint als Meldung statt in der Browserkonsole. Dazu eine Mehrfachauswahl in der Mediathek — gesehen, ungesehen, Metadaten neu holen für das Gewählte, in einer Anfrage statt in zweihundert. Ein neues Plakat steht sofort auf der Kachel, und ein Titel, den es nicht mehr gibt, endet nicht mehr in einer Sackgasse. Gemessen: ein POST auf /refresh ohne Rumpf antwortete nach der Erweiterung mit 404 — also genau der Aufruf „alles auffrischen", den es länger gibt als die Auswahl. Der Rumpf wird jetzt von Hand gelesen, und beide Formen stehen in einer Prüfung. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
c854c4a09a
commit
557708b769
+42
-16
@@ -23,6 +23,8 @@ export type Kachel = {
|
||||
stand?: Stand | null;
|
||||
/** Die Zahl offener Folgen, als Plakette oben rechts. */
|
||||
offen?: number | null;
|
||||
/** Wie viele Folgen es überhaupt sind — um die Plakette wiederherzustellen. */
|
||||
gesamt?: number | null;
|
||||
/** `null` heisst: wartet auf Freigabe. Ein Zeitpunkt in der Zukunft: geplant. */
|
||||
freigabe?: string | null;
|
||||
};
|
||||
@@ -35,8 +37,9 @@ export const alsKachel = (e: Film | Serie): Kachel => ({
|
||||
titel: e.title,
|
||||
zweite: e.year ? String(e.year) : null,
|
||||
bild: e.posterImage,
|
||||
stand: 'state' in e ? e.state : null,
|
||||
stand: e.state,
|
||||
offen: 'unwatchedCount' in e ? e.unwatchedCount : null,
|
||||
gesamt: 'episodeCount' in e ? e.episodeCount : null,
|
||||
freigabe: e.publishAt,
|
||||
});
|
||||
|
||||
@@ -67,6 +70,11 @@ export const angefangenAlsKachel = (e: Angefangen): Kachel => e.kind === 'episod
|
||||
export function kachel(k: Kachel, oeffnen: (art: 'filme' | 'serien', id: string) => void): HTMLElement {
|
||||
const knopf = document.createElement('button');
|
||||
knopf.className = 'kachel';
|
||||
// **Die Kennung steht am Knoten.** So kann ein Auswahlmodus über dem Raster
|
||||
// arbeiten, ohne dass jede der fünf Stellen, die Kacheln baut, davon wissen
|
||||
// muss — sie liest sie vom angeklickten Element ab.
|
||||
knopf.dataset.id = k.id;
|
||||
knopf.dataset.art = k.art;
|
||||
knopf.onclick = () => oeffnen(k.art, k.id);
|
||||
|
||||
// **Das Kontextmenü an jeder Kachel, überall.** Gesehen, Favorit und
|
||||
@@ -248,11 +256,14 @@ function kachelpunkte(
|
||||
text: istGesehen ? 'Als ungesehen markieren' : 'Als gesehen markieren',
|
||||
icon: 'hakenKreis',
|
||||
tun: async () => {
|
||||
await gesehen(k.id, !istGesehen);
|
||||
// **Die Antwort des Servers gilt, nicht die Annahme hier.** Bei einer
|
||||
// Serie zieht das Häkchen alle Folgen mit; was dabei herauskommt,
|
||||
// weiss nur der Server.
|
||||
k.stand = await gesehen(k.id, !istGesehen);
|
||||
// **Die Kachel spiegelt den neuen Zustand selbst.** Die Liste neu zu
|
||||
// laden verlöre Bildlauf und Filter — für einen Haken.
|
||||
if (k.stand) k.stand.watched = !istGesehen;
|
||||
hakenZeigen(knopf, !istGesehen);
|
||||
k.offen = istGesehen ? (k.gesamt ?? k.offen) : 0;
|
||||
hakenZeigen(knopf, k, !istGesehen);
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -260,8 +271,7 @@ function kachelpunkte(
|
||||
icon: 'stern',
|
||||
tun: async () => {
|
||||
const neuerWert = !k.stand?.favourite;
|
||||
await favorit(k.id, neuerWert);
|
||||
if (k.stand) k.stand.favourite = neuerWert;
|
||||
k.stand = await favorit(k.id, neuerWert);
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -286,7 +296,9 @@ function kachelpunkte(
|
||||
punkte.push({
|
||||
text: 'Bilder bearbeiten',
|
||||
icon: 'stift',
|
||||
tun: () => bilddialog(art, k.id, k.titel),
|
||||
// **Die Kachel holt sich das neue Plakat selbst.** Vorher blieb das
|
||||
// alte stehen, bis man die ganze Oberfläche neu lud.
|
||||
tun: () => bilddialog(art, k.id, k.titel, () => void kachelAuffrischen(k, knopf)),
|
||||
});
|
||||
punkte.push({
|
||||
text: 'Titel ändern',
|
||||
@@ -354,18 +366,32 @@ async function kachelAuffrischen(k: Kachel, knopf: HTMLElement): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
/** Setzt oder entfernt den Haken, ohne die Kachel neu zu bauen. */
|
||||
function hakenZeigen(knopf: HTMLElement, an: boolean): void {
|
||||
/** Setzt oder entfernt den Haken, ohne die Kachel neu zu bauen.
|
||||
*
|
||||
* **Die Ecke zeigt eines von beidem.** Haken oder Zahl offener Folgen — beides
|
||||
* nebeneinander wäre ein Widerspruch. Wird eine Serie abgehakt, geht die Zahl;
|
||||
* wird das Häkchen genommen, kommt sie zurück.
|
||||
*/
|
||||
function hakenZeigen(knopf: HTMLElement, k: Kachel, an: boolean): void {
|
||||
const plakat = knopf.querySelector('.plakat');
|
||||
if (!plakat) return;
|
||||
|
||||
plakat.querySelector('.ecke.haken')?.remove();
|
||||
plakat.querySelector('.ecke')?.remove();
|
||||
knopf.querySelector('.fortschritt')?.remove();
|
||||
|
||||
if (!an) return;
|
||||
const ecke = document.createElement('span');
|
||||
ecke.className = 'ecke haken';
|
||||
ecke.title = 'Gesehen';
|
||||
ecke.innerHTML = icons.haken;
|
||||
plakat.appendChild(ecke);
|
||||
if (an) {
|
||||
const ecke = document.createElement('span');
|
||||
ecke.className = 'ecke haken';
|
||||
ecke.title = 'Gesehen';
|
||||
ecke.innerHTML = icons.haken;
|
||||
plakat.appendChild(ecke);
|
||||
return;
|
||||
}
|
||||
|
||||
if (k.offen == null || k.offen <= 0) return;
|
||||
const plakette = document.createElement('span');
|
||||
plakette.className = 'ecke zahl';
|
||||
plakette.textContent = String(k.offen);
|
||||
plakette.title = `${k.offen} Folgen offen`;
|
||||
plakat.appendChild(plakette);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user