[Checkins] SVN: grok/branches/snowsprint-viewlets/src/grok/ A first stab at viewlets. This is basically mcweely's old viewlet branch, but using actions to register the viewlets and viewletmanagers. Viewlets are now registered for IBrowserView. To be able to register them for certain views we probably need a new directive grok.view(). Tests are coming tomorrow.

Tim Terlegård tim.terlegard at valentinewebsystems.se
Mon Jan 21 19:10:29 EST 2008


Log message for revision 83080:
  A first stab at viewlets. This is basically mcweely's old viewlet branch, but using actions to register the viewlets and viewletmanagers. Viewlets are now registered for IBrowserView. To be able to register them for certain views we probably need a new directive grok.view(). Tests are coming tomorrow.
  

Changed:
  U   grok/branches/snowsprint-viewlets/src/grok/__init__.py
  U   grok/branches/snowsprint-viewlets/src/grok/components.py
  U   grok/branches/snowsprint-viewlets/src/grok/directive.py
  U   grok/branches/snowsprint-viewlets/src/grok/interfaces.py
  U   grok/branches/snowsprint-viewlets/src/grok/meta.py

-=-
Modified: grok/branches/snowsprint-viewlets/src/grok/__init__.py
===================================================================
--- grok/branches/snowsprint-viewlets/src/grok/__init__.py	2008-01-21 23:31:58 UTC (rev 83079)
+++ grok/branches/snowsprint-viewlets/src/grok/__init__.py	2008-01-22 00:10:28 UTC (rev 83080)
@@ -40,9 +40,11 @@
 from grok.components import Skin, IGrokLayer
 from grok.components import RESTProtocol, IRESTLayer
 from grok.interfaces import IRESTSkinType
+from grok.components import ViewletManager, Viewlet
+
 from grok.directive import (context, name, title, template, templatedir,
                             provides, baseclass, global_utility, local_utility,
-                            permissions, require, site, layer, direct)
+                            permissions, require, site, layer, direct, viewletmanager)
 from grok.decorators import subscribe, adapter, implementer
 from martian.error import GrokError, GrokImportError
 

Modified: grok/branches/snowsprint-viewlets/src/grok/components.py
===================================================================
--- grok/branches/snowsprint-viewlets/src/grok/components.py	2008-01-21 23:31:58 UTC (rev 83079)
+++ grok/branches/snowsprint-viewlets/src/grok/components.py	2008-01-22 00:10:28 UTC (rev 83080)
@@ -47,6 +47,9 @@
 from zope.app.component.site import SiteManagerContainer
 from zope.app.component.site import LocalSiteManager
 
+from zope.viewlet.manager import ViewletManagerBase
+from zope.viewlet.viewlet import ViewletBase
+
 import z3c.flashmessage.interfaces
 
 import martian.util
@@ -608,3 +611,128 @@
 
 class RESTProtocol(object):
     pass
