.. index:: z3c.layout, z3c, pagelet, z3c.template, layout, pagelet, template Skinning mit z3c.layout, z3c.pagelet, und z3c.template ****************************************************** Im nächsten Schritt erstellen Sie eine schöne Oberfläche (Skin) für die Anwendung. Im normalen Zope 3 werden dafür Makros definiert, die in allen Page-Templates verwendet werden. Typischerweise sind die Makros in einer ``standard_macros``-Datei definiert. Mit z3c.*-Komponenten machen Page-Templates von diesen Makros keinen Gebrauch mehr. Abhängikeiten ============= Das Wichtigste zuerst: Sie konfigurieren die neuen Abhängigkeiten, die mit dem Skinning verbunden sind. Öffnen Sie die Datei ``src/zcontact/configure.zcml`` und fügen Sie ```` zu den anderen "meta includes" hinzu. Daraus ergibt sich eine neue ``z3c:pagelet``-zcml-Direktive. Weiter unten können Sie zwei weitere Include-Anweisungen einfügen: .. sourcecode:: xml Erstellung des Layouts ====================== Jetzt folgt der interessante Teil. Sie erstellen ein sogenanntes Layout, welches wie ein Makro funktioniert aber einfacher ist. Anstatt ein kompliziertes Makro zu erstellen, das von allen Seiten (z. B. mit use-macro und fill-slot) benutzt werden muss, wird hier ein normales Page-Template mit einem speziellen Satz von Elementen für den jeweils aktuellen Inhalt der Seite erstellt. Sie können dann unterschiedliche Layouts für unterschiedliche Skins oder auch verschiedene Objekt-Interfaces verwenden. Los gehts! Erstellen Sie die Datei ``src/zcontact/layout.pt`` und lassen Sie den Inhalt etwa wie folgt aussehen. Experimentieren Sie ruhig ein wenig (Kreativität ist gefragt): .. sourcecode:: xml ZContact

ZContact

