Struktur von Release Notes
Bevor wir mit der Bearbeitung von Templates beginnen, wäre es hilfreich zu verstehen, wie das Endresultat aufgebaut ist. Standardmäßig siehst Du in einer Pages-Datenbank eine Datensatzliste. Diese wird mit Hilfe von Template für Datensatzliste dargestellt. Wenn Du auf einen Datensatz klickst, wird er in eine neue Seite geladen. Diese Seite wird mit Hilfe von Template für Datensatzansicht dargestellt. In unserer Datenbank wird die Seite jedoch nicht neu geladen: der Datensatz wird dynamisch über AJAX geladen.
Das wird erreicht, indem sowohl das Template für die Auflistung als auch für die Anzeige gemischt werden. Der Gesamtaufbau der Seite und die Liste der Versionen auf der linken Seite wird mit Hilfe des Listing-Template erstellt. Wenn jedoch ein Datensatz angeklickt und dynamisch geladen wird, verwendet dieser Teil der Seite das Datensatztemplate:
Nun, da die Struktur klar ist, ist es endlich an der Zeit, mit der Bearbeitung von Vorlagen zu beginnen!
Tipp: Jede Vorlage, die unten und im nächsten Schritt besprochen wird, enthält einen Link zu einem Diff-Bericht, so dass Du die Änderungen, die wir an der Standardvorlage vorgenommen haben, leicht vergleichen kannst.
Kopfbereich für Auflistung - Template categoryHeader
(Siehe diff)
Das erste Template, an dem wir arbeiten werden, ist die Kategorieüberschrift. Dieses enthält den Kopfbereich einer Kategorie (in unserem Fall ist es eigentlich der Kopfbereich der gesamten Datenbank, da der Benutzer diese Seite während der Benutzung der Datenbank nicht verlässt). Das Template categoryHeader beinhaltet den Titel, die Schaltfläche "Folgen", die Schaltfläche "Datensatz hinzufügen" und mehr.
Hier ist der Code für diesen Template-Bit, der weiter unten erläutert wird.
{{if !\IPS\Request::i()->advancedSearchForm}} <div class="ipsType_center ipsSpacer_bottom ipsSpacer_top"> <h1 class="ipsType_veryLarge ipsType_reset">{$category->_title}</h1> <div class="ipsType_richText ipsType_large ipsType_light ipsSpacer_bottom"> {$category->_description|raw} </div> <div class='ipsResponsive_noFloat ipsResponsive_hidePhone'> {template="follow" app="core" group="global" params="'cms','categories' . $category->database_id, $category->_id, \IPS\cms\Records::containerFollowerCount( $category )"} </div> </div> {{endif}} {{if $category->hasChildren() AND ! isset( \IPS\Request::i()->advancedSearchForm )}} <div class="ipsBox ipsSpacer_bottom"> <h2 class='ipsType_sectionTitle ipsType_reset'>{lang="content_subcategories_title"}</h2> <ol class="ipsDataList"> {{foreach $category->children() as $cat}} {template="categoryRow" group="category_index" location="database" app="cms" params="$cat"} {{endforeach}} </ol> </div> {{endif}} {{if $category->can('add')}} {{if ! \IPS\Request::i()->isAjax() AND ! isset( \IPS\Request::i()->advancedSearchForm ) AND $category->show_records}} <ul class="ipsToolList ipsToolList_horizontal ipsClearfix ipsSpacer_both ipsResponsive_hidePhone"> <li class='ipsToolList_primaryAction'> <a class="ipsButton ipsButton_medium ipsButton_important ipsButton_fullWidth" href="{$category->url()->setQueryString( array( 'do' => 'form', 'd' => \IPS\cms\Databases\Dispatcher::i()->databaseId ) )}">{lang="cms_add_new_record_button" sprintf="\IPS\cms\Databases::load( $category->database_id )->recordWord( 1 )"}</a> </li> </ul> {{endif}} {{endif}} {{if count( $activeFilters ) AND ! isset( \IPS\Request::i()->advancedSearchForm )}} {template="filterMessage" app="cms" location="database" group="release_notes" params="$activeFilters, $category"} {{endif}}
Dieses Template ist dem Standardtemplate ziemlich ähnlich. Die wichtigsten Dinge, die sich geändert haben:
- Positionierung/Styling von Titel, Beschreibung und Follow-Button
- Der Link Als gelesen markieren entfernt, da wir diese Funktionalität nicht verwenden.
- Button mit {{if $category->can('add')}} umschlossen, da nur diejenigen, die die Berechtigung haben, Datensätze hinzuzufügen, den gesamten Bereich sehen müssen.
Auflistungstabelle - Template categoryTable
(Siehe diff)
Das Template categoryTable ist der Hauptteil der Listenansicht. Es erzeugt die Tabelle, in der Datensätze als Zeilen angezeigt werden. Dieses Template ist gegenüber dem Standardtemplate ziemlich stark modifiziert, was zum Teil darauf zurückzuführen ist, dass eine Menge unbenutzter Code entfernt wurde.
Hinweis: Vorlagen enthalten oft eine Menge Code, der verwendet wird, wenn eine bestimmte Option für die Datenbank aktiviert ist. Dieser Code ist von einer Logikprüfung umhüllt, so dass er nur angezeigt wird, wenn diese Option aktiviert ist. Es ist ratsam, diese unbenutzten Codeteile zu entfernen, wenn Du sicher bist, dass Du die Funktion darin in dieser Datenbank nicht benötigst; dadurch wird das Template kompakter und leichter zu lesen.
Hier ist der endgültige Code für diesen Template-Bit:
<div class='ipsAreaBackground ipsPad_half' data-baseurl='{$table->baseUrl}' data-resort='{$table->resortKey}' data-controller='core.global.core.table{{if $table->canModerate()}},core.front.core.moderation{{endif}}'> <div class='ipsAreaBackground_reset ipsColumns ipsColumns_collapsePhone' data-controller='pages.front.releaseNotes.main'> <div class='ipsColumn ipsColumn_wide ipsAreaBackground cReleaseColumn' data-role='releases'> {{if ! count($rows)}} <div class="ipsPad"> {lang="cms_no_records_to_show" sprintf="\IPS\cms\Databases::load( \IPS\cms\Databases\Dispatcher::i()->databaseId )->recordWord()"} </div> {{else}} <ol class='ipsDataList ipsDataList_zebra ipsClear cCmsListing {{foreach $table->classes as $class}}{$class} {{endforeach}}' id='elTable_{$table->uniqueId}' data-role="tableRows"> {template="$table->rowsTemplate[1]" params="$table, $headers, $rows" object="$table->rowsTemplate[0]"} </ol> {{endif}} {{if $table->pages > 1}} <div data-role="tablePagination"> {template="pagination" group="global" app="core" location="global" params="$table->baseUrl, $table->pages, $table->page, $table->limit"} </div> {{endif}} </div> <div class='ipsColumn ipsColumn_fluid'> <div data-role='releaseInfo' class='ipsPad_double'></div> </div> </div> </div>
Hier sind die wichtigsten Änderungen:
- Es gibt einige einfache Stiländerungen, damit die Ausgabe so aussieht, wie wir wollen
- Beachte, dass wir auf dem Wrapper-Element einen Javascript-Controller initialisieren, pages.front.releaseNotes.main. Dieser Controller wird in der Javascript-Datei erstellt, die wir zuvor eingerichtet haben.
- Eine Menge Code, den wir für unseren Gebrauch nicht benötigen, wird entfernt, z. B. die Moderationswerkzeuge und die Sortier-/Filteroptionen.
- Ein leeres div wird in der Fluid-Spalte mit dem Attribut data-role='releaseInfo' hinzugefügt. Dies ist das div, das einen Datensatz hält, wenn er in die Seite geladen wird.
Tabellenzeile - Template recordRow
(Siehe diff)
Dieses Template erzeugt eine Zeile in der Auflistungstabelle. Es ist das erste Template, in dem wir etwas Besonderes machen. Die Erklärungen kommen weiter unten und hier ist erstmal der Code:
{{$rowIds = array();}} {{foreach $rows as $row}} {{$idField = $row::$databaseColumnId;}} {{$rowIds[] = $row->$idField;}} {{endforeach}} {{$iposted = ( $table AND method_exists( $table, 'container' ) AND $table->container() !== NULL ) ? $table->container()->contentPostedIn( null, $rowIds ) : array();}} {{foreach $rows as $row}} {{$idField = $row::$databaseColumnId;}} <li class="cCmsRecord_row {{if $row->hidden()}}ipsModerated{{endif}}" data-rowID='{$row->$idField}'> <a href='{$row->url()}' class='cRelease' data-releaseID='{$row->$idField}' {{if $row->fieldValues()['field_163']}}data-currentRelease{{endif}}> {$row->customFieldDisplayByKey('security-release', 'listing')|raw} <h3 class='ipsType_sectionHead ipsType_break'> {{if $row->_title}}{$row->_title}{{else}}<em class="ipsType_light">{lang="content_deleted"}</em>{{endif}} {$row->customFieldDisplayByKey('current-release', 'listing')|raw} {$row->customFieldDisplayByKey('beta-release', 'listing')|raw} </h3> {{if $row->isFutureDate() || $row->mapped('pinned') || $row->mapped('featured') || $row->hidden() === -1 || $row->hidden() === 1}} <span> {{if $row->isFutureDate()}} <span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{$row->futureDateBlurb()}'><i class='fa fa-clock-o'></i></span> {{elseif $row->hidden() === -1}} <span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{$row->hiddenBlurb()}'><i class='fa fa-eye-slash'></i></span> {{elseif $row->hidden() === 1}} <span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{lang="pending_approval"}'><i class='fa fa-warning'></i></span> {{endif}} {{if $row->mapped('pinned')}} <span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="pinned"}'><i class='fa fa-thumb-tack'></i></span> {{endif}} {{if $row->mapped('featured')}} <span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span> {{endif}} </span> {{endif}} {{if count( $row->customFieldsForDisplay('listing') )}} <div class='ipsDataItem_meta'> {{foreach $row->customFieldsForDisplay('listing') as $fieldId => $fieldValue}} {{if $fieldValue && $fieldId != 'current-release' && $fieldId != 'beta-release' && $fieldId != 'security-release'}} {$fieldValue|raw} {{endif}} {{endforeach}} </div> {{endif}} </a> </li> {{endforeach}}
Wie bei dem vorherigen Template wurde auch hier eine Menge unbenutzter Code entfernt.
Die ersten paar Zeilen sind wie in dem Standardtemplate geblieben. Nach diesen gehen wir in die Hauptschleife, die über jede unserer Zeilen iteriert und das HTML für jede Zeile generiert.
Der erste Teil, den hier wichtig ist, ist das Element <a>. Beachte, dass wir einen benutzerdefinierten Klassennamen verwendet haben, den wir für das Styling verwenden werden. Wir haben auch ein Attribut data-releaseID hinzugefügt, dessen Wert die ID des Datensatzes ist. Das ist wichtig, da wir es verwenden werden, um später den richtigen Datensatz in Mittelteil zu laden, wenn der Benutzer auf diesen Datensatz in der Liste klickt.
Zugriff auf rohe Feldwerte
In der gleichen Linie siehst Du das hier:
{{if $row->fieldValues()['field_163']}}data-currentRelease{{endif}}
Was hier passiert, ist, dass wir $row->fieldValues() aufrufen (was ein Array mit allen Feldwerten für die Zeile zurückgibt) und es verwenden, um festzustellen, ob field_163 wahr ist. Wenn das der Fall ist, kennzeichnen wir dies als unsere aktuelle Version mit einem Datenattribut. Das Feld mit ID 163 ist das Feld der aktuellen Version markiert. Leider müssen wir bei der Verwendung der fieldValues()-Methode über die ID und nicht über den Schlüssel auf das Feld zugreifen.