Personal tools
You are here: Home Documentazione Guide Zope 3 con i pacchetti comunitari (z3c.*) z3c.zrtresource e viewlet CSS
Document Actions

z3c.zrtresource e viewlet CSS

Quando all'inizio abbiamo creato il nostro layout per ZContact, abbiamo incluso il foglio di stile CSS direttamente con l'intero layout. In generale questa non è buona pratica per varie ragioni che approfondiremo di seguito. Ora vogliamo spostare il nostro CSS in un suo file. Lo faremo usando un'altra libreria z3c.*: z3c.zrtresource.

Maurizio Delmonte

Paul Carduner ci propone un semplice ed efficace tutorial per mettere mano a Zope 3 apprezzandone l'estrema potenza implementativa.
Page 6 of 6.

Un importante obiettivo da raggiungere nello sviluppare applicazioni web consiste nel permettere ai designer che non conoscono nulla di programmazione di modificare gli aspetti puramente visivi dell'applicazione. Questo include i fogli di stile. I grafici tipicamente sviluppano in un ambiente locale senza mai eseguire codice, quindi dobbiamo gestire in qualche modo la disparità che c'è tra l'accedere a risorse come i fogli di stile dal file system locale e da un'applicazione web in esecuzione.

I page template ci aiutano già molto; aprite layout.pt direttamente in un browser e vedrete un'esposizione molto semplice di come appare l'applicazione anche se non è in esecuzione. z3c.zrtresource ci aiuterà a farlo con i fogli di stile e altre risorse.

Usiamo z3c.zrtresource

Dipendenze

Il primo passo nell'uso di qualsiasi nuovo pacchetto z3c.* consiste nell'aggiungerlo come dipendenza alla nostra applicazione. Aprite setup.py, aggiungete "z3c.zrtresource" al parametro install_requires e rilanciate ./bin/buildout. z3c.zrtresource definisce una nuova direttiva zcml che vedremo fra un attimo, perciò dobbiamo prima includere il file meta.zcml del pacchetto nel nostro src/zcontact/configure.zcml con la linea:

<include package="z3c.zrtresource" file="meta.zcml" />

Usiamo la Direttiva zrt-resource

Ora possiamo andare avanti e rimuovere il CSS dal file layout.pt e incollarlo in un nuovo file src/zcontact/style.css. Al posto dei tag style in layout.pt aggiungiamo un tag link come questo:

<link rel="stylesheet" type="text/css" href="style.css" />

Questo è solo un segnaposto che permette al foglio di stile di essere acceduto dal file system. In un attimo aggiungeremo del codice per ottenere dinamicamente la path del foglio di stile.

Se avviate il server ora e visitate http://localhost:8080/++skin++ZContact/ lo stile risulterà rotto. Questo perchè http://localhost:8080/++skin++ZContact/style.css non corrisponde ad una risorsa esistente. Prima dobbiamo aggiungere il foglio di stile come una risorsa in zope. Aprite skin.zcml e aggiungete la direttiva zrt-resource in fondo:

<browser:zrt-resource
    name="style.css"
    file="style.css"
    layer="zcontact.layer.IZContactBrowserLayer"
    />

Ora possiamo riavviare il server e dovreste essere in grado di accedere al foglio di stile tramite http://localhost:8080/++skin++ZContact/++resource++style.css

Ora possiamo cambiare il link del nostro foglio di stile in layout.pt come di seguito:

<link rel="stylesheet" type="text/css" href="style.css"
      tal:attributes="href string:++resource++style.css"/>

Questo dovrebbe soddisfare i bisogno tutti i grafici sul progetto, ma c'è qualcosa di più che potreste fare con le risorse zrt.

Sostituzione di Stringhe con zrt-resource

Fino a qui non abbiamo fatto nulla con le risorse zrt che non potreste fare con la normale direttiva resource che fa parte di zope core. Ma se andate alla pagina pypi di z3c.zrtresource troverete documentate alcune funzionalità di gestione template molto allettanti. Come esempio di ciò che si può fare (non che vogliate farlo necessariamente) andremo avanti disponendo del colore di sfondo per la nostra pagina generato dinamicamente dalla request.

Il nostro obiettivo consiste nell'ottenere dall'url http://localhost:8080/++skin++ZContact/@@index.html?color=LightGoldenRodYellow una pagina con uno sfondo LightGoldenRodYellow. Per prima cosa dobbiamo passare i dati della request al foglio di stile stesso modificando il link al foglio di stile in layout.pt come segue:

<link rel="stylesheet" type="text/css" href="style.css"
      tal:attributes="href string:++resource++style.css?color=${request/color|string:white}"/>

In questo modo quando renderizzeremo la pagina il foglio di stile punterà a ++resource++style.css?color=LightGoldenRodYellow. Ora possiamo modificare style.css aggiungendo un commento in cima e modificando il body come segue:

/* zrt-replace: "requestcolor" tal"request/color|string:white" */

body {
  padding: 1em;
  background: requestcolor;
}

Ora provate ad accedere http://localhost:8080/++skin++ZContact/@@index.html?color=LightGoldenRodYellow e dovreste vedere un magnifico sfondo color "light golden rod yellow". Accedendo al codice tal, non ci sono limiti a quello che potreste fare in questo modo. Date unn'occhiata alla documentazione e agli esempi di z3c.zrtresource.

Viewlet per gli stili CSS

Abbiamo visto un esempio di come i viewlet siano utili con i menu di navigazione, ma ci sono molti altri modi di rendere la nostra applicazione più gestibile utilizzando i viewlet.

Una delle cose che vogliamo è un modo per includere il giusto CSS su ogni pagina includendo all'occorrenza CSS personalizzato per pagine molto specifiche.

Inoltre vogliamo facilmente includere fogli di stile CSS definiti in altri pacchetti, ad esempio z3c.form senza dover copiare file.

Ecco i viewlet, che permettono a pezzi di html generati dinamicamente di apparire su qualsiasi pagina secondo una grande quantità di parametri, inclusi il contesto, skin/layer, e qualsiasi altra regola vi sia gradita. Un paradigma comune in questi giorni è quello di registrare tutti i fogli di stile CSS all'interno di viewlet che possono essere gestiti con zcml. Proviamo ad approfondire tale modalità.

Creiamo il Viewlet Manager

Per prima cosa creiamo un nuovo viewlet manager per raccogliere i nostri viewlet CSS. Lo faremo nello stesso modo che abbiamo usato per il viewlet manager del menu di navigazione. Aprite src/zcontact/skin.py e aggiungete queste due linee:

class ICSS(IViewletManager):
    """CSS viewlet manager."""

Ora vogliamo registrare questo nuovo viewlet manager nel file src/zcontact/skin.zcml:

<browser:viewletManager
    name="ICSS"
    provides="zcontact.skin.ICSS"
    class="zope.viewlet.manager.WeightOrderedViewletManager"
    layer="zcontact.layer.IZContactBrowserLayer"
    permission="zope.Public"
    />

Con un nuovo viewlet manager chiamato ICSS possiamo modificare il template principale del nostro layout per sostituire il tag link con un tal block che mostra i viewlet CSS rilevanti. Aprite src/zcontact/layout.pt e fate in modo che il tag link assomigli a questo:

<tal:block tal:content="structure provider:ICSS">
  <link rel="stylesheet" type="text/css" href="style.css"/>
</tal:block>

Una cosa da notare qui è che ancora lasciamo in giro il tag link originale. Quando la pagina viene generata in zope sarà sostituito dai nostri viewlet CSS, ma quando un grafico apre direttamente il file layout.pt, il foglio di stile sarà ancora caricato, anche se non dinamicamente.

Ora siamo pronti per aggiungere i viewlet dei CSS. Proprio come abbiamo fatto per i viewlet z3c.menu, esiste già una classe viewlet appositamente creata per i viewlet dei CSS, che li renderizza con tag di tipo link. Creiamo una tale viewlet aggiungendo due linee a src/zcontact/skin.py:

from zope.viewlet.viewlet import CSSViewlet

ZContactCSSViewlet = CSSViewlet('style.css')

Il parametro che passiamo alla classe CSSViewlet indica il nome della risorsa css non del file stesso. Poichè generalmente diamo lo stesso nome alla risorsa e al file si potrebbe generare confusione. Infine dobbiamo registrare il viewlet con dello zcml in src/zcontact/skin.zcml:

<browser:viewlet
    name="style.css"
    for="*"
    manager="zcontact.skin.ICSS"
    class="zcontact.skin.ZContactCSSViewlet"
    permission="zope.Public"
    layer="zcontact.layer.IZContactBrowserLayer"
    />

Note sui Layout Personalizzati

Normalmente a questo punto vremmo finito il nostro lavoro e potreste riavviare il server e vedere il foglio di stile ancora caricato. Sfortunatamente c'è una nota da fare derivante da un precedente passo del tutorial relativa all'uso di un layer che non eredita dal layer di default.