Page Content
ZContact Tutorial Application Beachten Sie die zwei Zeilen am Ende der Datei die sagen, das hier die Magie enthalten ist. .. sourcecode:: xml
Page Content
Der ``provider:pagelet``-Teil fordert zope auf, nach einem *content provider* zu suchen, der ``pagelet`` genannt wird. Mit z3c.pagelet wird der Inhalt der aufgerufenen Seite geliefert, ob es nun ein Formular oder ein anderes Page-Template ist. Und das ist ziemlich raffiniert, aber dazu muss das Layout für unseren Skin mit zcml registriert werden. Erstellen Sie die Datei ``zcontact/skin.zcml`` und fügen Sie die selbsterklärenden Zeilen ein: .. sourcecode:: xml Vergessen Sie nicht den z3c-Namensraum in die Konfigurationsdatei mit ``xmlns:z3c="http://namespaces.zope.org/z3c"`` einzufügen. Die Verwendung des Layouts in Pagelets (und Templates) ======================================================== Ist das Layout erstellt, müssen die existierenden Seiten ein wenig angepasst werden, damit das Layout auch verwendet wird. Der erste Schritt ist das Hinzufügen des z3c-Namensraumes ``xmlns:z3c="http://namespaces.zope.org/z3c"`` in der Datei ``zcontact/browser/configure.zcml``. Nun muss jedes page-Element durch ``z3c:pagelet`` ersetzt werden. Alles andere bleibt unverändert. Das Besondere an den Pagelets ist (und damit unterscheiden sie sich von normalen Page-Templates), *sie haben nichts mit Page-Templates zu tun*. Die pagelet-Direktive erhält *kein* template-Attribut und *benötigt* statt dessen ein Klassen-Attribut. Für die meisten Seiten mit automatisch generiertem Inhalt ist das kein Problem. Für die Startseite verwendet man ein eigenes Template. Ersetzen Sie die Konfiguration für die Startseite durch die folgenden Zeilen: .. sourcecode:: xml Beachten Sie die Veränderung. Das template-Attribut wurde durch das class-Attribut ersetzt, wobei die ``FrontPage``-Klasse noch erstellt werden muss. Um die Skin-Problematik abzuschließen, erstellen Sie diese Klasse indem Sie die am Ende der Datei ``zcontact/browser/contact.py`` folgenden Quellcode einfügen: .. sourcecode:: python class FrontPage(BrowserPagelet): """Pagelet for the front page.""" Gleichzeitig wird die Import-Anweisung ``from z3c.pagelet.browser import BrowserPagelet`` am Anfang der Datei benötigt. Sie werden nun vielleicht denken: "Was passiert mit unserem Template und die Klasse ist irgendwie ohne Funktionalität". Weil die Klasse jedoch von BrowserPagelet erbt, besitzt sie eine doch eine gewisse Funktionalität. Die BrowserPagelet-Klasse liefert eine spezielle Methode __call__ welche einen Adapter sucht, der wiederum das Template findet. Sie werden sagen: "Ein Adapter um ein Template zu finden? Bedeutet das, wir können unterschiedliche Templates für die gleiche Seite(Pagelet) verwenden?" Die Antwort ist ein eindeutiges JA. Sie können das Template für das Pagelet sowohl in der Klasse (unter Verwendung von ``template = ViewPageTemplateFile('frontpage.pt')``) als auch durch Registrierung des Templates mit zcml, einem speziellen Skin zuordnen. Zur Demonstration verwenden Sie die letztere Variante und fügen zu diesem Zweck in ``zcontact/browser/configure.zcml`` die folgende Directive unter dem "front page"-Pagelet ein: .. sourcecode:: xml Die Verwendung von Layouts mit Forms ==================================== Es ist noch ein Problem zu lösen, bevor unsere Applikation das Licht der Welt erblicken kann, Die z3c.form-Komponente wurde für die normale Nutzung entworfen, ohne den neuen Layout- und Pagelet-Mechanismus benutzen zu müssen (eine gute Sache). Leider liefert die z3c.formui-Komponente Unterstützung für ein eigenes form-Modul. Damit unsere Formulare das neue Layout verwenden, müssen wir unsere import-Anweisungen austauschen, statt ``from z3c.form import form``, verwenden wir nun ``from z3c.formui import form``. Die import-Anweisungen am Anfang der Datei ``zcontact/browser/contact.py`` sollten nun so aussehen: .. sourcecode:: python from z3c.form import field, button from z3c.form.interfaces import DISPLAY_MODE from z3c.formui import form from z3c.pagelet.browser import BrowserPagelet from zope.traversing.browser.absoluteurl import absoluteURL from zope.traversing.api import getParent, getName from zcontact import interfaces from zcontact.contact import Contact Das schließt die Skin-Transformation ab und Sie sollten nach dem Server-Neustart einen schönen Skin sehen, wenn Sie das beschriebenene CSS verwendet haben. Hier ein paar Bildschirmfotos der neuen Seiten: .. image:: images/skinFrontPageScreenShot.png .. image:: images/skinAddFormScreenShot.png Menüs für die z3c-Komponenten ***************************** Zur Zeit ist es schwierig, zwischen den Seiten der Applikation zu wechseln. Es wäre von Vorteil, wenn auf jeder Seite die gleichen Links erscheinen würden, um zwischen der Startseite und dem Hinzufügen-Formular wechseln zu können. Sie können keine hardcodierten Links in das Layout-Template einfügen, weil nicht bekannt ist, die URL auf dem Server aufgebaut ist. Auch ändern sich die relativen Pfadangaben, in Abhängigkeit von der gerade betrachteten Seite. Deshalb wird so etwas wie z3c.menu benötigt. Die Komponente z3c.menu ist ein einfaches Paket zur Erstellung von Menüs und enthält nur wenige Hilfs-Klassen. Die wirkliche Stärke steckt in der Zope-Kern-Komponente zope.viewlet. Die Idee ist, nicht mit den alten zope-Menüs zu arbeiten, die recht unflexibel sind, sondern mit der Verwendung von Viewlets auf einfache Art Menüs zu definieren und zu entscheiden, wann und wo sie zur Anzeige kommen. Ihr Navigationsmenü wird ein Viewlet-Manager sein und jeder Link im Menü wird als Viewlet definiert. Falls Sie noch nie mit Viewlets gearbeitet haben, werde ich die Funktionweise nun erklären. Einen Viewlet-Manager definieren ================================ Was ist ein Viewlet-Manager? In einem Satz gesagt, repräsentiert er einen Bereich auf einer Web-Seite, in dem dynamisch generierter Inhalt platziert wird. Ein einfaches Beispiel ist ein in vielen Blogs reservierter Bereich zum platzieren eines Bildes für den Blogger, eine kurze Beschreibung des Blogs, eine Liste der aktuellsten Beiträge, ein kleiner Kalender und vielleicht eine Region mit Tag's. Jeder der genannten Teile gilt als ein Viewlet (stellen Sie sich eine Mini-Anzeige vor), die von dem Viewlet-Manager gesammelt und zusammengehalten werden. Um einen Viewlet-Manager zu erstellen, öffnen Sie die Datei ``src/zcontact/skin.py`` und fügen die folgenden Zeilen hinzu: .. sourcecode:: python from zope.viewlet.interfaces import IViewletManager from zope.viewlet.manager import WeightOrderedViewletManager class INavigationMenu(IViewletManager): """Navigation Menu Viewlet Manager.""" class NavigationMenu(WeightOrderedViewletManager): zope.interface.implements(INavigationMenu) Wenn Sie Viewlets erstellen, werden diese für einen bestimmten Viewlet-Manger und den dazugehörigen Interface registriert. Deshalb wird ein eigenes Interface ``INavigationMenu`` für das Navigationsmenü erstellt, das wiederum vom ``IViewletManager`` (Zeilen 4-5) erbt. Als nächstes Implementieren Sie das Interface ``INavigationMenu`` (Zeilen 7-8). Die ``WeightOrderedViewletManager``-Klasse kann Viewlets nach einer gegebenen Wichtung sortieren, was für ein Navigationsmenü recht nützlich ist. Als nächstes registrieren Sie diese Viewlet-Manager-Instanz in zcml, damit es von einem Page-Template verwendet werden kann. Fügen Sie die folgenden Registrierungs-Anweisungen in der Datei ``src/zcontact/skin.zcml`` ein: .. sourcecode:: xml Auch hier muss der browser-Namensraum ``xmlns:browser="http://namespaces.zope.org/browser"`` ergänzt werden. Nun haben Sie einen Viewlet-Manager als Verwalter von Menüeinträgen definiert. Dieser Viewlet-Manger wird nun in den Skin integrieren, indem wir die Datei ``src/zcontact/layout.pt`` bearbeiten. Der folgende Schnipsel kann überall dort platziert werden, wo das Menü später erscheinen soll. Sie können es zum Beispiel rechts unter dem Header erscheinen lassen. .. sourcecode:: xml
Navigation Menu
Viewlets hinzufügen =================== Nachdem der Viewlet-Manager platziert ist, können Sie Viewlets (Menü-Einträge) hinzufügen. Dafür ist lediglich die Registierung der Viewlets genau dort notwendig, wo die Pagelets als Ziele der Navigationslinks definiert wurden. Deshalb öffnen Sie die Datei ``zcontact/browser/configure.zcml`` und ergänzen die beiden Konfigurationsblöcke: .. sourcecode:: xml Das Attribut name wird für die Link-Beschriftung verwendet und viewURL definiert die relative URL von der Wurzel der Anwendung zu den entsprechenden Ansichten. Dann setzen Sie noch das Attribut manger auf das ``INavigationMenu``-Interface, und endlich wird das erste Teil von z3c.menu unter Verwendung der Klasse ``GlobalMenuItem`` für das Viewlet sichtbar. Diese Klasse ermittelt den ersten Teil der URL und fügt den im viewURL-Attribut definierten Wert am Ende an. Wenn alles vollendet ist, können Sie den Server neu starten. Ein neues Menü erscheint, das auf allen Seiten der Anwendung verfügbar ist. Wie immer auch hierfür ein Bildschirmfoto: .. image:: images/menuScreenShot.png