Registration

In the course of this narrative we will demonstrate different usage scenarios. The example test setup contains the following files:

./skins/index.pt
./skins/main_template.pt
./skins/images/logo.png
./skins/about/index.pt
./skins/about/images/logo.png

       ↳ mount point

To explain this setup, imagine that the index.pt template represents some page in the site (e.g. the front page); it uses main_template.pt as the o-wrap template. The about directory represents some editorial about-section where about/index.pt is the index page. This section provides its own logo.

We begin by registering the directory. This makes the files listed above available as skin components. The ZCML-directive skins makes registration easy:

<configure xmlns="http://namespaces.repoze.org/bfg">
  <include package="repoze.bfg.skins" />
  <skins path="skins" />
</configure>

The path parameter indicates a relative path which defines the mount point for the skin registration.

Components

At this point the skin objects are available as utility components. This is the low-level interface:

from zope.component import getUtility
from repoze.bfg.skins.interfaces import ISkinObject
index = getUtility(ISkinObject, name="index")

The component name is available in the name attribute:

index.name

We now move up one layer and consider the skin components as objects.

Objects

The SkinObject class itself wraps the low-level utility lookup:

from repoze.bfg.skins import SkinObject
FrontPage = SkinObject("index")

This object is a callable which will render the template to a response (it could be an image, stylesheet or some other resource type). In the case of templates, the first two positional arguments (if given) are mapped to context and request. These symbols are available for use in the template.

response = FrontPage(u"Hello world!")

The index template simply inserts the context value into the body tag of the HTML document:

<html>
  <body>
    Hello world!
  </body>
</html>

The exact same approach works for the logo object:

from repoze.bfg.skins import SkinObject
logo = SkinObject("images/logo.png")

Calling the logo object returns an HTTP response:

200 OK

Views

The call method signature for skin templates is (context, request). This is the same as BFG views. That is, we can use skin template objects directly as view callables:

<view name="frontpage1" view=".FrontPage" />

In BFG we can also define a view using a class which provides __init__ and __call__. The call method must return a response. With skin objects, we can express it this way:

class FrontPageView(object):
    __call__ = SkinObject("index")

    def __init__(self, context, request):
        self.context = context
        self.request = request

When the __call__ attribute is accessed, the view instance dictionary (which in this case has the symbols context and request) is bound to the template. The dictionary is then passed as keyword arguments when the template is called:

<view name="frontpage2" view=".FrontPageView" />

While the two patterns are equivalent, using a view allows you to prepare data for the template. Both yield the exact same output when passed 'Hello world!' as the view context:

<html>
  <body>
    Hello world!
  </body>
</html>

Discovery

In some scenarios, it’s useful to be able to discover skin objects at run-time. An example is when you use skins to publish editorial content which is added to the file system.

The discovery parameter takes a boolean argument, e.g. True:

<configure xmlns="http://namespaces.repoze.org/bfg">
  <skins path="skins" discovery="True" />
</configure>

Let’s add a new skin template with the source:

<div>Hello world!</div>

Compatibility:

  • Mac OS X 10.5+ (requires the MacFSEvents library)
  • Linux 2.6.13+ with Libc >= 2.4 (requires pyinotify library)

Table Of Contents

Previous topic

The flexible skinning solution

Next topic

Templates

This Page