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:
@@ -76,7 +76,8 @@
|
||||
<div class="timeline-dropdown" id="timeline-dropdown"></div>
|
||||
</div>
|
||||
<div class="tab-nav" id="tab-nav">
|
||||
<button class="tab-btn active" data-tab="lagebild">Lagebild</button>
|
||||
<button class="tab-btn active" data-tab="ueberblick">Neueste Entwicklungen</button>
|
||||
<button class="tab-btn" data-tab="lagebild">Lagebild</button>
|
||||
<button class="tab-btn" data-tab="karte">Karte</button>
|
||||
<button class="tab-btn" data-tab="faktenchecks">Faktenchecks <span class="tab-badge" id="tab-badge-faktenchecks"></span></button>
|
||||
<button class="tab-btn" data-tab="quellen">Quellen <span class="tab-badge" id="tab-badge-quellen"></span></button>
|
||||
@@ -87,8 +88,26 @@
|
||||
<!-- Main Content -->
|
||||
<main class="lagebild-main">
|
||||
<div class="container">
|
||||
<!-- Tab: Ueberblick (Neueste Entwicklungen / Zusammenfassung) -->
|
||||
<div class="tab-panel active" id="panel-ueberblick">
|
||||
<p class="data-source-note">Daten bereitgestellt durch AegisSight Monitor</p>
|
||||
<section class="content-card">
|
||||
<div class="card-header">
|
||||
<h2 id="ueberblick-title">Neueste Entwicklungen</h2>
|
||||
<span class="card-timestamp" id="ueberblick-timestamp"></span>
|
||||
</div>
|
||||
<div class="card-body" id="ueberblick-content">
|
||||
<div class="loading-skeleton">
|
||||
<div class="skeleton-line"></div>
|
||||
<div class="skeleton-line"></div>
|
||||
<div class="skeleton-line short"></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<!-- Tab: Lagebild -->
|
||||
<div class="tab-panel active" id="panel-lagebild">
|
||||
<div class="tab-panel" id="panel-lagebild">
|
||||
<p class="data-source-note">Daten bereitgestellt durch AegisSight Monitor</p>
|
||||
<section class="content-card">
|
||||
<div class="card-header">
|
||||
|
||||
@@ -1567,3 +1567,69 @@ a.source-detail-article-title:hover {
|
||||
color: #0A1832;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* === Neueste Entwicklungen / Ueberblick-Tab === */
|
||||
.dev-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
.dev-bullet {
|
||||
background: rgba(30, 45, 69, 0.5);
|
||||
border-left: 3px solid #C8A851;
|
||||
border-radius: 4px;
|
||||
padding: 10px 14px;
|
||||
}
|
||||
.dev-bullet-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 6px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.dev-sources {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
}
|
||||
.dev-source-pill {
|
||||
display: inline-block;
|
||||
padding: 3px 10px;
|
||||
background: rgba(200, 168, 81, 0.18);
|
||||
color: #E8ECF4;
|
||||
border-radius: 3px;
|
||||
font-size: 0.78rem;
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
line-height: 1.5;
|
||||
max-width: 240px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
transition: background 0.15s;
|
||||
}
|
||||
a.dev-source-pill:hover {
|
||||
background: rgba(200, 168, 81, 0.35);
|
||||
text-decoration: none;
|
||||
color: #E8ECF4;
|
||||
}
|
||||
.dev-time {
|
||||
color: #8896AB;
|
||||
font-size: 0.78rem;
|
||||
font-variant-numeric: tabular-nums;
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.dev-body {
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.5;
|
||||
color: #E8ECF4;
|
||||
}
|
||||
.empty-hint {
|
||||
color: #8896AB;
|
||||
font-style: italic;
|
||||
padding: 16px 0;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ var Lagebild = {
|
||||
de: {
|
||||
hero: "LAGEBILD", heroResearch: "RECHERCHE",
|
||||
tabBriefing: "Lagebild", tabBriefingResearch: "Recherche",
|
||||
tabUeberblick: "Neueste Entwicklungen", tabUeberblickResearch: "Zusammenfassung",
|
||||
tabMap: "Karte", tabFactchecks: "Faktenchecks", tabSources: "Quellen",
|
||||
statArticles: "Artikel", statSources: "Quellen", statFactchecks: "Faktenchecks",
|
||||
dataSource: "Daten bereitgestellt durch AegisSight Monitor",
|
||||
@@ -44,6 +45,7 @@ var Lagebild = {
|
||||
en: {
|
||||
hero: "SITUATION REPORT", heroResearch: "RESEARCH BRIEFING",
|
||||
tabBriefing: "Briefing", tabBriefingResearch: "Research",
|
||||
tabUeberblick: "Latest Developments", tabUeberblickResearch: "Summary",
|
||||
tabMap: "Map", tabFactchecks: "Fact Checks", tabSources: "Sources",
|
||||
statArticles: "Articles", statSources: "Sources", statFactchecks: "Fact Checks",
|
||||
dataSource: "Data provided by AegisSight Monitor",
|
||||
@@ -133,6 +135,125 @@ var Lagebild = {
|
||||
this.renderTimeline();
|
||||
this.renderTabBadges();
|
||||
this.renderCurrentView();
|
||||
this.renderUeberblick();
|
||||
},
|
||||
|
||||
/* ===== TAB: UEBERBLICK (Neueste Entwicklungen / Zusammenfassung) ===== */
|
||||
renderUeberblick: function() {
|
||||
var inc = (this.data && this.data.incident) || {};
|
||||
var el = document.getElementById('ueberblick-content');
|
||||
var tsEl = document.getElementById('ueberblick-timestamp');
|
||||
if (!el) return;
|
||||
if (tsEl) tsEl.textContent = this.fmtDT(this.currentView && this.currentView.updated_at);
|
||||
|
||||
if (inc.type === 'adhoc') {
|
||||
var dev = inc.latest_developments || '';
|
||||
var sources = (this.currentView && this.currentView.sources_json) || [];
|
||||
var html = this.renderLatestDevelopmentsHtml(dev, sources);
|
||||
el.innerHTML = html || '<p class="empty-hint">Noch keine Entwicklungen erfasst.</p>';
|
||||
} else {
|
||||
var md = (this.currentView && this.currentView.summary) || '';
|
||||
var zf = this.extractZusammenfassung(md);
|
||||
if (!zf) {
|
||||
el.innerHTML = '<p class="empty-hint">Keine Zusammenfassung verfügbar.</p>';
|
||||
return;
|
||||
}
|
||||
var body = this.mdToHtml(this.fixUmlauts(zf));
|
||||
var srcMap = {};
|
||||
var sources = (this.currentView && this.currentView.sources_json) || [];
|
||||
for (var i = 0; i < sources.length; i++) srcMap[String(sources[i].nr)] = sources[i];
|
||||
var self = this;
|
||||
body = body.replace(/\[(\d+[a-z]?)\]/g, function(match, nr) {
|
||||
var src = srcMap[nr];
|
||||
if (src && src.url) {
|
||||
return '<a class="citation-ref" href="' + self.esc(src.url) + '" target="_blank" rel="noopener" title="' + self.esc(src.name || '') + '">[' + nr + ']</a>';
|
||||
}
|
||||
return '<a class="citation-ref" title="Quelle ' + nr + '">[' + nr + ']</a>';
|
||||
});
|
||||
el.innerHTML = body;
|
||||
}
|
||||
},
|
||||
|
||||
extractZusammenfassung: function(md) {
|
||||
if (!md) return '';
|
||||
var sections = md.split(/^## /m);
|
||||
for (var i = 0; i < sections.length; i++) {
|
||||
var s = sections[i];
|
||||
if (/^zusammenfassung/i.test(s.trim())) {
|
||||
var next = s.split(/\n## /)[0];
|
||||
return next.trim();
|
||||
}
|
||||
}
|
||||
return '';
|
||||
},
|
||||
|
||||
renderLatestDevelopmentsHtml: function(text, sources) {
|
||||
if (!text) return '';
|
||||
sources = Array.isArray(sources) ? sources : [];
|
||||
var self = this;
|
||||
|
||||
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 '';
|
||||
|
||||
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 normName(s) { return String(s||'').toLowerCase().replace(/^(der|die|das)\s+/,'').replace(/\s+/g,' ').trim(); }
|
||||
function lookupByName(name) {
|
||||
var n = normName(name); if (!n) return null;
|
||||
var exact = sources.find(function(s){ return normName(s.name) === n; });
|
||||
if (exact) return exact;
|
||||
return sources.find(function(s){ var sn=normName(s.name); return sn && (sn.indexOf(n)!==-1 || n.indexOf(sn)!==-1); }) || null;
|
||||
}
|
||||
function buildPill(src, name) {
|
||||
var disp = (src && src.name) || name;
|
||||
var e = self.esc(disp);
|
||||
if (src && src.url) return '<a href="'+self.esc(src.url)+'" target="_blank" rel="noopener" class="dev-source-pill" title="'+e+'">'+e+'</a>';
|
||||
return '<span class="dev-source-pill" title="'+e+'">'+e+'</span>';
|
||||
}
|
||||
|
||||
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 k = normName(n); if (seen[k]) return ''; seen[k] = 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">' + self.esc(time) + ' \u00b7 ' + self.esc(date) + '</span>'
|
||||
+ '</div>';
|
||||
cards.push('<div class="dev-bullet">' + head + '<div class="dev-body">' + self.esc(body) + '</div></div>');
|
||||
}
|
||||
|
||||
return cards.length ? '<div class="dev-list">' + cards.join('') + '</div>' : '';
|
||||
},
|
||||
|
||||
/* ===== SCROLL PROGRESS BAR ===== */
|
||||
@@ -1099,10 +1220,14 @@ var Lagebild = {
|
||||
for (var i = 0; i < tabBtns.length; i++) {
|
||||
var tab = tabBtns[i].getAttribute('data-tab');
|
||||
if (tab === 'lagebild') tabBtns[i].childNodes[0].textContent = isResearch ? this.t('tabBriefingResearch') : this.t('tabBriefing');
|
||||
else if (tab === 'ueberblick') tabBtns[i].childNodes[0].textContent = isResearch ? this.t('tabUeberblickResearch') : this.t('tabUeberblick');
|
||||
else if (tab === 'karte') tabBtns[i].childNodes[0].textContent = this.t('tabMap');
|
||||
else if (tab === 'faktenchecks') tabBtns[i].childNodes[0].textContent = this.t('tabFactchecks') + ' ';
|
||||
else if (tab === 'quellen') tabBtns[i].childNodes[0].textContent = this.t('tabSources') + ' ';
|
||||
}
|
||||
// Update Ueberblick H2 title
|
||||
var ueberblickH2 = document.getElementById('ueberblick-title');
|
||||
if (ueberblickH2) ueberblickH2.textContent = isResearch ? this.t('tabUeberblickResearch') : this.t('tabUeberblick');
|
||||
// Update data source note
|
||||
var dsNote = document.querySelector('.data-source-note');
|
||||
if (dsNote) dsNote.textContent = this.t('dataSource');
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren