// Modal, das beim Klick auf eine Abfahrtszeile oder einen Verbindungsabschnitt
// geöffnet wird: zeigt Linie, Richtung, eine kleine Karte mit dem Streckenverlauf
// und alle Zwischenhalte mit Zeiten/Verspätungen.
const TripModal = (() => {
let backdrop = null;
let miniMap = null;
function ensureBackdrop() {
if (backdrop) return backdrop;
backdrop = document.createElement('div');
backdrop.className = 'trip-modal-backdrop';
backdrop.hidden = true;
backdrop.innerHTML = `
`;
document.body.appendChild(backdrop);
backdrop.querySelector('.trip-modal__close').addEventListener('click', close);
backdrop.addEventListener('click', (e) => {
if (e.target === backdrop) close();
});
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && !backdrop.hidden) close();
});
return backdrop;
}
function close() {
if (!backdrop) return;
backdrop.hidden = true;
if (miniMap) {
miniMap.remove();
miniMap = null;
}
}
function formatTime(iso) {
if (!iso) return null;
return new Date(iso).toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' });
}
function renderStopover(s, isCurrentOrNext) {
const time = s.departure || s.arrival || s.plannedDeparture || s.plannedArrival;
const plannedTime = s.plannedDeparture || s.plannedArrival;
const delay = s.departureDelay ?? s.arrivalDelay;
let timeHtml;
if (s.cancelled) {
timeHtml = `${formatTime(plannedTime) || '–'}`;
} else if (delay && delay > 0) {
timeHtml = `${formatTime(time)} (+${Math.round(delay / 60)})`;
} else {
timeHtml = `${formatTime(time) || '–'}`;
}
return `
${s.name || ''}
${timeHtml}
`;
}
async function open(tripId) {
if (!tripId) return;
const el = ensureBackdrop();
el.hidden = false;
document.getElementById('trip-modal-line').textContent = '…';
document.getElementById('trip-modal-line').style.background = '#8E99A6';
document.getElementById('trip-modal-direction').textContent = '';
document.getElementById('trip-modal-meta').textContent = '';
document.getElementById('trip-modal-body').innerHTML = 'Lade Fahrt-Details…
';
let trip;
try {
trip = await API.getTrip(tripId, { polyline: true });
} catch (err) {
document.getElementById('trip-modal-body').innerHTML = `⚠ ${err.message}
`;
return;
}
const lineEl = document.getElementById('trip-modal-line');
lineEl.textContent = trip.line || '?';
lineEl.style.background = trip.color || '#8E99A6';
lineEl.style.color = trip.textColor || '#fff';
document.getElementById('trip-modal-direction').textContent = `→ ${trip.direction || trip.destination || ''}`;
document.getElementById('trip-modal-meta').textContent = trip.cancelled
? 'Fahrt fällt aus'
: `${trip.origin || ''} → ${trip.destination || ''}`;
// Mini-Karte mit dem Streckenverlauf zeichnen
if (miniMap) { miniMap.remove(); miniMap = null; }
if (trip.polyline) {
setTimeout(() => {
miniMap = LiveMap.createMiniMap('trip-modal-map', {
legs: [{ polyline: trip.polyline, walking: false, color: trip.color }],
});
if (trip.currentLocation) {
L.marker([trip.currentLocation.latitude, trip.currentLocation.longitude], {
icon: L.divIcon({
className: 'vehicle-marker',
html: `${trip.line || '?'}`,
iconSize: [null, null],
}),
}).addTo(miniMap);
}
}, 50);
} else {
document.getElementById('trip-modal-map').innerHTML = '';
}
const stopovers = trip.stopovers || [];
const now = Date.now();
let currentIndex = stopovers.findIndex((s) => {
const t = s.departure || s.plannedDeparture;
return t && new Date(t).getTime() >= now;
});
if (currentIndex === -1) currentIndex = stopovers.length - 1;
const bodyHtml = `
${stopovers.map((s, i) => renderStopover(s, i === currentIndex)).join('')}
`;
document.getElementById('trip-modal-body').innerHTML = stopovers.length
? bodyHtml
: 'Keine Zwischenhalte verfügbar.
';
}
return { open, close };
})();