This is a pre-production deployment of Warehouse, however changes made here WILL affect the production instance of PyPI.
Help us improve Python packaging - Donate today!
Project Description

HTML layout engine

This package implements a page rendering model based on a static HTML document that is made dynamic from the outside by mapping content provider definitions to locations in the HTML document tree. This is called a “layout”.

The component architecture is utilized to provide extension points that allow wide application. Two-phase rendering is supported using the zope.contentprovider rendering scheme (update/render).

Static resources, as referenced by the HTML document (images, stylesheets and javascript files) are included carbon copy and published as browser resources (see zope.app.publisher.browser).

Benefits:

  • No template language required
  • Support for two-phase rendering
  • Integrates with creative workflow
  • Flexible extension points

Walk-through

Layouts and regions

Let’s begin by instantiating a layout. We’ll do this manually for the sake of this demonstration; usually this is done using the included ZCML-directive <browser:layout>.

>>> from z3c.layout.model import Layout
>>> layout = Layout(
...     "test", "%s/templates/default/index.html" % test_path, "test")

Register resource directory.

>>> import zope.configuration.config as config
>>> context = config.ConfigurationMachine()
>>> from zope.app.publisher.browser import resourcemeta
>>> resourcemeta.resourceDirectory(
...     context, "test", "%s/templates/default" % test_path)
>>> context.execute_actions()

Layouts are made dynamic by defining one or more regions. They are mapped to HTML locations using an xpath-expression and an insertion mode, which is one of “replace”, “append”, “prepend”, “before” or “after”.

Regions can specify the name of a content provider directly or it may rely on adaptation to yield a content provider component. We’ll investigate both of these approaches:

>>> from z3c.layout.model import Region

First we define a title region where we directly specify the name of a content provider.

>>> title = Region("title", ".//title", title=u"Title", provider="title")

Then a content region where we leave it the content provider to component adaptation.

>>> content = Region("content", ".//div", "Content")

To register them with the layout we simply add them.

>>> layout.regions.add(title)
>>> layout.regions.add(content)

Let’s define a context class.

>>> class MockContext(object):
...     interface.implements(interface.Interface)

We need to provide a general adapter that can provide content providers for regions that do not specify them directly. As an example, we’ll define an adapter that simply tries to lookup a content provider with the same name as the region.

>>> from z3c.layout.interfaces import IContentProviderFactory
>>> class EponymousContentProviderFactory(object):
...     interface.implements(IContentProviderFactory)
...
...     def __init__(self, region):
...         self.region = region
...
...     def __call__(self, context, request, view):
...         name = self.region.name
...         return component.getMultiAdapter(
...            (view.context, request, view), IContentProvider, name)
>>> from z3c.layout.interfaces import IRegion
>>> component.provideAdapter(
...     EponymousContentProviderFactory, (IRegion,))

Rendering

Before we can render the layout, we need to register content providers for the two regions. We’ll use a mock class for demonstration.

>>> from zope.contentprovider.interfaces import IContentProvider
>>> class MockContentProvider(object):
...     interface.implements(IContentProvider)
...
...     __name__ = u""
...
...     def __init__(self, *args):
...         pass
...
...     def update(self):
...         pass
...
...     def render(self):
...         return self.__name__
...
...     def __repr__(self):
...         return "<MockContentProvider '%s'>" % self.__name__
>>> from zope.publisher.interfaces.browser import IBrowserRequest
>>> from zope.publisher.interfaces.browser import IBrowserView
>>> component.provideAdapter(
...     MockContentProvider, (MockContext, IBrowserRequest, IBrowserView),
...     name="title")
>>> component.provideAdapter(
...     MockContentProvider, (MockContext, IBrowserRequest, IBrowserView),
...     name="content")

Let’s instantiate the layout browser-view. We must define a context and set up a request.

>>> from zope.publisher.browser import TestRequest
>>> context = MockContext()
>>> request = TestRequest()

We need to have the request be annotatable.

>>> from zope.annotation.attribute import AttributeAnnotations
>>> component.provideAdapter(
...     AttributeAnnotations, (TestRequest,))

The view expects the context to adapt to ILayout.

>>> from z3c.layout.interfaces import ILayout
>>> component.provideAdapter(
...     lambda context: layout, (MockContext,), ILayout)
>>> from z3c.layout.browser.layout import LayoutView
>>> view = LayoutView(context, request)

Verify that the layout view is able to get to these providers.

>>> view.mapping
{'content':
 (<Region 'content' .//div (replace) None>, <MockContentProvider 'content'>),
 'title':
 (<Region 'title' .//title (replace) 'title'>, <MockContentProvider 'title'>)}

Now for the actual output.

>>> print view()
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<link rel="stylesheet" href="test/main.css" type="text/css" media="screen">
<title>title</title>
</head>
<body>
    <div id="content">content</div>
  </body>
</html>

Transforms

To support special cases where you need to use Python to transform the static HTML document at compile time, one or more transforms may be defined.

>>> from z3c.layout.model import Transform

Let’s add a transform that adds a language setting to the <html>-tag.

>>> def set_language(node):
...     node.attrib["lang"] = "en"
>>> layout.transforms.add(
...    Transform(set_language))
>>> layout.parse().getroot().attrib["lang"]
'en'

And another transform that assigns a class to the <body>-tag.

>>> def set_class(node, value):
...     node.attrib["class"] = value
>>> layout.transforms.add(
...    Transform(lambda body: set_class(body, "front-page"), ".//body"))
>>> layout.parse().xpath('.//body')[0].attrib["class"]
'front-page'
Release History

Release History

0.2

This version

History Node

TODO: Figure out how to actually get changelog content.

Changelog content for this version goes here.

Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Show More

0.1

History Node

TODO: Figure out how to actually get changelog content.

Changelog content for this version goes here.

Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Show More

Download Files

Download Files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

File Name & Checksum SHA256 Checksum Help Version File Type Upload Date
z3c.layout-0.2.tar.gz (11.6 kB) Copy SHA256 Checksum SHA256 Source Aug 4, 2008

Supported By

WebFaction WebFaction Technical Writing Elastic Elastic Search Pingdom Pingdom Monitoring Dyn Dyn DNS Sentry Sentry Error Logging CloudAMQP CloudAMQP RabbitMQ Heroku Heroku PaaS Kabu Creative Kabu Creative UX & Design Fastly Fastly CDN DigiCert DigiCert EV Certificate Rackspace Rackspace Cloud Servers DreamHost DreamHost Log Hosting