Quando la classe CSSViewlet renderizza la viewlet in html, l'url usato per accedere alla risorsa (style.css) non è /++resource++style.css ma piuttosto il più semplice /@@/style.css. Sfortunatamente @@ è in verità una vista registrata sul layer di default e perciò non esiste nel nostro IZContactBrowserLayer, che significa che la risorsa non sarà accessibile dall'interno della nostra skin con quella url.

Esistono alcune soluzioni a questo problema, ma la più semplice è di registrare nuovamente la vista @@ nella nostra skin. La registrazione zcml per questa vista dovrebbe essere quella che segue (in src/zcontact/skin.zcml):

<browser:page
    name=""
    for="zope.app.component.interfaces.ISite"
    class="zope.app.publisher.browser.resources.Resources"
    permission="zope.Public"
    allowed_interface="zope.publisher.interfaces.browser.IBrowserPublisher"
    layer="zcontact.layer.IZContactBrowserLayer"
    />

Nel caso siate curiosi la vista originale viene definita in zope/app/publisher/browser/configure.zcml.

Con questo ultimo ritocco potete riavviare il server per vedere esattamente la stessa cosa che avevate prima, ma ora costruita nel modo molto più potente e lessibile del viewlet.

Personalizziamo le Viewlet

Nota
La prossima sezione non è per i deboli di cuore.

Cosa ne dite di tutte le cose meravigliose che abbiamo fatto con z3c.zrtresource? Ora che il viewlet renderizza il tag link non includerà la variabile colore della request per impostare il colore di sfondo. Per tornare ad aggiungere questa funzionalità dovremo personalizzare il viewlet CSS con la nostra classe viewlet.

Prima vi mostrerò il codice, poi la spiegazione. In src/zcontact/skin.py ho aggiunto il seguente codice:

from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
from zope.viewlet.viewlet import CSSResourceViewletBase
from zope.viewlet.viewlet import ViewletBase

class RequestCSSResourceViewlet(CSSResourceViewletBase, ViewletBase):

    index = ViewPageTemplateFile(os.path.join(os.path.dirname(zope.viewlet.viewlet.__file__), 'css_viewlet.pt'))
    requestKey = ''
    default = ''
    path = ''

    def getURL(self):
        self._path = self.path
        baseURL = super(RequestCSSResourceViewlet, self).getURL()
        fullURL = baseURL + '?%s=%s' % (self.requestKey,
                                      self.request.get(self.requestKey, self.default))
        return fullURL

Mentre leggete il codice precedente, suggerisco caldamente di dare uno sguardo al codice delle classi di base CSSResourceViewletBase e ViewletBase. Ci sono tre parti delle classi di base su cui stiamo facendo override, l'attributo index che punta ad un page template per renderizzare il tag link, l'attributo path che restituisce il nome dela risorsa che stiamo cercando, e il metodo getURL che effettivamente renderizza l'url che vogliamo.

Per il page template di index vogliamo riusare il template esistente dal pacchetto zope.viewlet.viewlet chiamato css_viewlet.pt. Il metodo getURL esegue fa esattamente la stessa cosa del tag tal che avevamo in precedenza: concatena i parametri della request nell'url.

Abbiamo anche definito questa classe in modo generico in modo che possa essere usata per parametri diversi dal solo color. Una bella cosa dei viewlet che vedremo in un attimo è che possiamo specificare qualsiasi attributo di classe mediante zcml, semplicemente aggiungendo attributi ulteriori dello stesso nome al tag browser:viewlet. In questo caso passeremo tre attributi aggiuntivi: requestKey, default, e path. Ora aprite src/zcontact/skin.zcml e modificate il tag viewlet di style.css come segue:

<browser:viewlet
    name="style.css"
    for="*"
    manager="zcontact.skin.ICSS"
    class="zcontact.skin.RequestCSSResourceViewlet"
    permission="zope.Public"
    layer="zcontact.layer.IZContactBrowserLayer"
    requestKey="color"
    default="white"
    path="style.css"
    />

Come potete vedere abbiamo solo cambiato l'attributo class e aggiunto gli altri attributi di cui abbiamo bisogno per la viewlet. Questo conclude il nostro primo approccio alla personalizzazione delle viewlet CSS e dovreste ora essere in grado di riavviare il server e visitare http://localhost:8080/++skin++ZContact/@@index.html?color=LightGoldenRodYellow dove dovreste vedere uno sfondo color Light Golden Rod Yellow!

 
by Maurizio Delmonte last modified 2008-04-29 11:34
Contributors: Paul Carduner, Maurizio Delmonte

Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: