// SvxPortal — web front-end for SvxReflector // Copyright (C) 2026 SA7AUX (Björn) // SPDX-License-Identifier: AGPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify it under // the terms of the GNU Affero General Public License as published by the Free // Software Foundation, either version 3 of the License, or (at your option) any // later version. See the LICENSE file for details. // changelog.js — shared "recent updates" viewer (dmr-web, svx-web). // Canonical copy: callmgr2/www-mumien/lib/changelog.js; other repos carry a COPY. // Reads changelog.json (newest first, {date, repo, hash, type, summary}) and // renders a client-side paginated list. Needs lib/fmt.js (escHtml). // // const ch = changelogViewer({ body: 'chBody', pager: 'chPager', fetchAt: 'chFetchAt', // url: 'changelog.json', perPage: 6 }); // ch.load(); // fetch once, render; later calls just re-render (function () { 'use strict'; function changelogViewer(opts) { opts = opts || {}; const ids = { body: opts.body || 'chBody', pager: opts.pager || 'chPager', fetchAt: opts.fetchAt || 'chFetchAt' }; const url = opts.url || 'changelog.json'; const perPage = opts.perPage || 6; const $ = id => document.getElementById(id); let entries = null, page = 0, wired = false; function typeBadge(t) { const m = { feature: ['Added', 'bg-success'], fix: ['Fix', 'bg-danger'], change: ['Change', 'bg-info text-dark'] }; const x = m[String(t || '').toLowerCase()] || [t || '—', 'bg-secondary']; return `${escHtml(x[0])}`; } function render() { const body = $(ids.body), pager = $(ids.pager); if (!body || !entries) return; const n = entries.length, pages = Math.max(1, Math.ceil(n / perPage)); page = Math.min(Math.max(0, page), pages - 1); const start = page * perPage; const rows = entries.slice(start, start + perPage).map(e => `