/* ===================================================================== „Wer sieht was" — die Rechtetafel, gezeichnet (11.09.2026) Dieses Skript ENTSCHEIDET nichts. Es holt die Tafel vom Server und zeichnet sie. Jede Zahl und jeder Punkt darin kommt aus rechte.js — derselben Datei, aus der auch die Schranke ihre Antwort holt. WARUM DAS WICHTIG IST: Eine Übersicht, die im Browser gebaut wird („Rolle X darf wohl Y, weil …"), wäre eine zweite Meinung über die Rechte — und ausgerechnet die, der man glaubt, weil sie wie eine Auskunft aussieht. Sie würde altern, ohne dass man es ihr ansieht. ===================================================================== */ (() => { const $ = (id) => document.getElementById(id); const el = (t, k, text) => { const n = document.createElement(t); if (k) n.className = k; if (text !== undefined) n.textContent = text; return n; }; const melde = (t) => { const f = $('fehler'); if (f) { f.textContent = t; f.hidden = !t; } }; (async () => { let r; try { const a = await fetch('/workspace/api/rechte/tafel', { credentials: 'same-origin' }); if (a.status === 401) { location.assign('/workspace/'); return; } /* 404 heißt hier: diese Seite gibt es für dich nicht. Die Schranke hätte schon vorher umgeleitet; kommt es trotzdem hierher, ist die Startseite die richtige Antwort — und nicht eine Fehlermeldung, die verrät, dass es die Auskunft gibt. */ if (a.status === 404) { location.assign('/workspace/start.html'); return; } if (!a.ok) { melde('Die Tafel konnte nicht geladen werden.'); return; } r = await a.json(); } catch { melde('Die Tafel konnte nicht geladen werden.'); return; } const gesamt = r.seiten.length; /* ---- Die Zahlen je Rolle --------------------------------------- Sortiert nach Anzahl, absteigend. Eine alphabetische Reihenfolge hätte dieselben Zahlen gezeigt und die Frage nicht beantwortet: Man sieht hier auf einen Blick, wer viel sieht und wer wenig — und ob irgendwo eine Rolle steht, die mehr sieht, als sie sollte. */ const zahlen = $('zahlen'); if (zahlen) { zahlen.textContent = ''; for (const rolle of [...r.rollen].sort((a, b) => b.seiten - a.seiten)) { const li = document.createElement('li'); li.append(rolle.name + ' '); const b = document.createElement('b'); b.textContent = `${rolle.seiten} von ${gesamt}`; li.append(b); zahlen.append(li); } } /* ---- Die Tafel --------------------------------------------------- */ const ziel = $('tafel'); if (ziel) { ziel.textContent = ''; const tab = document.createElement('table'); const kopf = document.createElement('thead'); const kz = document.createElement('tr'); kz.append(el('th', null, 'Seite')); for (const rolle of r.rollen) { const th = el('th', null, rolle.name); /* Der Schlüssel als Titel: Im Alltag liest man „Community", im Code steht „gast". Wer die beiden nicht zusammenbringen kann, sucht im Quelltext an der falschen Stelle. */ th.title = rolle.schluessel; kz.append(th); } kopf.append(kz); tab.append(kopf); const koerper = document.createElement('tbody'); for (const seite of r.seiten) { const tr = document.createElement('tr'); tr.append(el('td', null, seite.datei)); for (const rolle of r.rollen) { const td = document.createElement('td'); if (seite.rollen.includes(rolle.schluessel)) { const punkt = el('span', 'rechte-ja'); punkt.setAttribute('role', 'img'); punkt.setAttribute('aria-label', 'darf'); td.append(punkt); } else { /* Ein Zeichen und nicht ein leeres Feld: Ein Bildschirmleser liest eine leere Zelle als nichts vor — man hört dann nicht, dass die Antwort „nein" ist, sondern gar nichts. */ const nein = el('span', 'rechte-nein', '–'); nein.setAttribute('aria-label', 'darf nicht'); td.append(nein); } tr.append(td); } koerper.append(tr); } tab.append(koerper); ziel.append(tab); ziel.setAttribute('aria-busy', 'false'); } /* ---- Ohne Anmeldung --------------------------------------------- */ const offen = $('offen'); if (offen) { offen.textContent = ''; for (const pfad of r.ohne_anmeldung) { offen.append(el('li', null, pfad)); } } })(); })();