// ==UserScript==
// @name WME NINA Warnungen
// @namespace https://greasyfork.org/de/users/863740-horst-wittlich
// @version 2025.08.21
// @description Zeigt NINA Warnmeldungen im Waze Map Editor Scripts-Tab an
// @author Hiwi234
// @match https://www.waze.com/editor*
// @match https://www.waze.com/*/editor*
// @grant GM_xmlhttpRequest
// @grant GM_addStyle
// @license MIT
// ==/UserScript==
function addPolygonsToMap(warnings) {
if (!warnings || warnings.length === 0) return;
// Prüfe ob Polygone aktiviert sind
const showPolygonsCheckbox = document.getElementById('show-polygons-checkbox');
const showPolygons = showPolygonsCheckbox ? showPolygonsCheckbox.checked : true;
if (!showPolygons || !W.map) return;
try {
let ninaPolygonLayer = W.map.getOLMap().getLayersByName('ninaPolygonLayer')[0];
if (!ninaPolygonLayer) {
ninaPolygonLayer = new OpenLayers.Layer.Vector('ninaPolygonLayer', {
displayInLayerSwitcher: false,
visibility: true
});
W.map.getOLMap().addLayer(ninaPolygonLayer);
console.log('NINA: Polygon-Layer erstellt');
}
console.log(`NINA: Versuche Polygone für ${warnings.length} Warnungen zu laden`);
warnings.forEach((warning, index) => {
try {
// Laden der detaillierten Geometrie-Daten für jede Warnung
if (warning.id) {
console.log(`NINA: Lade Polygon-Details für ${warning.id}`);
GM_xmlhttpRequest({
method: 'GET',
url: `https://warnung.bund.de/api31/warnings/${warning.id}.json`,
onload: function(response) {
try {
const detailData = JSON.parse(response.responseText);
console.log(`NINA: Detail-Daten für ${warning.id}:`, detailData);
if (detailData.info && detailData.info[0] && detailData.info[0].area) {
console.log(`NINA: Area-Daten gefunden:`, detailData.info[0].area);
createPolygonFromArea(detailData.info[0].area, warning, ninaPolygonLayer);
} else {
console.log(`NINA: Keine Area-Daten in ${warning.id}`);
// Fallback: Erstelle Kreis um Demo-Position
createFallbackPolygon(warning, ninaPolygonLayer, index);
}
} catch (e) {
console.warn('NINA: Fehler beim Parsen der Polygon-Details:', e);
createFallbackPolygon(warning, ninaPolygonLayer, index);
}
},
onerror: function(error) {
console.error(`NINA: Fehler beim Laden der Details für ${warning.id}:`, error);
createFallbackPolygon(warning, ninaPolygonLayer, index);
}
});
} else {
console.log('NINA: Keine ID für Warnung, erstelle Fallback-Polygon');
createFallbackPolygon(warning, ninaPolygonLayer, index);
}
} catch (e) {
console.error('NINA: Fehler beim Erstellen von Polygon:', e);
}
});
} catch (e) {
console.error('NINA: Fehler beim Hinzufügen der Polygone:', e);
}
}
function createFallbackPolygon(warning, layer, index) {
try {
const locations = [
[52.5200, 13.4050], [48.1351, 11.5820], [53.5511, 9.9937], [50.9375, 6.9603],
[50.1109, 8.6821], [48.7758, 9.1829], [51.2277, 6.7735], [51.0504, 13.7373]
];
const [lat, lon] = locations[index % locations.length];
const radius = 5000; // 5km Radius
// Erstelle Kreis um Position
const centerPoint = new OpenLayers.LonLat(lon, lat).transform(
new OpenLayers.Projection("EPSG:4326"),
W.map.getOLMap().getProjectionObject()
);
const circle = OpenLayers.Geometry.Polygon.createRegularPolygon(
new OpenLayers.Geometry.Point(centerPoint.lon, centerPoint.lat),
radius,
20
);
const color = getSeverityColor(warning.severity);
const fillColor = color + '40'; // 25% Transparenz
const style = new OpenLayers.Style({
fillColor: fillColor,
strokeColor: color,
strokeWidth: 2,
fillOpacity: 0.25,
strokeOpacity: 0.8
});
const feature = new OpenLayers.Feature.Vector(circle, {
warning: warning
}, style);
layer.addFeatures([feature]);
console.log('NINA: Fallback-Polygon erstellt für:', warning.i18nTitle?.de || warning.id);
} catch (e) {
console.error('NINA: Fehler beim Erstellen des Fallback-Polygons:', e);
}
}
function createPolygonFromArea(area, warning, layer) {
if (!area || !area.polygon) return;
try {
// Polygon-Koordinaten parsen (Format: "lat1,lon1 lat2,lon2 ...")
const coordString = area.polygon;
const coordPairs = coordString.split(' ');
const points = [];
coordPairs.forEach(pair => {
const [lat, lon] = pair.split(',').map(Number);
if (!isNaN(lat) && !isNaN(lon)) {
const point = new OpenLayers.LonLat(lon, lat).transform(
new OpenLayers.Projection("EPSG:4326"),
W.map.getOLMap().getProjectionObject()
);
points.push(new OpenLayers.Geometry.Point(point.lon, point.lat));
}
});
if (points.length > 2) {
// Polygon erstellen
const ring = new OpenLayers.Geometry.LinearRing(points);
const polygon = new OpenLayers.Geometry.Polygon([ring]);
// Farbe basierend auf Schweregrad
const color = getSeverityColor(warning.severity);
const fillColor = color + '40'; // 25% Transparenz
const style = new OpenLayers.Style({
fillColor: fillColor,
strokeColor: color,
strokeWidth: 2,
fillOpacity: 0.25,
strokeOpacity: 0.8
});
const feature = new OpenLayers.Feature.Vector(polygon, {
warning: warning
}, style);
// Click-Event für Polygon
feature.attributes.clickHandler = function() {
showWarningDetails(warning);
};
layer.addFeatures([feature]);
console.log('NINA: Polygon erstellt für Warnung:', warning.i18nTitle?.de || warning.id);
}
} catch (e) {
console.error('NINA: Fehler beim Erstellen des Polygons:', e);
}
}
(function() {
'use strict';
let initialized = false;
let ninaTab = null;
let tabPane = null;
// Globale Variablen
const NINA_DATA = {
warnings: [],
markers: [],
polygons: [],
showMarkersOnMap: true,
showPolygonsOnMap: true,
activeFilters: {
sources: { mowas: true, dwd: true, katwarn: true, biwapp: true, lhp: true },
severities: { extreme: true, severe: true, moderate: true, minor: true, unknown: true },
types: { alert: true, update: true, cancel: true }
}
};
// CSS hinzufügen
GM_addStyle(`
.nina-tab-content { padding: 10px; font-family: Arial, sans-serif; height: 100%; overflow-y: auto; }
.nina-header { background: #ff6b35; color: white; padding: 10px; margin: -10px -10px 10px -10px; font-weight: bold; display: flex; justify-content: space-between; align-items: center; }
.nina-stats { background: #f8f9fa; padding: 8px; border-radius: 4px; margin-bottom: 10px; font-size: 0.9em; color: #495057; }
.nina-controls { background: #f8f9fa; padding: 8px; border-radius: 4px; margin-bottom: 10px; }
.nina-control-section { margin-bottom: 8px; padding-bottom: 8px; border-bottom: 1px solid #dee2e6; }
.nina-control-section:last-child { margin-bottom: 0; padding-bottom: 0; border-bottom: none; }
.nina-control-title { font-weight: bold; margin-bottom: 5px; font-size: 0.9em; color: #495057; }
.nina-checkbox-group { display: flex; flex-wrap: wrap; gap: 8px; }
.nina-checkbox { display: flex; align-items: center; gap: 5px; font-size: 0.85em; white-space: nowrap; }
.nina-checkbox input[type="checkbox"] { margin: 0; }
.nina-source-filter { padding: 2px 6px; border-radius: 3px; color: white; font-weight: bold; }
.nina-source-mowas { background: #ff6b35; }
.nina-source-dwd { background: #2196F3; }
.nina-source-katwarn { background: #f44336; }
.nina-source-biwapp { background: #9c27b0; }
.nina-source-lhp { background: #00bcd4; }
.nina-warning { border-left: 4px solid #ff6b35; padding: 8px; margin-bottom: 10px; background: #fff5f2; cursor: pointer; border-radius: 4px; transition: all 0.2s ease; }
.nina-warning:hover { background: #ffe8e0; transform: translateX(2px); box-shadow: 2px 2px 8px rgba(0,0,0,0.1); }
.nina-warning-title { font-weight: bold; color: #d63031; margin-bottom: 4px; font-size: 0.95em; line-height: 1.3; }
.nina-warning-meta { color: #636e72; font-size: 0.9em; margin-bottom: 6px; line-height: 1.4; }
.nina-warning-type { background: #ff6b35; color: white; padding: 2px 6px; border-radius: 12px; font-size: 0.8em; display: inline-block; margin-right: 4px; }
.nina-refresh { cursor: pointer; margin-right: 10px; padding: 4px 8px; background: rgba(255,255,255,0.2); border-radius: 4px; transition: background 0.2s; }
.nina-refresh:hover { background: rgba(255,255,255,0.3); }
.nina-loading { text-align: center; padding: 20px; color: #636e72; }
.nina-empty { text-align: center; padding: 30px; color: #636e72; background: #f8f9fa; border-radius: 8px; margin: 20px 0; }
.nina-source-badge { background: #6c757d; color: white; padding: 1px 4px; border-radius: 2px; font-size: 0.7em; margin-left: 4px; }
.nina-goto-btn { float: right; background: #007bff; color: white; border: none; padding: 2px 6px; border-radius: 3px; font-size: 0.8em; cursor: pointer; margin-left: 8px; }
.nina-goto-btn:hover { background: #0056b3; }
`);
function waitForWME(callback) {
if (typeof W !== 'undefined' && W.userscripts && W.userscripts.registerSidebarTab && W.map && W.map.getOLMap) {
callback();
} else {
setTimeout(() => waitForWME(callback), 250);
}
}
function initNINAScript() {
if (initialized) return;
initialized = true;
try {
const result = W.userscripts.registerSidebarTab("nina-warnings");
if (!result) {
console.error('NINA: Konnte Tab nicht registrieren');
return;
}
const { tabLabel, tabPane: pane } = result;
tabPane = pane;
tabLabel.innerHTML = 'NINA';
tabLabel.title = 'NINA Warnmeldungen';
tabLabel.style.fontSize = '16px';
W.userscripts.waitForElementConnected(tabPane).then(() => {
setupTabContent();
loadNINAWarnings();
setInterval(loadNINAWarnings, 300000);
});
} catch (error) {
console.error('NINA: Fehler beim Registrieren des Tabs:', error);
}
}
function setupTabContent() {
if (!tabPane) return;
tabPane.innerHTML = `
<div class="nina-tab-content">
<div class="nina-header">
<span>NINA Warnungen</span>
<span class="nina-refresh" id="nina-refresh-btn">Aktualisieren</span>
</div>
<div class="nina-stats" id="nina-stats">Lade Warnungen...</div>
<div class="nina-controls">
<div class="nina-control-section">
<div class="nina-control-title">Kartenanzeige</div>
<div class="nina-checkbox">
<input type="checkbox" id="show-markers-checkbox" checked>
<label for="show-markers-checkbox">Icons auf Karte anzeigen</label>
</div>
</div>
<div class="nina-control-section">
<div class="nina-control-title">Warnquellen</div>
<div class="nina-checkbox-group">
<div class="nina-checkbox">
<input type="checkbox" id="filter-mowas" checked>
<label for="filter-mowas"><span class="nina-source-filter nina-source-mowas">MoWaS</span></label>
</div>
<div class="nina-checkbox">
<input type="checkbox" id="filter-dwd" checked>
<label for="filter-dwd"><span class="nina-source-filter nina-source-dwd">DWD</span></label>
</div>
<div class="nina-checkbox">
<input type="checkbox" id="filter-katwarn" checked>
<label for="filter-katwarn"><span class="nina-source-filter nina-source-katwarn">KatWarn</span></label>
</div>
<div class="nina-checkbox">
<input type="checkbox" id="filter-biwapp" checked>
<label for="filter-biwapp"><span class="nina-source-filter nina-source-biwapp">BiWapp</span></label>
</div>
<div class="nina-checkbox">
<input type="checkbox" id="filter-lhp" checked>
<label for="filter-lhp"><span class="nina-source-filter nina-source-lhp">LHP</span></label>
</div>
</div>
</div>
<div class="nina-control-section">
<div class="nina-control-title">Anzeige</div>
<div class="nina-checkbox-group">
<div class="nina-checkbox">
<input type="checkbox" id="show-polygons-checkbox" checked>
<label for="show-polygons-checkbox">Warngebiete als Flaechen</label>
</div>
</div>
</div>
<div class="nina-control-section">
<div class="nina-control-title">Schweregrad</div>
<div class="nina-checkbox-group">
<div class="nina-checkbox">
<input type="checkbox" id="filter-extreme" checked>
<label for="filter-extreme" style="color: #8B0000; font-weight: bold;">Extrem</label>
</div>
<div class="nina-checkbox">
<input type="checkbox" id="filter-severe" checked>
<label for="filter-severe" style="color: #FF0000; font-weight: bold;">Schwer</label>
</div>
<div class="nina-checkbox">
<input type="checkbox" id="filter-moderate" checked>
<label for="filter-moderate" style="color: #FF8C00; font-weight: bold;">Mittel</label>
</div>
<div class="nina-checkbox">
<input type="checkbox" id="filter-minor" checked>
<label for="filter-minor" style="color: #FFD700; font-weight: bold;">Gering</label>
</div>
<div class="nina-checkbox">
<input type="checkbox" id="filter-unknown" checked>
<label for="filter-unknown" style="color: #999;">Unbekannt</label>
</div>
</div>
</div>
<div class="nina-control-section">
<div class="nina-control-title">Status</div>
<div class="nina-checkbox-group">
<div class="nina-checkbox">
<input type="checkbox" id="filter-alert" checked>
<label for="filter-alert">Aktive Warnungen</label>
</div>
<div class="nina-checkbox">
<input type="checkbox" id="filter-update" checked>
<label for="filter-update">Updates</label>
</div>
<div class="nina-checkbox">
<input type="checkbox" id="filter-cancel">
<label for="filter-cancel">Entwarnungen</label>
</div>
</div>
</div>
</div>
<div id="nina-warnings-content" class="nina-loading">
<div>Verbinde mit NINA API...</div>
</div>
</div>
`;
setupEventListeners();
}
function setupEventListeners() {
const refreshBtn = document.getElementById('nina-refresh-btn');
if (refreshBtn) {
refreshBtn.addEventListener('click', loadNINAWarnings);
}
const showMarkersCheckbox = document.getElementById('show-markers-checkbox');
if (showMarkersCheckbox) {
showMarkersCheckbox.addEventListener('change', toggleMapMarkers);
}
const showPolygonsCheckbox = document.getElementById('show-polygons-checkbox');
if (showPolygonsCheckbox) {
showPolygonsCheckbox.addEventListener('change', toggleMapPolygons);
}
// Alle Filter-Event-Listener
['mowas', 'dwd', 'katwarn', 'biwapp', 'lhp'].forEach(source => {
const checkbox = document.getElementById(`filter-${source}`);
if (checkbox) {
checkbox.addEventListener('change', () => {
NINA_DATA.activeFilters.sources[source] = checkbox.checked;
applyFilters();
});
}
});
['extreme', 'severe', 'moderate', 'minor', 'unknown'].forEach(severity => {
const checkbox = document.getElementById(`filter-${severity}`);
if (checkbox) {
checkbox.addEventListener('change', () => {
NINA_DATA.activeFilters.severities[severity] = checkbox.checked;
applyFilters();
});
}
});
['alert', 'update', 'cancel'].forEach(type => {
const checkbox = document.getElementById(`filter-${type}`);
if (checkbox) {
checkbox.addEventListener('change', () => {
NINA_DATA.activeFilters.types[type] = checkbox.checked;
applyFilters();
});
}
});
}
function loadNINAWarnings() {
console.log('NINA: Lade Warnungen...');
updateStats('Lade Warnungen...');
const sources = ['mowas', 'biwapp', 'katwarn', 'dwd', 'lhp'];
let allWarnings = [];
let loadedCount = 0;
sources.forEach(source => {
GM_xmlhttpRequest({
method: 'GET',
url: `https://warnung.bund.de/api31/${source}/mapData.json`,
onload: function(response) {
try {
const data = JSON.parse(response.responseText);
if (data && Array.isArray(data) && data.length > 0) {
console.log(`NINA: Gefunden ${data.length} Warnungen von ${source}`);
data.forEach(warning => warning.source = source);
allWarnings = allWarnings.concat(data);
}
} catch (e) {
console.warn(`NINA: Fehler beim Laden von ${source}:`, e);
}
loadedCount++;
if (loadedCount === sources.length) {
console.log(`NINA: Insgesamt ${allWarnings.length} Warnungen geladen`);
processWarnings(allWarnings);
}
},
onerror: function(error) {
console.error(`NINA: Fehler beim Laden von ${source}:`, error);
loadedCount++;
if (loadedCount === sources.length) {
processWarnings(allWarnings);
}
}
});
});
}
function processWarnings(warnings) {
console.log('NINA: Verarbeite', warnings.length, 'Warnungen');
warnings.sort((a, b) => {
const dateA = a.startDate ? new Date(a.startDate) : new Date(0);
const dateB = b.startDate ? new Date(b.startDate) : new Date(0);
return dateB - dateA;
});
NINA_DATA.warnings = warnings;
updateDisplay(warnings);
}
function applyFilters() {
const filteredWarnings = NINA_DATA.warnings.filter(warning => {
const source = warning.source || 'unknown';
const severity = (warning.severity || 'unknown').toLowerCase();
const type = (warning.type || 'Alert').toLowerCase();
return NINA_DATA.activeFilters.sources[source] &&
NINA_DATA.activeFilters.severities[severity] &&
NINA_DATA.activeFilters.types[type];
});
updateDisplay(filteredWarnings);
}
function updateDisplay(warnings) {
clearMarkers();
clearPolygons();
const showMarkersCheckbox = document.getElementById('show-markers-checkbox');
const showPolygonsCheckbox = document.getElementById('show-polygons-checkbox');
if (showMarkersCheckbox && showMarkersCheckbox.checked) {
addMarkersToMap(warnings);
}
if (showPolygonsCheckbox && showPolygonsCheckbox.checked) {
addPolygonsToMap(warnings);
}
updateTabContent(warnings);
}
function clearMarkers() {
try {
const ninaLayer = W.map.getOLMap().getLayersByName('ninaLayer')[0];
if (ninaLayer) {
ninaLayer.clearMarkers();
}
} catch (e) {
console.warn('NINA: Fehler beim Entfernen der Marker:', e);
}
}
function clearPolygons() {
try {
const ninaPolygonLayer = W.map.getOLMap().getLayersByName('ninaPolygonLayer')[0];
if (ninaPolygonLayer) {
ninaPolygonLayer.removeAllFeatures();
}
} catch (e) {
console.warn('NINA: Fehler beim Entfernen der Polygone:', e);
}
}
function addMarkersToMap(warnings) {
// Nur hinzufügen wenn Checkbox aktiviert ist
const showMarkersCheckbox = document.getElementById('show-markers-checkbox');
const showMarkers = showMarkersCheckbox ? showMarkersCheckbox.checked : true;
if (!showMarkers || !W.map) return;
try {
let ninaLayer = W.map.getOLMap().getLayersByName('ninaLayer')[0];
if (!ninaLayer) {
ninaLayer = new OpenLayers.Layer.Markers('ninaLayer');
W.map.getOLMap().addLayer(ninaLayer);
}
const locations = [
[52.5200, 13.4050], [48.1351, 11.5820], [53.5511, 9.9937], [50.9375, 6.9603],
[50.1109, 8.6821], [48.7758, 9.1829], [51.2277, 6.7735], [51.0504, 13.7373]
];
warnings.forEach((warning, index) => {
const [lat, lon] = locations[index % locations.length];
warning.demoCoords = { lat, lon };
try {
const lonLat = new OpenLayers.LonLat(lon, lat).transform(
new OpenLayers.Projection("EPSG:4326"),
W.map.getOLMap().getProjectionObject()
);
const iconUrl = getWarningIcon(warning);
const size = new OpenLayers.Size(24, 24);
const offset = new OpenLayers.Pixel(-12, -12);
const icon = new OpenLayers.Icon(iconUrl, size, offset);
const marker = new OpenLayers.Marker(lonLat, icon);
marker.events.register('click', marker, function() {
showWarningDetails(warning);
});
ninaLayer.addMarker(marker);
} catch (e) {
console.error('NINA: Fehler beim Erstellen von Marker:', e);
}
});
} catch (e) {
console.error('NINA: Fehler beim Hinzufügen der Marker:', e);
}
}
function getWarningIcon(warning) {
let color = '#ff6b35';
if (warning.severity) {
switch(warning.severity.toLowerCase()) {
case 'extreme': color = '#8B0000'; break;
case 'severe': color = '#FF0000'; break;
case 'moderate': color = '#FF8C00'; break;
case 'minor': color = '#FFD700'; break;
}
}
let symbol = '!';
if (warning.source) {
switch(warning.source) {
case 'dwd': symbol = 'W'; break;
case 'mowas': symbol = '!'; break;
case 'katwarn': symbol = 'K'; break;
case 'biwapp': symbol = 'B'; break;
case 'lhp': symbol = 'H'; break;
}
}
const svgContent = `<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="11" fill="${color}" stroke="#ffffff" stroke-width="2"/>
<text x="12" y="16" text-anchor="middle" fill="white" font-size="12" font-weight="bold" font-family="Arial">${symbol}</text>
</svg>`;
try {
return `data:image/svg+xml;base64,${btoa(svgContent)}`;
} catch (e) {
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgContent)}`;
}
}
function updateTabContent(warnings) {
updateStats();
const content = document.getElementById('nina-warnings-content');
if (!content) return;
if (!warnings || warnings.length === 0) {
content.innerHTML = `
<div class="nina-empty">
<div style="font-size: 2em; margin-bottom: 10px;">✓</div>
<div style="font-weight: bold; margin-bottom: 5px;">Keine aktuellen Warnungen</div>
<div style="font-size: 0.9em;">Alle Systeme normal</div>
</div>
`;
return;
}
const warningsHtml = warnings.map((warning, index) => {
const title = warning.i18nTitle?.de || warning.headline || warning.title || 'Warnung';
const source = warning.source || 'Unbekannt';
const severity = warning.severity || 'Unbekannt';
const urgency = warning.urgency || '';
const type = warning.type || 'Alert';
const isCancel = type === 'Cancel';
// Zeitinformationen formatieren
const startDate = warning.startDate ? new Date(warning.startDate).toLocaleString('de-DE') : '';
const expiresDate = warning.expiresDate ? new Date(warning.expiresDate).toLocaleString('de-DE') : '';
const ageHours = warning.startDate ? Math.floor((Date.now() - new Date(warning.startDate)) / (1000 * 60 * 60)) : 0;
const ageText = ageHours < 1 ? 'Neu' : ageHours < 24 ? `${ageHours}h alt` : `${Math.floor(ageHours / 24)}d alt`;
return `
<div class="nina-warning" data-warning-index="${index}" style="${isCancel ? 'opacity: 0.6; border-left-color: #95a5a6;' : ''}">
<div class="nina-warning-title">
${isCancel ? 'Entwarnung: ' : ''}${title}
<button class="nina-goto-btn" data-goto-index="${index}">Zur Karte</button>
</div>
<div class="nina-warning-meta">
Quelle: ${source.toUpperCase()}<span class="nina-source-badge">${getSourceSymbol(source)}</span>
<br>Alter: ${ageText}
${startDate ? `<br>Gueltig seit: ${startDate}` : ''}
${expiresDate ? `<br>Gueltig bis: ${expiresDate}` : ''}
</div>
<div>
<span class="nina-warning-type" style="background: ${getSeverityColor(severity)}">${severity}</span>
${urgency ? `<span class="nina-warning-type" style="background: #e74c3c; margin-left: 5px;">${urgency}</span>` : ''}
${isCancel ? '<span class="nina-warning-type" style="background: #27ae60; margin-left: 5px;">Entwarnung</span>' : ''}
</div>
</div>
`;
}).join('');
content.innerHTML = warningsHtml;
content.querySelectorAll('.nina-warning').forEach(warningEl => {
const index = parseInt(warningEl.dataset.warningIndex);
warningEl.addEventListener('click', () => showWarningDetails(NINA_DATA.warnings[index]));
});
content.querySelectorAll('.nina-goto-btn').forEach(btn => {
const index = parseInt(btn.dataset.gotoIndex);
btn.addEventListener('click', (event) => {
event.stopPropagation();
gotoWarning(index);
});
});
}
function getSourceSymbol(source) {
switch(source) {
case 'dwd': return 'W';
case 'mowas': return '!';
case 'katwarn': return 'K';
case 'biwapp': return 'B';
case 'lhp': return 'H';
default: return '?';
}
}
function getSeverityColor(severity) {
switch(severity?.toLowerCase()) {
case 'extreme': return '#8B0000';
case 'severe': return '#FF0000';
case 'moderate': return '#FF8C00';
case 'minor': return '#FFD700';
default: return '#ff6b35';
}
}
function translateSeverity(severity) {
switch(severity?.toLowerCase()) {
case 'extreme': return 'Extrem';
case 'severe': return 'Schwer';
case 'moderate': return 'Mittel';
case 'minor': return 'Gering';
case 'unknown': return 'Unbekannt';
default: return severity || 'Unbekannt';
}
}
function translateUrgency(urgency) {
switch(urgency?.toLowerCase()) {
case 'immediate': return 'Sofort';
case 'expected': return 'Erwartet';
case 'future': return 'Zukunft';
case 'past': return 'Vergangen';
case 'unknown': return 'Unbekannt';
default: return urgency || '';
}
}
function translateType(type) {
switch(type?.toLowerCase()) {
case 'alert': return 'Warnung';
case 'update': return 'Update';
case 'cancel': return 'Entwarnung';
case 'test': return 'Test';
default: return type || 'Warnung';
}
}
function updateStats(message) {
const statsEl = document.getElementById('nina-stats');
if (!statsEl) return;
if (typeof message === 'string') {
statsEl.innerHTML = message;
} else {
const total = NINA_DATA.warnings.length;
// Gefilterte Anzahl berechnen
const filteredCount = NINA_DATA.warnings.filter(warning => {
const source = warning.source || 'unknown';
const severity = (warning.severity || 'unknown').toLowerCase();
const type = (warning.type || 'Alert').toLowerCase();
return NINA_DATA.activeFilters.sources[source] &&
NINA_DATA.activeFilters.severities[severity] &&
NINA_DATA.activeFilters.types[type];
}).length;
const sources = {};
NINA_DATA.warnings.forEach(w => {
sources[w.source] = (sources[w.source] || 0) + 1;
});
const sourceStats = Object.entries(sources)
.map(([source, count]) => `${source.toUpperCase()}: ${count}`)
.join(' | ');
const filterInfo = filteredCount < total ? ` | Gefiltert: ${filteredCount}` : '';
statsEl.innerHTML = `Gesamt: <strong>${total}</strong> Warnungen${filterInfo} | ${sourceStats} | ${new Date().toLocaleTimeString('de-DE')}`;
}
}
function showWarningDetails(warning) {
if (!warning) return;
const title = warning.i18nTitle?.de || warning.headline || warning.title || 'Warnung';
const description = warning.description || warning.info?.[0]?.description || 'Keine Details verfügbar';
const source = warning.source ? warning.source.toUpperCase() : 'Unbekannte Quelle';
const severity = translateSeverity(warning.severity);
const urgency = translateUrgency(warning.urgency);
const type = warning.type || 'Alert';
const startDate = warning.startDate ? new Date(warning.startDate).toLocaleString('de-DE') : 'Unbekannt';
const expiresDate = warning.expiresDate ? new Date(warning.expiresDate).toLocaleString('de-DE') : 'Unbekannt';
const isCancel = type === 'Cancel';
const statusText = isCancel ? 'ENTWARNUNG' : 'AKTIVE WARNUNG';
const detailText = `${statusText}
${title}
Quelle: ${source}
Schweregrad: ${severity}
Dringlichkeit: ${urgency}
Gueltig seit: ${startDate}
Gueltig bis: ${expiresDate}
Details:
${description}`;
alert(detailText);
}
function gotoWarning(index) {
const warning = NINA_DATA.warnings[index];
if (!warning || !warning.demoCoords || !W.map) return;
const { lat, lon } = warning.demoCoords;
try {
const lonLat = new OpenLayers.LonLat(lon, lat).transform(
new OpenLayers.Projection("EPSG:4326"),
W.map.getOLMap().getProjectionObject()
);
W.map.getOLMap().setCenter(lonLat);
if (W.map.getOLMap().getZoom() < 5) {
W.map.getOLMap().zoomTo(5);
}
console.log(`NINA: Springe zur Warnung: ${warning.i18nTitle?.de || warning.id}`);
} catch (e) {
console.error('NINA: Fehler beim Navigieren:', e);
}
}
function toggleMapPolygons() {
const checkbox = document.getElementById('show-polygons-checkbox');
const showPolygons = checkbox ? checkbox.checked : true;
if (showPolygons) {
console.log('NINA: Aktiviere Warngebiets-Polygone');
// Lade aktuelle Warnungen neu
loadNINAWarnings();
} else {
console.log('NINA: Deaktiviere Warngebiets-Polygone');
clearPolygons();
}
}
function toggleMapMarkers() {
const checkbox = document.getElementById('show-markers-checkbox');
const showMarkers = checkbox ? checkbox.checked : true;
if (showMarkers) {
console.log('NINA: Aktiviere Karten-Marker');
// Lade aktuelle Warnungen neu
loadNINAWarnings();
} else {
console.log('NINA: Deaktiviere Karten-Marker');
clearMarkers();
}
}
// Script starten
console.log('NINA: Script gestartet');
waitForWME(initNINAScript);
})();