[Checkins] SVN: z3c.template/branches/nadako-contexttemplate/ Make a branch for support context-specific templates.

Dan Korostelev nadako at gmail.com
Wed Feb 25 19:05:00 EST 2009


Log message for revision 97279:
  Make a branch for support context-specific templates.
  One test in the README.txt mystically fails and I currently don't have any idea why.
  Also, I would be glad if someone reviews this addition.

Changed:
  A   z3c.template/branches/nadako-contexttemplate/
  U   z3c.template/branches/nadako-contexttemplate/CHANGES.txt
  U   z3c.template/branches/nadako-contexttemplate/src/z3c/template/README.txt
  U   z3c.template/branches/nadako-contexttemplate/src/z3c/template/template.py
  U   z3c.template/branches/nadako-contexttemplate/src/z3c/template/zcml.py
  U   z3c.template/branches/nadako-contexttemplate/src/z3c/template/zcml.txt

-=-
Modified: z3c.template/branches/nadako-contexttemplate/CHANGES.txt
===================================================================
--- z3c.template/trunk/CHANGES.txt	2009-02-25 23:56:48 UTC (rev 97278)
+++ z3c.template/branches/nadako-contexttemplate/CHANGES.txt	2009-02-26 00:04:59 UTC (rev 97279)
@@ -5,6 +5,12 @@
 1.2.0 (unreleased)
 ------------------
 
+* 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

Modified: z3c.template/branches/nadako-contexttemplate/src/z3c/template/README.txt
===================================================================
--- z3c.template/trunk/src/z3c/template/README.txt	2009-02-25 23:56:48 UTC (rev 97278)
+++ z3c.template/branches/nadako-contexttemplate/src/z3c/template/README.txt	2009-02-26 00:04:59 UTC (rev 97279)
@@ -412,6 +412,47 @@
   <div>demo content</div>
 
 
+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('<div>context-specific</div>')
+  >>> factory = TemplateFactory(contextTemplate, 'text/html')
+
+  >>> component.provideAdapter(factory,
+  ...     (IUseOfViewTemplate, IDefaultBrowserLayer, IContent), IPageTemplate)
+
+First. Let's try to simply get it as a multi-adapter.
+
+  >>> template = zope.component.getMultiAdapter((view, request, content),
+  ...                 interfaces.IPageTemplate)
+  >>> print template(view)
+  <div>context-specific</div>
+
+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()
+  <div>context-specific</div>
+
+
 Use case ``template by interface``
 ----------------------------------
 

Modified: z3c.template/branches/nadako-contexttemplate/src/z3c/template/template.py
===================================================================
--- z3c.template/trunk/src/z3c/template/template.py	2009-02-25 23:56:48 UTC (rev 97278)
+++ z3c.template/branches/nadako-contexttemplate/src/z3c/template/template.py	2009-02-26 00:04:59 UTC (rev 97279)
@@ -45,7 +45,7 @@
         self.template = ptcompat.ViewPageTemplateFile(filename,
             content_type=contentType)
 
-    def __call__(self, view, request):
+    def __call__(self, view, request, context=None):
         if self.macro is None:
             return self.template
         return Macro(
@@ -76,8 +76,13 @@
         self.name = name
 
     def __call__(self, instance, *args, **keywords):
-        template = component.getMultiAdapter(
-                (instance, instance.request), self.provides, name=self.name)
+        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):

Modified: z3c.template/branches/nadako-contexttemplate/src/z3c/template/zcml.py
===================================================================
--- z3c.template/trunk/src/z3c/template/zcml.py	2009-02-25 23:56:48 UTC (rev 97278)
+++ z3c.template/branches/nadako-contexttemplate/src/z3c/template/zcml.py	2009-02-26 00:04:59 UTC (rev 97279)
@@ -74,6 +74,12 @@
         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"
@@ -106,7 +112,7 @@
     _context, template, name=u'',
     for_=zope.interface.Interface, layer=IDefaultBrowserLayer,
     provides=z3c.template.interfaces.IContentTemplate,
-    contentType='text/html', macro=None):
+    contentType='text/html', macro=None, context=None):
 
     # Make sure that the template exists
     template = os.path.abspath(str(_context.path(template)))
@@ -116,20 +122,25 @@
     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_, layer), name=name)
+                                    for_, name=name)
     else:
         zope.component.zcml.adapter(_context, (factory,), provides,
-                                    (for_, layer))
+                                    for_)
 
 
 def layoutTemplateDirective(
     _context, template, name=u'',
     for_=zope.interface.Interface, layer=IDefaultBrowserLayer,
     provides=z3c.template.interfaces.ILayoutTemplate,
-    contentType='text/html', macro=None):
+    contentType='text/html', macro=None, context=None):
 
     templateDirective(_context, template, name, for_, layer, provides,
-                      contentType, macro)
+                      contentType, macro, context)

Modified: z3c.template/branches/nadako-contexttemplate/src/z3c/template/zcml.txt
===================================================================
--- z3c.template/trunk/src/z3c/template/zcml.txt	2009-02-25 23:56:48 UTC (rev 97278)
+++ z3c.template/branches/nadako-contexttemplate/src/z3c/template/zcml.txt	2009-02-26 00:04:59 UTC (rev 97279)
@@ -109,6 +109,72 @@
   <div>layout</div>
 
 
+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('''<div>i'm context-specific</div>''')
+
+  >>> context = xmlconfig.string("""
+  ... <configure
+  ...     xmlns:z3c="http://namespaces.zope.org/z3c">
+  ...   <z3c:template
+  ...       template="%s"
+  ...       for="custom.IView"
+  ...       context="custom.IContent"
+  ...       />
+  ... </configure>
+  ... """ % 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)
+  <div>i'm context-specific</div>
+
+The same will work with layout registration directive:
+
+  >>> file = os.path.join(temp_dir, 'context_layout.pt')
+  >>> open(file, 'w').write('''<div>context-specific layout</div>''')
+  >>> context = xmlconfig.string("""
+  ... <configure
+  ...     xmlns:z3c="http://namespaces.zope.org/z3c">
+  ...   <z3c:layout
+  ...       template="%s"
+  ...       for="custom.IView"
+  ...       context="custom.IContent"
+  ...       />
+  ... </configure>
+  ... """ % file, context=context)
+
+  >>> layout = zope.component.queryMultiAdapter((view, request, content), 
+  ...     interface=ILayoutTemplate)
+
+  >>> print layout(view)
+  <div>context-specific layout</div>
+
+
 Named template
 --------------
 



More information about the Checkins mailing list