[Checkins] SVN: z3c.template/ Added z3c.template implementation

Roger Ineichen roger at projekt01.ch
Wed Jan 17 20:02:50 EST 2007


Log message for revision 72085:
  Added z3c.template implementation

Changed:
  A   z3c.template/branches/
  A   z3c.template/tags/
  A   z3c.template/trunk/
  A   z3c.template/trunk/src/
  A   z3c.template/trunk/src/z3c/
  A   z3c.template/trunk/src/z3c/__init__.py
  A   z3c.template/trunk/src/z3c/template/
  A   z3c.template/trunk/src/z3c/template/README.txt
  A   z3c.template/trunk/src/z3c/template/SETUP.cfg
  A   z3c.template/trunk/src/z3c/template/__init__.py
  A   z3c.template/trunk/src/z3c/template/interfaces.py
  A   z3c.template/trunk/src/z3c/template/macro.py
  A   z3c.template/trunk/src/z3c/template/meta.zcml
  A   z3c.template/trunk/src/z3c/template/template.py
  A   z3c.template/trunk/src/z3c/template/tests.py
  A   z3c.template/trunk/src/z3c/template/z3c.template-meta.zcml
  A   z3c.template/trunk/src/z3c/template/zcml.py
  A   z3c.template/trunk/src/z3c/template/zcml.txt

