PHP/Tutorials/Adventskalender
Der gestern vorgestellte Adventskalender soll nun in einer Komfort-Variante so umgebaut werden, dass man die Dateien nur einmal hochladen muss. Dabei werden die Türchen stets am richtigen Tag freigeschaltet.
Inhaltsverzeichnis
HTML und CSS
HTML
Der Adventskalender besteht aus einer HTML-Datei. Im Unterschied zur gestrigen Variante ist diese nun in einer index.php
-Datei integriert:
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?=$title?></title>
<style><?php include('css.php') ?></style>
<script><?php include('js.php') ?></script>
</head>
<body>
<h1><a href="https://selfhtml.org"><?=$title?></a></h1>
<ol> <?php
for ($k = 0; $k < sizeof($listitems); $k++) : ?>
<li><?=$listitems[$k]?></li> <?php
endfor ?>
</ol>
</body>
</html>
Dabei fällt auf, dass der HTML-Abschnitt nur aus dem Gerüst besteht:
- Veränderbare Inhalte wie die Überschrift und der Titel werden mit Platzhaltern
<?=$title?>
versehen und dynamisch gefüllt. - Externe Ressourcen wie das Stylesheet oder das JavaScript werden mit
<?php include('css.php') ?>
nachgeladen. - Die Listenelemente des Kalenders werden dynamisch erstellt und die Inhalte der Türchen über eine externe Datei
data.php
, die mit require() geladen wird, gefüllt.
Mischen der Türchen
Auf den ersten Blick mag es komisch erscheinen, eine CSS-Datei als css.php
einzubinden. ein Blick in den Quellcode zeigt aber, dass neben dem reinen CSS auch eine PHP-Schleife die Position der Türchen bestimmt. Anstelle der vielen manuellen Festlegungen mit order kann PHP die Reihenfolge ebenso hübsch, aber völlig zufällig durcheinanderbringen.
<?php
$order = range(1, 24);
shuffle($order);
$orderstring = implode(',',$order);
for ($k = 0; $k < 24; $k++) : ?>
li:nth-of-type(<?=$k+1?>) {
order: <?=$order[$k]?>;
} <?php
endfor ?>
Die Daten
Nachdem wir uns über die HTML-Struktur geeinigt haben (wir verwenden eine geordnete Liste von Links), geht es jetzt darum, die Daten für die Kalendertürchen bereitzustellen. Wir brauchen für jeden Tag ein Linkziel, eine Überschrift, den Autor und einen Teaser. Da sich das für jeden Tag wiederholt, verwenden wir ein Array, bei dem jedes der 24 Array-Elemente aus einem Array mit den 4 Elementen für Linkziel, Überschrift, Autor und Teaser besteht.
$data = [
1 => [
'href' => 'https://forum.selfhtml.org/m17175430',
'heading' => 'SVG skalieren',
'author' => 'Gunnar Bittersmann am 13.11.2019',
'teaser' => 'Ich hab mal ein Beispiel gebaut, ...',
],
// ...
24 => [
'href' => 'https://example.com',
'heading' => 'Überschrift',
'author' => 'Autor',
'teaser' => 'Teaser',
],
];
Da sich die Türchen nicht vorzeitig öffnen dürfen, brauchen wir noch einen Hinweistext für die ganz ungeduldigen.
$default = 'Dieses Türchen öffnet sich erst am ##date##. Dezember.';
##date##
wird bei der Scriptausführung durch den dazugehörenden Tag ersetzt.Ein bisschen Werbung kann man den ganz ungeduldigen (die, die immer in die 24 luschern wollen) auch zumuten:
$donate = [
'href' => 'https://selfhtml.org/spenden.html',
'heading' => 'Es ist noch zu früh.',
'text' => 'Wussten Sie, dass Sie <span class="self">self</span>HTML unterstützen können?',
];
text-transform
in die übliche Schreibweise umgewandelt. Damit wird für Nutzer assisitiver Technologien tatsächlich die Silbe self und nicht ES - E - EL - EF vorgelesen.Nun haben wir alles bereit, um zunächst das Array der Listenelemente zusammenzustellen.
index.php (Ausschnitt)
Zum Abschluss ein kleines Quiz
Was verbirgt sich hinter dem 15. Türchen am
- 14. November 2019,
- 14. Dezember 2019,
- 14. Januar 2020?
Komfort mit JavaScript
Im ersten Teil haben wir mithilfe von PHP eine zufällige Reihenfolge der Kalendertürchen erzeugt. Natürlich wird bei jedem Aufruf der Seite eine neue zufällige Reihenfolge generiert. Um unsere Besucher nicht in den Wahnsinn zu treiben, müssen wir also dafür sorgen, dass die aktuelle Konfiguration des Kalenders (dazu zählen neben der erstmaligen Reihenfolge auch die Status der Kalendertürchen) im Browser gespeichert bleibt. Dafür bedienen wir uns des localStorage
. Gut, wer JavaScript deaktiviert hat, muss halt jeden Tag neu suchen.
Beim Aufruf der Seite wird geprüft, ob das localStorage
-Objekt existiert. Falls es den Eintrag SELForder
nicht gibt, wird er angelegt und mit der (durch PHP erzeugten) zufälligen Reihenfolge befüllt. Das setzt voraus, dass die JavaScript-Ressource ebenso wie die CSS-Datei dynamisch durch PHP erzeugt werden muss.
if (!localStorage.getItem('SELFOrder')) {
localStorage.setItem('SELFOrder','<?=$orderstring?>');
}
Falls es den Eintrag gibt, wird die gespeicherte Reihenfolge (die als kommaseparierte Liste von Zahlen vorliegt) ausgelesen, aufgeteilt und den einzelnen Kalendertürchen zugewiesen.
else {
const SELForder = localStorage.getItem('SELFOrder').split(',');
for (let k = 1; k < 25; k++) {
document.querySelector('li:nth-child('+k+')').style.cssText = 'order: ' + SELForder[k-1];
}
}
Außerdem lesen wir noch aus, welche Türchen schon geöffnet sind
for (let k = 1; k < 25; k++) {
if (localStorage.getItem('SELFday'+k)) {
document.querySelector('li:nth-child('+k+') > a').classList.add('open');
}
}
und registrieren einen Eventlistener auf dem Kalender, damit jedes neu geöffnete Türchen auch flugs gespeichert werden kann.
let calendar = document.querySelector('ol');
calendar.addEventListener('click', saveTheDoor);
Bei Aktivierung eines Links im Kalender wird die Funktion saveTheDoor
aufgerufen. Wir registrieren hier nicht für jedes Türchen einen eigenen Eventhandler, sondern machen uns Eventdelegation zu Nutze.
function saveTheDoor (event) {
const elem = event.target,
link = elem.closest('a'),
listitem = link.parentElement,
day = Array.prototype.indexOf.call(calendar.children, listitem) + 1;
event.target
liefert das Element, auf dem die Aktion (beispielsweise der Mausklick) erfolgte, das kann auch das Span-Element mit dem Inhalt self sein. Mit elem.closest('a')
erhalten wir das a
-Element, innerhalb dessen die Aktion erfolgte, listitem
liefert das Listenelement und in day
steckt die Nummer des geklickten ListenelementsDie Klasse open
zu setzen und das Türchen als geöffnet im localStorage zu speichern, ist dann wirklich nicht schwer.
if (link.classList.length == 0) {
link.classList.add('open');
if (localStorage) {
localStorage.setItem('SELFday'+day,'open');
}
}
}
open
wird nur hinzugefügt, wenn das Linkelement noch keine Klasse besitzt. So werden die Türchen, die sich noch nicht öffnen lassen, nicht verändert.Das komplette Projekt
Das gesamte Projekt finden Sie unter https://github.com/MatthiasApsel/Advent.
$orderstring
speichern wir später imlocalStorage
, damit man nicht jeden Tag mit einer neuen Reihenfolge der Kästchen konfrontiert wird. In der Muggelwelt sind solche Kalender eher selten.