Harbingers Of Death
'Are you going to die?' sammelt historische Aberglauben über den Tod. Dieses Projekt satirisiert heutige Verschwörungstheorien, indem es veraltete Aberglauben als real darstellt.
Typ
LAMP Website
Jahr
2018
Angewandte Fähigkeiten
- Back-End
- Front-End
- Java
Team
- Eigenes Projekt
<h2>Die Aufgabe</h2>
<p>Ziel dieses Projekts war es, Back-end-Entwicklung mit dem LAMP-Stack zu üben. Nutzer können sich auf der Seite registrieren, mit Inhalten interagieren und werden von einer personalisierten Startseite begrüßt. Die Seite bietet datenbankgesteuerte Inhalte, sichere Authentifizierung sowie AJAX-Suche und -Filterung.</p>
Das Ergebnis
Harbingers of Death präsentiert veraltete Omen aus einem Artikel von 1889, als wären sie real – als Satire moderner Verschwörungstheorien. Die Content Units sind einzelne Omen. Sie enthalten Informationen darüber, wen sie betreffen, was sie auslöst und in welcher Situation man ihnen begegnet. Nutzer können sie über verschiedene Taxonomien und per Suche erkunden.
Besucher können Omen filtern nach Schuldigen, Betroffenen und Lebensaspekt. Außerdem können Omen über ein Textfeld durchsucht werden.
Mitglieder melden sich an, um zu verfolgen, welche Omen sie erlebt haben und wen sie als nächstes sterben lassen.
<figure onclick="viewImage(this)">
<img src="/assets/img/harbingersofdeath/lqip/animated-form.jpg" lqip-gif alt="Animiertes Formular mit schwebenden Labels (ARIA-freundlich)">
<figcaption class="center">Formular-Styling (ARIA-freundlich)</figcaption>
</figure>
<figure onclick="viewImage(this)">
<img src="/assets/img/harbingersofdeath/lqip/screen-member-home.jpg" alt="Harbingers of Death – Mitglieder-Startseite">
<figcaption class="center">Mitglieder-Startseite</figcaption>
</figure>
</div>
Der Code
Ein entscheidendes Element für den Erfolg dieses Projekts war die Trennung von Views und Logik. So konnten wir sehr sauberen Code schreiben. Als ich die einzelnen Omen-Inhaltsseiten implementierte, trennte ich Code für die Darstellung von Code für das Abrufen und Organisieren der Daten. Zur Laufzeit wird beim Verarbeiten der Omen-Route in index.php eine Omen-Instanz über OmenCollection.php erzeugt und an die Seitenansicht omen.php übergeben.
<?php// CODE SNIPPET, NOT THE FULL FILE ///************************************************* ** INDIVIDUAL OMEN ROUTE *************************************************/// Add the individual omen routeRoute::get('/omen/([a-z0-9]+(?:-[a-z0-9]+)*)', function($slug) { $omen = OmenCollection::getOmenBySlug($slug); Page::build('omen', ["omen" => $omen]);});?><?php// CODE SNIPPET, NOT THE FULL FILE ///** * @return Omen */public static function getOmenBySlug(string $slug) : Omen{ //Select all from the table that is created by performing inner joins. Tables joined: omen, aspect, death & fault. $query = "SELECT * FROM"; //Join omen with aspect $query .= " (((".self::T_OMEN." INNER JOIN ".self::T_ASPECT." ON ".self::T_OMEN.".".self::C_ASPECT." = ".self::T_ASPECT.".".self::C_TERM.")"; //Join result with death $query .= " INNER JOIN ".self::T_DEATH." ON ".self::T_OMEN.".".self::C_DEATH." = ".self::T_DEATH.".".self::C_TERM.")"; //Join result with fault $query .= " INNER JOIN ".self::T_FAULT." ON ".self::T_OMEN.".".self::C_FAULT." = ".self::T_FAULT.".".self::C_TERM.")"; //Filter result by omen slug $query .= " WHERE ".self::T_OMEN.".".self::C_SLUG." = '".$slug."';"; return (new self)->processQuery($query)->getOmens()[0];}?><?phpuse Taxonomy\Taxonomy\AspectTaxonomy;use Taxonomy\Death\DeathTaxonomy;use Taxonomy\Fault\FaultTaxonomy;use Entity\Omen;use Entity\Omen\OmenCollection;use View\Partial;// TODO: 404 error handling//Provide similar omens (same fault)$filter = array("fault" => $omen->getFault()->getSlug());$omensCollection = OmenCollection::findOmensByFilter($filter);// if the user is logged inif (isset($_SESSION['user'])){ //Get user omens so that we can set the title to statement on only those omens $user = $_SESSION['user']; // update the omen's that the user has selected $omensCollection->setStatements($user->getUserOmens());}?><?= Partial::build('layout/header'); ?><!--THE REGISTRATION MODAL WINDOW--><?= Partial::build('modal/register'); ?><!--THE LOGIN MODAL WINDOW--><?= Partial::build('modal/login'); ?><!--THE ACCOUNT MODAL WINDOW--><?= Partial::build('modal/account'); ?><!--THE HOMEPAGE WINDOW--><?= Partial::build('nav', ["breadcrumb" => $omen->getTitle()]) ?><img src="<?php echo $omen->getImage() ?>" class="omenImg" alt="<?php echo $omen->getImageAuthor() ?>" title="<?php echo $omen->getImageAuthor() ?>"><?= Partial::build("omenHero", ["omen" => $omen ]); ?><article itemscope itemtype="http://schema.org/CreativeWork" class="poem g-margin4of9 g-span4of9"> <p class="poem__body"> <?= str_replace('/',"<br>", $omen->getPoem()); ?> </p> <footer class="poem__author"> —<cite itemprop="author"><?php echo $omen->getPoemAuthor() ?></cite> </footer></article><?= Partial::build('taxonomyTile'); ?> <section> <div class="layout layout--distant g-flex"> <div class="tile__panel tile__panel--primary g-span3of9"> <h2>Other ways <?php echo strtolower($omen->getFault()->getTitle()) ?> can kill people</h2> <span class="callToAction"><a href="/omen/?fault=<?php echo $omen->getFault()->getSlug() ?>" class="input__seeMore" >See more</a></span> </div> <?= Partial::build('omenGrid', ["omenCollection" => $omensCollection]); ?> </div> </section> <?= Partial::build('footer'); ?></div>Eine interessante Herausforderung war die Implementierung schwebender Labels für Texteingaben. Die Labels erscheinen wie Platzhaltertext, bis der Nutzer Text eingibt; dann werden sie verkleinert und oberhalb des Eingabefelds positioniert – wie ein klassisches Label. Die Herausforderung bestand darin, Funktion und Form nicht zu beeinträchtigen. Labels und Eingabefelder sind daher separate DOM-Objekte, und das Formular ist ARIA-freundlich.
// CODE SNIPPET, NOT THE FULL FILE ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////__________________________________________________________ FLOATING LABEL TEXT INPUTS _________________________________________________________/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////For floating labels: User enters text into text input and label floats up.const labelMod = "input__label--selected";const labelModFloating = "input__label--floating"//Each instance contains a label & a text input. The input listens for user inputs and styles the label.//________________________________________________________________ Pair Classvar Pair = function(label, input) { this.label = label; this.input = input; //add floating modifier if (!this.label.classList.contains(labelModFloating)) this.label.classList.add(labelModFloating); if (this.input.value !== "") if (!this.label.classList.contains(labelMod)) this.label.classList.add(labelMod); this.input.addEventListener('input', (event) => { this.label.classList.add(labelMod); //console.log("Focus on: " + this.input.id + ", with label: " + this.label.innerHTML + ", text:" + event.target.value); //Change label style on input if (event.target.value === ""){ if (this.label.classList.contains(labelMod)) this.label.classList.remove(labelMod); } else { if (!this.label.classList.contains(labelMod)) this.label.classList.add(labelMod); } });};//Find all cellsvar cells = [...document.querySelectorAll(".form__cell")];//Create pair classes for each cell that contains exactly one label & one inputfor (let i = 0; i < cells.length; i++) { let cell = cells[i]; let labels = [...cell.querySelectorAll(".input__label")]; let inputs = [...cell.querySelectorAll(".input__text")]; if (labels.length === 1 && inputs.length === 1){ new Pair(labels[0], inputs[0]); }}Für dieses Projekt war ich außerdem für die Einrichtung der Datenbank und aller Abfragen verantwortlich. Ich entwarf die Datenbank mit folgenden Tabellen: user (Nutzerinformationen), user_omen (Zuordnungstabelle für erlebte Omen), omen (Informationen zu jedem Omen) sowie drei Taxonomie-Tabellen: aspect, death und fault (zum Taggen von Omen). Über die Website änderbar sind nur user und user_omen; die Omen- und Taxonomie-Tabellen sind statisch.