+
+class ViewletManager(ViewletManagerBase):
+    template = None
+
+    def __init__(self, context, request, view):
+        super(ViewletManager, self).__init__(context, request, view)
+        self.static = component.queryAdapter(
+            self.request,
+            interface.Interface,
+            name=self.module_info.package_dotted_name
+            )
+
+
+    def render(self):
+        """See zope.contentprovider.interfaces.IContentProvider"""
+        # Now render the view
+        if self.template:
+            #return self.template(viewlets=self.viewlets)
+            return self._render_template()
+        else:
+            return u'\n'.join([viewlet.render() for viewlet in self.viewlets])
+
+
+    @property
+    def response(self):
+        return self.request.response
+
+    def _render_template(self):
+        namespace = self.template.pt_getContext()
+        namespace['request'] = self.request
+        namespace['view'] = self
+        namespace['viewlets'] = self.viewlets
+        namespace['static'] = self.static
+        namespace['context'] = self.context
+        # XXX need to check whether we really want to put None here if missing
+        return self.template.pt_render(namespace)
+
+    def url(self, obj=None, name=None):
+        # if the first argument is a string, that's the name. There should
+        # be no second argument
+        if isinstance(obj, basestring):
+            if name is not None:
+                raise TypeError(
+                    'url() takes either obj argument, obj, string arguments, '
+                    'or string argument')
+            name = obj
+            obj = None
+
+        if name is None and obj is None:
+            # create URL to view itself
+            obj = self
+        elif name is not None and obj is None:
+            # create URL to view on context
+            obj = self.context
+        return util.url(self.request, obj, name)
+
+    def redirect(self, url):
+        return self.request.response.redirect(url)
+
+class Viewlet(ViewletBase):
+    """ Batteries included viewlet """
+
+
+    def __init__(self, context, request, view, manager):
+        super(Viewlet, self).__init__(context, request, view, manager)
+        self.static = component.queryAdapter(
+            self.request,
+            interface.Interface,
+            name=self.module_info.package_dotted_name
+            )
+
+
+    @property
+    def response(self):
+        return self.request.response
+
+
+    def render(self):
+        mapply(self.update, (), self.request)
+        if self.request.response.getStatus() in (302, 303):
+            # A redirect was triggered somewhere in update().  Don't
+            # continue rendering the template or doing anything else.
+            return
+
+        template = getattr(self, 'template', None)
+        if template is not None:
+            return self._render_template()
+
+    def _render_template(self):
+        namespace = self.template.pt_getContext()
+        namespace['request'] = self.request
+        namespace['view'] = self
+        namespace['context'] = self.context
+        # XXX need to check whether we really want to put None here if missing
+        namespace['static'] = self.static
+        return self.template.pt_render(namespace)
+
+    def __getitem__(self, key):
+        # XXX give nice error message if template is None
+        return self.template.macros[key]
+
+    def url(self, obj=None, name=None):
+        # if the first argument is a string, that's the name. There should
+        # be no second argument
+        if isinstance(obj, basestring):
+            if name is not None:
+                raise TypeError(
+                    'url() takes either obj argument, obj, string arguments, '
+                    'or string argument')
+            name = obj
+            obj = None
+
+        if name is None and obj is None:
+            # create URL to view itself
+            obj = self
+        elif name is not None and obj is None:
+            # create URL to view on context
+            obj = self.context
+        return util.url(self.request, obj, name)
+
+    def redirect(self, url):
+        return self.request.response.redirect(url)
+
+    def update(self):
+        pass

Modified: grok/branches/snowsprint-viewlets/src/grok/directive.py
===================================================================
--- grok/branches/snowsprint-viewlets/src/grok/directive.py	2008-01-21 23:31:58 UTC (rev 83079)
+++ grok/branches/snowsprint-viewlets/src/grok/directive.py	2008-01-22 00:10:28 UTC (rev 83080)
@@ -124,4 +124,6 @@
     'grok.permissions', ClassDirectiveContext())
 layer = InterfaceOrClassDirective('grok.layer',
                            ClassOrModuleDirectiveContext())
-direct = MarkerDirective('grok.direct', ClassDirectiveContext())
\ No newline at end of file
+direct = MarkerDirective('grok.direct', ClassDirectiveContext())
+viewletmanager = InterfaceOrClassDirective('grok.viewletmanager',
+                                           ClassDirectiveContext())

Modified: grok/branches/snowsprint-viewlets/src/grok/interfaces.py
===================================================================
--- grok/branches/snowsprint-viewlets/src/grok/interfaces.py	2008-01-21 23:31:58 UTC (rev 83079)
+++ grok/branches/snowsprint-viewlets/src/grok/interfaces.py	2008-01-22 00:10:28 UTC (rev 83080)
@@ -47,6 +47,8 @@
     Indexes = interface.Attribute("Base class for catalog index definitions.")
     Layer = interface.Attribute("Base interface for layers.")
     Skin = interface.Attribute("Base class for skin.")
+    ViewletManager = interface.Attribute("Base class for viewletmanager.")
+    Viewlet = interface.Attribute("Base class for viewlet.")
 
 
 class IGrokErrors(interface.Interface):

Modified: grok/branches/snowsprint-viewlets/src/grok/meta.py
===================================================================
--- grok/branches/snowsprint-viewlets/src/grok/meta.py	2008-01-21 23:31:58 UTC (rev 83079)
+++ grok/branches/snowsprint-viewlets/src/grok/meta.py	2008-01-22 00:10:28 UTC (rev 83080)
@@ -17,11 +17,14 @@
 
 import zope.component.interface
 from zope import interface, component
+from zope.publisher.browser import IBrowserView
 from zope.publisher.interfaces.browser import (IDefaultBrowserLayer,
                                                IBrowserRequest,
                                                IBrowserPublisher,
                                                IBrowserSkinType)
 from zope.publisher.interfaces.xmlrpc import IXMLRPCRequest
+from zope.viewlet.interfaces import IViewletManager, IViewlet
+from zope.security.checker import NamesChecker, defineChecker
 from zope.security.interfaces import IPermission
 from zope.securitypolicy.interfaces import IRole
 from zope.securitypolicy.rolepermission import rolePermissionManager
