[Checkins] SVN: grok/trunk/ Merge jw-viewlets-fix branch. Fixes
#226555.
Jan-Wijbrand Kolman
janwijbrand at gmail.com
Thu Jun 19 15:38:51 EDT 2008
Log message for revision 87563:
Merge jw-viewlets-fix branch. Fixes #226555.
Changed:
U grok/trunk/CHANGES.txt
U grok/trunk/src/grok/components.py
U grok/trunk/src/grok/ftests/viewlet/viewletmanager_template_templates/cavemanager.pt
U grok/trunk/src/grok/interfaces.py
A grok/trunk/src/grok/tests/viewlet/viewlet_references.py
-=-
Modified: grok/trunk/CHANGES.txt
===================================================================
--- grok/trunk/CHANGES.txt 2008-06-19 18:43:25 UTC (rev 87562)
+++ grok/trunk/CHANGES.txt 2008-06-19 19:38:50 UTC (rev 87563)
@@ -24,6 +24,11 @@
Feature changes
---------------
+* GrokTemplate sets up the namespaces for the template by calling
+ default_namespace() on the view component the template is associated
+ with. As a result, ViewletManagers and Viewlets can now push in the
+ viewletmanager and viewlet namespace into the template.
+
* Updated tutorial section about grokproject to fit the latest changes.
* Added ``grok.traversable`` directive for easy traversal to attributes and
@@ -76,6 +81,10 @@
Bug fixes
---------
+* Fix https://bugs.launchpad.net/grok/+bug/226555: the url() method on
+ ViewletManager and Viewlet has been removed now that there's easy
+ access to the view component the viewlet(manager) is registered for.
+
* Fix https://bugs.launchpad.net/grok/+bug/231106: Use the
viewletmanager.sort() method for sorting viewlets by using
util.sort_components().
Modified: grok/trunk/src/grok/components.py
===================================================================
--- grok/trunk/src/grok/components.py 2008-06-19 18:43:25 UTC (rev 87562)
+++ grok/trunk/src/grok/components.py 2008-06-19 19:38:50 UTC (rev 87563)
@@ -175,6 +175,14 @@
def _render_template(self):
return self.template.render(self)
+ def default_namespace(self):
+ namespace = {}
+ namespace['context'] = self.context
+ namespace['request'] = self.request
+ namespace['static'] = self.static
+ namespace['view'] = self
+ return namespace
+
def namespace(self):
return {}
@@ -312,7 +320,8 @@
self.__grok_module__ = martian.util.caller_module()
if not (string is None) ^ (filename is None):
- raise AssertionError("You must pass in template or filename, but not both.")
+ raise AssertionError(
+ "You must pass in template or filename, but not both.")
if string:
self.setFromString(string)
@@ -334,15 +343,10 @@
pass
def namespace(self, view):
- namespace = {}
- namespace['request'] = view.request
- namespace['view'] = view
- namespace['context'] = view.context
- # XXX need to check whether we really want to put None here if missing
- namespace['static'] = view.static
+ # By default use the namespaces that are defined as the
+ # default by the view implementation.
+ return view.default_namespace()
- return namespace
-
def getNamespace(self, view):
namespace = self.namespace(view)
namespace.update(view.namespace())
@@ -667,6 +671,9 @@
def __init__(self, context, request, view):
super(ViewletManager, self).__init__(context, request, view)
+ self.context = context
+ self.request = request
+ self.view = view
self.__name__ = self.__view_name__
self.static = component.queryAdapter(
self.request,
@@ -698,6 +705,18 @@
s_viewlets = util.sort_components(s_viewlets)
return [(viewlet.__viewlet_name__, viewlet) for viewlet in s_viewlets]
+ def default_namespace(self):
+ namespace = {}
+ namespace['context'] = self.context
+ namespace['request'] = self.request
+ namespace['static'] = self.static
+ namespace['view'] = self.view
+ namespace['viewletmanager'] = self
+ return namespace
+
+ def namespace(self):
+ return {}
+
def render(self):
"""See zope.contentprovider.interfaces.IContentProvider"""
# Now render the view
@@ -706,41 +725,17 @@
else:
return u'\n'.join([viewlet.render() for viewlet in self.viewlets])
- def namespace(self):
- return {}
- @property
- def response(self):
- return self.request.response
-
- 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 """
+ """Batteries included viewlet.
+ """
-
def __init__(self, context, request, view, manager):
super(Viewlet, self).__init__(context, request, view, manager)
+ self.context = context
+ self.request = request
+ self.view = view
+ self.viewletmanager = manager
self.__name__ = self.__view_name__
self.static = component.queryAdapter(
self.request,
@@ -748,34 +743,21 @@
name=self.module_info.package_dotted_name
)
- @property
- def response(self):
- return self.request.response
+ def default_namespace(self):
+ namespace = {}
+ namespace['context'] = self.context
+ namespace['request'] = self.request
+ namespace['static'] = self.static
+ namespace['view'] = self.view
+ namespace['viewlet'] = self
+ namespace['viewletmanager'] = self.manager
+ return namespace
- def render(self):
- return self.template.render(self)
-
def namespace(self):
return {}
- 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 update(self):
pass
+
+ def render(self):
+ return self.template.render(self)
Modified: grok/trunk/src/grok/ftests/viewlet/viewletmanager_template_templates/cavemanager.pt
===================================================================
--- grok/trunk/src/grok/ftests/viewlet/viewletmanager_template_templates/cavemanager.pt 2008-06-19 18:43:25 UTC (rev 87562)
+++ grok/trunk/src/grok/ftests/viewlet/viewletmanager_template_templates/cavemanager.pt 2008-06-19 19:38:50 UTC (rev 87563)
@@ -1,3 +1,3 @@
-<ul tal:define="v_dict view/viewlet_dict; v_keys view/viewlet_keys_sorted;">
+<ul tal:define="v_dict viewletmanager/viewlet_dict; v_keys viewletmanager/viewlet_keys_sorted;">
<li tal:repeat="k v_keys" tal:content="python:v_dict[k].render().strip()" />
</ul>
Modified: grok/trunk/src/grok/interfaces.py
===================================================================
--- grok/trunk/src/grok/interfaces.py 2008-06-19 18:43:25 UTC (rev 87562)
+++ grok/trunk/src/grok/interfaces.py 2008-06-19 19:38:50 UTC (rev 87563)
@@ -320,6 +320,22 @@
as a cgi query string.
"""
+ def default_namespace():
+ """Returns a dictionary of namespaces that the template
+ implementation expects to always be available.
+
+ This method is *not* intended to be overridden by application
+ developers.
+ """
+
+ def namespace():
+ """Returns a dictionary that is injected in the template
+ namespace in addition to the default namespace.
+
+ This method *is* intended to be overridden by the application
+ developer.
+ """
+
def update(**kw):
"""This method is meant to be implemented by grok.View
subclasses. It will be called *before* the view's associated
@@ -507,4 +523,3 @@
class IViewletManager(IViewletManagerBase):
"""The Grok viewlet manager.
"""
-
Added: grok/trunk/src/grok/tests/viewlet/viewlet_references.py
===================================================================
--- grok/trunk/src/grok/tests/viewlet/viewlet_references.py (rev 0)
+++ grok/trunk/src/grok/tests/viewlet/viewlet_references.py 2008-06-19 19:38:50 UTC (rev 87563)
@@ -0,0 +1,65 @@
+"""
+A grok.ViewletManager instance has references to the components it was
+registered for::
+
+ >>> grok.testing.grok(__name__)
+ >>> from zope import component
+ >>> from zope.contentprovider.interfaces import IContentProvider
+ >>> from zope.publisher.browser import TestRequest
+ >>> ctxt = AContext()
+ >>> request = TestRequest()
+ >>> view = component.getMultiAdapter((ctxt, request), name='with_items')
+ >>> items_mgr = component.getMultiAdapter(
+ ... (ctxt, request, view), IContentProvider, name='view_items_manager')
+ >>> items_mgr.context is ctxt
+ True
+ >>> items_mgr.view is view
+ True
+ >>> items_mgr.request is request
+ True
+
+Likewise, grok.Viewlet instances have references to the components they're
+registered for::
+
+ >>> items_mgr.update()
+ >>> for viewlet in items_mgr.viewlets:
+ ... viewlet.context is ctxt
+ ... viewlet.view is view
+ ... viewlet.viewletmanager is items_mgr
+ ... viewlet.request is request
+ True
+ True
+ True
+ True
+ True
+ True
+ True
+ True
+"""
+
+import grok
+from zope import interface
+
+class AContext(grok.Model):
+ pass
+
+class ViewWithItems(grok.View):
+ grok.name('with_items')
+
+ def render(self):
+ return ''
+
+class ViewItemsManager(grok.ViewletManager):
+ grok.name('view_items_manager')
+
+class ItemOneViewlet(grok.Viewlet):
+ grok.name('item_one')
+
+ def render(self):
+ return "Item one reporting, sir!"
+
+class ItemTwoViewlet(grok.Viewlet):
+ grok.name('item_two')
+
+ def render(self):
+ return "Item two reporting, sir!"
More information about the Checkins
mailing list