// Reflector Dashboard — 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.
'use strict';
// TG List editor — canonical TG -> name/system list (served publicly by
// /tglist.php). Mirrors the Global Bans admin pattern. Add/delete are admin-only;
// an owner (matching callsign) can edit their own TG. The server enforces this;
// the UI only reflects it.
var $ = function (id) { return document.getElementById(id); };
var tglData = [], tglCanAdmin = false, tglMyCalls = [], tglEditingTg = null;
function tglEsc(s) { var d = document.createElement('div'); d.textContent = s == null ? '' : s; return d.innerHTML; }
function tglMsg(t, err) {
var e = $('tglMsg'); if (!e) return;
if (!t) { e.style.display = 'none'; return; }
e.style.display = 'block'; e.textContent = t; e.style.color = err ? '#ff8080' : '#00ff80';
}
async function tapi(body) {
var r = await fetch('/auth/tglist_api.php', {
method: 'POST', credentials: 'same-origin',
headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': window._csrfToken || '' },
body: JSON.stringify(body)
});
return r.json().catch(function () { return null; });
}
function tglCanEdit(row) {
if (tglCanAdmin) return true;
var o = (row.owner || '').toUpperCase();
return o !== '' && tglMyCalls.indexOf(o) >= 0;
}
// Filter predicate from the search box: try regex, fall back to a literal
// substring if the pattern is invalid — it never throws.
function tglMatcher(q) {
q = (q || '').trim();
if (!q) return function () { return true; };
var re;
try { re = new RegExp(q, 'i'); }
catch (e) { var lit = q.toLowerCase(); return function (s) { return s.toLowerCase().indexOf(lit) >= 0; }; }
return function (s) { return re.test(s); };
}
function tglRender() {
var body = $('tglBody'); if (!body) return;
var match = tglMatcher($('tglSearch').value);
var key = $('tglSortKey').value;
var dir = $('tglSortDir').getAttribute('data-dir') === 'desc' ? -1 : 1;
var rows = tglData.filter(function (r) {
return match([r.tg, r.name, r.system, r.allstar, r.mode, r.owner].join(' '));
});
rows.sort(function (a, b) {
var x = a[key], y = b[key];
if (key === 'tg') return (x - y) * dir;
x = (x || '').toLowerCase(); y = (y || '').toLowerCase();
return (x < y ? -1 : x > y ? 1 : 0) * dir;
});
body.innerHTML = '';
rows.forEach(function (r) {
var tr = document.createElement('tr');
var canEdit = tglCanEdit(r);
tr.innerHTML =
'