Création d’un thème Plone 3

Définition

Ajout de nouveaux composants visuels à Plone.

Savoir

  • Introspection d’une page avec Gloworm
  • Ajout d’une viewlet
  • Ajout d’une action / onglet / lien
  • Ajout d’une portlet modélisé avec ArchGenXML
  • Ressources Zope 3

Installation de Gloworm

Gloworm est un outil pour introspecter une page Plone, très utile pour savoir comment customizer telle partie de la page.

Créez un fichier development.cfg :

[buildout]
extends = buildout.cfg

[instance]
eggs +=
    Products.Gloworm

Reexécutez bin/buildout -c development.cfg.

Création d’un theme

Dans le dossier src, créez un theme avec la commande :

$ cd /tmp
$ paster create -t plone3_theme formation.theme --svn-repository=http://devagile/Formation/packages
empty_styles False
include_doc True
zope2product True
$ svn rm --force formation.theme/formation.theme.egg-info
$ svn rm formation/theme/skins/formation_theme_styles/base.css.dtml
$ svn rm formation/theme/skins/formation_theme_styles/portlets.css.dtml
$ svn rm formation/theme/skins/formation_theme_styles/public.css.dtml
$ svn ci -m"First import"
$ svn rm formation/theme/version.txt
$ svn ci -m"Removed version.txt"

Ajoutez ensuite l’entry point z3c.autoinclude.plugin dans setup.py :

[z3c.autoinclude.plugin]
target = plone

et commitez :

$ svn ci -m"Added z3c.autoinclude entry point"

Retournez dans votre buildout, ajoutez formation.theme dans auto-checkout du fichier sources.cfg, ainsi que dans eggs de la section [instance] de buildout.cfg, commitez et relancez le buildout.

Exercice 1

Changer la couleur des documents dans l’état “En attente de modération” (pending). Utilisez l’extension Firebug de firefox pour récupérer la règle css utilisé par défaut pour colorisé le lien en orange. Copiez ensuite cette règle dans browser/stylesheets/main.css et changez la couleur :

.state-pending {
    color:#FFA5FF !important;
}

Passez portal_css en mode debug comme ça vous ne devrez pas redémarrer l’instance à chaque fois que vous modifiez les css.

Exercice 2

Créez une viewlet affichant une image dans le footer.

Ajouter une image

Ajoutez une image dans le dossier browser/images. Pour accéder ensuite à l’image, vous devez utiliser le nom de la resourceDirectory : ++resource++formation.theme.images, suivit de / et de le nom de votre image dans le dossier images. Exemple : ++resource++formation.theme.images/monimage.png

Éditez le fichier browser/viewlets.py, décommentez la classe, nommez la LogoViewlet. Copiez le fichier viewlet.pt en logoviewlet.pt Contenu du fichier logoviewlet.pt :

<img tal:define="portal_state context/@@plone_portal_state;
                 root_url portal_state/portal_url"
     tal:attributes="src string:$root_url/++resource++formation.theme.images/image.png" />

Éditez le fichier configure.zcml pour déclarer votre viewlet. Vous avez un exemple en commentaire. Il suffit de le décommenter et d’ajuster le nom de la viewlet et la classe. Cela donne :

<browser:viewlet
    name="formation.logoviewlet"
    manager="plone.app.layout.viewlets.interfaces.IPortalFooter"
    class=".viewlets.LogoViewlet"
    layer=".interfaces.IThemeSpecific"
    permission="zope2.View"
    />

Maintenant au lieu d’afficher votre LogoViewlet dans le PortalFooter, vous allez l’afficher dans portalheader en précisant que vous le voulez après le logo de plone. Dans configure.zcml, changez l’interface du viewletmanager en IPortalHeader :

<browser:viewlet
    name="formation.logoviewlet"
    manager="plone.app.layout.viewlets.interfaces.IPortalHeader"
    class=".viewlets.LogoViewlet"
    layer=".interfaces.IThemeSpecific"
    permission="zope2.View"
    />

Éditez ensuite profiles/default/viewlets.xml :

<?xml version="1.0"?>
<object>
  <order manager="plone.portalheader" skinname="formation's theme"
         based-on="Plone Default">
    <viewlet name="zdevan.logoviewlet"
             insert-after="plone.logo" />
  </order>
</object>

Relancez l’instance et réinstallez votre produit pour prendre en compte le changement.

Portlets

Créez le portlet :

$ cd /tmp
$ paster create -t plone3_portlet formation.portlet.docinfo --svn-repository=http://devagile/Formation/packages
  • Supprimez le répertoire egg-info, le fichier version.txt
  • Ajoutez ensuite l’entry point z3c.autoinclude.plugin dans setup.py
  • Commitez
  • Ajoutez ce nouveau egg dans votre buildout.cfg et sources.cfg
  • Relancez le buildout
  • Commitez les changements fait dans le buildout

Démarrez l’instance, installez le produit et ajoutez le portlet.

Éditez le fichier docinfoportlet.py et ajoutez un champ informations au schema IDocInfoPortlet :

informations = schema.List(title=_(u"Information list"),
                       description=_(u"A list of information about the document"),
                       required=True,
                       value_type=schema.Choice(values=('Creator','effective'))
                       )

Modifiez également l’implémentation :

class Assignment(base.Assignment):
    """Portlet assignment.

    This is what is actually managed through the portlets UI and associated
    with columns.
    """

    implements(IDocInfoPortlet)

    informations = ()

    def __init__(self, informations=()):
        self.informations = informations

Dans la template, afficher les informations qui ont été choisies via le formulaire du portlet :

<dl class="portlet portletDocInfoPortlet"
    i18n:domain="formation.portlet.docinfo">

    <dt class="portletHeader">
        <span class="portletTopLeft"></span>
        Information
        <span class="portletTopRight"></span>
    </dt>

    <dd class="portletItem odd" tal:define="informations view/data/informations;
                                            plone_view context/@@plone;
                                            mtool context/portal_membership" >

        <strong>Created by :</strong>

        <span tal:condition="python:'Creator' in informations"
              tal:replace="python:mtool.getMemberById(context.Creator()).getProperty('fullname',context.Creator())" />

        <strong>Date of creation :</strong>

        <span i18n:translate="text_effective_date">
        <span tal:condition="python:'effective' in informations"
              tal:content="python:plone_view.toLocalizedTime(context.effective())" />
        </span>

        <tal:block condition="python:'ExpirationDate' in informations">
          <span i18n:translate="text_expiration_date"
                tal:condition="context/ExpirationDate">

            <strong>Expiration :</strong>

            <span i18n:name="date"
                  tal:content="python:plone_view.toLocalizedTime(context.ExpirationDate())" />
          </span>
        </tal:block>
    </dd>

</dl>

Ajoutez une property available dans la classe Renderer pour afficher le portlet seulement pour les documents :

class Renderer(base.Renderer):
    """Portlet renderer.

    This is registered in configure.zcml. The referenced page template is
    rendered, and the implicit variable 'view' will refer to an instance
    of this class. Other methods can be added and referenced in the template.
    """

    @property
    def available(self):
        return self.context.meta_type == "ATDocument"

    render = ViewPageTemplateFile('docinfoportlet.pt')

Le futur de Plone

Fusion des concepts de viewlets et portlets en tiles : http://groups.google.com/group/plone-deco/files

Deliverance

Demo de Deliverance et Banjo :

svn co http://svn.plone.org/svn/collective/deliverancedemo