/** * AegisSight Lagebild Page v3 * Vollständige Darstellung aller Daten mit Tabs */ var Lagebild = { data: null, allSnapshots: {}, currentView: null, map: null, async init() { if (typeof initTranslations === 'function') { try { initTranslations(); } catch(e) {} } try { var resp = await fetch('data/current.json?t=' + Date.now()); if (!resp.ok) throw new Error('HTTP ' + resp.status); this.data = await resp.json(); this.currentView = { summary: this.data.current_lagebild.summary_markdown, sources_json: this.data.current_lagebild.sources_json, updated_at: this.data.current_lagebild.updated_at || this.data.generated_at, articles: this.data.articles, fact_checks: this.data.fact_checks }; this.render(); this.initTabs(); this.initLangToggle(); } catch (e) { console.error('Lagebild laden fehlgeschlagen:', e); this.showError(); } }, render: function() { this.renderHero(); this.renderSnapshotSelector(); this.renderCurrentView(); }, renderHero: function() { var d = this.data; document.getElementById('incident-title').textContent = this.fixUmlauts(d.incident.title); var metaHtml = ''; metaHtml += this.metaBadge('clock', 'Stand: ' + this.fmtDT(this.data.generated_at)); metaHtml += this.metaBadge('doc', d.incident.article_count + ' Artikel'); metaHtml += this.metaBadge('globe', d.incident.source_count + ' Quellen'); metaHtml += this.metaBadge('check', d.incident.factcheck_count + ' Faktenchecks'); document.getElementById('hero-meta').innerHTML = metaHtml; }, metaBadge: function(icon, text) { var icons = { clock: '', doc: '', globe: '', check: '' }; return '
' + icons[icon] + '' + text + '
'; }, renderSnapshotSelector: function() { var select = document.getElementById('snapshot-select'); select.innerHTML = ''; var optC = document.createElement('option'); optC.value = 'current'; optC.textContent = this.fmtDT(this.data.current_lagebild.updated_at || this.data.generated_at) + ' — Aktuell'; optC.selected = true; select.appendChild(optC); var snaps = this.data.available_snapshots || []; for (var i = 0; i < snaps.length; i++) { var s = snaps[i]; var opt = document.createElement('option'); opt.value = s.id; opt.textContent = this.fmtDT(s.created_at) + ' — ' + s.article_count + ' Artikel, ' + s.fact_check_count + ' Faktenchecks'; select.appendChild(opt); } var self = this; select.addEventListener('change', function() { if (this.value === 'current') { self.currentView = { summary: self.data.current_lagebild.summary_markdown, sources_json: self.data.current_lagebild.sources_json, updated_at: self.data.current_lagebild.updated_at || self.data.generated_at, articles: self.data.articles, fact_checks: self.data.fact_checks }; self.renderCurrentView(); } else { self.loadSnapshot(parseInt(this.value)); } }); }, loadSnapshot: async function(id) { if (this.allSnapshots[id]) { this.currentView = this.allSnapshots[id]; this.renderCurrentView(); return; } try { var resp = await fetch('data/snapshot-' + id + '.json'); if (!resp.ok) throw new Error('HTTP ' + resp.status); var sd = await resp.json(); var sj = sd.sources_json; if (typeof sj === 'string') { try { sj = JSON.parse(sj); } catch(e) { sj = []; } } this.currentView = { summary: sd.summary, sources_json: sj || [], updated_at: sd.created_at, articles: this.data.articles, fact_checks: this.data.fact_checks }; this.allSnapshots[id] = this.currentView; this.renderCurrentView(); } catch (e) { console.error('Snapshot Fehler:', e); } }, renderCurrentView: function() { this.renderSummary(); this.renderInlineSources(); this.renderSourcesTab(); this.renderArticlesTab(); this.renderFactChecksTab(); if (document.getElementById('panel-karte').classList.contains('active')) { this.renderMap(); } }, // ===== TAB: LAGEBILD ===== renderSummary: function() { var v = this.currentView; document.getElementById('lagebild-timestamp').textContent = this.fmtDT(v.updated_at); var md = this.fixUmlauts(v.summary || ''); var html = this.mdToHtml(md); html = html.replace(/\[(\d+)\]/g, '[$1]'); document.getElementById('summary-content').innerHTML = html; }, renderInlineSources: function() { var sources = this.currentView.sources_json || []; if (!sources.length) { document.getElementById('inline-sources').innerHTML = ''; return; } var h = '

Quellenverzeichnis

'; h += '
    '; for (var i = 0; i < sources.length; i++) { var s = sources[i]; h += '
  • [' + s.nr + ']'; h += '' + this.esc(s.name || '') + ''; if (s.url) h += ' — ' + this.esc(s.url) + ''; h += '
  • '; } h += '
'; document.getElementById('inline-sources').innerHTML = h; }, // ===== TAB: QUELLEN ===== renderSourcesTab: function() { var sources = this.currentView.sources_json || []; var articles = this.currentView.articles || []; var h = ''; // Zitierte Quellen h += '

Im Lagebild zitierte Quellen (' + sources.length + ')

'; if (sources.length) { h += '
    '; for (var i = 0; i < sources.length; i++) { var s = sources[i]; h += '
  1. ' + this.esc(s.name || '') + ''; if (s.url) h += ' — ' + this.esc(s.url) + ''; h += '
  2. '; } h += '
'; } h += '
'; document.getElementById('sources-cited').innerHTML = h; // Alle Artikel document.getElementById('articles-heading').textContent = 'Alle gesammelten Artikel (' + articles.length + ')'; var ah = ''; for (var i = 0; i < articles.length; i++) { var a = articles[i]; var dt = a.published_at || a.collected_at || ''; var dObj = dt ? new Date(this.toUTC(dt)) : null; var hl = this.fixUmlauts(a.headline_de || a.headline || ''); ah += '
'; ah += '
'; } document.getElementById('articles-content').innerHTML = ah; }, // Placeholder for separate articles render (not used in tab structure) renderArticlesTab: function() {}, // ===== TAB: KARTE ===== renderMap: function() { if (this.map) { this.map.remove(); this.map = null; } this.map = L.map('map-container').setView([33.0, 48.0], 5); // Deutsche Kartenbeschriftungen via OpenStreetMap DE L.tileLayer('https://tile.openstreetmap.de/{z}/{x}/{y}.png', { attribution: '© OpenStreetMap', maxZoom: 18 }).addTo(this.map); var redIcon = L.icon({ iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-red.png', shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-shadow.png', iconSize: [25, 41], iconAnchor: [12, 41], popupAnchor: [1, -34], shadowSize: [41, 41] }); var blueIcon = L.icon({ iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-blue.png', shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-shadow.png', iconSize: [25, 41], iconAnchor: [12, 41], popupAnchor: [1, -34], shadowSize: [41, 41] }); var orangeIcon = L.icon({ iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-orange.png', shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-shadow.png', iconSize: [25, 41], iconAnchor: [12, 41], popupAnchor: [1, -34], shadowSize: [41, 41] }); var locs = [ {n:'Teheran, Iran',lat:35.6892,lng:51.3890,d:'Hauptziel der US-israelischen Luftschläge. Über 1.000 Tote nach fünf Tagen Krieg.',ic:redIcon}, {n:'Beirut, Libanon',lat:33.8938,lng:35.5018,d:'Gleichzeitige US-israelische Luftschläge auf Beirut und Teheran [6].',ic:redIcon}, {n:'Juffair, Bahrain',lat:26.2235,lng:50.6001,d:'US-Marinebasis — Ziel iranischer Vergeltungsraketen [3].',ic:orangeIcon}, {n:'Al Udeid, Katar',lat:25.1173,lng:51.3150,d:'US-Luftwaffenstützpunkt — Ziel iranischer Gegenangriffe.',ic:orangeIcon}, {n:'Tel Aviv, Israel',lat:32.0853,lng:34.7818,d:'Operationsbasis für israelische Angriffe auf den Iran.',ic:blueIcon}, {n:'Ankara, Türkei',lat:39.9334,lng:32.8597,d:'NATO vermutet iranischen Raketenbeschuss auf Türkei [10]. Keine NATO-Beteiligung geplant.',ic:orangeIcon}, {n:'Bagdad, Irak',lat:33.3152,lng:44.3661,d:'Lage im Irak als Faktor im Kriegsverlauf [2].',ic:blueIcon}, {n:'Persischer Golf',lat:27.0,lng:51.5,d:'Iran greift Energieinfrastruktur und diplomatische Einrichtungen in der Golfregion an.',ic:orangeIcon}, {n:'Dubai, VAE',lat:25.2048,lng:55.2708,d:'US-Botschaft in Dubai durch iranischen Angriff getroffen.',ic:redIcon}, {n:'Washington D.C., USA',lat:38.9072,lng:-77.0369,d:'War-Powers-Abstimmung im Senat gescheitert (47:53). Trump verteidigt Iran-Krieg vor Kongress.',ic:blueIcon} ]; for (var i = 0; i < locs.length; i++) { var l = locs[i]; L.marker([l.lat, l.lng], {icon: l.ic}) .addTo(this.map) .bindPopup('' + l.n + '
' + l.d + ''); } // Legende var legend = L.control({position: 'bottomright'}); legend.onAdd = function() { var div = L.DomUtil.create('div', 'map-legend'); div.style.cssText = 'background:#fff;padding:10px 14px;border-radius:8px;box-shadow:0 2px 8px rgba(0,0,0,0.15);font-size:0.8rem;line-height:1.8;'; div.innerHTML = 'Legende
' + ' Angegriffene Ziele
' + ' Vergeltung / Eskalation
' + ' Strategische Akteure'; return div; }; legend.addTo(this.map); setTimeout(function() { if (Lagebild.map) Lagebild.map.invalidateSize(); }, 300); }, // ===== TAB: FAKTENCHECKS ===== renderFactChecksTab: function() { var checks = this.currentView.fact_checks || []; if (!checks.length) { document.getElementById('factchecks-content').innerHTML = '

Keine Faktenchecks verfügbar.

'; return; } // Statistik var stats = {confirmed:0, unconfirmed:0, contradicted:0, developing:0, established:0, disputed:0}; for (var k = 0; k < checks.length; k++) { var st = checks[k].status || 'developing'; if (stats[st] !== undefined) stats[st]++; } var h = '
'; h += '
' + checks.length + 'Gesamt
'; h += '
' + (stats.confirmed + stats.established) + 'Bestätigt
'; h += '
' + (stats.unconfirmed + stats.developing) + 'Offen
'; if (stats.contradicted + stats.disputed > 0) h += '
' + (stats.contradicted + stats.disputed) + 'Widerlegt
'; h += '
'; // Sortierung: mit History zuerst, dann sources_count checks = checks.slice().sort(function(a, b) { var aH = (a.status_history || []).length; var bH = (b.status_history || []).length; if (bH !== aH) return bH - aH; return (b.sources_count || 0) - (a.sources_count || 0); }); for (var i = 0; i < checks.length; i++) { var fc = checks[i]; var status = fc.status || 'developing'; var hasProg = fc.status_history && fc.status_history.length > 1; h += '
'; h += '
'; h += '' + this.stLabel(status) + ''; h += '' + (fc.sources_count || 0) + ' unabhängige Quellen'; h += '
'; h += '

' + this.esc(this.fixUmlauts(fc.claim || '')) + '

'; // Vollständige Evidenz anzeigen if (fc.evidence) { var ev = this.fixUmlauts(fc.evidence); // URLs in der Evidenz klickbar machen ev = this.esc(ev).replace(/(https?:\/\/[^\s,)]+)/g, '$1'); h += '
Evidenz: ' + ev + '
'; } // Status-Verlauf if (hasProg) { h += '
'; h += 'Verlauf:'; for (var j = 0; j < fc.status_history.length; j++) { var step = fc.status_history[j]; if (j > 0) h += ''; h += ''; h += '' + this.stLabel(step.status) + ''; if (step.at) h += '' + this.fmtShort(step.at) + ''; h += ''; } h += '
'; } h += '
'; } document.getElementById('factchecks-content').innerHTML = h; }, // ===== TABS ===== initTabs: function() { var btns = document.querySelectorAll('.tab-btn'); var self = this; for (var i = 0; i < btns.length; i++) { btns[i].addEventListener('click', function() { var tab = this.getAttribute('data-tab'); for (var j = 0; j < btns.length; j++) btns[j].classList.remove('active'); this.classList.add('active'); var panels = document.querySelectorAll('.tab-panel'); for (var j = 0; j < panels.length; j++) panels[j].classList.remove('active'); document.getElementById('panel-' + tab).classList.add('active'); if (tab === 'karte') self.renderMap(); }); } }, initLangToggle: function() { var btn = document.querySelector('.lang-toggle'); if (!btn) return; btn.addEventListener('click', function(e) { e.preventDefault(); if (typeof switchLanguage === 'function') { var cur = (typeof getCurrentLanguage === 'function') ? getCurrentLanguage() : 'de'; switchLanguage(cur === 'de' ? 'en' : 'de'); } }); }, // ===== HILFSFUNKTIONEN ===== fixUmlauts: function(text) { if (!text) return text; var skip = ['Israel','Israelis','Jazeera','Euronews','Reuters','Februar', 'Juffair','abgefeuert','Feindseligkeiten','Gegenschlag','neuesten', 'auszuweiten','befeuert','feuerte','Feuer','feuer','neue','neuen', 'neuer','neues','Neue','Aero','aero','Manoeuvre','Dauerfeuer']; var ph = []; var c = 0; for (var i = 0; i < skip.length; i++) { var re = new RegExp('\\b' + skip[i] + '\\b', 'g'); text = text.replace(re, function(m) { ph.push(m); return '##S' + (c++) + '##'; }); } text = text.replace(/ae/g, '\u00e4').replace(/Ae/g, '\u00c4'); text = text.replace(/oe/g, '\u00f6').replace(/Oe/g, '\u00d6'); text = text.replace(/ue/g, '\u00fc').replace(/Ue/g, '\u00dc'); text = text.replace(/##S(\d+)##/g, function(m, idx) { return ph[parseInt(idx)]; }); return text; }, stLabel: function(s) { return {confirmed:'Bestätigt',unconfirmed:'Unbestätigt',established:'Gesichert', unverified:'Nicht verifiziert',contradicted:'Widerlegt',disputed:'Umstritten', developing:'In Entwicklung','false':'Falsch'}[s] || s; }, mdToHtml: function(md) { if (!md) return ''; var lines = md.split('\n'), html = '', inList = false; for (var i = 0; i < lines.length; i++) { var l = lines[i]; if (/^### (.+)$/.test(l)) { if(inList){html+='';inList=false;} html+='

'+l.replace(/^### /,'')+'

'; continue; } if (/^## (.+)$/.test(l)) { if(inList){html+='';inList=false;} html+='

'+l.replace(/^## /,'')+'

'; continue; } if (/^[-*] (.+)$/.test(l)) { if(!inList){html+='
    ';inList=true;} html+='
  • '+l.replace(/^[-*] /,'')+'
  • '; continue; } if (inList) { html+='
'; inList=false; } if (l.trim()==='') continue; html += '

' + l + '

'; } if (inList) html += ''; html = html.replace(/\*\*(.+?)\*\*/g, '$1'); html = html.replace(/\*(.+?)\*/g, '$1'); return html; }, esc: function(s) { if(!s)return''; var d=document.createElement('div'); d.textContent=s; return d.innerHTML; }, truncUrl: function(u) { try{return new URL(u).hostname;}catch(e){return u;} }, // Timestamps aus der DB sind UTC, aber ohne Zeitzone-Suffix. // Diese Funktion haengt 'Z' an falls noetig, damit der Browser korrekt nach CET konvertiert. toUTC: function(s) { if (!s) return s; s = String(s).trim(); // Hat schon Zeitzone (+00:00, Z, +01:00 etc.)? Dann nichts tun. if (/[Zz]$/.test(s) || /[+-]\d{2}:?\d{2}$/.test(s)) return s; // "2026-03-07 00:42:01" -> "2026-03-07T00:42:01Z" return s.replace(' ', 'T') + 'Z'; }, fmtDT: function(iso) { if (!iso) return ''; try { var d = new Date(this.toUTC(iso)); if (isNaN(d.getTime())) return iso; var tage = ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag']; var mon = ['Januar','Februar','M\u00e4rz','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember']; return tage[d.getDay()] + ', ' + d.getDate() + '. ' + mon[d.getMonth()] + ' ' + d.getFullYear() + ' um ' + ('0'+d.getHours()).slice(-2) + ':' + ('0'+d.getMinutes()).slice(-2) + ' Uhr'; } catch(e) { return iso; } }, fmtShort: function(iso) { if (!iso) return ''; try { return new Date(this.toUTC(iso)).toLocaleDateString('de-DE', {day:'numeric',month:'short',hour:'2-digit',minute:'2-digit'}); } catch(e) { return iso; } }, showError: function() { document.getElementById('summary-content').innerHTML = '

Das Lagebild konnte nicht geladen werden. Bitte versuchen Sie es sp\u00e4ter erneut.

'; } }; document.addEventListener('DOMContentLoaded', function() { Lagebild.init(); });