Download-Datei Seitenansicht

Template “default/file.html”

Dieses Template erzeugt für eine Datei mit dem Layout layout: file die Seite, die am Ende im Browser zu sehen ist. Solche Dateien gibt es im Know-How-Bereich und im ft:pedia-Bereich. Das Format einer solchen Datei ist hier beschrieben. Dieses Template liegt daher unter layouts/_default/file.html.

Fangen wir vorne an.

{{ define "main" }}

   {{ $date_format_string := "2.1.2006" }}

   {{ $wir_email := .Site.Params.email_uns }}

{{ define "main" }} definiert einen Block für den eigentlichen Seiteninhalt.

Als nächstes geben wir das Muster vor, mit dem die Datumsangaben formatiert werden. Eine Erklärung, warum das Muster genau so aussieht, gibt es bei Hugo.

Aus der globalen Angabe, die für die ganze Website gilt, .Site.Params.email_uns, holen wir uns unsere Mail-Adresse und speichern sie in der Variablen $wir_email.

Prüfung auf Pflichtangaben und korrekte Listen

Wir überprüfen nun, ob die Pflichtangaben alle anwesend sind! Falls nicht, gibt es sehr deutlich “Mecker”!

   {{/* --- Überprüfe ob die Pflichtangaben alle vorhanden sind --- */}}
   {{/* --- Check all mandatory field entries are available --- */}}

   {{ if not .Params.title }}
      {{ errorf "Oh oh, der Seitentitel 'title' fehlt oder ist leer in Seite %q" .Path }}
   {{ end }}

Da kommt auch schon der erste Kniff, die Abfrage ob der Titel ‘title’ im Frontmatter definiert ist (z. B. title: "Flip Flop Baustein"), leer blieb (title: ) oder aber das title: gar komplett fehlt. Die etwas eigenwillige Hugo-Syntax if not .Params.title könnte in anderer Schreibweise if !defined("title:") || (title == "") lauten. Wenn die Bedingung zutrifft, wird die Zeile errorf "Oh oh, der Seitentitel 'title' fehlt oder ist leer in Seite %q" .Path ausgeführt. Hugo erzeugt dann eine Fehlermeldung, stoppt unmittelbar und produziert keine Seite. Das %q zusammen mit .Path gibt die fehlerhafte Datei mitsamt Zugriffspfad preis; ein Service, den der Admin sehr schätzt.

Außer dem Titel title gehören auch noch Dateiname file, Datum des Uploads date, und Name des hochladenden Nutzers uploadBy zu den Pflichtfeldern.

   {{ $fname := .Params.file }}
   {{ if not $fname }}
      {{ errorf "Oh oh, der Dateiname 'file' fehlt oder ist leer in Seite %q" .Path }}
   {{ end }}

$fname := .Params.file weist den Namen der Datei an eine eigene Variable zu. Das macht den Code später etwas übersichtlicher. Der Rest der Prüfung erfolgt baugleich zum Code für den Titel, also Fehlermeldung mit exakter Angabe der fehlerhaften Datei, falls der Dateiname fehlt.

   {{ $uploadDate := .Params.Date }}
   {{ if not $uploadDate }}
      {{ errorf "Oh oh, das Hochladedatum 'date' fehlt oder ist leer in Seite %q" .Path }}
   {{ end }}

