f2aef5c89a
- API: /api/history/diff liefert den Unified-Diff einer Fassung (git show) - „Version vom <Datum>"-Pill (statt Marke oben + Git-Links) öffnet den Verlauf direkt auf openbureau: Liste der Fassungen → Diff rot/grün wie auf GitHub, Toggle „ganze Fassung anzeigen", Rücksprung. Keine externen Git-Links mehr. - Pills neu: Dialog (Akzent-Outline, wie zuvor) + Version/Zitieren im Tag-Look - CSS: Tag-Pills, Diff-Styling (d-add/d-del/d-hunk), alte Badge-Styles raus Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
120 lines
5.3 KiB
JavaScript
120 lines
5.3 KiB
JavaScript
/* 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 = '<p class="version-loading">Lade Änderungen …</p>';
|
|
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 = '<p class="version-empty">Keine Änderungen an dieser Datei in dieser Fassung.</p>';
|
|
else content.appendChild(renderDiff(data.diff));
|
|
showBanner(v, 'diff');
|
|
toTop();
|
|
});
|
|
}
|
|
function loadVersion(v) {
|
|
closePanel();
|
|
content.innerHTML = '<p class="version-loading">Lade Fassung …</p>';
|
|
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 = '<p class="version-empty">Kein Verlauf verfügbar.</p>';
|
|
} 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(); });
|
|
})();
|