Metadata-Version: 1.0
Name: z3c.layout
Version: 0.2
Summary: HTML layout engine
Home-page: UNKNOWN
Author: Malthe Borch, Stefan Eletzhofer and the Zope Community
Author-email: zope-dev@zope.org
License: ZPL 2.1
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'
        
Keywords: zope3 layout HTML
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Zope Public License
Classifier: Programming Language :: Python
Classifier: Natural Language :: English
Classifier: Operating System :: OS Independent
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Framework :: Zope3