Das Datum ´date` sollte sich jetzt schon selbst erklären.

   {{ $uploader := .Params.uploadBy }}
   {{ if not $uploader }}
      {{ errorf "Oh oh, der Nutzername 'uploadBy' fehlt oder ist leer in Seite %q" .Path }}
   {{ end }}

Für den verantwortlichen Nutzer, also denjenigen, der den Upload gemacht hat, ist im Frontmatter der Eintrag uploadBy vorgesehen. Noch Fragen?

Damit ist die grundsätzlich “Anwesenheitskontrolle” erledigt. Allerdings gibt es noch einen weiteren notwendigen Test. Wie im Abschnitt über das Frontmatter erklärt, ist der Nutzername als Liste angelegt. Theoretisch kann die Liste auch mehrere Namen umfassen, das ist hier aber nicht sinnvoll. Die korrekte Angabe enthält exakt einen Namen!

   {{ $uploaderCount := 0 }}
   {{ $uploaderCount = len $uploader }}
   {{ if gt $uploaderCount 1 }}
      {{ errorf "Oh oh, zu viele 'uploadBy' in Seite %q. Nur ein Nutzername erlaubt!" .Path }}
   {{ end }}

Zunächst wird die Anzahl der Nutzer angelegt und auf ‘0’ gesetzt ($uploaderCount := 0), anschließend die Länge des Eintrags (die Zahl der Listeneinträge!) abgeholt ($uploaderCount = len $uploader). Nun erfolgt eine Abfrage, ob die Anzahl der Nutzer größer als ‘1’ ist (if gt $uploaderCount 1). Falls ja, erfolgt die bewährte Fehlermeldung und Hugo beendet seinen Dienst. Der Wert ‘0’ kann hier nicht auftreten, da ansonsten bereits die vorherige Kontrolle ihren eigenen Fehler produziert hätte. Faktisch käme if ne $uploaderCount 1 (if $uploaderCount != 1) zum exakt gleichen Ergebnis.

Für den Fall, dass es sich um eine aus der alten ftc importierte Seite handelt, wird abgefragt ob es außer dem imported-Eintrag auch eine gefüllte legacy_id gibt. Falls nicht, gibt es sehr deutlich eine Fehlermeldung.

   {{ if .Params.imported }}
      {{ if not .Params.legacy_id }}
         {{ errorf "'legacy_id' fehlt für Seite %q. Wenn der Eintrag importiert wurde, muss auch eine Legacy-ID vorhanden sein!" .Path }}
      {{ end }}
   {{ end }}

Auf diese Art stellen wir hoffentlich sicher, dass die Importe komplett sind.

Nun kommt die Liste mit den Autoren an die Reihe. Die Autoren sind wahlfrei, die Liste darf leer sein. Daher entfällt die Abfrage, ob sie definiert ist.

   {{/* --- Lies ein was sonst noch benötigt wird --- */}}
   {{/* --- Read additional data --- */}}

   {{ $authorsCount := 0 }}
   {{ $authors := .Params.konstrukteure }}
   {{ if $authors }}
      {{ $authorsCount = len $authors }}
   {{ end }}

$authorsCount := 0 initialisiert die neue Variable auf ‘0’, $authors := .Params.konstrukteure weist die Liste an eine Variable zu. Das erspart Tiparbeit und macht den Code später etwas übersichtlicher. Falls wenigstens ein Autor definiert ist (if $authors), wird die Anzahl der Autoren passend eingestellt ($authorsCount = len $authors). Ansonsten bleibt $authorsCount auf ‘0’ stehen.

Damit wäre der erste Teil der Vorbereitung auch schon erledigt - wenn es da nicht ein paar Altlasten aus der alten ftc gäbe. Es existieren tatsächlich Uploads ohne Angabe von Autor oder Nutzer! Würden diese Einträge ins Frontmatter übersetzt, könnte Hugo wegen des fehlenden Nutzers die Seite nicht bauen (Stichwort: Fehlermeldung an den Admin). Also wird mit einem kleinen Kniff und einer Ausnahmebehandlung einerseits die “Anwesenheitskontrolle” von eben befriedigt, aber die korrekte Information dann doch noch erzeugt.

   {{/* --- Spezialbehandlung für Altlasten aus den Anfängen der ftc --- */}}
   {{/* --- Special handling of legacy ftc problem sites --- */}}

   {{ if eq $uploader (slice "-LegacyAdmin-") }}
      {{ $uploaderCount = 0 }}
   {{ end }}

Zuerst wird geschaut, ob der ‘magische’ Nutzer -LegacyAdmin- angegeben ist. Im Frontmatter steht dafür

uploadBy:
- "-LegacyAdmin-"

Dieser Nutzername kann (und darf!) regulär sonst nicht erzeugt werden. Falls nun ‘-Legacy-Admin-’ eintragen ist, wird die Anzahl der Nutzer auf ‘0’ zurückgestellt. In dem if-Konstrukt wird ein bisschen getrickst, um Hugo auf die richtige Fährte zu bringen. Normalerweise ist hier ein Vergleich zweier Strings fällig (if $uploader == "-LegacyAdmin-"). Nun ist Hugo aber etwas anders drauf und bietet hier gleich den Vergleich zweier Listen an. $uploader ist nämlich bereits eine Liste (mit genau einem Eintrag), also wird per slice "-LegacyAdmin-" schnell eine zweite Liste mit genau einem Eintrag angefertigt. ‘slice’ ist hier das Zauberwort. Nun kann das mit dem if auch klappen.

Für die Autoren gibt es das auch.

   {{ if eq $authors (slice "-?-") }}
      {{ $authorsCount = 0 }}
   {{ end }}

Wie hier eine absichtlich leere Autorenliste ermittelt und die Anzahl der Autoren im Bedarfsfall auf ‘0’ zurückgestellt wird, sollte jetzt ohne neue Erklärung klar sein. Die aus alten Zeiten fehlende Angabe zum Autor ist per

konstrukteure:
- "-?-"

im Frontmatter definiert.

Kommen wir nun zu ein bisschen ‘Vorgeplänkel’. Das müsste hier nicht stehen, macht jedoch den späteren Code deutlich übersichtlicher. Ihr werdet schon sehen warum. Aber der Reihe nach.

Vorgeplänkel zum Haftungsausschluss

Auf der fertigen Seite gibt es einen “Haftungsausschluss”. Ein Bestandteil dabei ist die Möglichkeit per e-mail auf einen inhaltlichen Fehler der dargestellten Seite aufmerksam zu machen. Als puren Luxus für den Nutzer, und zur Unterstützung der Admins, gibt es einen vordefinierten Text, der den Link zur bemängelten Seite bereits enthält. Dieser Text ist im Zusammenbau nicht ganz trivial und erfolgt daher bereits vorab.

   {{/* --- Vorgeplänkel --- */}}
   {{/* --- Prologue --- */}}

   {{ $email_subject := "Da stimmt was nicht!" }}
   {{ $scratch2 := newScratch }}
   {{ printf "Hallo ihr Lieben,\n\n" | $scratch2.Set "email_body" }}
   {{ printf "ich möchte Euch auf ein Problem mit der ftc-Seite hinweisen:\n" | $scratch2.Add "email_body" }}
   {{ printf "%s%s\n" .Site.BaseURL (path.Join .File.Dir (split (lower $fname) "." | first 1)) | $scratch2.Add "email_body" }}
   {{/* printf "%s\n" (path.Join .File.Dir $fname) | $scratch2.Add "email_body" */}}
   {{/* printf "%s\n" .Path | $scratch2.Add "email_body" */}}
   {{/* printf "(Bitte diese Referenzen nicht löschen!)\n" | $scratch2.Add "email_body" */}}
   {{ printf "\n<Problembeschreibung>" | $scratch2.Add "email_body" }}

Drei Zeilen sind derzeit auskommentiert, können aber zugeschaltet werden, um außer dem URL der Seite auch noch die Dateipositionen mitzugeben. Die Dateipfade ergeben sich jedoch aus dem URL und so muss die E-Mail nicht mit dieser Information überfrachtet werden.

Für den Text wird zunächst ein “Notizzettel” angelegt: $scratch2 := newScratch. Die erste Zeile wird per $scratch2.Set zugewiesen, die folgenden Textbausteine fügt $scratch2.Add jeweils hinten an.

printf "%s%s\n" baut aus dem Seitennamen (https://www.ftcommunity.de oder wo auch immer sie gerade liegt und per .Site.BaseURL zu erfragen) und ein bisschen Stringbastelei (path.Join .File.Dir (split (lower $fname) "." | first 1)) den kompletten Namen der Unterseite zusammen. Dabei sorgt lower $fname für eine konsequente Kleinschreibung der URL, so wie sie im Browser auch angezeigt wird. Ein Klick auf den späteren Link öffnet das E-Mail-Programm des Besuchers und bietet die Vorbelegung in einer neu zu schreibenden E-Mail an. Das sieht dann so aus (ungefähr, der Link variiert mit dem Seitennamen):

Hallo ihr Lieben,

ich möchte Euch auf ein Problem mit der ftc-Seite hinweisen:
https://www.ftcommunity.de/knowhow/elektronik/silberlinge/flipflop/

<Problembeschreibung>

Mit diesen Zeilen endet das Vorgeplänkel und der produktive Teil, also der HTML-Code, der vom Browser dargestellt wird, tritt auf den Plan.

   {{/* --- HTML-Seite zusammenbauen --- */}}
   {{/* --- Assemble the HTML site --- */}}

   <div class="padding highlightable">
      {{ partial "topbar.html" . }}
      <div id="body-inner">
         <h2>{{.Title}}</h2>

Zunächst gibt es den Start der Seite und die einheitliche Kopfzeile. Für die Kopfzeile gibt es so eine Art “Unterprogramm”, das im Framework an anderer Stelle vordefiniert ist. Das ist die Zeile {{ partial "topbar.html" . }}. Danach kommt sofort der Seitentitel in Form von <h1>{{.Title}}</h1>. Das HTML-tag <h2> startet die Überschrift, </h2> beendet sie. Wie sie genau aussieht, ist irgendwo im Framework ‘versteckt’ - global für alle Seiten. Das Stichwort dazu heisst “Stylesheet” und hat eine eigene Beschreibung.

In einem eigenen Absatz wird der Inhaltsbereich aus der jeweiligen .md-Datei unterhalb des Frontmatter eingefügt.

   <p>
      {{ .Content }}
   </p>

<p> und </p> definieren den Absatz, .Content füllt ihn.

Darstellung des Downloads

Nach dieser Beschreibung zum Downloadfile - die vom Nutzer erstellt wurde - soll das anklickbare Icon für den Download folgen.

   <br />
   <p>
      <a href="../{{ $fname }}" style = "float: left; margin: 1em 1.5em 1em 0;">
      {{ partial "download-icon.html" . }}
   </a>

Für ein etwas weniger gedrängtes Aussehen gibt es zuerst noch einen Zeilenvorschub (<br />) und ein neuer Absatz startet mit <p>.

Der Hyperlink wird ganz klassisch mittels <a href="../{{ $fname }}"> eingeleitet. Dabei ist die Sequenz ../ vor dem Dateinamen ($fname) essentiell. Ohne diese Angabe würde der Link falsch umgesetzt und die Datei nicht gefunden! Das ist wohl eine Eigenheit von Hugo, man muss sie halt kennen.

Per Default erscheint das Icon mittig auf der Seite, Text wird nur oberhalb und unterhalb zugelassen. Hier soll das Icon allerdings linksbündig angeordnet sein und der weitere Text auf der rechten Seite um das Icon herumfliessen. Die Angabe style= zusammen mit css-Syntax ermöglicht den gewünschten Effekt. Dabei bewirkt float: left; die Anordnung des Icons links im umlaufenden Text.

Danach sorgt margin: für eine Feinplatzierung des Icons durch Angabe der Randbreiten (in dieser Reihenfolge!):

  • Oben: 1em (Abstand zur Textzeile obendrüber - hier Absatzbeginn)
  • Rechts:1.5em (Abstand zum rechts umlaufenden Text)
  • Unten: 1em (Abstand zur Textzeile untendrunter - hier Absatzende)
  • Links: 0 (Abstand zum linken Rand des Absatzes)

Die Einheit em steht kurz für “die Breite des Buchstaben ‘m’ im Font”. Damit skaliert die Größe des Icons mit der Größe der Schriftzeichen und die Gestaltung bleibt beim Verändern der Zoomstufe unverändert.

Mehr Doku:

Diese Angaben zur Größe und Position des Icons sind feinstsäuberlich auf die drei weiter unten beschriebenen Textzeilen abgestimmt!

Anstelle eines Textes zum Anklicken soll hier ein kleines Bild, ein Icon, stehen. Die Zeilen zum Bild haben es nun allerdings “in sich”:

      {{ partial "download-icon.html" . }}

partial "download-icon.html" . ist eine Art “Unterprogramm” oder auch “Makro”. Diese Art der Auslagerung gestattet es. die Funktion “Generisches Icon passend zur Dateiendung eines Files” auch von anderen Stellen aus zu nutzen; und so wird der Code deutlich besser lesbar. Das partial ‘download-icon’ hat seine eigene Doku. Siehe auch https://gohugo.io/templates/partials/

</a> schließt den Hyperlink ab.

Dieses Stück Code erzeugt also ein anklickbares Bild und der Browser fragt üblicherweise, wohin die referenzierte Datei gespeichert werden darf.

Im gleichen Absatz (sozusagen rechts oben vom Bild) kommt zunächst der Name der Downloaddatei mit einer Angabe zur Dateigröße.

   {{ $fname }}
   ( {{- partial "download-size.html" . -}} )

Der Dateiname wird als Text angezeigt. Eine ‘(’ kommt dahinter, partial "download-size.html" . liefert die Größe mit Einheit und eine ‘)’ schließt die Zeile ab.

Angabe von Autoren, Uploader und Lizenz

Nun kommt die Information über den / die Autor(en).

   <small>
      <br />

Diese Angabe (und auch noch die nachfolgende) ist vom Dateinamen durch eine kleinere Schriftgröße abgesetzt (<small>) und der Text beginnt in einer neuen Zeile (<br />).

Der Code für den Satzbau ist ziemlich unschön zu lesen, weil die diversen Textbausteine in Abhängigkeit von diversen Angaben ausgewählt werden. Hugo-Code, HTML und Text scheinen wirr miteinander verwoben.

   {{- if gt $authorsCount 0 -}}
      Erstellt
      {{- if eq $authors $uploader }}
         und hochgeladen
      {{- end }}
      von
      {{ range $index, $name := $authors -}}
         {{- if and (gt $index 0) (sub $authorsCount 1 | lt $index) -}}
            ,
         {{- else if gt $index 0 }}
            und
         {{- end }}
         {{ if eq $authors $uploader -}}
            <a href = "{{ $.Site.BaseURL }}konstrukteure/{{ $name|urlize }}">{{ $name }}</a>
         {{- else -}}
            <i>{{ $name -}}</i>
         {{- end -}}
      {{- end -}}
      .
   {{- else -}}
      Leider ist kein Autor angegeben.
   {{- end -}}

Als erste “Amtshandlung” wird per if gt $authorsCount 0 festgestellt, ob es einen Autor gibt. Falls dem nicht so ist, erledigt der else Zweig die nötige Angabe: “Leider ist kein Autor angegeben.”

Der übriggebliebene Rest bei Zutreffen der Bedingung $authorsCount > 0 erledigt den Zusammenbau eines lesbaren Satzes.

   Erstellt
   {{- if eq $authors $uploader }}
      und hochgeladen
   {{- end }}
   von

Lässt den Satz je nach Übereinstimmung von Autor und Nutzer unterschiedlich beginnen.

Bedingung Satzanfang
$authors == $uploader Erstellt und hochgeladen von
$authors != $uploader Erstellt von

Es folgt die Auflistung der Autoren, mit Komma, ‘und’ und allem, was so dazugehört.

   {{ range $index, $name := $authors -}}
      {{- if and (gt $index 0) (sub $authorsCount 1 | lt $index) -}}
         ,
      {{- else if gt $index 0 }}
         und
      {{- end }}
      {{ if eq $authors $uploader -}}
         <a href = "{{ $.Site.BaseURL }}konstrukteure/{{ $name|urlize }}">{{ $name }}</a>
      {{- else -}}
         {{ $name -}}
      {{- end -}}
   {{- end -}}
   .

Das Schleifenkonstrukt range $index, $name := $authors arbeitet sich durch alle vorhandenen Einträge. Dabei zählt $index von ‘0’ aus hoch - der erste Autor hat dabei den Index ‘0’, der letzte Autor den Index ‘$authorsCount - 1’ (oder wie Hugo es ausdrückt: sub $authorsCount 1).

Der Ausdruck if and (gt $index 0) (sub $authorsCount 1 | lt $index) wäre als if ($index > 0) && ($index < ($authorsCount - 1)) wohl gewohnter. Er sorgt dafür, dass das ‘,’ nur nur vom ersten bis zum vorletzten Autor der Liste eingefügt wird. Besteht die Liste aus weniger als drei Autoren, kommt kein ‘,'. Trifft die “Kommaregel” nicht zu, kommt else zum Zuge.

Das ist entweder der erste Autor ($index = 0) oder der letzte Autor der Liste ($index > 0) und insgesamt erteilt else if gt $index nur im letzten Fall die Erlaubnis das ‘und’ einzufügen.

Nun kommt noch eine Unterscheidung ob Autor und Nutzer identisch sind (if eq $authors $uploader). Falls ja, gibt es den Autorennamen mit Hyperlink hinterlegt (<a href = ...). Falls nein, kann es ein nicht registrierter Mensch sein und so gibt es pauschal keinen Hyperlink dazu ($name). Eine besondere Eigenschaft dieses Konstrukts ist: Nur wenn beide Listen exakt einen und den gleichen Eintrag haben, wird der Hyperlink gegeben, sonst nie.

Jetzt folgt noch der ‘.’ und der Satz ist fertig gebaut.

Die seltsamen {{- und -}}bewirken eine Unterdrückung sämtlicher ‘Whitespace’-Leerzeichen entweder vor oder hinter dem Hugo-Code. Ohne die wäre beispielsweise zwischen Wort und Satzzeichen eine unerwünschte Lücke.

Ein paar Beispiele:
Frontmatter Satzende
konstrukteure:
- "Hinz & Kunz"
Hinz & Kunz.
konstrukteure:
- "Hinz & Kunz"
- "Miez & Maunz"
Hinz & Kunz und Miez & Maunz.
konstrukteure:
- "Hinz & Kunz"
- "Miez & Maunz"
- "Alter Sack"
Hinz & Kunz, Miez & Maunz und Alter Sack.
konstrukteure:
- "Hinz & Kunz"
- "Miez & Maunz"
- "Alter Sack"
- "Niemand Sonst"
Hinz & Kunz, Miez & Maunz, Alter Sack und Niemand Sonst.

Das war ein dicker Brocken.

    {{ if not (eq .Params.license "unknown") }}
        Lizenz: {{- partial "download-license.html" .  -}}
    {{ end }}

Wenn der Autor der Download-Datei eine Lizenz angegeben hat, die anderen die Nutzung erlaubt, wird hier ein Partial aufgerufen, das diese Lizenz darstellt. Für alle aus der alten Seite importierten Dateien gilt: license: unknown.

Vergleichsweise entspannt ist die Darstellung, wann die Datei hochgeladen wurde und von wem.

   <br />
   Hochgeladen
   {{  if eq $uploaderCount 1 -}}
      {{ if not (eq $authors $uploader) -}}
         von
         <a href = "{{ $.Site.BaseURL -}} uploadBy/ {{- delimit $uploader ", " | urlize -}}">{{- delimit $uploader ", " -}}</a>
      {{ end -}}
   {{  end -}}
   am
   {{ dateFormat $date_format_string $uploadDate -}}
   .

Die Auskunft, wer den Upload wann gemacht hat, kommt in eine neue Zeile. <br /> kennen wir ja jetzt schon. Der Satz beginnt grundsätzlich mit ‘Hochgeladen’. Gibt es genau einen Nutzer in der Liste (if eq $uploaderCount 1), wird mittels if not (eq $authors $uploader) untersucht, ob Autor und Nutzer nicht identisch sind. In dem Fall wird der Satzteil ‘von >Nutzer<’ eingefügt. Der Nutzername wird außerdem mit einem Hyperlink hinterlegt. In allen anderen Fällen entfällt dieser Teil. delimit wird normalerweise benutzt, um eine Liste mit Trennzeichen zu versehen und in einen zusammengesetzten String umzuwandeln. Hier wird es ‘missbraucht’ um den einen Listeneintrag in einen String umzuwandeln. Die Angabe ‘am’ ergänzt durch das formatierte Datum beendet den Satz.

Ein paar Beispiele für den Nutzer 'Alter Sack' und Upload-Datum 5. Januar 1900:
Bedingung Satz
$uploaderCount != 1 Hochgeladen am 5.1.1900.
$uploaderCount == 1
UND
$authors == $uploadBy
Hochgeladen am 5.1.1900.
$uploaderCount == 1
UND
$authors != $uploadBy
Hochgeladen von Alter Sack am 5.1.1900.
      </small>
   </p>

Der Bereich mit der Kleinschrift endet hier (</small>) wie auch der Absatz (</p).

Haftungsausschluss

Es folgt nun ein weiterer Absatz in kleiner Schrift.

   <p>
      <small>

Zweck der Übung ist ein Hinweistext, der mit einem fett gesetzten ‘Hinweis:’ beginnt.

   <b>Hinweis:</b>
   Das Herunterladen, Öffnen und Ausführen von Dateien geschieht auf
   eigene Gefahr.
   Wir können keine Verantwortung für eventuelle Fehler oder gar Schäden
   übernehmen.
   Falls Du einen Fehler findest, kontaktiere bitte

Ein ‘uns’ beendet den Satz. Das ‘uns’ ist mit einem Hyperlink hinterlegt. Eine Verlinkung zu dem oder den Autoren bzw. dem User, der den Upload gemacht hat, ist nicht vorgesehen, weil wir hier keine Kontaktdaten dieses Users haben. Hier wird der Versand einer E-Mail an das Betreuungsteam vorbereitet.

         <a href="mailto:{{$wir_email}}?subject={{$email_subject}}&body={{$scratch2.Get "email_body"}}">uns</a>.

$wir_email gibt den Adressaten an, $email_subject liefert den Betreff und $scratch2.Get "email_body" enthält dann die Nachricht. Das ist der lange Text aus dem Vorgeplänkel oben “Hallo ihr Lieben, …".

Der Absatz mit dem Hinweistext wird beendet (Kleinschrift aus und Absatzende).

      </small>
   </p>

Der spezielle Inhalt einer Downloadseite ist damit beendet, jetzt folgt noch die Navigation.

      <div id="navigation">

Die Navigation wird per <div id="navigation"> eingeleitet. Das hilft, den Abschnitt per Texteditor schnell aufzuspüren.

         {{ $prev := slice }}
         {{ $next := slice }}
         {{ $node := . }}
         {{ $match := 0 }}         

Zunächst werden einige Variablen definiert, die wir weiter unten noch brauchen.

         {{ $neighbours := slice }}
         {{ range .Parent.Pages.ByTitle }}
            {{ if gt .Parent.Pages 1 }}
               {{ $neighbours = append . $neighbours }}
            {{ end }}
         {{ end }}
         {{ $neighbours = append .Parent.Sections.ByTitle $neighbours }}

Jetzt suchen wir alle Nachbarn. Das sind andere Seiten, die das gleiche Elternverzeichnis haben, sowie Unterverzeichnisse (.Sections) im gleichen Verzeichnis. Diese Liste der Nachbarn ist nach dem Titel alphabetisch sortiert.

         {{ with $neighbours }}
            {{ $i := 0 }}
            {{ range . }}
               {{ if eq . $node }}
                  {{ $match = $i }}
               {{ end }}
               {{ $i = add $i 1 }}
            {{ end }}
         {{ end }}
         {{ $prev = index $neighbours (sub $match 1) }}
         {{ $next = index $neighbours (add $match 1) }}

Jetzt finden wir heraus, wo in dieser Liste der Nachbarn die aktuelle Datei liegt. Ihren Index ordnen wir der Variablen $match zu. Der vorige Eintrag in der Liste ist der Vorgänger ($prev), der nächste der Nachfolger ($next).

         {{ with $prev }}
            <a class="nav nav-prev" href="{{.RelPermalink}}" title="{{.Title}}"> <i class="fa fa-chevron-left"></i></a>
         {{else}}
            {{with .Parent}}
               <a class="nav nav-prev" href="{{.RelPermalink}}" title="{{.Title}}"> <i class="fas fa-arrow-up"></i></a>
            {{end}}
         {{end}}
         {{with $next}}
            <a class="nav nav-next" href="{{.RelPermalink}}" title="{{.Title}}"> <i class="fa fa-chevron-right"></i></a>
         {{else}}
            {{with .Parent}}
               <a class="nav nav-next" href="{{.RelPermalink}}" title="{{.Title}}"> <i class="fas fa-arrow-up"></i></a>
            {{end}}
         {{end}}
      </div>

Die Navigation ist in zwei Hälften aufgeteilt. Eine Hälfte behandelt die horizontale Navigation “nach links”, die andere, baugleiche, Hälfte bedient die Navigation “nach rechts”.

Die linke Hälfte startet mit {{with $prev }}. Auf die Art schaltet man Hugo in den Kontext des nächsten Eintrags aus der Sammlung der Seiten.

Mit der Info aus dem Kontext des vorigen Nachbarn wird nun ein Hyperlink gebaut:

<a class="nav nav-prev" href="{{.RelPermalink}}" title="{{.Title}}"> <i class="fa fa-chevron-left"></i></a>

<a leitet die Hyperlink-Sequenz ein. Mittels der CSS-Klasse nav nav-prev bekommt der Hyperlink seinen Platz, seine Gestaltung und sein Verhalten zugewiesen (derzeit links, vor dem Seiteninhalt und mit Animationseffekten wenn die Maus drüberläuft). Es folgt der unvermeidliche Link selbst href="{{.RelPermalink}}", bei dem die URL der betreffenden Seite von Hugo erzeugt wird ({{.RelPermalink}}) - gemäß Kontext vom Nachbarn. title="{{.Title}}"> gibt dann noch den Namen der Zielseite aus deren Frontmatter in den Tooltip ({{.Title}}). So sieht man, wohin die Reise gehen wird, wenn die Maus über den Link gezogen wird. Jetzt fehlt noch der Text, der als klickbarer Link angezeigt wird. Hier ist es ein ‘<’, das aus einem speziellen Font ausgewählt wurde: <i class="fa fa-chevron-left"></i>. Ordnungsgemäß schließt ein </a> den Hyperlink ab. Puh, geschafft.

Was passiert nun wenn es keinen älteren (linken) Nachbarn gibt? Dann wirkt das with wie ein if und wir betreten den {{else}} Zweig. {{with .Parent}} versucht nun den Kontext der übergeordneten Ebene zu erreichen. Der Pfad soll diesmal eine Ebene nach oben führen. Der Hyperlink kann nun aus dem Kontext des Parent gebaut werden, siehe oben. Der einzige Unterschied ist hier das Symbol in der Navigation. Diesmal wird die Richtung durch einen Pfeil nach oben angezeigt: <i class="fas fa-arrow-up"></i>.

Und was ist wenn es auch keinen Parent gibt? In unserem Fall gibt es immer einen Parent. Der fehlt lediglich auf der Homepage, die ja die Wurzel darstellt. Trotzdem wirkt auch hier wieder das with wie ein if und baut keinen Hyperlink nach oben, wenn es keinen Parent gibt. Das {{end}} schließt den Bau der linksseitigen Navigation ab.

Die Navigation auf der rechten Seite ist

  1. exakt baugleich,
  2. spiegelbildlich angeordnet (‘>’ anstelle ‘<’ sowie auf der rechten Seite nav nav-next) und
  3. führt zum nächsten Element in der Sammlung ({{with $next }}) bzw. “nach oben” ({{with .Parent}}).

Gibt es weder einen linken noch einen rechten Nachbarn, so führen halt beide Navigationen nach oben.

Der Abschnitt der Navigation wird durch </div> geschlossen.

Stand: 14. Juni 2020