/* OPENBUREAU — Versionsverlauf eines Beitrags direkt auf der Seite. Die Pill „Version vom …" öffnet die Liste der Fassungen (aus /api/history). Auswahl zeigt standardmäßig den Diff (rot/grün, wie auf GitHub) aus /api/history/diff; ein Toggle zeigt die ganze alte Fassung (/api/history/version). Alles auf openbureau — keine externen Git-Links. */ (function () { var trigger = document.getElementById('version-badge'); if (!trigger) return; var path = trigger.dataset.path; var content = document.querySelector('.single-content'); var article = document.querySelector('article.single'); if (!path || !content || !article) return; var originalHTML = content.innerHTML; var panel = null, banner = null; function api(p) { return fetch(p).then(function (r) { return r.ok ? r.json() : null; }).catch(function () { return null; }); } function fmt(d) { try { return new Date(d).toLocaleDateString('de-CH'); } catch (e) { return d || ''; } } function q(p, rev) { return p + '?path=' + encodeURIComponent(path) + '&rev=' + encodeURIComponent(rev); } function toTop() { window.scrollTo({ top: 0, behavior: 'smooth' }); } function closePanel() { if (panel) { panel.remove(); panel = null; } trigger.setAttribute('aria-expanded', 'false'); } function restore() { content.innerHTML = originalHTML; if (banner) { banner.remove(); banner = null; } } // Unified-Diff → farbige Zeilen (rot gelöscht, grün neu, grau Hunk/Kontext). function renderDiff(diff) { var box = document.createElement('div'); box.className = 'diff'; diff.split('\n').forEach(function (ln) { if (/^(diff --git|index |new file|deleted file|similarity |rename |--- |\+\+\+ )/.test(ln)) return; var cls = 'd-ctx'; if (/^@@/.test(ln)) cls = 'd-hunk'; else if (ln.charAt(0) === '+') cls = 'd-add'; else if (ln.charAt(0) === '-') cls = 'd-del'; var row = document.createElement('div'); row.className = 'diff-line ' + cls; row.textContent = ln || ' '; box.appendChild(row); }); return box; } function showBanner(v, mode) { if (banner) banner.remove(); banner = document.createElement('div'); banner.className = 'version-banner'; banner.append((mode === 'diff' ? 'Änderungen' : 'Fassung') + ' vom ' + fmt(v.date) + ' · Version ' + v.short + ' '); var toggle = document.createElement('button'); toggle.type = 'button'; toggle.className = 'version-toggle'; toggle.textContent = mode === 'diff' ? 'ganze Fassung anzeigen' : 'Änderungen anzeigen'; toggle.addEventListener('click', function () { mode === 'diff' ? loadVersion(v) : loadDiff(v); }); var back = document.createElement('button'); back.type = 'button'; back.className = 'version-back'; back.textContent = '→ zur aktuellen Fassung'; back.addEventListener('click', restore); banner.append(toggle, ' ', back); article.insertBefore(banner, article.firstChild); } function loadDiff(v) { closePanel(); content.innerHTML = '
Lade Änderungen …
'; api(q('/api/history/diff', v.rev)).then(function (data) { if (!data || data.diff == null) { restore(); return; } content.innerHTML = ''; if (!data.diff.trim()) content.innerHTML = 'Keine Änderungen an dieser Datei in dieser Fassung.
'; else content.appendChild(renderDiff(data.diff)); showBanner(v, 'diff'); toTop(); }); } function loadVersion(v) { closePanel(); content.innerHTML = 'Lade Fassung …
'; api(q('/api/history/version', v.rev)).then(function (data) { if (!data || !data.html) { restore(); return; } content.innerHTML = data.html; showBanner(v, 'full'); toTop(); }); } function openPanel() { api('/api/history?path=' + encodeURIComponent(path)).then(function (list) { panel = document.createElement('div'); panel.className = 'version-panel'; if (!list || !list.length) { panel.innerHTML = 'Kein Verlauf verfügbar.
'; } else { var ol = document.createElement('ol'); ol.className = 'version-list'; list.forEach(function (v, i) { var li = document.createElement('li'); var b = document.createElement('button'); b.type = 'button'; var date = document.createElement('span'); date.className = 'v-date'; date.textContent = fmt(v.date); var subj = document.createElement('span'); subj.className = 'v-subject'; subj.textContent = v.subject || ''; var hash = document.createElement('span'); hash.className = 'v-hash'; hash.textContent = v.short + (i === 0 ? ' · aktuell' : ''); b.append(date, subj, hash); if (i === 0) b.addEventListener('click', function () { restore(); closePanel(); }); else b.addEventListener('click', function () { loadDiff(v); }); li.appendChild(b); ol.appendChild(li); }); panel.appendChild(ol); } var prov = trigger.closest('.provenance') || trigger; prov.parentNode.insertBefore(panel, prov.nextSibling); trigger.setAttribute('aria-expanded', 'true'); }); } trigger.addEventListener('click', function () { panel ? closePanel() : openPanel(); }); })();