[Checkins] SVN: five.customerize/branches/plone-3.0-branch-with-viewlet-support/src/five/customerize/ first, still unfinished attempt on viewlet support for five.customerize

Andreas Zeidler az at zitc.de
Mon May 7 07:31:36 EDT 2007


Log message for revision 75610:
  first, still unfinished attempt on viewlet support for five.customerize
  

Changed:
  A   five.customerize/branches/plone-3.0-branch-with-viewlet-support/src/five/customerize/utils.py
  U   five.customerize/branches/plone-3.0-branch-with-viewlet-support/src/five/customerize/zpt.py

-=-
Added: five.customerize/branches/plone-3.0-branch-with-viewlet-support/src/five/customerize/utils.py
===================================================================
--- five.customerize/branches/plone-3.0-branch-with-viewlet-support/src/five/customerize/utils.py	2007-05-07 11:29:26 UTC (rev 75609)
+++ five.customerize/branches/plone-3.0-branch-with-viewlet-support/src/five/customerize/utils.py	2007-05-07 11:31:35 UTC (rev 75610)
@@ -0,0 +1,27 @@
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile as Z2PTF
+from zope.pagetemplate.pagetemplatefile import PageTemplateFile as Z3PTF
+from zope.app.pagetemplate.viewpagetemplatefile import BoundPageTemplate
+
+
+def isTemplate(obj):
+    """ check if the given object is a or is derived from a template class """
+    # TODO: we should really check via interfaces, i.e. `providedBy` here,
+    #       but the only class using interfaces atm is Z3PTF :(
+    return isinstance(obj, Z2PTF) or isinstance(obj, Z3PTF) or \
+        isinstance(obj, BoundPageTemplate)
+
+
+def findViewletTemplate(viewlet):
+    """ try to find the attribute holding the template within a viewlet """
+    for attr in 'index', 'template', '__call__', 'render':
+        item = getattr(viewlet, attr, None)
+        if isTemplate(item):
+            return attr, item
+    attrs = [ attr for attr in dir(viewlet) if isTemplate(getattr(viewlet, attr)) ]
+    if len(attrs) == 1:
+        return attrs[0], getattr(viewlet, attrs[0])
+    else:
+        # TODO: we should pass on the message if we find multiple templates
+        pass
+    return None, None
+

Modified: five.customerize/branches/plone-3.0-branch-with-viewlet-support/src/five/customerize/zpt.py
===================================================================
--- five.customerize/branches/plone-3.0-branch-with-viewlet-support/src/five/customerize/zpt.py	2007-05-07 11:29:26 UTC (rev 75609)
+++ five.customerize/branches/plone-3.0-branch-with-viewlet-support/src/five/customerize/zpt.py	2007-05-07 11:31:35 UTC (rev 75610)
@@ -4,9 +4,11 @@
 
 from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
 from zope.app.container.interfaces import IObjectRemovedEvent
+from zope.viewlet.interfaces import IViewlet, IViewletManager
 from zope.interface import implements
 
 from five.customerize.interfaces import ITTWViewTemplate
+from five.customerize.utils import findViewletTemplate
 
 
 class TTWViewTemplate(ZopePageTemplate):
@@ -25,7 +27,7 @@
         super(TTWViewTemplate, self).__init__(id, text, content_type, encoding,
                                               strict)
 
-    def __call__(self, context, request):
+    def __call__(self, context, request, viewlet=None, manager=None):
         #XXX raise a sensible exception if context and request are
         # omitted, IOW, if someone tries to render the template not as
         # a view.
@@ -35,7 +37,11 @@
                 raise Unauthorized('The current user does not have the '
                                    'required "%s" permission'
                                    % self.permission)
-        return TTWViewTemplateRenderer(context, request, self, self.view)
+        if IViewlet.providedBy(viewlet) and IViewletManager.providedBy(manager):
+            return TTWViewletRenderer(context, request, self, self.view,
+                viewlet, manager)
+        else:
+            return TTWViewTemplateRenderer(context, request, self, self.view)
 
     # overwrite Shared.DC.Scripts.Binding.Binding's before traversal
     # hook that would prevent to look up views for instances of this
@@ -92,6 +98,64 @@
     def __of__(self, obj):
         return self
 
+
+class TTWViewletRenderer(object):
+    """ analogon to TTWViewTemplateRenderer for viewlets """
+    implements(IViewlet)
+
+    __allow_access_to_unprotected_subobjects__ = True
+
+    def __init__(self, context, request, template, view, viewlet=None, manager=None):
+        self.context = context
+        self.request = request
+        self.template = template
+        self.view = view
+        self.viewlet = viewlet
+        self.manager = manager
+
+    def update(self):
+        # TODO: do we have to do anything here in regard to the customized
+        #    template?  i don't think so...
+        return
+
+    def render(self, *args, **kwargs):
+        """ render the viewlet using the customized template """
+        attr, tmpl = findViewletTemplate(self.view)
+        view = self._getViewlet()
+
+        # TODO: the bound names still have to be fixed here...
+
+        # we need to override the template's context and request as
+        # they generally point to the wrong objects (a template's
+        # context usually is what it was acquired from, which isn't
+        # what the context is for a view template).
+        bound_names = {'context': self.context,
+                       'request': self.request,
+                       'view': view}
+        template = self.template.__of__(self.context)
+        return template._exec(bound_names, args, kwargs)
+
+    def _getViewlet(self):
+        view = self.view
+        if view is not None:
+            # Filesystem-based view templates are trusted code and
+            # have unrestricted access to the view class.  We simulate
+            # that for TTW templates (which are trusted code) by
+            # creating a subclass with unrestricted access to all
+            # subobjects.
+            class TTWViewlet(view):
+                __allow_access_to_unprotected_subobjects__ = 1
+            view = TTWViewlet(self.context, self.request, self.viewlet, self.manager)
+        return view
+
+    # Zope 2 wants to acquisition-wrap every view object (via __of__).
+    # We don't need this as the TTWViewTemplate object is already
+    # properly acquisition-wrapped in __call__.  Nevertheless we need
+    # to support the __of__ method as a no-op.
+    def __of__(self, obj):
+        return self
+
+
 @zope.component.adapter(TTWViewTemplate, IObjectRemovedEvent)
 def unregisterViewWhenZPTIsDeleted(zpt, event):
     components = zope.component.getSiteManager(zpt)



More information about the Checkins mailing list