[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