Fix Calendar Loading Problems
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
|
||||
<?php
|
||||
// URL der öffentlichen ICS-Datei
|
||||
define(
|
||||
@@ -83,13 +82,10 @@ function format_ics_date_with_timezone($date, $timezone = null)
|
||||
}
|
||||
}
|
||||
|
||||
// ICS-Datei laden
|
||||
$ics = @file_get_contents(CAL_URL);
|
||||
if (!$ics) {
|
||||
echo '<div class="text-red-600">Kalender konnte nicht geladen werden.</div>';
|
||||
|
||||
return;
|
||||
}
|
||||
// Cache für 24 Stunden (in Minuten)
|
||||
$cacheDuration = 24 * 60;
|
||||
$cacheId = 'google_calendar_events';
|
||||
$cache = kirby()->cache('pages');
|
||||
|
||||
// Termine parsen
|
||||
function parse_ics($ics)
|
||||
@@ -134,9 +130,26 @@ function parse_ics($ics)
|
||||
return $events;
|
||||
}
|
||||
|
||||
$events = parse_ics($ics);
|
||||
return function () use ($cache, $cacheId, $cacheDuration) {
|
||||
// Versuche Daten aus dem Cache zu laden
|
||||
$events = $cache->get($cacheId);
|
||||
|
||||
if ($events === null) {
|
||||
// Wenn nicht im Cache, neu laden
|
||||
$ics = @file_get_contents(CAL_URL);
|
||||
|
||||
if (!$ics) {
|
||||
// Fehler beim Laden (z.B. 429 Error)
|
||||
return null;
|
||||
}
|
||||
|
||||
// Termine parsen
|
||||
$events = parse_ics($ics);
|
||||
|
||||
// In Cache speichern
|
||||
$cache->set($cacheId, $events, $cacheDuration);
|
||||
}
|
||||
|
||||
return function () use ($events) {
|
||||
return $events;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,33 +1,40 @@
|
||||
<?php
|
||||
$events = collection('termine');
|
||||
|
||||
if ($events === null): ?>
|
||||
<div class="container mx-auto py-8">
|
||||
<h2>Bevorstehende Termine</h2>
|
||||
<div class="text-red-600">Die Termine können gerade nicht geladen werden.</div>
|
||||
</div>
|
||||
<?php return; endif;
|
||||
|
||||
// Aktuelles Datum - PHP 8.3 kompatibel
|
||||
$today = (new DateTime('now'))->format('Ymd');
|
||||
|
||||
// Nur zukünftige Termine anzeigen
|
||||
$future_events = array_filter($events, function ($event) use ($today) {
|
||||
return isset($event['DTSTART']) && $event['DTSTART'] >= $today;
|
||||
return isset($event['DTSTART']) && $event['DTSTART'] >= $today;
|
||||
});
|
||||
|
||||
// Termine nach DTSTART in aufsteigender Reihenfolge sortieren
|
||||
usort($future_events, function ($a, $b) {
|
||||
return $a['DTSTART'] <=> $b['DTSTART'];
|
||||
return $a['DTSTART'] <=> $b['DTSTART'];
|
||||
});
|
||||
|
||||
// --- Deutsche Monatsnamen ---
|
||||
$de_months = [
|
||||
'01' => 'Jan',
|
||||
'02' => 'Feb',
|
||||
'03' => 'Mrz',
|
||||
'04' => 'Apr',
|
||||
'05' => 'Mai',
|
||||
'06' => 'Jun',
|
||||
'07' => 'Jul',
|
||||
'08' => 'Aug',
|
||||
'09' => 'Sep',
|
||||
'10' => 'Okt',
|
||||
'11' => 'Nov',
|
||||
'12' => 'Dez',
|
||||
'01' => 'Jan',
|
||||
'02' => 'Feb',
|
||||
'03' => 'Mrz',
|
||||
'04' => 'Apr',
|
||||
'05' => 'Mai',
|
||||
'06' => 'Jun',
|
||||
'07' => 'Jul',
|
||||
'08' => 'Aug',
|
||||
'09' => 'Sep',
|
||||
'10' => 'Okt',
|
||||
'11' => 'Nov',
|
||||
'12' => 'Dez',
|
||||
];
|
||||
?>
|
||||
|
||||
@@ -35,8 +42,12 @@ $de_months = [
|
||||
<h2>Bevorstehende Termine</h2>
|
||||
|
||||
<div class="relative flex items-center justify-center">
|
||||
<button id="scroll-left" class="flex-shrink-0 bg-white p-3 rounded-full shadow-lg hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500 z-10 hidden md:block mr-4">
|
||||
<svg class="w-6 h-6 text-gray-700" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path></svg>
|
||||
<button id="scroll-left"
|
||||
class="flex-shrink-0 bg-white p-3 rounded-full shadow-lg hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500 z-10 hidden md:block mr-4">
|
||||
<svg class="w-6 h-6 text-gray-700" fill="none" stroke="currentColor" viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<div id="termine-wrapper" class="relative w-full max-w-7xl overflow-hidden">
|
||||
@@ -69,57 +80,64 @@ $de_months = [
|
||||
$safe_time = htmlspecialchars($time, ENT_QUOTES, 'UTF-8');
|
||||
?>
|
||||
|
||||
<div class="termine-card flex-none w-full md:w-1/2 bg-gradient-to-br from-blue-50 to-blue-100 rounded-2xl transform hover:scale-102 transition-all duration-300 ease-in-out border border-blue-200">
|
||||
<!-- Inhalt der ersten Karte bleibt unverändert -->
|
||||
<div class="p-6 flex flex-col h-full">
|
||||
<div class="flex items-top mb-5">
|
||||
<div class="relative flex-shrink-0 bg-white rounded-lg shadow-md overflow-hidden w-16 h-16 flex flex-col border border-blue-200">
|
||||
<!-- Kopfzeile des Kalenders mit Monat -->
|
||||
<div class="bg-blue-600 text-white text-xs font-semibold py-1 text-center uppercase">
|
||||
<span data-month><?= $month_name ?></span>
|
||||
</div>
|
||||
<div
|
||||
class="termine-card flex-none w-full md:w-1/2 bg-gradient-to-br from-blue-50 to-blue-100 rounded-2xl transform hover:scale-102 transition-all duration-300 ease-in-out border border-blue-200">
|
||||
<!-- Inhalt der ersten Karte bleibt unverändert -->
|
||||
<div class="p-6 flex flex-col h-full">
|
||||
<div class="flex items-top mb-5">
|
||||
<div
|
||||
class="relative flex-shrink-0 bg-white rounded-lg shadow-md overflow-hidden w-16 h-16 flex flex-col border border-blue-200">
|
||||
<!-- Kopfzeile des Kalenders mit Monat -->
|
||||
<div class="bg-blue-600 text-white text-xs font-semibold py-1 text-center uppercase">
|
||||
<span data-month><?= $month_name ?></span>
|
||||
</div>
|
||||
|
||||
<!-- Datumsanzeige -->
|
||||
<div class="flex-grow flex items-center justify-center">
|
||||
<div class="text-3xl font-bold text-sf_grau-800" data-day><?= $safe_day ?></div>
|
||||
</div>
|
||||
<!-- Datumsanzeige -->
|
||||
<div class="flex-grow flex items-center justify-center">
|
||||
<div class="text-3xl font-bold text-sf_grau-800" data-day><?= $safe_day ?></div>
|
||||
</div>
|
||||
|
||||
<!-- Dekorative Elemente - kleine Punkte für Kalendertage -->
|
||||
<div class="absolute bottom-1 left-0 right-0 flex justify-center space-x-0.5 px-1">
|
||||
<div class="w-1 h-1 rounded-full bg-sf_blau-200"></div>
|
||||
<div class="w-1 h-1 rounded-full bg-sf_blau-300"></div>
|
||||
<div class="w-1 h-1 rounded-full bg-sf_blau-400"></div>
|
||||
<div class="w-1 h-1 rounded-full bg-sf_blau-500"></div>
|
||||
<div class="w-1 h-1 rounded-full bg-sf_blau-400"></div>
|
||||
<div class="w-1 h-1 rounded-full bg-sf_blau-300"></div>
|
||||
<div class="w-1 h-1 rounded-full bg-sf_blau-200"></div>
|
||||
<!-- Dekorative Elemente - kleine Punkte für Kalendertage -->
|
||||
<div class="absolute bottom-1 left-0 right-0 flex justify-center space-x-0.5 px-1">
|
||||
<div class="w-1 h-1 rounded-full bg-sf_blau-200"></div>
|
||||
<div class="w-1 h-1 rounded-full bg-sf_blau-300"></div>
|
||||
<div class="w-1 h-1 rounded-full bg-sf_blau-400"></div>
|
||||
<div class="w-1 h-1 rounded-full bg-sf_blau-500"></div>
|
||||
<div class="w-1 h-1 rounded-full bg-sf_blau-400"></div>
|
||||
<div class="w-1 h-1 rounded-full bg-sf_blau-300"></div>
|
||||
<div class="w-1 h-1 rounded-full bg-sf_blau-200"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ml-5 flex-grow">
|
||||
<p class="text-xl font-medium text-sf_grau-900"><?= $event_summary ?></p>
|
||||
<p class="text-sf_blau-700 text-lg font-medium mt-1">
|
||||
<?php if ($date_info['has_time'] ?? false): ?>
|
||||
ab <span class="local-time"
|
||||
data-iso-date="<?= $safe_iso_date ?>"><?= $safe_time ?></span> Uhr
|
||||
<?php else: ?>
|
||||
ganztägig
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ml-5 flex-grow">
|
||||
<p class="text-xl font-medium text-sf_grau-900"><?= $event_summary ?></p>
|
||||
<p class="text-sf_blau-700 text-lg font-medium mt-1">
|
||||
<?php if ($date_info['has_time'] ?? false): ?>
|
||||
ab <span class="local-time" data-iso-date="<?= $safe_iso_date ?>"><?= $safe_time ?></span> Uhr
|
||||
<?php else: ?>
|
||||
ganztägig
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button id="scroll-right" class="flex-shrink-0 bg-white p-3 rounded-full shadow-lg hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500 z-10 hidden md:block ml-4">
|
||||
<svg class="w-6 h-6 text-gray-700" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path></svg>
|
||||
<button id="scroll-right"
|
||||
class="flex-shrink-0 bg-white p-3 rounded-full shadow-lg hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500 z-10 hidden md:block ml-4">
|
||||
<svg class="w-6 h-6 text-gray-700" fill="none" stroke="currentColor" viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const termineWrapper = document.getElementById('termine-wrapper');
|
||||
const termineContainer = document.getElementById('termine-container');
|
||||
const scrollLeftBtn = document.getElementById('scroll-left');
|
||||
@@ -250,32 +268,41 @@ $de_months = [
|
||||
<style>
|
||||
/* Versteckt die Scrollbar vollständig, behält aber die Scrollfunktionalität */
|
||||
#termine-container {
|
||||
-ms-overflow-style: none; /* IE and Edge */
|
||||
scrollbar-width: none; /* Firefox */
|
||||
-ms-overflow-style: none;
|
||||
/* IE and Edge */
|
||||
scrollbar-width: none;
|
||||
/* Firefox */
|
||||
overflow-x: visible;
|
||||
}
|
||||
|
||||
#termine-container::-webkit-scrollbar {
|
||||
display: none; /* Chrome, Safari, Opera */
|
||||
display: none;
|
||||
/* Chrome, Safari, Opera */
|
||||
}
|
||||
|
||||
/* Gleiche Kartenbreiten sicherstellen */
|
||||
@media (min-width: 1280px) {
|
||||
.termine-card {
|
||||
width: 100%; /* 100% minus 2 Gaps (2 * 24px) geteilt durch 3 */
|
||||
width: 100%;
|
||||
/* 100% minus 2 Gaps (2 * 24px) geteilt durch 3 */
|
||||
}
|
||||
|
||||
#termine-container {
|
||||
space-x-0; /* Kein Abstand zwischen Karten nötig */
|
||||
space-x-0;
|
||||
/* Kein Abstand zwischen Karten nötig */
|
||||
}
|
||||
}
|
||||
|
||||
/* Auf mobilen Geräten eine Karte anzeigen */
|
||||
@media (max-width: 1280px) {
|
||||
.termine-card {
|
||||
width: 100%; /* Volle Breite */
|
||||
width: 100%;
|
||||
/* Volle Breite */
|
||||
}
|
||||
|
||||
#termine-container {
|
||||
space-x-0; /* Kein Abstand zwischen Karten nötig */
|
||||
space-x-0;
|
||||
/* Kein Abstand zwischen Karten nötig */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,9 +310,11 @@ $de_months = [
|
||||
.termine-card h3 {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
/* white-space: nowrap; */ /* Diese Zeile entfernen oder kommentieren */
|
||||
/* white-space: nowrap; */
|
||||
/* Diese Zeile entfernen oder kommentieren */
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2; /* Maximal 2 Zeilen anzeigen */
|
||||
-webkit-line-clamp: 2;
|
||||
/* Maximal 2 Zeilen anzeigen */
|
||||
-webkit-box-orient: vertical;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
+94
-85
@@ -2,14 +2,22 @@
|
||||
|
||||
$events = collection('termine');
|
||||
|
||||
if ($events === null): ?>
|
||||
<section class="py-24 bg-sf_grau-50">
|
||||
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||
<div class="text-red-600 bg-white p-6 rounded-lg shadow">Die Termine können gerade nicht geladen werden.</div>
|
||||
</div>
|
||||
</section>
|
||||
<?php return; endif;
|
||||
|
||||
// Nur Events mit DTSTART berücksichtigen
|
||||
$events = array_filter($events, function ($event) {
|
||||
return isset($event['DTSTART']) && !empty($event['DTSTART']);
|
||||
return isset($event['DTSTART']) && !empty($event['DTSTART']);
|
||||
});
|
||||
|
||||
// Nach Datum sortieren
|
||||
usort($events, function ($a, $b) {
|
||||
return strcmp($a['DTSTART'], $b['DTSTART']);
|
||||
return strcmp($a['DTSTART'], $b['DTSTART']);
|
||||
});
|
||||
|
||||
// Aktuelles Datum - PHP 8.3 kompatibel
|
||||
@@ -17,44 +25,44 @@ $today = (new DateTime('now'))->format('Ymd');
|
||||
|
||||
// Nur zukünftige Termine anzeigen
|
||||
$future_events = array_filter($events, function ($event) use ($today) {
|
||||
return isset($event['DTSTART']) && $event['DTSTART'] >= $today;
|
||||
return isset($event['DTSTART']) && $event['DTSTART'] >= $today;
|
||||
});
|
||||
|
||||
// --- Deutsche Monatsnamen ---
|
||||
$de_months = [
|
||||
'01' => 'Januar',
|
||||
'02' => 'Februar',
|
||||
'03' => 'März',
|
||||
'04' => 'April',
|
||||
'05' => 'Mai',
|
||||
'06' => 'Juni',
|
||||
'07' => 'Juli',
|
||||
'08' => 'August',
|
||||
'09' => 'September',
|
||||
'10' => 'Oktober',
|
||||
'11' => 'November',
|
||||
'12' => 'Dezember',
|
||||
'01' => 'Januar',
|
||||
'02' => 'Februar',
|
||||
'03' => 'März',
|
||||
'04' => 'April',
|
||||
'05' => 'Mai',
|
||||
'06' => 'Juni',
|
||||
'07' => 'Juli',
|
||||
'08' => 'August',
|
||||
'09' => 'September',
|
||||
'10' => 'Oktober',
|
||||
'11' => 'November',
|
||||
'12' => 'Dezember',
|
||||
];
|
||||
|
||||
// --- Gruppierung aller Termine nach Jahr und Monat für die Sidebar ---
|
||||
function group_events_by_year_month($events)
|
||||
{
|
||||
$grouped = [];
|
||||
foreach ($events as $event) {
|
||||
if (!isset($event['DTSTART'])) {
|
||||
continue;
|
||||
$grouped = [];
|
||||
foreach ($events as $event) {
|
||||
if (!isset($event['DTSTART'])) {
|
||||
continue;
|
||||
}
|
||||
$date = $event['DTSTART'];
|
||||
$year = substr($date, 0, 4);
|
||||
$month = substr($date, 4, 2);
|
||||
$grouped[$year][$month][] = $event;
|
||||
}
|
||||
krsort($grouped); // Jahre absteigend
|
||||
foreach ($grouped as &$months) {
|
||||
krsort($months); // Monate absteigend
|
||||
}
|
||||
$date = $event['DTSTART'];
|
||||
$year = substr($date, 0, 4);
|
||||
$month = substr($date, 4, 2);
|
||||
$grouped[$year][$month][] = $event;
|
||||
}
|
||||
krsort($grouped); // Jahre absteigend
|
||||
foreach ($grouped as &$months) {
|
||||
krsort($months); // Monate absteigend
|
||||
}
|
||||
|
||||
return $grouped;
|
||||
return $grouped;
|
||||
}
|
||||
|
||||
$all_events_grouped = group_events_by_year_month($events);
|
||||
@@ -64,19 +72,19 @@ $filter_jahr = filter_input(INPUT_GET, 'jahr', FILTER_SANITIZE_FULL_SPECIAL_CHAR
|
||||
$filter_monat = filter_input(INPUT_GET, 'monat', FILTER_SANITIZE_FULL_SPECIAL_CHARS) ?? null;
|
||||
|
||||
if ($filter_jahr && $filter_monat) {
|
||||
$filtered_events = array_filter($events, function ($event) use ($filter_jahr, $filter_monat) {
|
||||
$date = $event['DTSTART'] ?? '';
|
||||
$filtered_events = array_filter($events, function ($event) use ($filter_jahr, $filter_monat) {
|
||||
$date = $event['DTSTART'] ?? '';
|
||||
|
||||
return substr($date, 0, 4) === $filter_jahr && substr($date, 4, 2) === $filter_monat;
|
||||
});
|
||||
return substr($date, 0, 4) === $filter_jahr && substr($date, 4, 2) === $filter_monat;
|
||||
});
|
||||
} elseif ($filter_jahr) {
|
||||
$filtered_events = array_filter($events, function ($event) use ($filter_jahr) {
|
||||
$date = $event['DTSTART'] ?? '';
|
||||
$filtered_events = array_filter($events, function ($event) use ($filter_jahr) {
|
||||
$date = $event['DTSTART'] ?? '';
|
||||
|
||||
return substr($date, 0, 4) === $filter_jahr;
|
||||
});
|
||||
return substr($date, 0, 4) === $filter_jahr;
|
||||
});
|
||||
} else {
|
||||
$filtered_events = $future_events;
|
||||
$filtered_events = $future_events;
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -95,14 +103,15 @@ if ($filter_jahr && $filter_monat) {
|
||||
$is_year_selected = ($filter_jahr === $year && !$filter_monat);
|
||||
?>
|
||||
<a href="?jahr=<?= $safe_year ?>"
|
||||
class="font-bold text-sf_blau-600 focus:outline-none flex items-center group<?= $is_year_selected ? ' underline selected' : '' ?>"
|
||||
onclick="event.stopPropagation(); openYear('<?= $safe_year ?>')">
|
||||
class="font-bold text-sf_blau-600 focus:outline-none flex items-center group<?= $is_year_selected ? ' underline selected' : '' ?>"
|
||||
onclick="event.stopPropagation(); openYear('<?= $safe_year ?>')">
|
||||
<span><?= $safe_year ?></span>
|
||||
</a>
|
||||
<button type="button" class="ml-1 focus:outline-none" onclick="toggleYear('<?= $safe_year ?>')">
|
||||
<svg class="w-4 h-4 transition-transform" id="arrow-<?= $safe_year ?>" fill="none" stroke="currentColor" stroke-width="2"
|
||||
viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/>
|
||||
<button type="button" class="ml-1 focus:outline-none"
|
||||
onclick="toggleYear('<?= $safe_year ?>')">
|
||||
<svg class="w-4 h-4 transition-transform" id="arrow-<?= $safe_year ?>" fill="none"
|
||||
stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
@@ -116,7 +125,7 @@ if ($filter_jahr && $filter_monat) {
|
||||
$event_count = count($evts);
|
||||
?>
|
||||
<a href="?jahr=<?= $safe_year ?>&monat=<?= $safe_month ?>"
|
||||
class="text-sf_blau-500 hover:underline<?= $is_month_selected ? ' font-bold underline selected' : '' ?>">
|
||||
class="text-sf_blau-500 hover:underline<?= $is_month_selected ? ' font-bold underline selected' : '' ?>">
|
||||
<?= htmlspecialchars($month_name, ENT_QUOTES, 'UTF-8') ?> (<?= $event_count ?>)
|
||||
</a>
|
||||
</li>
|
||||
@@ -157,50 +166,50 @@ if ($filter_jahr && $filter_monat) {
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full border border-gray-200 bg-white rounded-lg shadow">
|
||||
<thead>
|
||||
<tr class="bg-gray-100">
|
||||
<th class="py-2 px-4 border-b text-left">Datum</th>
|
||||
<th class="py-2 px-4 border-b text-left">Uhrzeit</th>
|
||||
<th class="py-2 px-4 border-b text-left">Titel</th>
|
||||
</tr>
|
||||
<tr class="bg-gray-100">
|
||||
<th class="py-2 px-4 border-b text-left">Datum</th>
|
||||
<th class="py-2 px-4 border-b text-left">Uhrzeit</th>
|
||||
<th class="py-2 px-4 border-b text-left">Titel</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($filtered_events as $event): ?>
|
||||
<?php
|
||||
$start = $event['DTSTART'] ?? '';
|
||||
$end = $event['DTEND'] ?? '';
|
||||
$summary = $event['SUMMARY'] ?? '';
|
||||
$location = $event['LOCATION'] ?? '';
|
||||
$desc = $event['DESCRIPTION'] ?? '';
|
||||
$timezone = $event['DTSTART_TZID'] ?? null;
|
||||
<?php foreach ($filtered_events as $event): ?>
|
||||
<?php
|
||||
$start = $event['DTSTART'] ?? '';
|
||||
$end = $event['DTEND'] ?? '';
|
||||
$summary = $event['SUMMARY'] ?? '';
|
||||
$location = $event['LOCATION'] ?? '';
|
||||
$desc = $event['DESCRIPTION'] ?? '';
|
||||
$timezone = $event['DTSTART_TZID'] ?? null;
|
||||
|
||||
// Sichere Funktionsaufrufe mit Null-Checks
|
||||
$date_info = function_exists('format_ics_date_with_timezone')
|
||||
? format_ics_date_with_timezone($start, $timezone)
|
||||
: ['display' => '', 'has_time' => false, 'iso' => ''];
|
||||
// Sichere Funktionsaufrufe mit Null-Checks
|
||||
$date_info = function_exists('format_ics_date_with_timezone')
|
||||
? format_ics_date_with_timezone($start, $timezone)
|
||||
: ['display' => '', 'has_time' => false, 'iso' => ''];
|
||||
|
||||
$date = $date_info['display'] ?? '';
|
||||
$time = ($date_info['has_time'] ?? false) ? substr($date, 11) : 'ganztägig';
|
||||
$date = substr($date, 0, 10);
|
||||
$iso_date = $date_info['iso'] ?? '';
|
||||
$date = $date_info['display'] ?? '';
|
||||
$time = ($date_info['has_time'] ?? false) ? substr($date, 11) : 'ganztägig';
|
||||
$date = substr($date, 0, 10);
|
||||
$iso_date = $date_info['iso'] ?? '';
|
||||
|
||||
// Sichere HTML-Ausgabe
|
||||
$safe_date = htmlspecialchars($date, ENT_QUOTES, 'UTF-8');
|
||||
$safe_time = htmlspecialchars($time, ENT_QUOTES, 'UTF-8');
|
||||
$safe_iso_date = htmlspecialchars($iso_date, ENT_QUOTES, 'UTF-8');
|
||||
$safe_summary = htmlspecialchars($summary, ENT_QUOTES, 'UTF-8');
|
||||
?>
|
||||
<tr class="hover:bg-gray-50">
|
||||
<td class="py-2 px-4 border-b whitespace-nowrap"><?= $safe_date ?></td>
|
||||
<td class="py-2 px-4 border-b whitespace-nowrap">
|
||||
<?php if ($date_info['has_time'] ?? false): ?>
|
||||
<span class="local-time" data-iso-date="<?= $safe_iso_date ?>"><?= $safe_time ?></span>
|
||||
<?php else: ?>
|
||||
ganztägig
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td class="py-2 px-4 border-b"><?= $safe_summary ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
// Sichere HTML-Ausgabe
|
||||
$safe_date = htmlspecialchars($date, ENT_QUOTES, 'UTF-8');
|
||||
$safe_time = htmlspecialchars($time, ENT_QUOTES, 'UTF-8');
|
||||
$safe_iso_date = htmlspecialchars($iso_date, ENT_QUOTES, 'UTF-8');
|
||||
$safe_summary = htmlspecialchars($summary, ENT_QUOTES, 'UTF-8');
|
||||
?>
|
||||
<tr class="hover:bg-gray-50">
|
||||
<td class="py-2 px-4 border-b whitespace-nowrap"><?= $safe_date ?></td>
|
||||
<td class="py-2 px-4 border-b whitespace-nowrap">
|
||||
<?php if ($date_info['has_time'] ?? false): ?>
|
||||
<span class="local-time" data-iso-date="<?= $safe_iso_date ?>"><?= $safe_time ?></span>
|
||||
<?php else: ?>
|
||||
ganztägig
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td class="py-2 px-4 border-b"><?= $safe_summary ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -253,7 +262,7 @@ if ($filter_jahr && $filter_monat) {
|
||||
}
|
||||
|
||||
// Zeitzonenkonvertierung beim Laden der Seite
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
convertTimesToLocal();
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user