@@ -869,3 +872,117 @@
             args=(name, layer, IRESTSkinType)
             )
         return True
+
+class ViewletManagerGrokker(martian.ClassGrokker):
+    component_class = grok.ViewletManager
+
+    def grok(self, name, factory, module_info, config, **kw):
+
+        factory.module_info = module_info # to make /static available
+
+        name = grok.util.class_annotation(factory, 'grok.name', factory.__name__.lower())
+        view_layer = util.class_annotation(factory, 'grok.layer',
+                                                    None) or module_info.getAnnotation('grok.layer',
+                                                     None) or IDefaultBrowserLayer
+
+        context = module_info.getAnnotation('grok.context', None)
+        view_context = util.determine_class_context(factory, context)
+
+        view_layer = determine_class_directive('grok.layer', factory,
+                                               module_info,
+                                               default=IDefaultBrowserLayer)
+
+        # TODO - manager is registered for IBrowserView instead of the real view
+        config.action(
+            discriminator = ('viewletManager', view_context, view_layer,
+                             IBrowserView, name),
+            callable = component.provideAdapter,
+            args = (factory, (interface.Interface, view_layer, IBrowserView),
+                    IViewletManager, name)
+            )
+
+        return True
+
+class ViewletGrokker(martian.ClassGrokker):
+    component_class = grok.Viewlet
+
+    def grok(self, name, factory, module_info, config, **kw):
+        # Try to set up permissions (copied from the View grokker)
+
+        factory.module_info = module_info # to make /static available
+        factory_name = factory.__name__.lower()
+
+        permissions = grok.util.class_annotation(factory, 'grok.require', [])
+        if not permissions:
+            checker = NamesChecker(['update', 'render'])
+        elif len(permissions) > 1:
+            raise GrokError('grok.require was called multiple times in viewlet '
+                            '%r. It may only be called once.' % factory,
+                            factory)
+        elif permissions[0] == 'zope.Public':
+            checker = NamesChecker(['update','render'])
+        else:
+            perm = permissions[0]
+            if component.queryUtility(IPermission, name=perm) is None:
+                raise GrokError('Undefined permission %r in view %r. Use '                            'grok.define_permission first.'
+                            % (perm, factory), factory)
+            checker = NamesChecker(['update','render'], permissions[0])
+
+        defineChecker(factory, checker)
+
+        # find templates
+        template_name = util.class_annotation(factory, 'grok.template',
+                                              factory_name)
+        templates = module_info.getAnnotation('grok.templates', None)
+        template = templates.get(template_name)
+
+        if factory_name != template_name:
+            # grok.template is being used
+            if templates.get(factory_name):
+                raise GrokError("Multiple possible templates for view %r. It "
+                                "uses grok.template('%s'), but there is also "
+                                "a template called '%s'."
+                                % (factory, template_name, factory_name),
+                                factory)
+
+        factory_template = getattr(factory,'template', None)
+
+        if template:
+            if (getattr(factory, 'render', None) and not
+                util.check_subclass(factory, components.GrokForm) and not
+                util.check_subclass(factory, components.Viewlet)):
+                # we do not accept render and template both for a view
+                # (unless it's a form, they happen to have render.)
+                # Forms currently not implemented in viewlets.
+                raise GrokError(
+                    "Multiple possible ways to render view %r. "
+                    "It has both a 'render' method as well as "
+                    "an associated template." % factory, factory)
+
+            templates.markAssociated(template_name)
+            factory.template = template
+        elif factory_template and isinstance(factory_template, (components.PageTemplate, components.PageTemplateFile)):
+            pass
+        else:
+            if not getattr(factory, 'render', None):
+                # we do not accept a view without any way to render it
+                raise GrokError("View %r has no associated template or "
+                                "'render' method." % factory, factory)
+
+        context = module_info.getAnnotation('grok.context', None)
+        view_context = util.determine_class_context(factory, context)
+
+        viewletmanager = grok.util.class_annotation(factory, 'grok.viewletmanager', [])
+        view_layer = util.class_annotation(factory, 'grok.layer',
+                                            None) or module_info.getAnnotation('grok.layer',
+                                             None) or IDefaultBrowserLayer
+
+        config.action(
+            discriminator = ('viewlet', view_context, view_layer,
+                             IBrowserView, viewletmanager, name),
+            callable = component.provideAdapter,
+            args = (factory, (view_context, view_layer, IBrowserView,
+                    viewletmanager), IViewlet, name)
+            )
+
+        return True



More information about the Checkins mailing list