Lagen-Seiten: Englische Übersetzung + Sprachwechsel-Logik
- LANG-Objekt mit de/en Strings für ~40 UI-Elemente - t() Hilfsfunktion + getLocale() + getHeadline() - switchContent(): Lädt current_en.json bei Sprachwechsel - Fallback auf deutsche Version wenn EN nicht verfügbar - Datumsformatierung sprachabhängig (de-DE / en-GB) - Artikel-Headlines: Original bei EN, Übersetzung bei DE - Snapshot-Hinweis bei EN (Historical data in German only) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dieser Commit ist enthalten in:
@@ -14,6 +14,78 @@ var Lagebild = {
|
|||||||
timelineGroups: null,
|
timelineGroups: null,
|
||||||
|
|
||||||
/* ===== Inline SVG Icons ===== */
|
/* ===== Inline SVG Icons ===== */
|
||||||
|
/* ===== LANGUAGE SUPPORT ===== */
|
||||||
|
lang: {
|
||||||
|
de: {
|
||||||
|
hero: "LAGEBILD", heroResearch: "RECHERCHE",
|
||||||
|
tabBriefing: "Lagebild", tabBriefingResearch: "Recherche",
|
||||||
|
tabMap: "Karte", tabFactchecks: "Faktenchecks", tabSources: "Quellen",
|
||||||
|
statArticles: "Artikel", statSources: "Quellen", statFactchecks: "Faktenchecks",
|
||||||
|
dataSource: "Daten bereitgestellt durch AegisSight Monitor",
|
||||||
|
timelineCurrent: "Aktuell", timelineArticles: "Artikel", timelineFcs: "Faktenchecks",
|
||||||
|
srcArticlesFrom: "{count} Artikel aus {sources} Quellen",
|
||||||
|
srcArticle: "Artikel", srcClose: "Schlie\u00dfen",
|
||||||
|
mapNoData: "Keine Standortdaten verf\u00fcgbar", mapLegend: "Legende", mapArticles: "Artikel",
|
||||||
|
fcTotal: "Gesamt", fcConfirmed: "Best\u00e4tigt", fcOpen: "Offen", fcContradicted: "Widerlegt",
|
||||||
|
fcEvidence: "Evidenz:", fcProgression: "Verlauf:", fcSources: "unabh\u00e4ngige Quellen",
|
||||||
|
fcNone: "Keine Faktenchecks verf\u00fcgbar.",
|
||||||
|
fcCleaned: "{count} von {total} Faktenchecks verf\u00fcgbar (\u00e4ltere wurden bereinigt)",
|
||||||
|
ctaText: "AegisSight Monitor f\u00fcr Ihre Organisation", ctaButton: "Kontakt aufnehmen \u2192",
|
||||||
|
errorLoad: "Das Lagebild konnte nicht geladen werden. Bitte versuchen Sie es sp\u00e4ter erneut.",
|
||||||
|
snapshotHint: "",
|
||||||
|
standPrefix: "Stand: ", standSuffix: " Uhr",
|
||||||
|
stConfirmed: "Best\u00e4tigt", stUnconfirmed: "Unbest\u00e4tigt", stContradicted: "Widerlegt",
|
||||||
|
stDeveloping: "Unklar", stEstablished: "Gesichert", stDisputed: "Umstritten",
|
||||||
|
stFalse: "Falsch", stUnverified: "Nicht verifiziert",
|
||||||
|
sourceRef: "Quelle",
|
||||||
|
lastUpdate: "Letzte Aktualisierung: ",
|
||||||
|
minAgo: "vor {n} Min", hrsAgo: "vor {n} Std",
|
||||||
|
},
|
||||||
|
en: {
|
||||||
|
hero: "SITUATION REPORT", heroResearch: "RESEARCH BRIEFING",
|
||||||
|
tabBriefing: "Briefing", tabBriefingResearch: "Research",
|
||||||
|
tabMap: "Map", tabFactchecks: "Fact Checks", tabSources: "Sources",
|
||||||
|
statArticles: "Articles", statSources: "Sources", statFactchecks: "Fact Checks",
|
||||||
|
dataSource: "Data provided by AegisSight Monitor",
|
||||||
|
timelineCurrent: "Current", timelineArticles: "Articles", timelineFcs: "Fact Checks",
|
||||||
|
srcArticlesFrom: "{count} articles from {sources} sources",
|
||||||
|
srcArticle: "Articles", srcClose: "Close",
|
||||||
|
mapNoData: "No location data available", mapLegend: "Legend", mapArticles: "Articles",
|
||||||
|
fcTotal: "Total", fcConfirmed: "Confirmed", fcOpen: "Open", fcContradicted: "Contradicted",
|
||||||
|
fcEvidence: "Evidence:", fcProgression: "History:", fcSources: "independent sources",
|
||||||
|
fcNone: "No fact checks available.",
|
||||||
|
fcCleaned: "{count} of {total} fact checks available (older ones were cleaned up)",
|
||||||
|
ctaText: "AegisSight Monitor for your organization", ctaButton: "Contact us \u2192",
|
||||||
|
errorLoad: "The briefing could not be loaded. Please try again later.",
|
||||||
|
snapshotHint: "Historical data available in German only",
|
||||||
|
standPrefix: "As of: ", standSuffix: "",
|
||||||
|
stConfirmed: "Confirmed", stUnconfirmed: "Unconfirmed", stContradicted: "Contradicted",
|
||||||
|
stDeveloping: "Developing", stEstablished: "Established", stDisputed: "Disputed",
|
||||||
|
stFalse: "False", stUnverified: "Unverified",
|
||||||
|
sourceRef: "Source",
|
||||||
|
lastUpdate: "Last update: ",
|
||||||
|
minAgo: "{n} min ago", hrsAgo: "{n} hrs ago",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
curLang: function() {
|
||||||
|
return (typeof getCurrentLanguage === 'function') ? getCurrentLanguage() : 'de';
|
||||||
|
},
|
||||||
|
|
||||||
|
t: function(key) {
|
||||||
|
var cl = this.curLang();
|
||||||
|
return (this.lang[cl] && this.lang[cl][key]) || this.lang.de[key] || key;
|
||||||
|
},
|
||||||
|
|
||||||
|
getLocale: function() {
|
||||||
|
return this.curLang() === 'en' ? 'en-GB' : 'de-DE';
|
||||||
|
},
|
||||||
|
|
||||||
|
getHeadline: function(article) {
|
||||||
|
if (this.curLang() === 'en') return article.headline || article.headline_de || '';
|
||||||
|
return article.headline_de || article.headline || '';
|
||||||
|
},
|
||||||
|
|
||||||
icons: {
|
icons: {
|
||||||
clock: '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>',
|
clock: '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>',
|
||||||
fileText: '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg>',
|
fileText: '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg>',
|
||||||
@@ -29,7 +101,10 @@ var Lagebild = {
|
|||||||
this.initScrollProgress();
|
this.initScrollProgress();
|
||||||
this.initParticles();
|
this.initParticles();
|
||||||
try {
|
try {
|
||||||
var resp = await fetch('data/current.json?t=' + Date.now());
|
var savedLang = (typeof getCurrentLanguage === 'function') ? getCurrentLanguage() : 'de';
|
||||||
|
var jsonFile = savedLang === 'en' ? 'data/current_en.json' : 'data/current.json';
|
||||||
|
var resp = await fetch(jsonFile + '?t=' + Date.now());
|
||||||
|
if (!resp.ok && savedLang === 'en') { resp = await fetch('data/current.json?t=' + Date.now()); }
|
||||||
if (!resp.ok) throw new Error('HTTP ' + resp.status);
|
if (!resp.ok) throw new Error('HTTP ' + resp.status);
|
||||||
this.data = await resp.json();
|
this.data = await resp.json();
|
||||||
this.currentView = {
|
this.currentView = {
|
||||||
@@ -147,11 +222,11 @@ var Lagebild = {
|
|||||||
var d = this.data;
|
var d = this.data;
|
||||||
var genDate = new Date(this.toUTC(d.generated_at));
|
var genDate = new Date(this.toUTC(d.generated_at));
|
||||||
var diffMin = Math.max(1, Math.round((Date.now() - genDate.getTime()) / 60000));
|
var diffMin = Math.max(1, Math.round((Date.now() - genDate.getTime()) / 60000));
|
||||||
var diffText = diffMin < 60 ? ('vor ' + diffMin + ' Min') : ('vor ' + Math.round(diffMin / 60) + ' Std');
|
var diffText = diffMin < 60 ? this.t('minAgo').replace('{n}', diffMin) : this.t('hrsAgo').replace('{n}', Math.round(diffMin / 60));
|
||||||
|
|
||||||
container.innerHTML = '<div class="live-feed-item active">'
|
container.innerHTML = '<div class="live-feed-item active">'
|
||||||
+ '<span class="live-feed-dot"></span>'
|
+ '<span class="live-feed-dot"></span>'
|
||||||
+ '<span>Letzte Aktualisierung: ' + diffText + '</span>'
|
+ '<span>' + this.t('lastUpdate') + diffText + '</span>'
|
||||||
+ '</div>';
|
+ '</div>';
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -160,13 +235,13 @@ var Lagebild = {
|
|||||||
var d = this.data;
|
var d = this.data;
|
||||||
document.getElementById('incident-title').innerHTML =
|
document.getElementById('incident-title').innerHTML =
|
||||||
this.esc(this.fixUmlauts(d.incident.title)) +
|
this.esc(this.fixUmlauts(d.incident.title)) +
|
||||||
' <span class="hero-date-info">\u2013 Stand: ' + this.fmtDateOnly(d.generated_at) + ', ' + this.fmtTimeOnly(d.generated_at) + ' Uhr</span>';
|
' <span class="hero-date-info">\u2013 ' + this.t('standPrefix') + this.fmtDateOnly(d.generated_at) + ', ' + this.fmtTimeOnly(d.generated_at) + this.t('standSuffix') + '</span>';
|
||||||
|
|
||||||
// Stat Cards (3: Artikel, Quellen, Faktenchecks)
|
// Stat Cards (3: Artikel, Quellen, Faktenchecks)
|
||||||
var statsHtml = '';
|
var statsHtml = '';
|
||||||
statsHtml += this.statCard(this.icons.fileText, '<span class="count-up" id="hero-art-count" data-target="' + d.incident.article_count + '">0</span>', 'Artikel');
|
statsHtml += this.statCard(this.icons.fileText, '<span class="count-up" id="hero-art-count" data-target="' + d.incident.article_count + '">0</span>', this.t("statArticles"));
|
||||||
statsHtml += this.statCard(this.icons.globe, '<span class="count-up" id="hero-src-count" data-target="' + d.incident.source_count + '">0</span>', 'Quellen');
|
statsHtml += this.statCard(this.icons.globe, '<span class="count-up" id="hero-src-count" data-target="' + d.incident.source_count + '">0</span>', this.t("statSources"));
|
||||||
statsHtml += this.statCard(this.icons.shieldCheck, '<span class="count-up" id="hero-fc-count" data-target="' + d.incident.factcheck_count + '">0</span>', 'Faktenchecks');
|
statsHtml += this.statCard(this.icons.shieldCheck, '<span class="count-up" id="hero-fc-count" data-target="' + d.incident.factcheck_count + '">0</span>', this.t("statFactchecks"));
|
||||||
document.getElementById('hero-stats').innerHTML = statsHtml;
|
document.getElementById('hero-stats').innerHTML = statsHtml;
|
||||||
|
|
||||||
// Start count-up animations
|
// Start count-up animations
|
||||||
@@ -196,7 +271,7 @@ var Lagebild = {
|
|||||||
var progress = Math.min(elapsed / duration, 1);
|
var progress = Math.min(elapsed / duration, 1);
|
||||||
var eased = 1 - Math.pow(1 - progress, 3); // easeOutCubic
|
var eased = 1 - Math.pow(1 - progress, 3); // easeOutCubic
|
||||||
var current = Math.round(target * eased);
|
var current = Math.round(target * eased);
|
||||||
element.textContent = current.toLocaleString('de-DE');
|
element.textContent = current.toLocaleString(Lagebild.getLocale());
|
||||||
if (progress < 1) {
|
if (progress < 1) {
|
||||||
requestAnimationFrame(update);
|
requestAnimationFrame(update);
|
||||||
}
|
}
|
||||||
@@ -271,13 +346,13 @@ var Lagebild = {
|
|||||||
h += '>';
|
h += '>';
|
||||||
if (isActive) h += '<span class="timeline-dot"></span>';
|
if (isActive) h += '<span class="timeline-dot"></span>';
|
||||||
h += '<span class="timeline-day-num">' + d.getUTCDate() + '</span>';
|
h += '<span class="timeline-day-num">' + d.getUTCDate() + '</span>';
|
||||||
h += '<span class="timeline-day-month">' + d.toLocaleDateString('de-DE', { month: 'short', timeZone: 'UTC' }) + '</span>';
|
h += '<span class="timeline-day-month">' + d.toLocaleDateString(this.getLocale(), { month: 'short', timeZone: 'UTC' }) + '</span>';
|
||||||
h += '<span class="timeline-day-count">' + defaultSnap.article_count + '</span>';
|
h += '<span class="timeline-day-count">' + defaultSnap.article_count + '</span>';
|
||||||
if (daySnaps.length > 1) {
|
if (daySnaps.length > 1) {
|
||||||
h += '<span class="timeline-day-updates">' + daySnaps.length + 'x</span>';
|
h += '<span class="timeline-day-updates">' + daySnaps.length + 'x</span>';
|
||||||
}
|
}
|
||||||
if (isActive) {
|
if (isActive) {
|
||||||
h += '<span class="timeline-day-label">Aktuell</span>';
|
h += '<span class="timeline-day-label">' + this.t('timelineCurrent') + '</span>';
|
||||||
}
|
}
|
||||||
h += '</button>';
|
h += '</button>';
|
||||||
}
|
}
|
||||||
@@ -378,8 +453,8 @@ var Lagebild = {
|
|||||||
h += ' data-snapshot-id="' + snap.id + '">';
|
h += ' data-snapshot-id="' + snap.id + '">';
|
||||||
h += '<span class="h-timeline-time">' + this.fmtTimeOnly(snap.created_at) + '</span>';
|
h += '<span class="h-timeline-time">' + this.fmtTimeOnly(snap.created_at) + '</span>';
|
||||||
h += '<span class="h-timeline-dot"></span>';
|
h += '<span class="h-timeline-dot"></span>';
|
||||||
h += '<span class="h-timeline-meta">' + snap.article_count + ' Artikel</span>';
|
h += '<span class="h-timeline-meta">' + snap.article_count + ' ' + this.t('timelineArticles') + '</span>';
|
||||||
h += '<span class="h-timeline-meta">' + (snap.fact_check_count || 0) + ' Faktenchecks</span>';
|
h += '<span class="h-timeline-meta">' + (snap.fact_check_count || 0) + ' ' + this.t('timelineFcs') + '</span>';
|
||||||
h += '</button>';
|
h += '</button>';
|
||||||
}
|
}
|
||||||
h += '</div>';
|
h += '</div>';
|
||||||
@@ -453,11 +528,11 @@ var Lagebild = {
|
|||||||
var fcCount = this.currentView.fact_check_count || (this.currentView.fact_checks || []).length;
|
var fcCount = this.currentView.fact_check_count || (this.currentView.fact_checks || []).length;
|
||||||
|
|
||||||
var heroArt = document.getElementById('hero-art-count');
|
var heroArt = document.getElementById('hero-art-count');
|
||||||
if (heroArt) heroArt.textContent = artCount.toLocaleString('de-DE');
|
if (heroArt) heroArt.textContent = artCount.toLocaleString(this.getLocale());
|
||||||
var heroSrc = document.getElementById('hero-src-count');
|
var heroSrc = document.getElementById('hero-src-count');
|
||||||
if (heroSrc) heroSrc.textContent = srcCount.toLocaleString('de-DE');
|
if (heroSrc) heroSrc.textContent = srcCount.toLocaleString(this.getLocale());
|
||||||
var heroFc = document.getElementById('hero-fc-count');
|
var heroFc = document.getElementById('hero-fc-count');
|
||||||
if (heroFc) heroFc.textContent = fcCount.toLocaleString('de-DE');
|
if (heroFc) heroFc.textContent = fcCount.toLocaleString(this.getLocale());
|
||||||
|
|
||||||
var fcBadge = document.getElementById('tab-badge-faktenchecks');
|
var fcBadge = document.getElementById('tab-badge-faktenchecks');
|
||||||
if (fcBadge) fcBadge.textContent = fcCount;
|
if (fcBadge) fcBadge.textContent = fcCount;
|
||||||
@@ -484,7 +559,7 @@ var Lagebild = {
|
|||||||
if (src && src.url) {
|
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" 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>';
|
return '<a class="citation-ref" title="' + self.t('sourceRef') + ' ' + nr + '">[' + nr + ']</a>';
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById('summary-content').innerHTML = html;
|
document.getElementById('summary-content').innerHTML = html;
|
||||||
@@ -504,7 +579,7 @@ var Lagebild = {
|
|||||||
var sourceMap = {};
|
var sourceMap = {};
|
||||||
for (var i = 0; i < articles.length; i++) {
|
for (var i = 0; i < articles.length; i++) {
|
||||||
var a = articles[i];
|
var a = articles[i];
|
||||||
var name = a.source || 'Unbekannt';
|
var name = a.source || 'Unknown';
|
||||||
if (!sourceMap[name]) sourceMap[name] = { count: 0, articles: [], languages: {}, domain: null };
|
if (!sourceMap[name]) sourceMap[name] = { count: 0, articles: [], languages: {}, domain: null };
|
||||||
sourceMap[name].count++;
|
sourceMap[name].count++;
|
||||||
sourceMap[name].articles.push(a);
|
sourceMap[name].articles.push(a);
|
||||||
@@ -531,7 +606,7 @@ var Lagebild = {
|
|||||||
|
|
||||||
// Header
|
// Header
|
||||||
h += '<div class="sources-overview-header">';
|
h += '<div class="sources-overview-header">';
|
||||||
h += '<span class="sources-overview-title">' + articles.length + ' Artikel aus ' + sources.length + ' Quellen</span>';
|
h += '<span class="sources-overview-title">' + this.t('srcArticlesFrom').replace('{count}', articles.length).replace('{sources}', sources.length) + '</span>';
|
||||||
h += '<div class="sources-lang-chips">';
|
h += '<div class="sources-lang-chips">';
|
||||||
var langKeys = Object.keys(langTotals).sort(function(a, b) { return langTotals[b] - langTotals[a]; });
|
var langKeys = Object.keys(langTotals).sort(function(a, b) { return langTotals[b] - langTotals[a]; });
|
||||||
for (var i = 0; i < langKeys.length; i++) {
|
for (var i = 0; i < langKeys.length; i++) {
|
||||||
@@ -613,15 +688,15 @@ var Lagebild = {
|
|||||||
h += '<img class="source-tile-favicon" src="https://www.google.com/s2/favicons?domain=' + encodeURIComponent(src.data.domain) + '&sz=16" width="16" height="16" alt="" loading="lazy"> ';
|
h += '<img class="source-tile-favicon" src="https://www.google.com/s2/favicons?domain=' + encodeURIComponent(src.data.domain) + '&sz=16" width="16" height="16" alt="" loading="lazy"> ';
|
||||||
}
|
}
|
||||||
h += this.esc(src.name) + '</span>';
|
h += this.esc(src.name) + '</span>';
|
||||||
h += '<span class="source-detail-count">' + src.data.count + ' Artikel</span>';
|
h += '<span class="source-detail-count">' + src.data.count + ' ' + Lagebild.t('srcArticle') + '</span>';
|
||||||
h += '<button class="source-detail-close" aria-label="Schließen">×</button>';
|
h += '<button class="source-detail-close" aria-label="' + Lagebild.t('srcClose') + '">×</button>';
|
||||||
h += '</div>';
|
h += '</div>';
|
||||||
h += '<div class="source-detail-articles">';
|
h += '<div class="source-detail-articles">';
|
||||||
for (var j = 0; j < arts.length; j++) {
|
for (var j = 0; j < arts.length; j++) {
|
||||||
var a = arts[j];
|
var a = arts[j];
|
||||||
var dt = a.published_at || a.collected_at || '';
|
var dt = a.published_at || a.collected_at || '';
|
||||||
var dObj = dt ? new Date(this.toUTC(dt)) : null;
|
var dObj = dt ? new Date(this.toUTC(dt)) : null;
|
||||||
var hl = this.fixUmlauts(a.headline_de || a.headline || '');
|
var hl = this.fixUmlauts(Lagebild.getHeadline(a));
|
||||||
h += '<div class="source-detail-article">';
|
h += '<div class="source-detail-article">';
|
||||||
if (a.source_url) {
|
if (a.source_url) {
|
||||||
h += '<a href="' + this.esc(a.source_url) + '" target="_blank" rel="noopener" class="source-detail-article-title">' + this.esc(hl) + ' ' + this.icons.externalLink + '</a>';
|
h += '<a href="' + this.esc(a.source_url) + '" target="_blank" rel="noopener" class="source-detail-article-title">' + this.esc(hl) + ' ' + this.icons.externalLink + '</a>';
|
||||||
@@ -629,7 +704,7 @@ var Lagebild = {
|
|||||||
h += '<span class="source-detail-article-title">' + this.esc(hl) + '</span>';
|
h += '<span class="source-detail-article-title">' + this.esc(hl) + '</span>';
|
||||||
}
|
}
|
||||||
if (dObj && !isNaN(dObj.getTime())) {
|
if (dObj && !isNaN(dObj.getTime())) {
|
||||||
h += '<span class="source-detail-article-date">' + dObj.toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric', timeZone: TIMEZONE }) + '</span>';
|
h += '<span class="source-detail-article-date">' + dObj.toLocaleDateString(Lagebild.getLocale(), { day: '2-digit', month: '2-digit', year: 'numeric', timeZone: TIMEZONE }) + '</span>';
|
||||||
}
|
}
|
||||||
h += '</div>';
|
h += '</div>';
|
||||||
}
|
}
|
||||||
@@ -712,7 +787,7 @@ var Lagebild = {
|
|||||||
if (locs.length === 0) {
|
if (locs.length === 0) {
|
||||||
var emptyDiv = document.createElement('div');
|
var emptyDiv = document.createElement('div');
|
||||||
emptyDiv.style.cssText = 'position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:1000;background:#151D2E;padding:20px 30px;border-radius:8px;border:1px solid #1E2D45;color:#8896AB;text-align:center;';
|
emptyDiv.style.cssText = 'position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:1000;background:#151D2E;padding:20px 30px;border-radius:8px;border:1px solid #1E2D45;color:#8896AB;text-align:center;';
|
||||||
emptyDiv.innerHTML = 'Keine Standortdaten verfuegbar';
|
emptyDiv.innerHTML = Lagebild.t('mapNoData');
|
||||||
document.getElementById('map-container').appendChild(emptyDiv);
|
document.getElementById('map-container').appendChild(emptyDiv);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -736,7 +811,7 @@ var Lagebild = {
|
|||||||
// Popup mit Artikel-Links
|
// Popup mit Artikel-Links
|
||||||
var popupText = '<strong style="color:#E8ECF4;">' + (l.name || '') + '</strong>';
|
var popupText = '<strong style="color:#E8ECF4;">' + (l.name || '') + '</strong>';
|
||||||
if (l.country_code) popupText += ' <span style="color:#8896AB;font-size:0.8rem;">(' + l.country_code + ')</span>';
|
if (l.country_code) popupText += ' <span style="color:#8896AB;font-size:0.8rem;">(' + l.country_code + ')</span>';
|
||||||
popupText += '<br><span style="font-size:0.85rem;color:#8896AB;">' + (l.article_count || 0) + ' Artikel</span>';
|
popupText += '<br><span style="font-size:0.85rem;color:#8896AB;">' + (l.article_count || 0) + ' ' + Lagebild.t('mapArticles') + '</span>';
|
||||||
if (l.top_articles && l.top_articles.length > 0) {
|
if (l.top_articles && l.top_articles.length > 0) {
|
||||||
popupText += '<div style="margin-top:6px;border-top:1px solid #1E2D45;padding-top:6px;">';
|
popupText += '<div style="margin-top:6px;border-top:1px solid #1E2D45;padding-top:6px;">';
|
||||||
for (var j = 0; j < l.top_articles.length; j++) {
|
for (var j = 0; j < l.top_articles.length; j++) {
|
||||||
@@ -774,7 +849,7 @@ var Lagebild = {
|
|||||||
legend.onAdd = function() {
|
legend.onAdd = function() {
|
||||||
var div = L.DomUtil.create('div', 'map-legend');
|
var div = L.DomUtil.create('div', 'map-legend');
|
||||||
div.style.cssText = 'background:#151D2E;padding:10px 14px;border-radius:4px;border:1px solid #1E2D45;box-shadow:0 2px 8px rgba(0,0,0,0.3);font-size:0.8rem;line-height:1.8;color:#E8ECF4;';
|
div.style.cssText = 'background:#151D2E;padding:10px 14px;border-radius:4px;border:1px solid #1E2D45;box-shadow:0 2px 8px rgba(0,0,0,0.3);font-size:0.8rem;line-height:1.8;color:#E8ECF4;';
|
||||||
var html = '<strong style="color:#C8A851;">Legende</strong><br>';
|
var html = '<strong style="color:#C8A851;">' + Lagebild.t('mapLegend') + '</strong><br>';
|
||||||
['primary', 'secondary', 'tertiary', 'mentioned'].forEach(function(cat) {
|
['primary', 'secondary', 'tertiary', 'mentioned'].forEach(function(cat) {
|
||||||
if (usedCategories[cat] && categoryLabels[cat]) {
|
if (usedCategories[cat] && categoryLabels[cat]) {
|
||||||
html += '<span style="color:' + categoryColors[cat] + ';">●</span> ' + categoryLabels[cat] + '<br>';
|
html += '<span style="color:' + categoryColors[cat] + ';">●</span> ' + categoryLabels[cat] + '<br>';
|
||||||
@@ -813,21 +888,12 @@ var Lagebild = {
|
|||||||
unverified: '?'
|
unverified: '?'
|
||||||
},
|
},
|
||||||
|
|
||||||
fcLabels: {
|
fcLabels: {},
|
||||||
confirmed: 'Bestätigt',
|
|
||||||
unconfirmed: 'Unbestätigt',
|
|
||||||
contradicted: 'Widerlegt',
|
|
||||||
developing: 'Unklar',
|
|
||||||
established: 'Gesichert',
|
|
||||||
disputed: 'Umstritten',
|
|
||||||
'false': 'Falsch',
|
|
||||||
unverified: 'Nicht verifiziert'
|
|
||||||
},
|
|
||||||
|
|
||||||
renderFactChecksTab: function() {
|
renderFactChecksTab: function() {
|
||||||
var checks = this.currentView.fact_checks || [];
|
var checks = this.currentView.fact_checks || [];
|
||||||
if (!checks.length) {
|
if (!checks.length) {
|
||||||
document.getElementById('factchecks-content').innerHTML = '<p style="color:#8896AB">Keine Faktenchecks verfügbar.</p>';
|
document.getElementById('factchecks-content').innerHTML = '<p style="color:#8896AB">' + this.t('fcNone') + '</p>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -844,18 +910,18 @@ var Lagebild = {
|
|||||||
|
|
||||||
// Stat cards (clickable filters)
|
// Stat cards (clickable filters)
|
||||||
var h = '<div class="fc-stats">';
|
var h = '<div class="fc-stats">';
|
||||||
h += '<button class="fc-stat active" data-filter="all"><span class="fc-stat-num">' + checks.length + '</span><span class="fc-stat-label">Gesamt</span></button>';
|
h += '<button class="fc-stat active" data-filter="all"><span class="fc-stat-num">' + checks.length + '</span><span class="fc-stat-label">' + this.t('fcTotal') + '</span></button>';
|
||||||
h += '<button class="fc-stat confirmed" data-filter="confirmed"><span class="fc-stat-num">' + confirmedTotal + '</span><span class="fc-stat-label">Bestätigt</span></button>';
|
h += '<button class="fc-stat confirmed" data-filter="confirmed"><span class="fc-stat-num">' + confirmedTotal + '</span><span class="fc-stat-label">' + this.t('fcConfirmed') + '</span></button>';
|
||||||
h += '<button class="fc-stat unconfirmed" data-filter="unconfirmed"><span class="fc-stat-num">' + openTotal + '</span><span class="fc-stat-label">Offen</span></button>';
|
h += '<button class="fc-stat unconfirmed" data-filter="unconfirmed"><span class="fc-stat-num">' + openTotal + '</span><span class="fc-stat-label">' + this.t('fcOpen') + '</span></button>';
|
||||||
if (contradictedTotal > 0)
|
if (contradictedTotal > 0)
|
||||||
h += '<button class="fc-stat contradicted" data-filter="contradicted"><span class="fc-stat-num">' + contradictedTotal + '</span><span class="fc-stat-label">Widerlegt</span></button>';
|
h += '<button class="fc-stat contradicted" data-filter="contradicted"><span class="fc-stat-num">' + contradictedTotal + '</span><span class="fc-stat-label">' + this.t('fcContradicted') + '</span></button>';
|
||||||
h += '</div>';
|
h += '</div>';
|
||||||
|
|
||||||
// Hinweis bei unvollständiger Liste
|
// Hinweis bei unvollständiger Liste
|
||||||
var storedFcCount = this.currentView.fact_check_count || 0;
|
var storedFcCount = this.currentView.fact_check_count || 0;
|
||||||
if (storedFcCount > 0 && checks.length < storedFcCount) {
|
if (storedFcCount > 0 && checks.length < storedFcCount) {
|
||||||
h += '<div style="padding:8px 12px;margin:8px 0;background:rgba(200,168,81,0.1);border:1px solid rgba(200,168,81,0.3);border-radius:6px;color:#C8A851;font-size:0.85rem;">';
|
h += '<div style="padding:8px 12px;margin:8px 0;background:rgba(200,168,81,0.1);border:1px solid rgba(200,168,81,0.3);border-radius:6px;color:#C8A851;font-size:0.85rem;">';
|
||||||
h += checks.length + ' von ' + storedFcCount + ' Faktenchecks verfügbar (ältere wurden bereinigt)';
|
h += this.t('fcCleaned').replace('{count}', checks.length).replace('{total}', storedFcCount);
|
||||||
h += '</div>';
|
h += '</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -879,7 +945,7 @@ var Lagebild = {
|
|||||||
|
|
||||||
var hasProg = fc.status_history && fc.status_history.length > 1;
|
var hasProg = fc.status_history && fc.status_history.length > 1;
|
||||||
var icon = this.fcIcons[status] || '?';
|
var icon = this.fcIcons[status] || '?';
|
||||||
var label = this.fcLabels[status] || status;
|
var label = this.stLabel(status);
|
||||||
|
|
||||||
h += '<div class="fc-row" data-status-group="' + filterGroup + '">';
|
h += '<div class="fc-row" data-status-group="' + filterGroup + '">';
|
||||||
h += '<div class="fc-row-header" data-fc-index="' + i + '">';
|
h += '<div class="fc-row-header" data-fc-index="' + i + '">';
|
||||||
@@ -893,17 +959,17 @@ var Lagebild = {
|
|||||||
// Expandable detail
|
// Expandable detail
|
||||||
h += '<div class="fc-row-detail">';
|
h += '<div class="fc-row-detail">';
|
||||||
h += '<div class="fc-row-detail-inner">';
|
h += '<div class="fc-row-detail-inner">';
|
||||||
h += '<div class="fc-detail-status"><span class="fc-icon ' + status + '">' + icon + '</span> <strong>' + label + '</strong> – ' + (fc.sources_count || 0) + ' unabhängige Quellen</div>';
|
h += '<div class="fc-detail-status"><span class="fc-icon ' + status + '">' + icon + '</span> <strong>' + label + '</strong> – ' + (fc.sources_count || 0) + ' ' + this.t('fcSources') + '</div>';
|
||||||
|
|
||||||
if (fc.evidence) {
|
if (fc.evidence) {
|
||||||
var ev = this.fixUmlauts(fc.evidence);
|
var ev = this.fixUmlauts(fc.evidence);
|
||||||
ev = this.esc(ev).replace(/(https?:\/\/[^\s,)]+)/g, '<a href="$1" target="_blank" rel="noopener">$1</a>');
|
ev = this.esc(ev).replace(/(https?:\/\/[^\s,)]+)/g, '<a href="$1" target="_blank" rel="noopener">$1</a>');
|
||||||
h += '<div class="fc-detail-evidence"><strong>Evidenz:</strong> ' + ev + '</div>';
|
h += '<div class="fc-detail-evidence"><strong>' + this.t('fcEvidence') + '</strong> ' + ev + '</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasProg) {
|
if (hasProg) {
|
||||||
h += '<div class="fc-detail-progression">';
|
h += '<div class="fc-detail-progression">';
|
||||||
h += '<span class="fc-detail-prog-label">Verlauf:</span>';
|
h += '<span class="fc-detail-prog-label">' + this.t('fcProgression') + '</span>';
|
||||||
for (var j = 0; j < fc.status_history.length; j++) {
|
for (var j = 0; j < fc.status_history.length; j++) {
|
||||||
var step = fc.status_history[j];
|
var step = fc.status_history[j];
|
||||||
if (j > 0) h += '<span class="progression-arrow">→</span>';
|
if (j > 0) h += '<span class="progression-arrow">→</span>';
|
||||||
@@ -991,21 +1057,66 @@ var Lagebild = {
|
|||||||
initLangToggle: function() {
|
initLangToggle: function() {
|
||||||
var btn = document.querySelector('.lang-toggle');
|
var btn = document.querySelector('.lang-toggle');
|
||||||
if (!btn) return;
|
if (!btn) return;
|
||||||
|
var self = this;
|
||||||
btn.addEventListener('click', function(e) {
|
btn.addEventListener('click', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (typeof switchLanguage === 'function') {
|
|
||||||
var cur = (typeof getCurrentLanguage === 'function') ? getCurrentLanguage() : 'de';
|
var cur = (typeof getCurrentLanguage === 'function') ? getCurrentLanguage() : 'de';
|
||||||
switchLanguage(cur === 'de' ? 'en' : 'de');
|
var newLang = cur === 'de' ? 'en' : 'de';
|
||||||
}
|
if (typeof switchLanguage === 'function') switchLanguage(newLang);
|
||||||
|
self.switchContent(newLang);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
switchContent: async function(lang) {
|
||||||
|
var jsonFile = lang === 'en' ? 'data/current_en.json' : 'data/current.json';
|
||||||
|
try {
|
||||||
|
var resp = await fetch(jsonFile + '?t=' + Date.now());
|
||||||
|
if (!resp.ok && lang === 'en') {
|
||||||
|
resp = await fetch('data/current.json?t=' + Date.now());
|
||||||
|
}
|
||||||
|
if (!resp.ok) throw new Error('HTTP ' + resp.status);
|
||||||
|
this.data = await resp.json();
|
||||||
|
this.allSnapshots = {};
|
||||||
|
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,
|
||||||
|
article_count: this.data.incident.article_count,
|
||||||
|
fact_check_count: this.data.incident.factcheck_count
|
||||||
|
};
|
||||||
|
this.render();
|
||||||
|
// Update hero title for language
|
||||||
|
var heroH1 = document.getElementById('hero-title');
|
||||||
|
if (heroH1) {
|
||||||
|
var isResearch = this.data.incident && this.data.incident.type === 'research';
|
||||||
|
heroH1.textContent = isResearch ? this.t('heroResearch') : this.t('hero');
|
||||||
|
}
|
||||||
|
// Update tab labels
|
||||||
|
var tabBtns = document.querySelectorAll('.tab-btn');
|
||||||
|
var isResearch = this.data.incident && this.data.incident.type === 'research';
|
||||||
|
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 === '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 data source note
|
||||||
|
var dsNote = document.querySelector('.data-source-note');
|
||||||
|
if (dsNote) dsNote.textContent = this.t('dataSource');
|
||||||
|
} catch(e) {
|
||||||
|
console.error('Language switch failed:', e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/* ===== FLOATING CTA ===== */
|
/* ===== FLOATING CTA ===== */
|
||||||
initFloatingCta: function() {
|
initFloatingCta: function() {
|
||||||
var cta = document.createElement('div');
|
var cta = document.createElement('div');
|
||||||
cta.className = 'floating-cta';
|
cta.className = 'floating-cta';
|
||||||
cta.innerHTML = '<span class="floating-cta-text">AegisSight Monitor f\u00fcr Ihre Organisation</span>'
|
cta.innerHTML = '<span class="floating-cta-text">' + this.t('ctaText') + '</span>'
|
||||||
+ '<a href="mailto:info@aegis-sight.de" class="floating-cta-btn">Kontakt aufnehmen \u2192</a>'
|
+ '<a href="mailto:info@aegis-sight.de" class="floating-cta-btn">' + this.t('ctaButton') + '</a>'
|
||||||
+ '<button class="floating-cta-close" aria-label="Schlie\u00dfen">×</button>';
|
+ '<button class="floating-cta-close" aria-label="Schlie\u00dfen">×</button>';
|
||||||
document.body.appendChild(cta);
|
document.body.appendChild(cta);
|
||||||
|
|
||||||
@@ -1115,9 +1226,8 @@ var Lagebild = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
stLabel: function(s) {
|
stLabel: function(s) {
|
||||||
return { confirmed: 'Best\u00e4tigt', unconfirmed: 'Unbest\u00e4tigt', established: 'Gesichert',
|
var key = 'st' + s.charAt(0).toUpperCase() + s.slice(1);
|
||||||
unverified: 'Nicht verifiziert', contradicted: 'Widerlegt', disputed: 'Umstritten',
|
return this.t(key) || s;
|
||||||
developing: 'In Entwicklung', 'false': 'Falsch' }[s] || s;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
mdToHtml: function(md) {
|
mdToHtml: function(md) {
|
||||||
@@ -1163,11 +1273,12 @@ var Lagebild = {
|
|||||||
var d = new Date(this.toUTC(iso));
|
var d = new Date(this.toUTC(iso));
|
||||||
if (isNaN(d.getTime())) return iso;
|
if (isNaN(d.getTime())) return iso;
|
||||||
var opts = { timeZone: TIMEZONE, weekday: 'long', day: 'numeric', month: 'long', year: 'numeric', hour: '2-digit', minute: '2-digit', hour12: false };
|
var opts = { timeZone: TIMEZONE, weekday: 'long', day: 'numeric', month: 'long', year: 'numeric', hour: '2-digit', minute: '2-digit', hour12: false };
|
||||||
var parts = new Intl.DateTimeFormat('de-DE', opts).formatToParts(d);
|
var locale = Lagebild.getLocale();
|
||||||
|
var parts = new Intl.DateTimeFormat(locale, opts).formatToParts(d);
|
||||||
var p = {};
|
var p = {};
|
||||||
parts.forEach(function(x) { p[x.type] = x.value; });
|
parts.forEach(function(x) { p[x.type] = x.value; });
|
||||||
return p.weekday + ', ' + p.day + '. ' + p.month + ' ' + p.year
|
if (locale === 'en-GB') return p.weekday + ', ' + p.day + ' ' + p.month + ' ' + p.year + ', ' + p.hour + ':' + p.minute;
|
||||||
+ ' um ' + p.hour + ':' + p.minute + ' Uhr';
|
return p.weekday + ', ' + p.day + '. ' + p.month + ' ' + p.year + ' um ' + p.hour + ':' + p.minute + ' Uhr';
|
||||||
} catch(e) { return iso; }
|
} catch(e) { return iso; }
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1176,7 +1287,7 @@ var Lagebild = {
|
|||||||
try {
|
try {
|
||||||
var d = new Date(this.toUTC(iso));
|
var d = new Date(this.toUTC(iso));
|
||||||
if (isNaN(d.getTime())) return iso;
|
if (isNaN(d.getTime())) return iso;
|
||||||
return d.toLocaleDateString('de-DE', { day: 'numeric', month: 'short', year: 'numeric', timeZone: TIMEZONE });
|
return d.toLocaleDateString(Lagebild.getLocale(), { day: 'numeric', month: 'short', year: 'numeric', timeZone: TIMEZONE });
|
||||||
} catch(e) { return iso; }
|
} catch(e) { return iso; }
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1185,19 +1296,19 @@ var Lagebild = {
|
|||||||
try {
|
try {
|
||||||
var d = new Date(this.toUTC(iso));
|
var d = new Date(this.toUTC(iso));
|
||||||
if (isNaN(d.getTime())) return iso;
|
if (isNaN(d.getTime())) return iso;
|
||||||
return d.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit', timeZone: TIMEZONE });
|
return d.toLocaleTimeString(Lagebild.getLocale(), { hour: '2-digit', minute: '2-digit', timeZone: TIMEZONE });
|
||||||
} catch(e) { return iso; }
|
} catch(e) { return iso; }
|
||||||
},
|
},
|
||||||
|
|
||||||
fmtShort: function(iso) {
|
fmtShort: function(iso) {
|
||||||
if (!iso) return '';
|
if (!iso) return '';
|
||||||
try { return new Date(this.toUTC(iso)).toLocaleDateString('de-DE', { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit', timeZone: TIMEZONE }); }
|
try { return new Date(this.toUTC(iso)).toLocaleDateString(Lagebild.getLocale(), { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit', timeZone: TIMEZONE }); }
|
||||||
catch(e) { return iso; }
|
catch(e) { return iso; }
|
||||||
},
|
},
|
||||||
|
|
||||||
showError: function() {
|
showError: function() {
|
||||||
document.getElementById('summary-content').innerHTML =
|
document.getElementById('summary-content').innerHTML =
|
||||||
'<div class="lagebild-error"><p>Das Lagebild konnte nicht geladen werden. Bitte versuchen Sie es sp\u00e4ter erneut.</p></div>';
|
'<div class="lagebild-error"><p>' + this.t('errorLoad') + '</p></div>';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
In neuem Issue referenzieren
Einen Benutzer sperren