Lagebild-Seite: Tab Neueste Entwicklungen / Zusammenfassung
Live-Lagen (iran-konflikt, cyberangriffe) bekommen einen neuen ersten Tab Neueste Entwicklungen mit Bullet-Cards, klickbaren Quellen-Pills und Zeitstempel. Recherche-Lagen (deepfakes) bekommen an selber Stelle einen Tab Zusammenfassung, der den Zusammenfassung-Abschnitt aus dem Markdown extrahiert und mit Citation-Links rendert. lagebild.js: renderUeberblick, renderLatestDevelopmentsHtml, extractZusammenfassung ergaenzt. i18n-Keys tabUeberblick/Research. Lang-Toggle aktualisiert Tab-Label und h2. Vorschau-Karten zeigen wieder den Lagebild-Text fuer alle Lagen (renderLatestDevelopments-Calls aus loadLiveData entfernt).
Dieser Commit ist enthalten in:
@@ -216,6 +216,102 @@
|
||||
positionCards((activeIndex + 1) % cards.length);
|
||||
});
|
||||
|
||||
/* ==================== NEUESTE ENTWICKLUNGEN (Live-Monitoring) ==================== */
|
||||
function htmlEscape(s) {
|
||||
return String(s == null ? '' : s)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"');
|
||||
}
|
||||
|
||||
function normalizeSourceName(s) {
|
||||
return String(s || '').toLowerCase().replace(/^(der|die|das)\s+/, '').replace(/\s+/g, ' ').trim();
|
||||
}
|
||||
|
||||
function renderLatestDevelopments(text, sources) {
|
||||
if (!text) return null;
|
||||
sources = Array.isArray(sources) ? sources : [];
|
||||
|
||||
var lines = text.split('\n').map(function (l) { return l.trim(); })
|
||||
.filter(function (l) { return l && (l.charAt(0) === '-' || l.charAt(0) === '['); });
|
||||
if (!lines.length) return null;
|
||||
|
||||
var bulletRe = /^(?:-\s*)?\[\s*(\d{1,2})\.(\d{1,2})\.?(?:\d{2,4})?\s+(\d{1,2}:\d{2})\s*\]\s*(.+?)\s*$/;
|
||||
var trailingRe = /\s*\{([^{}]+)\}\s*\.?\s*$/;
|
||||
var citationRe = /\[(\d+[a-z]?)\]/g;
|
||||
var junkRe = /^(unbekannt|unknown|n\/?a|keine|keine quelle|tba)$/i;
|
||||
|
||||
function buildPill(src, name) {
|
||||
var disp = (src && src.name) || name;
|
||||
var e = htmlEscape(disp);
|
||||
if (src && src.url) {
|
||||
return '<a href="' + htmlEscape(src.url) + '" target="_blank" rel="noopener" class="dev-source-pill" title="' + e + '">' + e + '</a>';
|
||||
}
|
||||
return '<span class="dev-source-pill" title="' + e + '">' + e + '</span>';
|
||||
}
|
||||
|
||||
function lookupByName(name) {
|
||||
var n = normalizeSourceName(name);
|
||||
if (!n) return null;
|
||||
var exact = sources.find(function (s) { return normalizeSourceName(s.name) === n; });
|
||||
if (exact) return exact;
|
||||
return sources.find(function (s) {
|
||||
var sn = normalizeSourceName(s.name);
|
||||
return sn && (sn.indexOf(n) !== -1 || n.indexOf(sn) !== -1);
|
||||
}) || null;
|
||||
}
|
||||
|
||||
var cards = [];
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var m = bulletRe.exec(lines[i]);
|
||||
if (!m) continue;
|
||||
var date = String(m[1]).padStart(2, '0') + '.' + String(m[2]).padStart(2, '0') + '.';
|
||||
var time = m[3];
|
||||
var body = m[4];
|
||||
|
||||
var pills = '';
|
||||
var t = trailingRe.exec(body);
|
||||
if (t) {
|
||||
body = body.replace(trailingRe, '').trim();
|
||||
var names = t[1].split(',').map(function (n) { return n.trim(); }).filter(Boolean);
|
||||
var seen = {};
|
||||
pills = names.map(function (n) {
|
||||
if (junkRe.test(n)) return '';
|
||||
var key = normalizeSourceName(n);
|
||||
if (seen[key]) return '';
|
||||
seen[key] = true;
|
||||
return buildPill(lookupByName(n), n);
|
||||
}).filter(Boolean).join('');
|
||||
}
|
||||
if (!pills) {
|
||||
var nums = [];
|
||||
var cm;
|
||||
while ((cm = citationRe.exec(body)) !== null) {
|
||||
if (nums.indexOf(cm[1]) === -1) nums.push(cm[1]);
|
||||
}
|
||||
citationRe.lastIndex = 0;
|
||||
if (nums.length) {
|
||||
body = body.replace(citationRe, '').replace(/\s+/g, ' ').trim();
|
||||
pills = nums.map(function (num) {
|
||||
var src = sources.find(function (s) { return String(s.nr) === num || Number(s.nr) === Number(num); });
|
||||
return src ? buildPill(src, src.name) : '';
|
||||
}).filter(Boolean).join('');
|
||||
}
|
||||
}
|
||||
|
||||
var head = '<div class="dev-bullet-head">'
|
||||
+ '<span class="dev-sources">' + pills + '</span>'
|
||||
+ '<span class="dev-time">' + htmlEscape(time) + ' \u00b7 ' + htmlEscape(date) + '</span>'
|
||||
+ '</div>';
|
||||
cards.push('<div class="dev-bullet">' + head + '<div class="dev-body">' + htmlEscape(body) + '</div></div>');
|
||||
}
|
||||
|
||||
if (!cards.length) return null;
|
||||
return '<div class="dev-list-heading">Neueste Entwicklungen</div>'
|
||||
+ '<div class="dev-list">' + cards.join('') + '</div>';
|
||||
}
|
||||
|
||||
/* ==================== SIMPLE MARKDOWN ==================== */
|
||||
function mdToHtml(md) {
|
||||
if (!md) return '';
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren