z3c.template-1.4.1/0000775000177100020040000000000011716774041015164 5ustar menesismenesis00000000000000z3c.template-1.4.1/setup.py0000664000177100020040000000500411716774027016701 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2007 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. # ############################################################################## """Setup $Id: setup.py 124412 2012-02-15 18:22:34Z menesis $ """ import os from setuptools import setup, find_packages def read(*rnames): return open(os.path.join(os.path.dirname(__file__), *rnames)).read() setup ( name='z3c.template', version='1.4.1', author = "Roger Ineichen and the Zope Community", author_email = "zope-dev@zope.org", description = "A package implementing advanced Page Template patterns.", long_description=( read('README.txt') + '\n\n.. contents::\n\n'+ read('src', 'z3c', 'template', 'README.txt') + '\n' + read('src', 'z3c', 'template', 'zcml.txt') + '\n' + read('CHANGES.txt') ), license = "ZPL 2.1", keywords = "zope3 template layout zpt pagetemplate", classifiers = [ 'Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', 'Intended Audience :: Developers', 'License :: OSI Approved :: Zope Public License', 'Programming Language :: Python', 'Natural Language :: English', 'Operating System :: OS Independent', 'Topic :: Internet :: WWW/HTTP', 'Framework :: Zope3'], url = 'http://pypi.python.org/pypi/z3c.template', packages = find_packages('src'), package_dir = {'':'src'}, namespace_packages = ['z3c'], extras_require = dict( test = [ 'zope.app.testing', 'zope.app.pagetemplate', 'zope.testing', 'z3c.ptcompat>=1.0', ], chameleon = [ 'z3c.pt >= 2.1', 'z3c.ptcompat', ], ), install_requires = [ 'setuptools', 'zope.component', 'zope.configuration', 'zope.interface', 'zope.pagetemplate', 'zope.publisher', 'zope.schema', ], include_package_data = True, zip_safe = False, ) z3c.template-1.4.1/CHANGES.txt0000664000177100020040000000535411716774027017010 0ustar menesismenesis00000000000000======= CHANGES ======= 1.4.1 (2012-02-15) ------------------ - Remove hooks to use ViewPageTemplateFile from z3c.pt because this breaks when z3c.pt is available, but z3c.ptcompat is not included. As recommended by notes below. 1.4.0 (2011-10-29) ------------------ - Moved z3c.pt include to extras_require chameleon. This makes the package independent from chameleon and friends and allows to include this dependencies in your own project. - Upgrade to chameleon 2.0 template engine and use the newest z3c.pt and z3c.ptcompat packages adjusted to work with chameleon 2.0. See the notes from the z3c.ptcompat package: Update z3c.ptcompat implementation to use component-based template engine configuration, plugging directly into the Zope Toolkit framework. The z3c.ptcompat package no longer provides template classes, or ZCML directives; you should import directly from the ZTK codebase. Note that the ``PREFER_Z3C_PT`` environment option has been rendered obsolete; instead, this is now managed via component configuration. Also note that the chameleon CHAMELEON_CACHE environment value changed from True/False to a path. Skip this property if you don't like to use a cache. None or False defined in buildout environment section doesn't work. At least with chameleon <= 2.5.4 Attention: You need to include the configure.zcml file from z3c.ptcompat for enable the z3c.pt template engine. The configure.zcml will plugin the template engine. Also remove any custom built hooks which will import z3c.ptcompat in your tests or other places. 1.3.0 (2011-10-28) ------------------ - Update to z3c.ptcompat 1.0 (and as a result, to the z3c.pt 2.x series). - Using Python's ``doctest`` module instead of depreacted ``zope.testing.doctest``. 1.2.1 (2009-08-22) ------------------ * Corrected description of ``ITemplateDirective.name``. * Added `zcml.txt` to ``long_description`` to show up on pypi. * Removed zpkg helper files and zcml slugs. 1.2.0 (2009-02-26) ------------------ * Add support for context-specific templates. Now, templates can be registered and looked up using (view, request, context) triple. To do that, pass the ``context`` argument to the ZCML directives. The ``getPageTemplate`` and friends will now try to lookup context specific template first and then fall back to (view, request) lookup. * Allow use of ``z3c.pt`` using ``z3c.ptcompat`` compatibility layer. * Forward the template kwargs to the options of the macro * Changed package's mailing list address to zope-dev at zope.org instead of retired one. 1.1.0 (2007-10-08) ------------------ * Added an ``IContentTemplate`` interface which is used for ````. 1.0.0 (2007-??-??) ------------------ * Initial release. z3c.template-1.4.1/PKG-INFO0000664000177100020040000011076111716774041016267 0ustar menesismenesis00000000000000Metadata-Version: 1.1 Name: z3c.template Version: 1.4.1 Summary: A package implementing advanced Page Template patterns. Home-page: http://pypi.python.org/pypi/z3c.template Author: Roger Ineichen and the Zope Community Author-email: zope-dev@zope.org License: ZPL 2.1 Description: ------------ Z3C template ------------ This package allows you to register templates independently from view code. In Zope 3, when registering a `browser:page` both presentation and computation are registered together. Unfortunately the registration tangles presentation and computation so tightly that it is not possible to re-register a different template depending on context. (You can override the whole registration but this is not the main point of this package.) With z3c.template the registration is split up between the view and the template and allows to differentiate the template based on the skin layer and the view. In addition this package lays the foundation to differentiate between templates that provide specific presentation templates and generic layout templates. .. contents:: ============= Z3C Templates ============= 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 content from a view: >>> import os, tempfile >>> temp_dir = tempfile.mkdtemp() >>> contentTemplate = os.path.join(temp_dir, 'contentTemplate.pt') >>> open(contentTemplate, 'w').write('''
demo content
''') 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), interfaces.IContentTemplate) ... 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') >>> factory We register the factory on a view interface and a layer. >>> component.provideAdapter( ... factory, ... (zope.interface.Interface, IDefaultBrowserLayer), ... interfaces.IContentTemplate) >>> template = component.getMultiAdapter((view, request), ... interfaces.IPageTemplate) >>> template <...ViewPageTemplateFile...> Now that we have a registered layout template for the default layer we can call our view again. >>> print view.render()
demo content
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('''
My content
''') >>> factory = TemplateFactory(myTemplate, 'text/html') >>> component.provideAdapter( ... factory, ... (IMyView, IDefaultBrowserLayer), interfaces.IContentTemplate) >>> print view.render()
My content
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('''
view content
''') and a view: >>> from z3c.template 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), interfaces.IContentTemplate) ... 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()
view content
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('''
demo layout
''') >>> 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 <...ViewPageTemplateFile...> Now that we have a registered layout template for the default layer we can call our view again. >>> print view2()
demo layout
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('''
My layout
''') >>> factory = TemplateFactory(myLayout, 'text/html') >>> component.provideAdapter(factory, ... (ILayoutView, IDefaultBrowserLayer), ... interfaces.ILayoutTemplate) >>> print view2()
My layout
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('''
view layout
''') >>> 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()
view layout
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(''' ...
... Full layout ...
... ''') >>> 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__()
rendered content
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(''' ...
... here comes the value of attr ...
... ''') >>> 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(''' ... ... ...
... here comes the rendered content ...
... ... ... ''') >>> 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()
content updated
Macros ------ Use of macros. >>> macroTemplate = os.path.join(temp_dir, 'macroTemplate.pt') >>> open(macroTemplate, 'w').write(''' ... ...
macro1
...
... ...
macro2
...
the content of div 2
...
... ''') >>> factory = TemplateFactory(macroTemplate, 'text/html', 'macro1') >>> print factory(view, request)()
macro1
>>> m2factory = TemplateFactory(macroTemplate, 'text/html', 'macro2') >>> print m2factory(view, request)(div2="from the options")
macro2
from the options
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 getPageTemplate 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 getPageTemplate >>> class IUseOfViewTemplate(zope.interface.Interface): ... pass >>> class UseOfViewTemplate(object): ... zope.interface.implements(IUseOfViewTemplate) ... ... template = getPageTemplate() ... ... def __init__(self, context, request): ... self.context = context ... self.request = request By defining the "template" property as a "getPageTemplate" a lookup for a registered template is done when it is called. >>> simple = UseOfViewTemplate(root, request) >>> print simple.template()
demo content
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 note that the "macroTemplate" has been created earlier in this test. >>> factory = TemplateFactory(contentTemplate, 'text/html') >>> component.provideAdapter(factory, ... (IUseOfViewTemplate, IDefaultBrowserLayer), IPageTemplate) >>> print simple.template()
demo content
Context-specific templates -------------------------- The ``TemplateFactory`` can be also used for (view, request, context) lookup. It's useful when you want to override a template for specific content object or type. Let's define a sample content type and instantiate a view for it. >>> class IContent(zope.interface.Interface): ... pass >>> class Content(object): ... zope.interface.implements(IContent) >>> content = Content() >>> view = UseOfViewTemplate(content, request) Now, let's provide a (view, request, context) adapter using TemplateFactory. >>> contextTemplate = os.path.join(temp_dir, 'context.pt') >>> open(contextTemplate, 'w').write('
context-specific
') >>> factory = TemplateFactory(contextTemplate, 'text/html') >>> component.provideAdapter(factory, ... (IUseOfViewTemplate, IDefaultBrowserLayer, IContent), ... interfaces.IContentTemplate) First. Let's try to simply get it as a multi-adapter. >>> template = zope.component.getMultiAdapter((view, request, content), ... interfaces.IContentTemplate) >>> print template(view)
context-specific
The ``getPageTemplate`` and friends will try to lookup a context-specific template before doing more generic (view, request) lookup, so our view should already use our context-specific template: >>> print view.template()
context-specific
Use case ``template by interface`` ---------------------------------- Templates can also get registered on different interfaces then IPageTemplate or ILayoutTemplate. >>> from z3c.template.template import getViewTemplate >>> 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()
demo content
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 template 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()
demo content
Use case ``named layout template`` ---------------------------------- We can also register a new layout template by name and use it in a view: >>> from z3c.template.template import getLayoutTemplate >>> editLayout = os.path.join(temp_dir, 'editLayout.pt') >>> open(editLayout, 'w').write(''' ...
Edit layout
...
content
... ''') >>> factory = TemplateFactory(editLayout, 'text/html') >>> component.provideAdapter(factory, ... (zope.interface.Interface, IDefaultBrowserLayer), ... interfaces.ILayoutTemplate, name='edit') Now define a view using such a custom named template registration: >>> class MyEditView(BrowserPage): ... ... layout = getLayoutTemplate('edit') ... ... def render(self): ... return u'edit content' ... ... def __call__(self): ... if self.layout is None: ... layout = zope.component.getMultiAdapter((self, self.request), ... interfaces.ILayoutTemplate) ... return layout(self) ... return self.layout() >>> myEditView = MyEditView(root, request) >>> print myEditView()
Edit layout
edit content
Cleanup ------- >>> import shutil >>> shutil.rmtree(temp_dir) Pagelet ------- See z3c.pagelet for another template based layout generating implementation. ================== 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, 'content.pt') >>> open(file, 'w').write('''
content
''') 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 template within the ``z3c:template`` directive: >>> context = xmlconfig.string(""" ... ... ... ... """ % file, context=context) Let's get the template >>> import zope.component >>> from z3c.template.interfaces import IContentTemplate >>> template = zope.component.queryMultiAdapter( ... (view, request), ... interface=IContentTemplate) and check them: >>> from z3c.template.template import ViewPageTemplateFile >>> isinstance(template, ViewPageTemplateFile) True >>> print template(view)
content
Layout template --------------- Define a layout template >>> file = os.path.join(temp_dir, 'layout.pt') >>> open(file, 'w').write('''
layout
''') and register them as a layout template within the ``z3c:layout`` directive: >>> context = xmlconfig.string(""" ... ... ... ... """ % 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: >>> isinstance(template, ViewPageTemplateFile) True >>> print layout(view)
layout
Context-specific template ------------------------- Most of views have some object as their context and it's ofter very useful to be able register context-specific template. We can do that using the ``context`` argument of the ZCML directive. Let's define some content type: >>> class IContent(zope.interface.Interface): ... pass >>> class Content(object): ... zope.interface.implements(IContent) >>> sys.modules['custom'].IContent = IContent Now, we can register a template for this class. Let's create one and register: >>> file = os.path.join(temp_dir, 'context.pt') >>> open(file, 'w').write('''
i'm context-specific
''') >>> context = xmlconfig.string(""" ... ... ... ... """ % file, context=context) We can now lookup it using the (view, request, context) discriminator: >>> content = Content() >>> view = View(content, request) >>> template = zope.component.queryMultiAdapter((view, request, content), ... interface=IContentTemplate) >>> print template(view)
i'm context-specific
The same will work with layout registration directive: >>> file = os.path.join(temp_dir, 'context_layout.pt') >>> open(file, 'w').write('''
context-specific layout
''') >>> context = xmlconfig.string(""" ... ... ... ... """ % file, context=context) >>> layout = zope.component.queryMultiAdapter((view, request, content), ... interface=ILayoutTemplate) >>> print layout(view)
context-specific layout
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('''
edit
''') >>> context = xmlconfig.string(""" ... ... ... ... """ % editTemplate, context=context) And call it: >>> from z3c.template.interfaces import ILayoutTemplate >>> template = zope.component.queryMultiAdapter( ... (view, request), ... interface=IContentTemplate, name='edit') >>> print template(view)
edit
Custom template --------------- Or you can define own interfaces and register templates for them: >>> from zope.pagetemplate.interfaces import IPageTemplate >>> 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('''
interface
''') >>> context = xmlconfig.string(""" ... ... ... ... """ % 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)
interface
Cleanup ------- Now we need to clean up the custom module. >>> del sys.modules['custom'] ======= CHANGES ======= 1.4.1 (2012-02-15) ------------------ - Remove hooks to use ViewPageTemplateFile from z3c.pt because this breaks when z3c.pt is available, but z3c.ptcompat is not included. As recommended by notes below. 1.4.0 (2011-10-29) ------------------ - Moved z3c.pt include to extras_require chameleon. This makes the package independent from chameleon and friends and allows to include this dependencies in your own project. - Upgrade to chameleon 2.0 template engine and use the newest z3c.pt and z3c.ptcompat packages adjusted to work with chameleon 2.0. See the notes from the z3c.ptcompat package: Update z3c.ptcompat implementation to use component-based template engine configuration, plugging directly into the Zope Toolkit framework. The z3c.ptcompat package no longer provides template classes, or ZCML directives; you should import directly from the ZTK codebase. Note that the ``PREFER_Z3C_PT`` environment option has been rendered obsolete; instead, this is now managed via component configuration. Also note that the chameleon CHAMELEON_CACHE environment value changed from True/False to a path. Skip this property if you don't like to use a cache. None or False defined in buildout environment section doesn't work. At least with chameleon <= 2.5.4 Attention: You need to include the configure.zcml file from z3c.ptcompat for enable the z3c.pt template engine. The configure.zcml will plugin the template engine. Also remove any custom built hooks which will import z3c.ptcompat in your tests or other places. 1.3.0 (2011-10-28) ------------------ - Update to z3c.ptcompat 1.0 (and as a result, to the z3c.pt 2.x series). - Using Python's ``doctest`` module instead of depreacted ``zope.testing.doctest``. 1.2.1 (2009-08-22) ------------------ * Corrected description of ``ITemplateDirective.name``. * Added `zcml.txt` to ``long_description`` to show up on pypi. * Removed zpkg helper files and zcml slugs. 1.2.0 (2009-02-26) ------------------ * Add support for context-specific templates. Now, templates can be registered and looked up using (view, request, context) triple. To do that, pass the ``context`` argument to the ZCML directives. The ``getPageTemplate`` and friends will now try to lookup context specific template first and then fall back to (view, request) lookup. * Allow use of ``z3c.pt`` using ``z3c.ptcompat`` compatibility layer. * Forward the template kwargs to the options of the macro * Changed package's mailing list address to zope-dev at zope.org instead of retired one. 1.1.0 (2007-10-08) ------------------ * Added an ``IContentTemplate`` interface which is used for ````. 1.0.0 (2007-??-??) ------------------ * Initial release. Keywords: zope3 template layout zpt pagetemplate Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable 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 z3c.template-1.4.1/bootstrap.py0000664000177100020040000000337111716774027017563 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2007 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. # ############################################################################## """Bootstrap a buildout-based project Simply run this script in a directory containing a buildout.cfg. The script accepts buildout command-line options, so you can use the -c option to specify an alternate configuration file. $Id: bootstrap.py 113745 2010-06-22 06:57:34Z jinty $ """ import os, shutil, sys, tempfile, urllib2 tmpeggs = tempfile.mkdtemp() ez = {} exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py' ).read() in ez ez['use_setuptools'](to_dir=tmpeggs, download_delay=0) import pkg_resources cmd = 'from setuptools.command.easy_install import main; main()' if sys.platform == 'win32': cmd = '"%s"' % cmd # work around spawn lamosity on windows ws = pkg_resources.working_set assert os.spawnle( os.P_WAIT, sys.executable, sys.executable, '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout', dict(os.environ, PYTHONPATH= ws.find(pkg_resources.Requirement.parse('setuptools')).location ), ) == 0 ws.add_entry(tmpeggs) ws.require('zc.buildout') import zc.buildout.buildout zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap']) shutil.rmtree(tmpeggs) z3c.template-1.4.1/COPYRIGHT.txt0000664000177100020040000000004011716774027017273 0ustar menesismenesis00000000000000Zope Foundation and Contributorsz3c.template-1.4.1/src/0000775000177100020040000000000011716774041015753 5ustar menesismenesis00000000000000z3c.template-1.4.1/src/z3c.template.egg-info/0000775000177100020040000000000011716774041021756 5ustar menesismenesis00000000000000z3c.template-1.4.1/src/z3c.template.egg-info/PKG-INFO0000664000177100020040000011076111716774032023061 0ustar menesismenesis00000000000000Metadata-Version: 1.1 Name: z3c.template Version: 1.4.1 Summary: A package implementing advanced Page Template patterns. Home-page: http://pypi.python.org/pypi/z3c.template Author: Roger Ineichen and the Zope Community Author-email: zope-dev@zope.org License: ZPL 2.1 Description: ------------ Z3C template ------------ This package allows you to register templates independently from view code. In Zope 3, when registering a `browser:page` both presentation and computation are registered together. Unfortunately the registration tangles presentation and computation so tightly that it is not possible to re-register a different template depending on context. (You can override the whole registration but this is not the main point of this package.) With z3c.template the registration is split up between the view and the template and allows to differentiate the template based on the skin layer and the view. In addition this package lays the foundation to differentiate between templates that provide specific presentation templates and generic layout templates. .. contents:: ============= Z3C Templates ============= 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 content from a view: >>> import os, tempfile >>> temp_dir = tempfile.mkdtemp() >>> contentTemplate = os.path.join(temp_dir, 'contentTemplate.pt') >>> open(contentTemplate, 'w').write('''
demo content
''') 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), interfaces.IContentTemplate) ... 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') >>> factory We register the factory on a view interface and a layer. >>> component.provideAdapter( ... factory, ... (zope.interface.Interface, IDefaultBrowserLayer), ... interfaces.IContentTemplate) >>> template = component.getMultiAdapter((view, request), ... interfaces.IPageTemplate) >>> template <...ViewPageTemplateFile...> Now that we have a registered layout template for the default layer we can call our view again. >>> print view.render()
demo content
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('''
My content
''') >>> factory = TemplateFactory(myTemplate, 'text/html') >>> component.provideAdapter( ... factory, ... (IMyView, IDefaultBrowserLayer), interfaces.IContentTemplate) >>> print view.render()
My content
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('''
view content
''') and a view: >>> from z3c.template 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), interfaces.IContentTemplate) ... 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()
view content
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('''
demo layout
''') >>> 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 <...ViewPageTemplateFile...> Now that we have a registered layout template for the default layer we can call our view again. >>> print view2()
demo layout
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('''
My layout
''') >>> factory = TemplateFactory(myLayout, 'text/html') >>> component.provideAdapter(factory, ... (ILayoutView, IDefaultBrowserLayer), ... interfaces.ILayoutTemplate) >>> print view2()
My layout
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('''
view layout
''') >>> 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()
view layout
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(''' ...
... Full layout ...
... ''') >>> 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__()
rendered content
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(''' ...
... here comes the value of attr ...
... ''') >>> 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(''' ... ... ...
... here comes the rendered content ...
... ... ... ''') >>> 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()
content updated
Macros ------ Use of macros. >>> macroTemplate = os.path.join(temp_dir, 'macroTemplate.pt') >>> open(macroTemplate, 'w').write(''' ... ...
macro1
...
... ...
macro2
...
the content of div 2
...
... ''') >>> factory = TemplateFactory(macroTemplate, 'text/html', 'macro1') >>> print factory(view, request)()
macro1
>>> m2factory = TemplateFactory(macroTemplate, 'text/html', 'macro2') >>> print m2factory(view, request)(div2="from the options")
macro2
from the options
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 getPageTemplate 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 getPageTemplate >>> class IUseOfViewTemplate(zope.interface.Interface): ... pass >>> class UseOfViewTemplate(object): ... zope.interface.implements(IUseOfViewTemplate) ... ... template = getPageTemplate() ... ... def __init__(self, context, request): ... self.context = context ... self.request = request By defining the "template" property as a "getPageTemplate" a lookup for a registered template is done when it is called. >>> simple = UseOfViewTemplate(root, request) >>> print simple.template()
demo content
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 note that the "macroTemplate" has been created earlier in this test. >>> factory = TemplateFactory(contentTemplate, 'text/html') >>> component.provideAdapter(factory, ... (IUseOfViewTemplate, IDefaultBrowserLayer), IPageTemplate) >>> print simple.template()
demo content
Context-specific templates -------------------------- The ``TemplateFactory`` can be also used for (view, request, context) lookup. It's useful when you want to override a template for specific content object or type. Let's define a sample content type and instantiate a view for it. >>> class IContent(zope.interface.Interface): ... pass >>> class Content(object): ... zope.interface.implements(IContent) >>> content = Content() >>> view = UseOfViewTemplate(content, request) Now, let's provide a (view, request, context) adapter using TemplateFactory. >>> contextTemplate = os.path.join(temp_dir, 'context.pt') >>> open(contextTemplate, 'w').write('
context-specific
') >>> factory = TemplateFactory(contextTemplate, 'text/html') >>> component.provideAdapter(factory, ... (IUseOfViewTemplate, IDefaultBrowserLayer, IContent), ... interfaces.IContentTemplate) First. Let's try to simply get it as a multi-adapter. >>> template = zope.component.getMultiAdapter((view, request, content), ... interfaces.IContentTemplate) >>> print template(view)
context-specific
The ``getPageTemplate`` and friends will try to lookup a context-specific template before doing more generic (view, request) lookup, so our view should already use our context-specific template: >>> print view.template()
context-specific
Use case ``template by interface`` ---------------------------------- Templates can also get registered on different interfaces then IPageTemplate or ILayoutTemplate. >>> from z3c.template.template import getViewTemplate >>> 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()
demo content
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 template 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()
demo content
Use case ``named layout template`` ---------------------------------- We can also register a new layout template by name and use it in a view: >>> from z3c.template.template import getLayoutTemplate >>> editLayout = os.path.join(temp_dir, 'editLayout.pt') >>> open(editLayout, 'w').write(''' ...
Edit layout
...
content
... ''') >>> factory = TemplateFactory(editLayout, 'text/html') >>> component.provideAdapter(factory, ... (zope.interface.Interface, IDefaultBrowserLayer), ... interfaces.ILayoutTemplate, name='edit') Now define a view using such a custom named template registration: >>> class MyEditView(BrowserPage): ... ... layout = getLayoutTemplate('edit') ... ... def render(self): ... return u'edit content' ... ... def __call__(self): ... if self.layout is None: ... layout = zope.component.getMultiAdapter((self, self.request), ... interfaces.ILayoutTemplate) ... return layout(self) ... return self.layout() >>> myEditView = MyEditView(root, request) >>> print myEditView()
Edit layout
edit content
Cleanup ------- >>> import shutil >>> shutil.rmtree(temp_dir) Pagelet ------- See z3c.pagelet for another template based layout generating implementation. ================== 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, 'content.pt') >>> open(file, 'w').write('''
content
''') 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 template within the ``z3c:template`` directive: >>> context = xmlconfig.string(""" ... ... ... ... """ % file, context=context) Let's get the template >>> import zope.component >>> from z3c.template.interfaces import IContentTemplate >>> template = zope.component.queryMultiAdapter( ... (view, request), ... interface=IContentTemplate) and check them: >>> from z3c.template.template import ViewPageTemplateFile >>> isinstance(template, ViewPageTemplateFile) True >>> print template(view)
content
Layout template --------------- Define a layout template >>> file = os.path.join(temp_dir, 'layout.pt') >>> open(file, 'w').write('''
layout
''') and register them as a layout template within the ``z3c:layout`` directive: >>> context = xmlconfig.string(""" ... ... ... ... """ % 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: >>> isinstance(template, ViewPageTemplateFile) True >>> print layout(view)
layout
Context-specific template ------------------------- Most of views have some object as their context and it's ofter very useful to be able register context-specific template. We can do that using the ``context`` argument of the ZCML directive. Let's define some content type: >>> class IContent(zope.interface.Interface): ... pass >>> class Content(object): ... zope.interface.implements(IContent) >>> sys.modules['custom'].IContent = IContent Now, we can register a template for this class. Let's create one and register: >>> file = os.path.join(temp_dir, 'context.pt') >>> open(file, 'w').write('''
i'm context-specific
''') >>> context = xmlconfig.string(""" ... ... ... ... """ % file, context=context) We can now lookup it using the (view, request, context) discriminator: >>> content = Content() >>> view = View(content, request) >>> template = zope.component.queryMultiAdapter((view, request, content), ... interface=IContentTemplate) >>> print template(view)
i'm context-specific
The same will work with layout registration directive: >>> file = os.path.join(temp_dir, 'context_layout.pt') >>> open(file, 'w').write('''
context-specific layout
''') >>> context = xmlconfig.string(""" ... ... ... ... """ % file, context=context) >>> layout = zope.component.queryMultiAdapter((view, request, content), ... interface=ILayoutTemplate) >>> print layout(view)
context-specific layout
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('''
edit
''') >>> context = xmlconfig.string(""" ... ... ... ... """ % editTemplate, context=context) And call it: >>> from z3c.template.interfaces import ILayoutTemplate >>> template = zope.component.queryMultiAdapter( ... (view, request), ... interface=IContentTemplate, name='edit') >>> print template(view)
edit
Custom template --------------- Or you can define own interfaces and register templates for them: >>> from zope.pagetemplate.interfaces import IPageTemplate >>> 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('''
interface
''') >>> context = xmlconfig.string(""" ... ... ... ... """ % 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)
interface
Cleanup ------- Now we need to clean up the custom module. >>> del sys.modules['custom'] ======= CHANGES ======= 1.4.1 (2012-02-15) ------------------ - Remove hooks to use ViewPageTemplateFile from z3c.pt because this breaks when z3c.pt is available, but z3c.ptcompat is not included. As recommended by notes below. 1.4.0 (2011-10-29) ------------------ - Moved z3c.pt include to extras_require chameleon. This makes the package independent from chameleon and friends and allows to include this dependencies in your own project. - Upgrade to chameleon 2.0 template engine and use the newest z3c.pt and z3c.ptcompat packages adjusted to work with chameleon 2.0. See the notes from the z3c.ptcompat package: Update z3c.ptcompat implementation to use component-based template engine configuration, plugging directly into the Zope Toolkit framework. The z3c.ptcompat package no longer provides template classes, or ZCML directives; you should import directly from the ZTK codebase. Note that the ``PREFER_Z3C_PT`` environment option has been rendered obsolete; instead, this is now managed via component configuration. Also note that the chameleon CHAMELEON_CACHE environment value changed from True/False to a path. Skip this property if you don't like to use a cache. None or False defined in buildout environment section doesn't work. At least with chameleon <= 2.5.4 Attention: You need to include the configure.zcml file from z3c.ptcompat for enable the z3c.pt template engine. The configure.zcml will plugin the template engine. Also remove any custom built hooks which will import z3c.ptcompat in your tests or other places. 1.3.0 (2011-10-28) ------------------ - Update to z3c.ptcompat 1.0 (and as a result, to the z3c.pt 2.x series). - Using Python's ``doctest`` module instead of depreacted ``zope.testing.doctest``. 1.2.1 (2009-08-22) ------------------ * Corrected description of ``ITemplateDirective.name``. * Added `zcml.txt` to ``long_description`` to show up on pypi. * Removed zpkg helper files and zcml slugs. 1.2.0 (2009-02-26) ------------------ * Add support for context-specific templates. Now, templates can be registered and looked up using (view, request, context) triple. To do that, pass the ``context`` argument to the ZCML directives. The ``getPageTemplate`` and friends will now try to lookup context specific template first and then fall back to (view, request) lookup. * Allow use of ``z3c.pt`` using ``z3c.ptcompat`` compatibility layer. * Forward the template kwargs to the options of the macro * Changed package's mailing list address to zope-dev at zope.org instead of retired one. 1.1.0 (2007-10-08) ------------------ * Added an ``IContentTemplate`` interface which is used for ````. 1.0.0 (2007-??-??) ------------------ * Initial release. Keywords: zope3 template layout zpt pagetemplate Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable 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 z3c.template-1.4.1/src/z3c.template.egg-info/dependency_links.txt0000664000177100020040000000000111716774032026024 0ustar menesismenesis00000000000000 z3c.template-1.4.1/src/z3c.template.egg-info/namespace_packages.txt0000664000177100020040000000000411716774032026303 0ustar menesismenesis00000000000000z3c z3c.template-1.4.1/src/z3c.template.egg-info/not-zip-safe0000664000177100020040000000000111716774027024210 0ustar menesismenesis00000000000000 z3c.template-1.4.1/src/z3c.template.egg-info/top_level.txt0000664000177100020040000000000411716774032024502 0ustar menesismenesis00000000000000z3c z3c.template-1.4.1/src/z3c.template.egg-info/requires.txt0000664000177100020040000000033611716774032024360 0ustar menesismenesis00000000000000setuptools zope.component zope.configuration zope.interface zope.pagetemplate zope.publisher zope.schema [test] zope.app.testing zope.app.pagetemplate zope.testing z3c.ptcompat>=1.0 [chameleon] z3c.pt >= 2.1 z3c.ptcompatz3c.template-1.4.1/src/z3c.template.egg-info/SOURCES.txt0000664000177100020040000000114311716774032023641 0ustar menesismenesis00000000000000CHANGES.txt COPYRIGHT.txt LICENSE.txt README.txt bootstrap.py buildout.cfg setup.py src/z3c/__init__.py src/z3c.template.egg-info/PKG-INFO src/z3c.template.egg-info/SOURCES.txt src/z3c.template.egg-info/dependency_links.txt src/z3c.template.egg-info/namespace_packages.txt src/z3c.template.egg-info/not-zip-safe src/z3c.template.egg-info/requires.txt src/z3c.template.egg-info/top_level.txt src/z3c/template/README.txt src/z3c/template/__init__.py src/z3c/template/interfaces.py src/z3c/template/meta.zcml src/z3c/template/template.py src/z3c/template/tests.py src/z3c/template/zcml.py src/z3c/template/zcml.txtz3c.template-1.4.1/src/z3c/0000775000177100020040000000000011716774041016452 5ustar menesismenesis00000000000000z3c.template-1.4.1/src/z3c/__init__.py0000664000177100020040000000025511716774027020571 0ustar menesismenesis00000000000000try: # Declare this a namespace package if pkg_resources is available. import pkg_resources pkg_resources.declare_namespace('z3c') except ImportError: pass z3c.template-1.4.1/src/z3c/template/0000775000177100020040000000000011716774041020265 5ustar menesismenesis00000000000000z3c.template-1.4.1/src/z3c/template/meta.zcml0000664000177100020040000000076011716774027022111 0ustar menesismenesis00000000000000 z3c.template-1.4.1/src/z3c/template/template.py0000664000177100020040000000773411716774027022471 0ustar menesismenesis00000000000000############################################################################## # # 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: template.py 124401 2012-02-15 17:50:33Z menesis $ """ from zope import component from zope.pagetemplate.interfaces import IPageTemplate from zope.pagetemplate.pagetemplate import PageTemplate from zope.browserpage.viewpagetemplatefile import ViewPageTemplateFile from z3c.template import interfaces class Macro(object): # XXX: We can't use Zope's `TALInterpreter` class directly # because it (obviously) only supports the Zope page template # implementation. As a workaround or trick we use a wrapper # template. wrapper = PageTemplate() wrapper.write( '' ) def __init__(self, template, name, view, request, contentType): self.macro = template.macros[name] self.contentType = contentType self.view = view self.request = request def __call__(self, **kwargs): kwargs['macro'] = self.macro kwargs.setdefault('view', self.view) kwargs.setdefault('request', self.request) result = self.wrapper(**kwargs) if not self.request.response.getHeader("Content-Type"): self.request.response.setHeader( "Content-Type", self.contentType) return result class TemplateFactory(object): """Template factory.""" template = None def __init__(self, filename, contentType, macro=None): self.contentType = contentType self.template = ViewPageTemplateFile( filename, content_type=contentType) self.macro = macro def __call__(self, view, request, context=None): 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 "" % 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 = component.queryMultiAdapter( (instance, instance.request, instance.context), self.provides, name=self.name) if template is None: template = 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 class GetPageTemplate(ViewTemplate): def __init__(self, name=u''): self.provides = interfaces.IContentTemplate self.name = name getPageTemplate = GetPageTemplate class GetLayoutTemplate(ViewTemplate): def __init__(self, name=u''): self.provides = interfaces.ILayoutTemplate self.name = name getLayoutTemplate = GetLayoutTemplate z3c.template-1.4.1/src/z3c/template/tests.py0000664000177100020040000000353511716774027022013 0ustar menesismenesis00000000000000############################################################################## # # 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: tests.py 124401 2012-02-15 17:50:33Z menesis $ """ __docformat__ = "reStructuredText" from zope.app.testing import setup from zope.configuration import xmlconfig import doctest import itertools import unittest import z3c.template.template def setUp(test): root = setup.placefulSetUp(site=True) test.globs['root'] = root def tearDown(test): setup.placefulTearDown() def setUpZPT(suite): setUp(suite) def setUpZ3CPT(suite): setUp(suite) import z3c.pt import z3c.ptcompat xmlconfig.XMLConfig('configure.zcml', z3c.pt)() xmlconfig.XMLConfig('configure.zcml', z3c.ptcompat)() # We have to cook this template explicitly, because it's a module # global. from z3c.template.template import Macro Macro.wrapper._cook() def test_suite(): tests = (( doctest.DocFileSuite('README.txt', setUp=setUp, tearDown=tearDown, optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS, ), doctest.DocFileSuite('zcml.txt', setUp=setUp, tearDown=tearDown, optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS, ), ) for setUp in (setUpZPT, setUpZ3CPT,)) return unittest.TestSuite(itertools.chain(*tests)) z3c.template-1.4.1/src/z3c/template/zcml.txt0000664000177100020040000001463211716774027022005 0ustar menesismenesis00000000000000================== 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, 'content.pt') >>> open(file, 'w').write('''
content
''') 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 template within the ``z3c:template`` directive: >>> context = xmlconfig.string(""" ... ... ... ... """ % file, context=context) Let's get the template >>> import zope.component >>> from z3c.template.interfaces import IContentTemplate >>> template = zope.component.queryMultiAdapter( ... (view, request), ... interface=IContentTemplate) and check them: >>> from z3c.template.template import ViewPageTemplateFile >>> isinstance(template, ViewPageTemplateFile) True >>> print template(view)
content
Layout template --------------- Define a layout template >>> file = os.path.join(temp_dir, 'layout.pt') >>> open(file, 'w').write('''
layout
''') and register them as a layout template within the ``z3c:layout`` directive: >>> context = xmlconfig.string(""" ... ... ... ... """ % 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: >>> isinstance(template, ViewPageTemplateFile) True >>> print layout(view)
layout
Context-specific template ------------------------- Most of views have some object as their context and it's ofter very useful to be able register context-specific template. We can do that using the ``context`` argument of the ZCML directive. Let's define some content type: >>> class IContent(zope.interface.Interface): ... pass >>> class Content(object): ... zope.interface.implements(IContent) >>> sys.modules['custom'].IContent = IContent Now, we can register a template for this class. Let's create one and register: >>> file = os.path.join(temp_dir, 'context.pt') >>> open(file, 'w').write('''
i'm context-specific
''') >>> context = xmlconfig.string(""" ... ... ... ... """ % file, context=context) We can now lookup it using the (view, request, context) discriminator: >>> content = Content() >>> view = View(content, request) >>> template = zope.component.queryMultiAdapter((view, request, content), ... interface=IContentTemplate) >>> print template(view)
i'm context-specific
The same will work with layout registration directive: >>> file = os.path.join(temp_dir, 'context_layout.pt') >>> open(file, 'w').write('''
context-specific layout
''') >>> context = xmlconfig.string(""" ... ... ... ... """ % file, context=context) >>> layout = zope.component.queryMultiAdapter((view, request, content), ... interface=ILayoutTemplate) >>> print layout(view)
context-specific layout
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('''
edit
''') >>> context = xmlconfig.string(""" ... ... ... ... """ % editTemplate, context=context) And call it: >>> from z3c.template.interfaces import ILayoutTemplate >>> template = zope.component.queryMultiAdapter( ... (view, request), ... interface=IContentTemplate, name='edit') >>> print template(view)
edit
Custom template --------------- Or you can define own interfaces and register templates for them: >>> from zope.pagetemplate.interfaces import IPageTemplate >>> 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('''
interface
''') >>> context = xmlconfig.string(""" ... ... ... ... """ % 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)
interface
Cleanup ------- Now we need to clean up the custom module. >>> del sys.modules['custom'] z3c.template-1.4.1/src/z3c/template/README.txt0000664000177100020040000004500111716774027021767 0ustar menesismenesis00000000000000============= Z3C Templates ============= 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 content from a view: >>> import os, tempfile >>> temp_dir = tempfile.mkdtemp() >>> contentTemplate = os.path.join(temp_dir, 'contentTemplate.pt') >>> open(contentTemplate, 'w').write('''
demo content
''') 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), interfaces.IContentTemplate) ... 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') >>> factory We register the factory on a view interface and a layer. >>> component.provideAdapter( ... factory, ... (zope.interface.Interface, IDefaultBrowserLayer), ... interfaces.IContentTemplate) >>> template = component.getMultiAdapter((view, request), ... interfaces.IPageTemplate) >>> template <...ViewPageTemplateFile...> Now that we have a registered layout template for the default layer we can call our view again. >>> print view.render()
demo content
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('''
My content
''') >>> factory = TemplateFactory(myTemplate, 'text/html') >>> component.provideAdapter( ... factory, ... (IMyView, IDefaultBrowserLayer), interfaces.IContentTemplate) >>> print view.render()
My content
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('''
view content
''') and a view: >>> from z3c.template 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), interfaces.IContentTemplate) ... 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()
view content
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('''
demo layout
''') >>> 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 <...ViewPageTemplateFile...> Now that we have a registered layout template for the default layer we can call our view again. >>> print view2()
demo layout
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('''
My layout
''') >>> factory = TemplateFactory(myLayout, 'text/html') >>> component.provideAdapter(factory, ... (ILayoutView, IDefaultBrowserLayer), ... interfaces.ILayoutTemplate) >>> print view2()
My layout
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('''
view layout
''') >>> 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()
view layout
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(''' ...
... Full layout ...
... ''') >>> 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__()
rendered content
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(''' ...
... here comes the value of attr ...
... ''') >>> 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(''' ... ... ...
... here comes the rendered content ...
... ... ... ''') >>> 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()
content updated
Macros ------ Use of macros. >>> macroTemplate = os.path.join(temp_dir, 'macroTemplate.pt') >>> open(macroTemplate, 'w').write(''' ... ...
macro1
...
... ...
macro2
...
the content of div 2
...
... ''') >>> factory = TemplateFactory(macroTemplate, 'text/html', 'macro1') >>> print factory(view, request)()
macro1
>>> m2factory = TemplateFactory(macroTemplate, 'text/html', 'macro2') >>> print m2factory(view, request)(div2="from the options")
macro2
from the options
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 getPageTemplate 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 getPageTemplate >>> class IUseOfViewTemplate(zope.interface.Interface): ... pass >>> class UseOfViewTemplate(object): ... zope.interface.implements(IUseOfViewTemplate) ... ... template = getPageTemplate() ... ... def __init__(self, context, request): ... self.context = context ... self.request = request By defining the "template" property as a "getPageTemplate" a lookup for a registered template is done when it is called. >>> simple = UseOfViewTemplate(root, request) >>> print simple.template()
demo content
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 note that the "macroTemplate" has been created earlier in this test. >>> factory = TemplateFactory(contentTemplate, 'text/html') >>> component.provideAdapter(factory, ... (IUseOfViewTemplate, IDefaultBrowserLayer), IPageTemplate) >>> print simple.template()
demo content
Context-specific templates -------------------------- The ``TemplateFactory`` can be also used for (view, request, context) lookup. It's useful when you want to override a template for specific content object or type. Let's define a sample content type and instantiate a view for it. >>> class IContent(zope.interface.Interface): ... pass >>> class Content(object): ... zope.interface.implements(IContent) >>> content = Content() >>> view = UseOfViewTemplate(content, request) Now, let's provide a (view, request, context) adapter using TemplateFactory. >>> contextTemplate = os.path.join(temp_dir, 'context.pt') >>> open(contextTemplate, 'w').write('
context-specific
') >>> factory = TemplateFactory(contextTemplate, 'text/html') >>> component.provideAdapter(factory, ... (IUseOfViewTemplate, IDefaultBrowserLayer, IContent), ... interfaces.IContentTemplate) First. Let's try to simply get it as a multi-adapter. >>> template = zope.component.getMultiAdapter((view, request, content), ... interfaces.IContentTemplate) >>> print template(view)
context-specific
The ``getPageTemplate`` and friends will try to lookup a context-specific template before doing more generic (view, request) lookup, so our view should already use our context-specific template: >>> print view.template()
context-specific
Use case ``template by interface`` ---------------------------------- Templates can also get registered on different interfaces then IPageTemplate or ILayoutTemplate. >>> from z3c.template.template import getViewTemplate >>> 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()
demo content
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 template 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()
demo content
Use case ``named layout template`` ---------------------------------- We can also register a new layout template by name and use it in a view: >>> from z3c.template.template import getLayoutTemplate >>> editLayout = os.path.join(temp_dir, 'editLayout.pt') >>> open(editLayout, 'w').write(''' ...
Edit layout
...
content
... ''') >>> factory = TemplateFactory(editLayout, 'text/html') >>> component.provideAdapter(factory, ... (zope.interface.Interface, IDefaultBrowserLayer), ... interfaces.ILayoutTemplate, name='edit') Now define a view using such a custom named template registration: >>> class MyEditView(BrowserPage): ... ... layout = getLayoutTemplate('edit') ... ... def render(self): ... return u'edit content' ... ... def __call__(self): ... if self.layout is None: ... layout = zope.component.getMultiAdapter((self, self.request), ... interfaces.ILayoutTemplate) ... return layout(self) ... return self.layout() >>> myEditView = MyEditView(root, request) >>> print myEditView()
Edit layout
edit content
Cleanup ------- >>> import shutil >>> shutil.rmtree(temp_dir) Pagelet ------- See z3c.pagelet for another template based layout generating implementation. z3c.template-1.4.1/src/z3c/template/__init__.py0000664000177100020040000000134511716774027022405 0ustar menesismenesis00000000000000############################################################################## # # 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: __init__.py 123094 2011-10-14 14:53:12Z malthe $ """ from template import ViewPageTemplateFile z3c.template-1.4.1/src/z3c/template/zcml.py0000664000177100020040000001165311716774027021616 0ustar menesismenesis00000000000000############################################################################## # # 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: zcml.py 98086 2009-03-14 09:56:58Z icemac $ """ __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.publisher.interfaces.browser import IDefaultBrowserLayer import z3c.template.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 template.", description=u"The name is used to look up the template.", 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 one template. The template designer can now create a whole site, the ViewTemplate can then extract the macros for single viewlets or views. If no macro is given the whole 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, ) context = zope.configuration.fields.GlobalObject( title = u'Context', description = u'The context for which the template should be available', required = False, ) provides = zope.configuration.fields.GlobalInterface( title=u"Interface the template provides", description=u"This attribute specifies the interface the template" " instance will provide.", default=z3c.template.interfaces.IContentTemplate, 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.""" provides = zope.configuration.fields.GlobalInterface( title=u"Interface the template provides", description=u"This attribute specifies the interface the template" " instance will provide.", default=z3c.template.interfaces.ILayoutTemplate, required=False, ) def templateDirective( _context, template, name=u'', for_=zope.interface.Interface, layer=IDefaultBrowserLayer, provides=z3c.template.interfaces.IContentTemplate, contentType='text/html', macro=None, context=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) if context is not None: for_ = (for_, layer, context) else: for_ = (for_, layer) # register the template if name: zope.component.zcml.adapter(_context, (factory,), provides, for_, name=name) else: zope.component.zcml.adapter(_context, (factory,), provides, for_) def layoutTemplateDirective( _context, template, name=u'', for_=zope.interface.Interface, layer=IDefaultBrowserLayer, provides=z3c.template.interfaces.ILayoutTemplate, contentType='text/html', macro=None, context=None): templateDirective(_context, template, name, for_, layer, provides, contentType, macro, context) z3c.template-1.4.1/src/z3c/template/interfaces.py0000664000177100020040000000164511716774027022774 0ustar menesismenesis00000000000000############################################################################## # # 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: interfaces.py 80185 2007-09-27 08:14:53Z zagy $ """ from zope.pagetemplate.interfaces import IPageTemplate class ILayoutTemplate(IPageTemplate): """A template used for render the layout.""" class IContentTemplate(IPageTemplate): """A template used for render the content.""" z3c.template-1.4.1/buildout.cfg0000664000177100020040000000061211716774027017477 0ustar menesismenesis00000000000000[buildout] develop = . parts = test coverage-test coverage-report [test] recipe = zc.recipe.testrunner eggs = z3c.template [test] [coverage-test] recipe = zc.recipe.testrunner eggs = z3c.template [test] defaults = ['--coverage', '../../coverage'] [coverage-report] recipe = zc.recipe.egg eggs = z3c.coverage scripts = coveragereport arguments = ('parts/coverage', 'parts/coverage/report') z3c.template-1.4.1/README.txt0000664000177100020040000000142511716774027016670 0ustar menesismenesis00000000000000------------ Z3C template ------------ This package allows you to register templates independently from view code. In Zope 3, when registering a `browser:page` both presentation and computation are registered together. Unfortunately the registration tangles presentation and computation so tightly that it is not possible to re-register a different template depending on context. (You can override the whole registration but this is not the main point of this package.) With z3c.template the registration is split up between the view and the template and allows to differentiate the template based on the skin layer and the view. In addition this package lays the foundation to differentiate between templates that provide specific presentation templates and generic layout templates. z3c.template-1.4.1/setup.cfg0000664000177100020040000000007311716774041017005 0ustar menesismenesis00000000000000[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 z3c.template-1.4.1/LICENSE.txt0000664000177100020040000000402611716774027017015 0ustar menesismenesis00000000000000Zope Public License (ZPL) Version 2.1 A copyright notice accompanies this license document that identifies the copyright holders. This license has been certified as open source. It has also been designated as GPL compatible by the Free Software Foundation (FSF). Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions in source code must retain the accompanying copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the accompanying copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Names of the copyright holders must not be used to endorse or promote products derived from this software without prior written permission from the copyright holders. 4. The right to distribute this software or to use it for any purpose does not give you the right to use Servicemarks (sm) or Trademarks (tm) of the copyright holders. Use of them is covered by separate agreement with the copyright holders. 5. If any files are modified, you must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. Disclaimer THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.