-=-
Added: z3c.template/trunk/src/z3c/__init__.py
===================================================================
--- z3c.template/trunk/src/z3c/__init__.py	2007-01-18 01:02:26 UTC (rev 72084)
+++ z3c.template/trunk/src/z3c/__init__.py	2007-01-18 01:02:49 UTC (rev 72085)
@@ -0,0 +1,16 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id$
+"""


Property changes on: z3c.template/trunk/src/z3c/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: z3c.template/trunk/src/z3c/template/README.txt
===================================================================
--- z3c.template/trunk/src/z3c/template/README.txt	2007-01-18 01:02:26 UTC (rev 72084)
+++ z3c.template/trunk/src/z3c/template/README.txt	2007-01-18 01:02:49 UTC (rev 72085)
@@ -0,0 +1,476 @@
+======
+README
+======
+
+This package allows us to separate the registration of the view code and the
+layout.
+
+A template is used for separate the HTML part from a view. This is done in 
+z3 via a page templates. Such page template are implemented in the view, 
+registered included in a page directive etc. But they do not use the adapter
+pattern which makes it hard to replace existing templates.
+
+Another part of template is, that they normaly separate one part presenting
+content from a view and another part offer a layout used by the content 
+template.
+
+How can this package make it simpler to use templates?
+
+Templates can be registered as adapters adapting context, request where the 
+context is a view implementation. Such a template get adapted from the view
+if the template is needed. This adaption makes it very pluggable and modular.
+
+We offer two base template directive for register content producing templates
+and layout producing tempaltes. This is most the time enough but you also
+can register different type of templates using a specific interface. This 
+could be usefull if your view implementation needs to separate HTMl in
+more then one template. Now let's take a look how we an use this templates.
+
+
+Content template
+----------------
+
+First let's show how we use a template for produce conent from a view:
+
+  >>> import os, tempfile
+  >>> temp_dir = tempfile.mkdtemp()
+  >>> contentTemplate = os.path.join(temp_dir, 'contentTemplate.pt')
+  >>> open(contentTemplate, 'w').write('''<div>demo content</div>''')
+
+And register a view class implementing a interface:
+
+  >>> import zope.interface
+  >>> from z3c.template import interfaces
+  >>> from zope.pagetemplate.interfaces import IPageTemplate
+  >>> from zope.publisher.browser import BrowserPage
+
+  >>> class IMyView(zope.interface.Interface):
+  ...     pass
+  >>> class MyView(BrowserPage):
+  ...     zope.interface.implements(IMyView)
+  ...     template = None
+  ...     def render(self):
+  ...         if self.template is None:
+  ...             template = zope.component.getMultiAdapter(
+  ...                 (self, self.request), IPageTemplate)
+  ...             return template(self)
+  ...         return self.template()
+
+Let's call the view and check the output:
+
+  >>> from zope.publisher.browser import TestRequest
+  >>> request = TestRequest()
+  >>> view = MyView(root, request)
+
+Since the template is not yet registered, rendering the view will fail:
+
+  >>> print view.render()
+  Traceback (most recent call last):
+  ...
+  ComponentLookupError: ......
+
+Let's now register the template (commonly done using ZCML):
+
+  >>> from zope import component
+  >>> from zope.publisher.interfaces.browser import IDefaultBrowserLayer
+  >>> from z3c.template.template import TemplateFactory
+
+The template factory allows us to create a ViewPageTeplateFile instance.
+
+  >>> factory = TemplateFactory(contentTemplate, 'text/html')
+
+We register the factory on a view interface and a layer.
+
+  >>> component.provideAdapter(factory,
+  ...     (zope.interface.Interface, IDefaultBrowserLayer), IPageTemplate)
+  >>> template = component.getMultiAdapter((view, request), IPageTemplate)
+  >>> template
+  <zope.app.pagetemplate.viewpagetemplatefile.ViewPageTemplateFile object at ...>
+
+Now that we have a registered layout template for the default layer we can 
+call our view again.
+
+  >>> print view.render()
+  <div>demo content</div>
+
+Now we register a new template on the specific interface of our view.
+
+  >>> myTemplate = os.path.join(temp_dir, 'myTemplate.pt')
+  >>> open(myTemplate, 'w').write('''<div>My content</div>''')
+  >>> factory = TemplateFactory(myTemplate, 'text/html')
+  >>> component.provideAdapter(factory,
+  ...     (IMyView, IDefaultBrowserLayer), IPageTemplate)
+  >>> print view.render()
+  <div>My content</div>
+
+It is possible to provide the template directly.
+
+We create a new template.
+
+  >>> viewContent = os.path.join(temp_dir, 'viewContent.pt')
+  >>> open(viewContent, 'w').write('''<div>view content</div>''')
+
+and a view:
+
+  >>> from zope.app.pagetemplate import ViewPageTemplateFile
+  >>> class MyViewWithTemplate(BrowserPage):
+  ...     zope.interface.implements(IMyView)
+  ...     template = ViewPageTemplateFile(viewContent)
+  ...     def render(self):
+  ...         if self.template is None:
+  ...             template = zope.component.getMultiAdapter(
+  ...                 (self, self.request), IPageTemplate)
+  ...             return template(self)
+  ...         return self.template()
+  >>> contentView = MyViewWithTemplate(root, request)
+
+If we render this view we get the implemented layout template and not the 
+registered one.
+
+  >>> print contentView.render()
+  <div>view content</div>
+
+
+Layout template
+---------------
+
+First we nee to register a new view class calling a layout template. Note,
+that this view uses the __call__ method for invoke a layout template:
+
+  >>> class ILayoutView(zope.interface.Interface):
+  ...     pass
+  >>> class LayoutView(BrowserPage):
+  ...     zope.interface.implements(ILayoutView)
+  ...     layout = None
+  ...     def __call__(self):
+  ...         if self.layout is None:
+  ...             layout = zope.component.getMultiAdapter(
+  ...                 (self, self.request), interfaces.ILayoutTemplate)
+  ...             return layout(self)
+  ...         return self.layout()
+  >>> view2 = LayoutView(root, request)
+
+Define and register a new layout template:
+
+  >>> layoutTemplate = os.path.join(temp_dir, 'layoutTemplate.pt')
+  >>> open(layoutTemplate, 'w').write('''<div>demo layout</div>''')
+  >>> factory = TemplateFactory(layoutTemplate, 'text/html')
+
+We register the template factory on a view interface and a layer providing the 
+ILayoutTemplate interface.
+
+  >>> component.provideAdapter(factory,
+  ...     (zope.interface.Interface, IDefaultBrowserLayer), 
+  ...      interfaces.ILayoutTemplate)
+  >>> layout = component.getMultiAdapter(
+  ...     (view2, request), interfaces.ILayoutTemplate)
+  >>> layout
+  <zope.app.pagetemplate.viewpagetemplatefile.ViewPageTemplateFile ...>
+
+Now that we have a registered layout template for the default layer we can 
+call our view again.
+
+  >>> print view2()
+  <div>demo layout</div>
+
+Now we register a new layout template on the specific interface of our view.
+
+  >>> myLayout = os.path.join(temp_dir, 'myLayout.pt')
+  >>> open(myLayout, 'w').write('''<div>My layout</div>''')
+  >>> factory = TemplateFactory(myLayout, 'text/html')
+  >>> component.provideAdapter(factory,
+  ...     (ILayoutView, IDefaultBrowserLayer),
+  ...      interfaces.ILayoutTemplate)
+  >>> print view2()
+  <div>My layout</div>
+
+It is possible to provide the layout template directly.
+
+We create a new template.
+
+  >>> viewLayout = os.path.join(temp_dir, 'viewLayout.pt')
+  >>> open(viewLayout, 'w').write('''<div>view layout</div>''')
+
+  >>> class LayoutViewWithLayoutTemplate(BrowserPage):
+  ...     zope.interface.implements(ILayoutView)
+  ...     layout = ViewPageTemplateFile(viewLayout)
+  ...     def __call__(self):
+  ...         if self.layout is None:
+  ...             layout = zope.component.getMultiAdapter((self, self.request), 
+  ...                 interfaces.ILayoutTemplate)
+  ...             return layout(self)
+  ...         return self.layout()
+  >>> layoutView = LayoutViewWithLayoutTemplate(root, request)
+
+If we render this view we get the implemented layout template and not the 
+registered one.
+
+  >>> print layoutView()
+  <div>view layout</div>
+
+
+Since we return the layout template in the sample views above, how can we get
+the content from the used view? This is not directly a part of this package 
+but let's show some pattern were can be used for render content in a used
+layout template. Note, since we offer to register each layout template for
+a specific view, you can always very selectiv this layout pattern. This means
+you can use the defualt z3 macro based layout registration in combination with 
+this layout concept if you register a own layout template.
+
+The simplest concept is calling the content from the view in the layout 
+template is to call it from a method. Let's define a view providing a layout
+template and offer a method for call content.
+
+  >>> class IFullView(zope.interface.Interface):
+  ...     pass
+
+  >>> class FullView(BrowserPage):
+  ...     zope.interface.implements(IFullView)
+  ...     layout = None
+  ...     def render(self):
+  ...         return u'rendered content'
+  ...     def __call__(self):
+  ...         if self.layout is None:
+  ...             layout = zope.component.getMultiAdapter((self, self.request), 
+  ...                 interfaces.ILayoutTemplate)
+  ...             return layout(self)
+  ...         return self.layout()
+  >>> completeView = FullView(root, request)
+
+Now define a layout for the view and register them:
+
+  >>> completeLayout = os.path.join(temp_dir, 'completeLayout.pt')
+  >>> open(completeLayout, 'w').write('''
+  ...   <div tal:content="view/render">
+  ...     Full layout
+  ...   </div>
+  ... ''')
+
+  >>> factory = TemplateFactory(completeLayout, 'text/html')
+  >>> component.provideAdapter(factory,
+  ...     (IFullView, IDefaultBrowserLayer), interfaces.ILayoutTemplate)
+
+Now let's see if the layout template can call the content via calling render 
+on the view:
+
+  >>> print completeView.__call__()
+  <div>rendered content</div>
+
+
+Content and Layout
+------------------
+
+Now let's show how we combine this two templates in a real use case:
+
+  >>> class IDocumentView(zope.interface.Interface):
+  ...     pass
+
+  >>> class DocumentView(BrowserPage):
+  ...     zope.interface.implements(IDocumentView)
+  ...     template = None
+  ...     layout = None
+  ...     attr = None
+  ...     def update(self):
+  ...         self.attr = u'content updated'
+  ...     def render(self):
+  ...         if self.template is None:
+  ...             template = zope.component.getMultiAdapter(
+  ...                 (self, self.request), IPageTemplate)
+  ...             return template(self)
+  ...         return self.template()
+  ...     def __call__(self):
+  ...         self.update()
+  ...         if self.layout is None:
+  ...             layout = zope.component.getMultiAdapter((self, self.request), 
+  ...                 interfaces.ILayoutTemplate)
+  ...             return layout(self)
+  ...         return self.layout()
+
+Define and register a content template...
+
+  >>> template = os.path.join(temp_dir, 'template.pt')
+  >>> open(template, 'w').write('''
+  ...   <div tal:content="view/attr">
+  ...     here comes the value of attr
+  ...   </div>
+  ... ''')
+
+  >>> factory = TemplateFactory(template, 'text/html')
+  >>> component.provideAdapter(factory,
+  ...     (IDocumentView, IDefaultBrowserLayer), IPageTemplate)
+
+and define and register a layout template:
+
+  >>> layout = os.path.join(temp_dir, 'layout.pt')
+  >>> open(layout, 'w').write('''
+  ... <html>
+  ...   <body>
+  ...     <div tal:content="structure view/render">
+  ...       here comes the rendered content
+  ...     </div>
+  ...   </body>
+  ... </html>
+  ... ''')
+
+  >>> factory = TemplateFactory(layout, 'text/html')
+  >>> component.provideAdapter(factory,
+  ...     (IDocumentView, IDefaultBrowserLayer), interfaces.ILayoutTemplate)
+
+Now call the view and check the result:
+
+  >>> documentView = DocumentView(root, request)
+  >>> print documentView()
+  <html>
+    <body>
+      <div>
+        <div>content updated</div>
+      </div>
+    </body>
+  </html>
+
+
+Macros
+------
+
+Use of macros.
+
+  >>> macroTemplate = os.path.join(temp_dir, 'macroTemplate.pt')
+  >>> open(macroTemplate, 'w').write('''
+  ...   <metal:block define-macro="macro1">
+  ...     <div>macro1</div>
+  ...   </metal:block>
+  ...   <metal:block define-macro="macro2">
+  ...     <div>macro2</div>
+  ...   </metal:block>
+  ...   ''')
+
+  >>> factory = TemplateFactory(macroTemplate, 'text/html', 'macro1')
+  >>> print factory(view, request)()
+  <div>macro1</div>
+
+
+Why didn't we use named templates from the ``zope.formlib`` package?
+
+While named templates allow us to separate the view code from the template
+registration, they are not registrable for a particular layer making it
+impossible to implement multiple skins using named templates.
+
+
+Use case ``simple template``
+----------------------------
+
+And for the simplest possible use we provide a hook for call registered 
+templates. Such page templates can get called with the getViewTemplate method
+and return a registered bound ViewTemplate a la ViewPageTemplateFile or 
+NamedTemplate.
+
+The getViewTemplate allows us to use the new template registration
+system with all existing implementations such as `zope.formlib` and
+`zope.viewlet`.
+
+  >>> from z3c.template.template import getViewTemplate
+  >>> class IUseOfViewTemplate(zope.interface.Interface):
+  ...     pass
+  >>> class UseOfViewTemplate(object):
+  ...     zope.interface.implements(IUseOfViewTemplate)
+  ...
+  ...     template = getViewTemplate()
+  ...
+  ...     def __init__(self, context, request):
+  ...         self.context = context
+  ...         self.request = request
+
+By defining the "template" property as a "RegisteredPageTemplate" a lookup for
+a registered template is done when it is called. Also notice that it is no
+longer necessary to derive the view from BaseView!
+
+  >>> simple = UseOfViewTemplate(root, request)
+  >>> print simple.template()
+  <div>demo content</div>
+
+Because the demo template was registered for any ("None") interface we see the
+demo template when rendering our new view. We register a new template
+especially for the new view. Also not that the "macroTemplate" has been
+created earlier in this test.
+
+  >>> factory = TemplateFactory(contentTemplate, 'text/html')
+  >>> component.provideAdapter(factory,
+  ...     (IUseOfViewTemplate, IDefaultBrowserLayer), IPageTemplate)
+  >>> print simple.template()
+  <div>demo content</div>
+
+
+Use case ``template by interface``
+----------------------------------
+
+Templates can also get registered on different interfaces then IPageTemplate
+or ILayoutTemplate.
+
+  >>> class IMyTemplate(zope.interface.Interface):
+  ...     """My custom tempalte marker."""
+
+  >>> factory = TemplateFactory(contentTemplate, 'text/html')
+  >>> component.provideAdapter(factory,
+  ...     (zope.interface.Interface, IDefaultBrowserLayer), IMyTemplate)
+
+Now define a view using such a custom template registration:
+
+  >>> class IMyTemplateView(zope.interface.Interface):
+  ...     pass
+  >>> class MyTemplateView(object):
+  ...     zope.interface.implements(IMyTemplateView)
+  ...
+  ...     template = getViewTemplate(IMyTemplate)
+  ...
+  ...     def __init__(self, context, request):
+  ...         self.context = context
+  ...         self.request = request
+
+  >>> myTempalteView = MyTemplateView(root, request)
+  >>> print myTempalteView.template()
+  <div>demo content</div>
+
+
+Use case ``named template``
+----------------------------------
+
+Templates can also get registered on names. In this expample we use a named
+template combined with a custom template marker interface.
+
+  >>> class IMyNamedTemplate(zope.interface.Interface):
+  ...     """My custom tempalte marker."""
+
+  >>> factory = TemplateFactory(contentTemplate, 'text/html')
+  >>> component.provideAdapter(factory,
+  ...     (zope.interface.Interface, IDefaultBrowserLayer), IMyNamedTemplate, 
+  ...     name='my template')
+
+Now define a view using such a custom named template registration:
+
+  >>> class IMyNamedTemplateView(zope.interface.Interface):
+  ...     pass
+  >>> class MyNamedTemplateView(object):
+  ...     zope.interface.implements(IMyNamedTemplateView)
+  ...
+  ...     template = getViewTemplate(IMyNamedTemplate, 'my template')
+  ...
+  ...     def __init__(self, context, request):
+  ...         self.context = context
+  ...         self.request = request
+
+  >>> myNamedTempalteView = MyNamedTemplateView(root, request)
+  >>> print myNamedTempalteView.template()
+  <div>demo content</div>
+
+
+Cleanup
+-------
+
+  >>> import shutil
+  >>> shutil.rmtree(temp_dir)
+
+
+Pagelet
+-------
+
+See z3c.pagelet for another template based layout genering implementation.


Property changes on: z3c.template/trunk/src/z3c/template/README.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.template/trunk/src/z3c/template/SETUP.cfg
===================================================================
--- z3c.template/trunk/src/z3c/template/SETUP.cfg	2007-01-18 01:02:26 UTC (rev 72084)
+++ z3c.template/trunk/src/z3c/template/SETUP.cfg	2007-01-18 01:02:49 UTC (rev 72085)
@@ -0,0 +1,3 @@
+<data-files zopeskel/etc/package-includes>
+  z3c.template-*.zcml
+</data-files>


Property changes on: z3c.template/trunk/src/z3c/template/SETUP.cfg
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.template/trunk/src/z3c/template/__init__.py
===================================================================
--- z3c.template/trunk/src/z3c/template/__init__.py	2007-01-18 01:02:26 UTC (rev 72084)
+++ z3c.template/trunk/src/z3c/template/__init__.py	2007-01-18 01:02:49 UTC (rev 72085)
@@ -0,0 +1,16 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id$
+"""


Property changes on: z3c.template/trunk/src/z3c/template/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: z3c.template/trunk/src/z3c/template/interfaces.py
===================================================================
--- z3c.template/trunk/src/z3c/template/interfaces.py	2007-01-18 01:02:26 UTC (rev 72084)
+++ z3c.template/trunk/src/z3c/template/interfaces.py	2007-01-18 01:02:49 UTC (rev 72085)
@@ -0,0 +1,22 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id$
+"""
+
+from zope.pagetemplate.interfaces import IPageTemplate
+
+
+class ILayoutTemplate(IPageTemplate):
+    """A template used for render the layout."""


Property changes on: z3c.template/trunk/src/z3c/template/interfaces.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: z3c.template/trunk/src/z3c/template/macro.py
===================================================================
--- z3c.template/trunk/src/z3c/template/macro.py	2007-01-18 01:02:26 UTC (rev 72084)
+++ z3c.template/trunk/src/z3c/template/macro.py	2007-01-18 01:02:49 UTC (rev 72085)
@@ -0,0 +1,46 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id$
+"""
+__docformat__ = "reStructuredText"
+
+from StringIO import StringIO
+
+from zope.tal.talinterpreter import TALInterpreter
+
+
+class Macro(object):
+    """Provides a single macro from a template for rendering."""
+
+    def __init__(self, template, macroName, view, request, contentType):
+        self.template = template
+        self.macroName = macroName
+        self.view = view
+        self.request = request
+        self.contentType = contentType
+
+    def __call__(self, *args, **kwargs):
+        program = self.template.macros[self.macroName]
+        output = StringIO(u'')
+        namespace = self.template.pt_getContext(self.view, self.request)
+        context = self.template.pt_getEngineContext(namespace)
+        TALInterpreter(program, None,
+                       context, output, tal=True, showtal=False,
+                       strictinsert=0, sourceAnnotations=False)()
+        if not self.request.response.getHeader("Content-Type"):
+            self.request.response.setHeader("Content-Type",
+                                            self.contentType)
+        return output.getvalue()
+


Property changes on: z3c.template/trunk/src/z3c/template/macro.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: z3c.template/trunk/src/z3c/template/meta.zcml
===================================================================
--- z3c.template/trunk/src/z3c/template/meta.zcml	2007-01-18 01:02:26 UTC (rev 72084)
+++ z3c.template/trunk/src/z3c/template/meta.zcml	2007-01-18 01:02:49 UTC (rev 72085)
@@ -0,0 +1,22 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:meta="http://namespaces.zope.org/meta">
+
+  <meta:directives namespace="http://namespaces.zope.org/z3c">
+
+    <meta:directive
+        name="template"
+        schema=".zcml.ITemplateDirective"
+        handler=".zcml.templateDirective"
+        />
+
+    <meta:directive
+        name="layout"
+        schema=".zcml.ILayoutTemplateDirective"
+        handler=".zcml.layoutTemplateDirective"
+        />
+
+  </meta:directives>
+
+</configure>
+


Property changes on: z3c.template/trunk/src/z3c/template/meta.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.template/trunk/src/z3c/template/template.py
===================================================================
--- z3c.template/trunk/src/z3c/template/template.py	2007-01-18 01:02:26 UTC (rev 72084)
+++ z3c.template/trunk/src/z3c/template/template.py	2007-01-18 01:02:49 UTC (rev 72085)
@@ -0,0 +1,76 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id$
+"""
+
+import zope.component
+from zope.pagetemplate.interfaces import IPageTemplate
+from zope.app.pagetemplate import ViewPageTemplateFile
+
+from z3c.template.macro import Macro
+
+
+class TemplateFactory(object):
+    """Template factory."""
+
+    template = None
+
+    def __init__(self, filename, contentType, macro=None):
+        self.macro = macro
+        self.contentType = contentType
+        self.template = ViewPageTemplateFile(filename, 
+            content_type=contentType)
+
+    def __call__(self, view, request):
+        if self.macro is None:
+            return self.template
+        return Macro(self.template, self.macro, view, request, 
+            self.contentType)
+
+
+class BoundViewTemplate(object):
+    def __init__(self, pt, ob):
+        object.__setattr__(self, 'im_func', pt)
+        object.__setattr__(self, 'im_self', ob)
+
+    def __call__(self, *args, **kw):
+        if self.im_self is None:
+            im_self, args = args[0], args[1:]
+        else:
+            im_self = self.im_self
+        return self.im_func(im_self, *args, **kw)
+
+    def __setattr__(self, name, v):
+        raise AttributeError("Can't set attribute", name)
+
+    def __repr__(self):
+        return "<BoundViewTemplate of %r>" % self.im_self
+
+
+class ViewTemplate(object):
+
+    def __init__(self, provides=IPageTemplate, name=u''):
+        self.provides = provides
+        self.name = name
+
+    def __call__(self, instance, *args, **keywords):
+        template = zope.component.getMultiAdapter(
+                (instance, instance.request), self.provides, name=self.name)
+        return template(instance, *args, **keywords)
+
+    def __get__(self, instance, type):
+        return BoundViewTemplate(self, instance)
+
+getViewTemplate = ViewTemplate


Property changes on: z3c.template/trunk/src/z3c/template/template.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: z3c.template/trunk/src/z3c/template/tests.py
===================================================================
--- z3c.template/trunk/src/z3c/template/tests.py	2007-01-18 01:02:26 UTC (rev 72084)
+++ z3c.template/trunk/src/z3c/template/tests.py	2007-01-18 01:02:49 UTC (rev 72085)
@@ -0,0 +1,47 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id$
+"""
+__docformat__ = "reStructuredText"
+
+import unittest
+
+from zope.testing import doctest
+from zope.testing.doctestunit import DocFileSuite
+from zope.app.testing import setup
+
+
+def setUp(test):
+    root = setup.placefulSetUp(site=True)
+    test.globs['root'] = root
+
+
+def tearDown(test):
+    setup.placefulTearDown()
+
+
+def test_suite():
+    return unittest.TestSuite((
+        DocFileSuite('README.txt',
+            setUp=setUp, tearDown=tearDown,
+            optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+            ),
+        DocFileSuite('zcml.txt', setUp=setUp, tearDown=tearDown,
+            optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,),
+        ))
+
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')


Property changes on: z3c.template/trunk/src/z3c/template/tests.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: z3c.template/trunk/src/z3c/template/z3c.template-meta.zcml
===================================================================
--- z3c.template/trunk/src/z3c/template/z3c.template-meta.zcml	2007-01-18 01:02:26 UTC (rev 72084)
+++ z3c.template/trunk/src/z3c/template/z3c.template-meta.zcml	2007-01-18 01:02:49 UTC (rev 72085)
@@ -0,0 +1,6 @@
+<configure
+    xmlns:zcml="http://namespaces.zope.org/zcml">
+
+  <include package="z3c.template" file="meta.zcml" />
+
+</configure>


Property changes on: z3c.template/trunk/src/z3c/template/z3c.template-meta.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.template/trunk/src/z3c/template/zcml.py
===================================================================
--- z3c.template/trunk/src/z3c/template/zcml.py	2007-01-18 01:02:26 UTC (rev 72084)
+++ z3c.template/trunk/src/z3c/template/zcml.py	2007-01-18 01:02:49 UTC (rev 72085)
@@ -0,0 +1,124 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id$
+"""
+__docformat__ = "reStructuredText"
+
+import os
+
+import zope.interface
+import zope.component.zcml
+import zope.schema
+import zope.configuration.fields
+from zope.configuration.exceptions import ConfigurationError
+from zope.pagetemplate.interfaces import IPageTemplate
+from zope.publisher.interfaces.browser import IDefaultBrowserLayer
+
+from z3c.template import interfaces
+from z3c.template.template import TemplateFactory
+
+
+class ITemplateDirective(zope.interface.Interface):
+    """Parameters for the template directive."""
+
+    template = zope.configuration.fields.Path(
+        title=u'Layout template.',
+        description=u"Refers to a file containing a page template (should "
+                     "end in extension ``.pt`` or ``.html``).",
+        required=True,
+        )
+
+    name = zope.schema.TextLine(
+        title=u"The name of the pagelet.",
+        description=u"The name is used in the IController to look up the "
+                      "pagelet.",
+        default=u'',
+        required=False)
+
+    macro = zope.schema.TextLine(
+        title = u'Macro',
+        description = u"""
+            The macro to be used.
+            This allows us to define different macros in on template.
+            The template designer can now create hole site, the
+            ViewTemplate can then extract the macros for single viewlets
+            or views.
+            If no macro is given the hole template is used for rendering.
+            """,
+        default = u'',
+        required = False,
+        )
+
+    for_ = zope.configuration.fields.GlobalObject(
+        title = u'View',
+        description = u'The view for which the template should be available',
+        default=zope.interface.Interface,
+        required = False,
+        )
+
+    layer = zope.configuration.fields.GlobalObject(
+        title = u'Layer',
+        description = u'The layer for which the template should be available',
+        required = False,
+        default=IDefaultBrowserLayer,
+        )
+
+    provides = zope.configuration.fields.GlobalInterface(
+        title=u"Interface the template provides",
+        description=u"This attribute specifies the interface the template"
+                      " instance will provide.",
+        default=IPageTemplate,
+        required=False,
+        )
+
+    contentType = zope.schema.BytesLine(
+        title = u'Content Type',
+        description=u'The content type identifies the type of data.',
+        default='text/html',
+        required=False,
+        )
+
+
+class ILayoutTemplateDirective(ITemplateDirective):
+    """Parameters for the layout template directive."""
+
+
+def templateDirective(_context, template, name=u'',
+    for_=zope.interface.Interface, layer=IDefaultBrowserLayer, 
+    provides=IPageTemplate, contentType='text/html', macro=None):
+
+    # Make sure that the template exists
+    template = os.path.abspath(str(_context.path(template)))
+    if not os.path.isfile(template):
+        raise ConfigurationError("No such file", template)
+
+    factory = TemplateFactory(template, contentType, macro)
+    zope.interface.directlyProvides(factory, provides)
+
+    # register the template
+    if name:
+        zope.component.zcml.adapter(_context, (factory,), provides, 
+            (for_, layer), name=name)
+    else:
+        zope.component.zcml.adapter(_context, (factory,), provides, 
+            (for_, layer))
+
+
+def layoutTemplateDirective(_context, template, name=u'', 
+    for_=zope.interface.Interface, layer=IDefaultBrowserLayer, 
+    provides=interfaces.ILayoutTemplate, contentType='text/html', macro=None):
+
+    templateDirective(_context, template, name, for_, layer, provides, 
+        contentType, macro)


Property changes on: z3c.template/trunk/src/z3c/template/zcml.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: z3c.template/trunk/src/z3c/template/zcml.txt
===================================================================
--- z3c.template/trunk/src/z3c/template/zcml.txt	2007-01-18 01:02:26 UTC (rev 72084)
+++ z3c.template/trunk/src/z3c/template/zcml.txt	2007-01-18 01:02:49 UTC (rev 72085)
@@ -0,0 +1,182 @@
+==================
+Template directive
+==================
+
+Show how we can use the template directive. Register the meta configuration for 
+the directive.
+
+  >>> import sys
+  >>> from zope.configuration import xmlconfig
+  >>> import z3c.template
+  >>> context = xmlconfig.file('meta.zcml', z3c.template)
+
+
+PageTemplate
+~~~~~~~~~~~~
+
+We need a custom content template
+
+  >>> import os, tempfile
+  >>> temp_dir = tempfile.mkdtemp()
+  >>> file = os.path.join(temp_dir, 'file.pt')
+  >>> open(file, 'w').write('''<div>content</div>''')
+
+and a interface
+
+  >>> import zope.interface
+  >>> class IView(zope.interface.Interface):
+  ...     """Marker interface"""
+
+and a view class:
+
+  >>> from zope.publisher.browser import TestRequest
+  >>> class View(object):
+  ...     zope.interface.implements(IView)
+  ...     def __init__(self, context, request):
+  ...         self.context = context
+  ...         self.request = request
+  >>> request = TestRequest()
+  >>> view = View(object(), request)
+
+Make them available under the fake package ``custom``:
+
+  >>> sys.modules['custom'] = type(
+  ...     'Module', (), 
+  ...     {'IView': IView})()
+
+and register them as a layout template within the ``z3c:layout`` directive:
+
+  >>> context = xmlconfig.string("""
+  ... <configure
+  ...     xmlns:z3c="http://namespaces.zope.org/z3c">
+  ...   <z3c:template
+  ...       template="%s"
+  ...       for="custom.IView"
+  ...       />
+  ... </configure>
+  ... """ % file, context=context)
+
+Let's get the template
+
+  >>> import zope.component
+  >>> from z3c.template.interfaces import IPageTemplate
+  >>> template = zope.component.queryMultiAdapter((view, request), 
+  ...     interface=IPageTemplate)
+
+and check them:
+
+  >>> template
+  <zope.app.pagetemplate.viewpagetemplatefile.ViewPageTemplateFile object ...>
+
+  >>> print template(view)
+  <div>content</div>
+
+
+Layout template
+~~~~~~~~~~~~~~~
+
+Define a layout template
+
+  >>> file = os.path.join(temp_dir, 'file.pt')
+  >>> open(file, 'w').write('''<div>layout</div>''')
+
+and register them as a layout template within the ``z3c:layout`` directive:
+
+  >>> context = xmlconfig.string("""
+  ... <configure
+  ...     xmlns:z3c="http://namespaces.zope.org/z3c">
+  ...   <z3c:layout
+  ...       template="%s"
+  ...       for="custom.IView"
+  ...       />
+  ... </configure>
+  ... """ % file, context=context)
+
+Let's get the template
+
+  >>> from z3c.template.interfaces import ILayoutTemplate
+  >>> layout = zope.component.queryMultiAdapter((view, request), 
+  ...     interface=ILayoutTemplate)
+
+and check them:
+
+  >>> layout
+  <zope.app.pagetemplate.viewpagetemplatefile.ViewPageTemplateFile object ...>
+
+  >>> print layout(view)
+  <div>layout</div>
+
+
+Named template
+--------------
+
+Its possible to register template by name. Let us register a pagelet with the
+name edit:
+
+  >>> editTemplate = os.path.join(temp_dir, 'edit.pt')
+  >>> open(editTemplate, 'w').write('''<div>edit</div>''')
+
+  >>> context = xmlconfig.string("""
+  ... <configure
+  ...     xmlns:z3c="http://namespaces.zope.org/z3c">
+  ...   <z3c:template
+  ...       name="edit"
+  ...       template="%s"
+  ...       for="custom.IView"
+  ...       />
+  ... </configure>
+  ... """ % editTemplate, context=context)
+
+And call it:
+
+  >>> from z3c.template.interfaces import ILayoutTemplate
+  >>> template = zope.component.queryMultiAdapter((view, request), 
+  ...     interface=IPageTemplate, name='edit')
+
+  >>> print template(view)
+  <div>edit</div>
+
+Custom template
+---------------
+
+Or you can define own interfaces and register templates for them:
+
+  >>> class IMyTemplate(IPageTemplate):
+  ...     """My template"""
+
+Make the template interface available as a custom module class.
+
+  >>> sys.modules['custom'].IMyTemplate = IMyTemplate
+
+Dfine a new template
+
+  >>> interfaceTemplate = os.path.join(temp_dir, 'interface.pt')
+  >>> open(interfaceTemplate, 'w').write('''<div>interface</div>''')
+
+  >>> context = xmlconfig.string("""
+  ... <configure
+  ...     xmlns:z3c="http://namespaces.zope.org/z3c">
+  ...   <z3c:template
+  ...       template="%s"
+  ...       for="custom.IView"
+  ...       provides="custom.IMyTemplate"
+  ...       />
+  ... </configure>
+  ... """ % interfaceTemplate, context=context)
+
+Let's see if we get the template by the new interface:
+
+  >>> from z3c.template.interfaces import ILayoutTemplate
+  >>> template = zope.component.queryMultiAdapter((view, request), 
+  ...     interface=IMyTemplate,)
+
+  >>> print template(view)
+  <div>interface</div>
+
+
+Cleanup
+-------
+
+Now we need to clean up the custom module.
+
+  >>> del sys.modules['custom']


Property changes on: z3c.template/trunk/src/z3c/template/zcml.txt
___________________________________________________________________
Name: svn:eol-style
   + native



More information about the Checkins mailing list