[Checkins] SVN: z3ext.layout/trunk/ api refactoring

Nikolay Kim fafhrd at datacom.kz
Sun Dec 21 18:05:17 EST 2008


Log message for revision 94231:
  api refactoring

Changed:
  U   z3ext.layout/trunk/CHANGES.txt
  U   z3ext.layout/trunk/setup.py
  U   z3ext.layout/trunk/src/z3ext/layout/configure.zcml
  U   z3ext.layout/trunk/src/z3ext/layout/interfaces.py
  U   z3ext.layout/trunk/src/z3ext/layout/meta.zcml
  U   z3ext.layout/trunk/src/z3ext/layout/pagelet.py
  U   z3ext.layout/trunk/src/z3ext/layout/pagelet.txt
  U   z3ext.layout/trunk/src/z3ext/layout/tales.py
  U   z3ext.layout/trunk/src/z3ext/layout/zcml.py

-=-
Modified: z3ext.layout/trunk/CHANGES.txt
===================================================================
--- z3ext.layout/trunk/CHANGES.txt	2008-12-21 20:08:09 UTC (rev 94230)
+++ z3ext.layout/trunk/CHANGES.txt	2008-12-21 23:05:17 UTC (rev 94231)
@@ -2,12 +2,21 @@
 CHANGES
 =======
 
-1.7.4 (2008-12-??)
+2.0.0 (2008-12-22)
 ------------------
 
-- Added IPageletManagerType, same as IPageletType but use extra parameters for adopter
+- Added 'type' attribute to 'z3ext:pagelet' 
 
+- Added 'z3ext:pageletType' directive for registering new pagelet types
 
+- multiple params is allowed for 'for' attribute
+
+- Removed pagelet 'manager' attribute
+
+- 'pagelet' tales expression and 'pagelet' view checks additional context IPageletContext
+  if exists use it as adapter parameter
+
+
 1.7.3 (2008-12-18)
 ------------------
 

Modified: z3ext.layout/trunk/setup.py
===================================================================
--- z3ext.layout/trunk/setup.py	2008-12-21 20:08:09 UTC (rev 94230)
+++ z3ext.layout/trunk/setup.py	2008-12-21 23:05:17 UTC (rev 94231)
@@ -21,7 +21,7 @@
 def read(*rnames):
     return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
 
-version='1.7.4dev'
+version='2.0.0'
 
 
 setup(name='z3ext.layout',

Modified: z3ext.layout/trunk/src/z3ext/layout/configure.zcml
===================================================================
--- z3ext.layout/trunk/src/z3ext/layout/configure.zcml	2008-12-21 20:08:09 UTC (rev 94230)
+++ z3ext.layout/trunk/src/z3ext/layout/configure.zcml	2008-12-21 23:05:17 UTC (rev 94231)
@@ -7,6 +7,10 @@
 
   <includeDependencies package="z3ext.layout" />
 
+  <z3ext:pageletType
+     name="pagelet"
+     interface="z3ext.layout.interfaces.IPageletType" />
+
   <!-- adapter provides IPagelet for (context, request) -->
   <adapter factory=".pagelet.queryPagelet" />
 

Modified: z3ext.layout/trunk/src/z3ext/layout/interfaces.py
===================================================================
--- z3ext.layout/trunk/src/z3ext/layout/interfaces.py	2008-12-21 20:08:09 UTC (rev 94230)
+++ z3ext.layout/trunk/src/z3ext/layout/interfaces.py	2008-12-21 23:05:17 UTC (rev 94231)
@@ -26,7 +26,7 @@
 class IPagelet(IBrowserPage):
     """ pagelet """
 
-    managers = interface.Attribute('Additional managers')
+    contexts = interface.Attribute('Additional contexts')
 
     isRedirected = interface.Attribute('is redirected')
 
@@ -46,13 +46,10 @@
     """ pagelet interface type """
 
 
-class IPageletManager(interface.Interface):
-    """ pagelet manager """
+class IPageletContext(interface.Interface):
+    """ pagelet contexts """
 
-class IPageletManagerType(IPageletType):
-    """ pagelet interface type with view as manager """
 
-
 class ILayout(IBrowserPage):
     """ layout """
 

Modified: z3ext.layout/trunk/src/z3ext/layout/meta.zcml
===================================================================
--- z3ext.layout/trunk/src/z3ext/layout/meta.zcml	2008-12-21 20:08:09 UTC (rev 94230)
+++ z3ext.layout/trunk/src/z3ext/layout/meta.zcml	2008-12-21 23:05:17 UTC (rev 94231)
@@ -12,6 +12,11 @@
        name="pagelet"
        schema=".zcml.IPageletDirective"
        handler=".zcml.pageletDirective" />
+
+    <meta:directive
+       name="pageletType"
+       schema=".zcml.IPageletTypeDirective"
+       handler=".zcml.pageletTypeDirective" />
   </meta:directives>
 
 </configure>

Modified: z3ext.layout/trunk/src/z3ext/layout/pagelet.py
===================================================================
--- z3ext.layout/trunk/src/z3ext/layout/pagelet.py	2008-12-21 20:08:09 UTC (rev 94230)
+++ z3ext.layout/trunk/src/z3ext/layout/pagelet.py	2008-12-21 23:05:17 UTC (rev 94231)
@@ -17,16 +17,14 @@
 """
 import logging, sys
 from zope import interface, component
-from zope.component import queryUtility
-from zope.component import queryMultiAdapter
+from zope.component import queryUtility, queryAdapter, queryMultiAdapter
 from zope.publisher.browser import BrowserPage
 from zope.publisher.interfaces import NotFound
 from zope.publisher.interfaces.browser import IBrowserPublisher
 from zope.tales.expressions import SimpleModuleImporter
 from zope.app.publisher.browser import queryDefaultViewName
 
-from z3ext.layout.interfaces import IPagelet, ILayout, IPageletType
-from z3ext.layout.interfaces import IPageletManager, IPageletManagerType
+from interfaces import ILayout, IPagelet, IPageletType, IPageletContext
 
 
 @interface.implementer(IPagelet)
@@ -59,10 +57,16 @@
     template = None
     layoutname = u''
 
-    def __init__(self, context, request, *args):
-        self.managers = args
+    def __init__(self, context, *args):
+        request = args[-1]
         super(BrowserPagelet, self).__init__(context, request)
 
+        args = args[:-1]
+        self.contexts = args
+
+        for idx in range(len(args)):
+            setattr(self, 'context%s'%idx, args[idx])
+
     def update(self):
         pass
 
@@ -70,7 +74,7 @@
         if self.template is not None:
             return self.template()
         else:
-            template = queryMultiAdapter((self, self.request), IPagelet, name='')
+            template = queryMultiAdapter((self, self.request), IPagelet)
             if template is not None:
                 template.update()
                 return template.render()
@@ -114,9 +118,9 @@
 
         raise NotFound(self.context, name, request)
 
-    def __call__(self):
+    def __call__(self, name=''):
         try:
-            return self['']
+            return self[name]
         except KeyError:
             pass
 
@@ -124,9 +128,7 @@
 
     def __getitem__(self, name):
         if name:
-            iface = queryUtility(IPageletManagerType, name)
-            if iface is None:
-                iface = queryUtility(IPageletType, name)
+            iface = queryUtility(IPageletType, name)
 
             if iface is None:
                 try:
@@ -142,12 +144,15 @@
         if iface.providedBy(context):
             return context.render()
 
-        if IPageletManagerType.providedBy(iface):
-            manager = IPageletManager(context, None)
-            context = [context, self.request]
-            if type(manager) in (list, tuple):
-                context.extend(manager)
-            view = queryMultiAdapter(context, iface)
+        contexts = queryAdapter(context, IPageletContext, name)
+        if contexts is not None:
+            required = [context]
+            if type(contexts) in (list, tuple):
+                required.extend(contexts)
+            else:
+                required.append(contexts)
+            required.append(self.request)
+            view = queryMultiAdapter(required, iface)
         else:
             view = queryMultiAdapter((context, self.request), iface)
 

Modified: z3ext.layout/trunk/src/z3ext/layout/pagelet.txt
===================================================================
--- z3ext.layout/trunk/src/z3ext/layout/pagelet.txt	2008-12-21 20:08:09 UTC (rev 94230)
+++ z3ext.layout/trunk/src/z3ext/layout/pagelet.txt	2008-12-21 23:05:17 UTC (rev 94231)
@@ -8,7 +8,7 @@
   >>> import os, tempfile, sys
   >>> from zope import interface, component, schema
   >>> from zope.configuration import xmlconfig
-  >>> from z3ext.layout.interfaces import IPagelet
+  >>> from z3ext.layout.interfaces import IPagelet, IPageletType, IPageletContext
 
   >>> import z3ext.layout
   >>> context = xmlconfig.file('meta.zcml', z3ext.layout)
@@ -24,6 +24,7 @@
   >>> context = xmlconfig.string("""
   ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
   ...   <z3ext:pagelet
+  ...       for="*"
   ...       name="index.html"
   ...       class="z3ext.layout.TESTS.MyPagelet"
   ...       permission="zope.Public"
@@ -99,9 +100,9 @@
   >>> context = xmlconfig.string("""
   ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
   ...   <z3ext:pagelet
+  ...       for="*"
   ...       name="new.html"
   ...       class="z3ext.layout.TESTS.NewPagelet"
-  ...       permission="zope.Public"
   ...       provides="z3ext.layout.TESTS.INewPagelet" />
   ... </configure>
   ... """, context)
@@ -133,9 +134,9 @@
   >>> xmlconfig.string("""
   ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
   ...   <z3ext:pagelet
+  ...       for="*"
   ...       name="new.html"
   ...       class="z3ext.layout.TESTS.NewPagelet"
-  ...       permission="zope.Public"
   ...       provides="z3ext.layout.TESTS.INewPagelet2" />
   ... </configure>
   ... """, context)
@@ -156,15 +157,15 @@
   >>> context = xmlconfig.string("""
   ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
   ...   <z3ext:pagelet
+  ...       for="*"
   ...       name="new.html"
   ...       class="z3ext.layout.TESTS.NewPagelet"
-  ...       permission="zope.Public"
   ...       provides="z3ext.layout.TESTS.INewPagelet2" />
   ... </configure>
   ... """, context)
 
   >>> pagelet = component.getMultiAdapter(
-  ...     (object(), TestRequest()), INewPagelet2, name='new.html')
+  ...     (object(), TestRequest()), IPagelet, name='new.html')
   >>> print pagelet.number
   9
 
@@ -173,16 +174,16 @@
   >>> context = xmlconfig.string("""
   ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
   ...   <z3ext:pagelet
+  ...       for="*"
   ...       name="new1.html"
   ...       class="z3ext.layout.TESTS.NewPagelet"
-  ...       permission="zope.Public"
   ...       provides="z3ext.layout.TESTS.INewPagelet2"
   ...       number="10" />
   ... </configure>
   ... """, context)
 
   >>> pagelet = component.getMultiAdapter(
-  ...     (object(), TestRequest()), INewPagelet2, name='new1.html')
+  ...     (object(), TestRequest()), IPagelet, name='new1.html')
   >>> print pagelet.number, ':', type(pagelet.number)
   10 : <type 'int'>
 
@@ -191,9 +192,9 @@
   >>> context = xmlconfig.string("""
   ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
   ...   <z3ext:pagelet
+  ...       for="*"
   ...       name="new1.html"
   ...       class="z3ext.layout.TESTS.NewPagelet"
-  ...       permission="zope.Public"
   ...       provides="z3ext.layout.TESTS.INewPagelet2"
   ...       number="xxxxx" />
   ... </configure>
@@ -213,9 +214,9 @@
   >>> context = xmlconfig.string("""
   ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
   ...   <z3ext:pagelet
+  ...       for="*"
   ...       name="new.html"
   ...       class="z3ext.layout.TESTS.NewPagelet"
-  ...       permission="zope.Public"
   ...       date="2007-10-10"
   ...       provides="z3ext.layout.TESTS.INewPagelet3" />
   ... </configure>
@@ -224,15 +225,33 @@
   ...
   ZopeXMLConfigurationError:...ConfigurationError: ("Can't convert value", 'date')
 
+If pagelet is typed, type schema also checked
 
+  >>> from zope.component.interface import provideInterface
+  >>> provideInterface('newPagelet3', INewPagelet3, IPageletType)
 
+  >>> context = xmlconfig.string("""
+  ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
+  ...   <z3ext:pagelet
+  ...       for="*"
+  ...       name="new.html"
+  ...       class="z3ext.layout.TESTS.NewPagelet"
+  ...       date="2007-10-10"
+  ...       type="newPagelet3" />
+  ... </configure>
+  ... """, context)
+  Traceback (most recent call last):
+  ...
+  ZopeXMLConfigurationError:...ConfigurationError: ("Can't convert value", 'date')
+
+
 We can create pagelet without specific class
 
   >>> context = xmlconfig.string("""
   ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
   ...   <z3ext:pagelet
-  ...       name="noclass.html"
-  ...       permission="zope.Public" />
+  ...       for="*"
+  ...       name="noclass.html" />
   ... </configure>
   ... """, context) 
 
@@ -247,15 +266,15 @@
   >>> context = xmlconfig.string("""
   ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
   ...   <z3ext:pagelet
+  ...       for="*"
   ...       name="unknown.html"
-  ...       template="unknown.pt"
-  ...       permission="zope.Public" />
+  ...       template="unknown.pt" />
   ... </configure>
   ... """, context)
   Traceback (most recent call last):
   ...
-  ZopeXMLConfigurationError: File "<string>", line 3.2-6.33
-  ConfigurationError: ('No such file', ...unknown.pt')
+  ZopeXMLConfigurationError: File "<string>", line 3.2-6.30
+  ConfigurationError: ('No such file', '...unknown.pt')
 
   >>> temp_dir = tempfile.mkdtemp()
   >>> template = os.path.join(temp_dir, 'pagelet.pt')
@@ -264,6 +283,7 @@
   >>> context = xmlconfig.string("""
   ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
   ...   <z3ext:pagelet
+  ...       for="*"
   ...       name="template.html"
   ...       template="%s"
   ...       permission="zope.Public" />
@@ -290,20 +310,18 @@
   ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
   ...   <z3ext:pagelet
   ...       name="index.html"
-  ...       for="*"
-  ...       manager="z3ext.layout.TESTS.IContext2"
-  ...       permission="zope.Public" />
+  ...       for="* z3ext.layout.TESTS.IContext2" />
   ... </configure>
   ... """, context) 
 
   >>> context2 = Context2()
 
   >>> c2Pagelet = component.queryMultiAdapter(
-  ...     (object(), TestRequest(), context2), name='index.html')
+  ...     (object(), context2, TestRequest()), name='index.html')
   >>> c2Pagelet
   <z3ext.layout.zcml.PageletClass from None ...>
 
-  >>> c2Pagelet.managers
+  >>> c2Pagelet.contexts
   (<z3ext.layout.TESTS.Context2 ...>,)
 
 
@@ -370,34 +388,63 @@
   u'index.html'
 
 
-Pagelet without name
+Typed pagelets
 
-  >>> class IMyPagelet1(interface.Interface):
+  >>> class IMyPagelet2(interface.Interface):
   ...     pass
 
-  >>> class IMyPagelet2(interface.Interface):
+  >>> class IMyPagelet3(interface.Interface):
   ...     pass
 
+  >>> from z3ext.layout.tests import ITestPagelet
+
+We need register types
+
+  >>> context = xmlconfig.string("""
+  ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
+  ...   <z3ext:pageletType name="pagelet"
+  ...       interface="z3ext.layout.interfaces.IPagelet" />
+  ...   <z3ext:pageletType name="myPagelet1"
+  ...       interface="z3ext.layout.tests.ITestPagelet" />
+  ...   <z3ext:pageletType name="myPagelet2"
+  ...       interface="z3ext.layout.TESTS.IMyPagelet2" />
+  ...   <z3ext:pageletType name="myPagelet3"
+  ...       interface="z3ext.layout.TESTS.IMyPagelet3" />
+  ... </configure>""", context)
+
   >>> template2 = os.path.join(temp_dir, 'pagelet2.pt')
   >>> open(template2, 'w').write('''<div>My pagelet2</div>''')
 
-  >>> from z3ext.layout.tests import ITestPagelet
+  >>> template3 = os.path.join(temp_dir, 'pagelet3.pt')
+  >>> open(template3, 'w').write('''<div>My pagelet3</div>''')
 
+  >>> template4 = os.path.join(temp_dir, 'pagelet4.pt')
+  >>> open(template4, 'w').write('''<div>My pagelet - default</div>''')
+
   >>> context = xmlconfig.string("""
   ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
   ...   <z3ext:pagelet
+  ...       for="*"
   ...       template="%s"
-  ...       provides="z3ext.layout.tests.ITestPagelet"
+  ...       type="myPagelet1"
   ...       permission="zope.Public" />
   ...   <z3ext:pagelet
+  ...       for="*"
   ...       template="%s"
-  ...       provides="z3ext.layout.TESTS.IMyPagelet2"
+  ...       type="myPagelet2"
   ...       permission="zope.Public" />
   ...   <z3ext:pagelet
+  ...       for="*"
   ...       template="%s"
+  ...       type="myPagelet3"
   ...       permission="zope.Public" />
+  ...   <z3ext:pagelet
+  ...       for="*"
+  ...       template="%s"
+  ...       type="pagelet"
+  ...       permission="zope.Public" />
   ... </configure>
-  ... """%(template, template2, template2), context)
+  ... """%(template, template2, template3, template4), context)
 
   >>> pagelet = component.queryMultiAdapter(
   ...     (object(), TestRequest()), ITestPagelet)
@@ -415,7 +462,7 @@
   <div>My pagelet2</div>
 
 
-Access nameless pagelet from view
+Access typed pagelet from view
 
   >>> pagelet = component.getMultiAdapter((object(), request), name='pagelet')
 
@@ -431,10 +478,10 @@
 by default IPagelet
 
   >>> print pagelet()
-  <div>My pagelet2</div>
+  <div>My pagelet - default</div>
 
   >>> print pagelet.publishTraverse(request, '')
-  <div>My pagelet2</div>
+  <div>My pagelet - default</div>
 
   >>> print pagelet.publishTraverse(
   ...     request, 'z3ext.layout.tests.ITestPagelet')
@@ -450,6 +497,65 @@
   >>> print pagelet.publishTraverse(request, 'testPageletType')
   <div>My pagelet</div>
 
+We can provide additional context for pagelet
+
+  >>> def getContexts(content):
+  ...     return Content()
+
+  >>> component.provideAdapter(
+  ...     getContexts, (IContent,), IPageletContext, name='myPagelet4')
+
+  >>> class IMyPagelet4(interface.Interface):
+  ...     pass
+
+  >>> provideInterface('myPagelet4', IMyPagelet4, IPageletType)
+
+  >>> template4 = os.path.join(temp_dir, 'pagelet4.pt')
+  >>> open(template4, 'w').write('''<div>My pagelet4</div>''')
+
+  >>> context = xmlconfig.string("""
+  ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
+  ...   <z3ext:pagelet
+  ...       for="* z3ext.layout.TESTS.IContent"
+  ...       template="%s"
+  ...       type="myPagelet4"
+  ...       permission="zope.Public" />
+  ... </configure>"""%template4, context)
+
+  >>> pagelet = component.getMultiAdapter((Content(), request), name='pagelet')
+  >>> print pagelet.publishTraverse(request, 'myPagelet4')
+  <div>My pagelet4</div>
+
+Or multiple contexts
+
+  >>> def getContexts2(content):
+  ...     return (Content(), Content())
+
+  >>> component.provideAdapter(
+  ...     getContexts2, (IContent,), IPageletContext, name='myPagelet5')
+
+  >>> class IMyPagelet5(interface.Interface):
+  ...     pass
+
+  >>> provideInterface('myPagelet5', IMyPagelet5, IPageletType)
+
+  >>> template5 = os.path.join(temp_dir, 'pagelet5.pt')
+  >>> open(template5, 'w').write('''<div>My pagelet5</div>''')
+
+  >>> context = xmlconfig.string("""
+  ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
+  ...   <z3ext:pagelet
+  ...       for="* z3ext.layout.TESTS.IContent z3ext.layout.TESTS.IContent"
+  ...       template="%s"
+  ...       type="myPagelet5"
+  ...       permission="zope.Public" />
+  ... </configure>"""%template5, context)
+
+  >>> pagelet = component.getMultiAdapter((Content(), request), name='pagelet')
+  >>> print pagelet.publishTraverse(request, 'myPagelet5')
+  <div>My pagelet5</div>
+
+
 We can register nameless pagelet only if provided interface is not
 inherited from IBrowserPublisher, because we can override
 IBrowserPublisher for content.
@@ -460,6 +566,7 @@
   >>> context = xmlconfig.string("""
   ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
   ...   <z3ext:pagelet
+  ...       for="*"
   ...       template="%s"
   ...       provides="z3ext.layout.TESTS.IWrongPageletInterface"
   ...       permission="zope.Public" />
@@ -483,8 +590,7 @@
   ... """%template, context)
 
 
-If we register named pagelet and provided interface provides IPageletType,
-also nameless adapter registered
+We can register typed pagelet with name
 
   >>> context = xmlconfig.string("""
   ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
@@ -492,19 +598,45 @@
   ...       name="test.html"
   ...       for="z3ext.layout.TESTS.IContent"
   ...       template="%s"
-  ...       provides="z3ext.layout.TESTS.ITestPagelet"
+  ...       type="myPagelet1"
   ...       permission="zope.Public" />
   ... </configure>
   ... """%template, context)
 
   >>> content = Content()
-  >>> pagelet1 = component.getMultiAdapter((content, request), name='test.html')
-  >>> pagelet2 = component.getMultiAdapter((content, request), ITestPagelet)
+  >>> pagelet = component.getMultiAdapter(
+  ...     (content, request), ITestPagelet, name='test.html')
 
-  >>> pagelet1.__class__ is pagelet2.__class__
-  True
+Pagelets with errors
 
+  >>> class PageletWithError(object):
+  ...     def render(self):
+  ...         raise Exception('Error')
 
+  >>> context = xmlconfig.string("""
+  ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
+  ...   <z3ext:pagelet
+  ...       for="z3ext.layout.TESTS.IContent"
+  ...       class="z3ext.layout.TESTS.PageletWithError"
+  ...       type="myPagelet2" />
+  ... </configure>
+  ... """, context)
+
+  >>> pagelet = component.getMultiAdapter((content, request), name='pagelet')
+  >>> pagelet.publishTraverse(request, 'myPagelet2')
+  Traceback (most recent call last):
+  ...
+  NotFound: ...
+
+  >>> pagelet('myPagelet2')
+  u''
+
+  >>> pagelet['myPagelet2']
+  Traceback (most recent call last):
+  ...
+  KeyError: 'myPagelet2'
+
+
 The TALES `pagelet` expression
 ==============================
 
@@ -625,7 +757,7 @@
     <body>
       <h1>My Web Page</h1>
       <div class="left-column">
-        <div>My pagelet2</div>
+        <div>My pagelet - default</div>
       </div>
       <div class="main">
         Content here
@@ -662,10 +794,131 @@
     <body>
       <h1>My Web Page</h1>
       <div class="left-column">
-  <BLANKLINE>
       </div>
       <div class="main">
         Content here
       </div>
     </body>
   </html>
+
+
+Pagelets with errors
+
+  >>> class PageletWithError(object):
+  ...     def render(self):
+  ...         raise Exception('Error')
+
+  >>> context = xmlconfig.string("""
+  ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
+  ...   <z3ext:pagelet
+  ...       for="z3ext.layout.TESTS.IContent"
+  ...       class="z3ext.layout.TESTS.PageletWithError"
+  ...       type="myPagelet2" />
+  ... </configure>
+  ... """, context)
+
+  >>> open(templateFileName, 'w').write('''
+  ... <html>
+  ...   <body>
+  ...     <h1>My Web Page</h1>
+  ...     <div class="left-column">
+  ...       <tal:block replace="structure pagelet:myPagelet2" />
+  ...     </div>
+  ...     <div class="main">
+  ...       Content here
+  ...     </div>
+  ...   </body>
+  ... </html>
+  ... ''')
+
+  >>> FrontPage = SimpleViewClass(templateFileName, name='error.html')
+  >>> component.provideAdapter(
+  ...     FrontPage,
+  ...     (IContent, interface.Interface), interface.Interface,
+  ...     name='error.html')
+
+  >>> view = component.getMultiAdapter((Content(), request), name='error.html')
+  >>> print view()
+    <html>
+      <body>
+        <h1>My Web Page</h1>
+        <div class="left-column">
+        </div>
+        <div class="main">
+          Content here
+        </div>
+      </body>
+    </html>
+
+Pagelet with extra context
+
+  >>> open(templateFileName, 'w').write('''
+  ... <html>
+  ...   <body>
+  ...     <h1>My Web Page</h1>
+  ...     <div class="left-column">
+  ...       <tal:block replace="structure pagelet:myPagelet4" />
+  ...     </div>
+  ...     <div class="main">
+  ...       Content here
+  ...     </div>
+  ...   </body>
+  ... </html>
+  ... ''')
+
+  >>> FrontPage = SimpleViewClass(templateFileName, name='extra4.html')
+  >>> component.provideAdapter(
+  ...     FrontPage,
+  ...     (IContent, interface.Interface), interface.Interface,
+  ...     name='extra4.html')
+
+  >>> view = component.getMultiAdapter((Content(), request), name='extra4.html')
+  >>> print view()
+  <html>
+    <body>
+      <h1>My Web Page</h1>
+      <div class="left-column">
+        <div>My pagelet4</div>
+      </div>
+      <div class="main">
+        Content here
+      </div>
+    </body>
+  </html>
+
+
+Pagelet with extra context
+
+  >>> open(templateFileName, 'w').write('''
+  ... <html>
+  ...   <body>
+  ...     <h1>My Web Page</h1>
+  ...     <div class="left-column">
+  ...       <tal:block replace="structure pagelet:myPagelet5" />
+  ...     </div>
+  ...     <div class="main">
+  ...       Content here
+  ...     </div>
+  ...   </body>
+  ... </html>
+  ... ''')
+
+  >>> FrontPage = SimpleViewClass(templateFileName, name='extra5.html')
+  >>> component.provideAdapter(
+  ...     FrontPage,
+  ...     (IContent, interface.Interface), interface.Interface,
+  ...     name='extra5.html')
+
+  >>> view = component.getMultiAdapter((Content(), request), name='extra5.html')
+  >>> print view()
+  <html>
+    <body>
+      <h1>My Web Page</h1>
+      <div class="left-column">
+        <div>My pagelet5</div>
+      </div>
+      <div class="main">
+        Content here
+      </div>
+    </body>
+  </html>

Modified: z3ext.layout/trunk/src/z3ext/layout/tales.py
===================================================================
--- z3ext.layout/trunk/src/z3ext/layout/tales.py	2008-12-21 20:08:09 UTC (rev 94230)
+++ z3ext.layout/trunk/src/z3ext/layout/tales.py	2008-12-21 23:05:17 UTC (rev 94231)
@@ -16,12 +16,10 @@
 $Id: tales.py 2720 2008-08-25 11:15:10Z fafhrd91 $
 """
 import logging, sys
-from zope.component import queryUtility
-from zope.component import queryMultiAdapter
 from zope.tales.expressions import StringExpr
+from zope.component import queryUtility, queryAdapter, queryMultiAdapter
 
-from interfaces import IPagelet, IPageletType
-from interfaces import IPageletManager, IPageletManagerType
+from interfaces import IPagelet, IPageletType, IPageletContext
 
 
 class TALESPageletExpression(StringExpr):
@@ -35,9 +33,7 @@
 
         # lookup pagelet
         if name:
-            iface = queryUtility(IPageletManagerType, name)
-            if iface is None:
-                iface = queryUtility(IPageletType, name)
+            iface = queryUtility(IPageletType, name)
 
             if iface is None:
                 try:
@@ -53,12 +49,15 @@
         if iface.providedBy(context):
             return context.render()
 
-        if IPageletManagerType.providedBy(iface):
-            manager = IPageletManager(context, None)
-            context = [context, request]
-            if type(manager) in (list, tuple):
-                context.extend(manager)
-            view = queryMultiAdapter(context, iface)
+        contexts = queryAdapter(context, IPageletContext, name)
+        if contexts is not None:
+            required = [context]
+            if type(contexts) in (list, tuple):
+                required.extend(contexts)
+            else:
+                required.append(contexts)
+            required.append(request)
+            view = queryMultiAdapter(required, iface)
         else:
             view = queryMultiAdapter((context, request), iface)
 

Modified: z3ext.layout/trunk/src/z3ext/layout/zcml.py
===================================================================
--- z3ext.layout/trunk/src/z3ext/layout/zcml.py	2008-12-21 20:08:09 UTC (rev 94230)
+++ z3ext.layout/trunk/src/z3ext/layout/zcml.py	2008-12-21 23:05:17 UTC (rev 94231)
@@ -18,6 +18,7 @@
 import os.path
 from zope import schema, interface, event
 from zope.schema.interfaces import IFromUnicode
+from zope.component import getUtility, queryUtility
 from zope.component.interface import provideInterface
 from zope.component.zcml import handler, adapter, utility
 from zope.security.checker import defineChecker, Checker, CheckerPublic
@@ -27,6 +28,7 @@
 from zope.publisher.interfaces.browser import IDefaultBrowserLayer
 from zope.app.component.metadirectives import IBasicViewInformation
 from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
+from zope.security.zcml import Permission
 
 from interfaces import IPagelet, IPageletType
 from interfaces import ILayout, ILayoutCreatedEvent
@@ -35,6 +37,20 @@
 from layout import Layout, LayoutTemplateFile
 
 
+class IPageletTypeDirective(interface.Interface):
+    """A directive to register a new pagelet type."""
+
+    name = schema.TextLine(
+        title = u'Name',
+        description = u'Pagelet type name',
+        required = True)
+
+    interface = GlobalInterface(
+        title = u'Interface',
+        description = u'Interface that is used as pagelet type.',
+        required = True)
+
+
 class IPageletDirective(IBasicViewInformation):
     """A directive to register a new pagelet.
 
@@ -42,29 +58,27 @@
     that are set as attributes on the pagelet after creation.
     """
 
-    for_ = GlobalObject(
+    for_ = Tokens(
         title = u"Context",
         description = u"The content interface or class this pagelet is for.",
-        required = False)
+        value_type = GlobalObject(missing_value=object()),
+        required = True)
 
     name = schema.TextLine(
         title = u"The name of the pagelet.",
         description = u"The name shows up in URLs/paths. For example 'foo'.",
         required = False)
 
-    manager = Tokens(
-        title = u"Additional managers.",
-        description = u"""A pagelet can adapt (for, layer). With managers pagelet can adats as (for, layer, manager1, manager2, manager3, ...)""",
+    type = Tokens(
+        title = u"Pagelet type.",
         required = False,
-        value_type = GlobalObject())
+        value_type = schema.TextLine())
 
     provides = Tokens(
         title = u"The interface this pagelets provides.",
-        description = u"""A pagelet can provide an interface.  This would be used for
-        views that support other views.""",
+        description = u"""A pagelet can provide an interface.  This would be used for views that support other views.""",
         required = False,
-        value_type = GlobalInterface(),
-        default = [IPagelet,])
+        value_type = GlobalInterface())
 
     class_ = GlobalObject(
         title=u"Class",
@@ -84,6 +98,13 @@
         default=u'',
         required=False)
 
+    layer = GlobalObject(
+        title = u'Layer',
+        description = u'The layer for which the template should be available',
+        required = False,
+        default = IDefaultBrowserLayer)
+
+
 # Arbitrary keys and values are allowed to be passed to the pagelet.
 IPageletDirective.setTaggedValue('keyword_arguments', True)
 
@@ -165,10 +186,14 @@
 ILayoutDirective.setTaggedValue('keyword_arguments', True)
 
 
+def pageletTypeDirective(_context, name, interface):
+    provideInterface(name, interface, IPageletType)
+
+
 def layoutDirective(
     _context, uid='', template='', for_=None, view=None, name = u'',
     layer = IDefaultBrowserLayer, provides = ILayout,
-    contentType='text/html', class_ = None, layout = '', 
+    contentType='text/html', class_ = None, layout = '',
     title='', description='', **kwargs):
 
     if not layout:
@@ -280,13 +305,18 @@
             uid, name, view, context, layer, layoutclass, keywords))
 
 
+Type = type
+
 # pagelet directive
-def pageletDirective(
-    _context, permission, for_=interface.Interface, name=u'', manager=(),
-    class_=None, layer=IDefaultBrowserLayer, provides=[IPagelet,],
-    allowed_interface=[], allowed_attributes=[],
-    template=u'', layout=u'', **kwargs):
+def pageletDirective(_context, for_, name=u'', type=(),
+                     class_=None, layer=IDefaultBrowserLayer, provides=[],
+                     allowed_interface=[], allowed_attributes=[],
+                     template=u'', layout=u'', permission='zope.Public', **kwargs):
 
+    provides = list(provides)
+    if IPagelet not in provides:
+        provides.append(IPagelet)
+
     # Security map dictionary
     required = {}
 
@@ -316,8 +346,14 @@
     else:
         bases = (BrowserPagelet,)
 
-    new_class = type('PageletClass from %s'%class_, bases, cdict)
+    new_class = Type('PageletClass from %s'%class_, bases, cdict)
 
+    # extend provides with type
+    for tp in type:
+        iface = queryUtility(IPageletType, tp)
+        if iface is not None:
+            provides.append(iface)
+
     # convert kwargs
     for iface in provides:
         for fname, field in schema.getFields(iface).items():
@@ -328,6 +364,7 @@
                 setattr(new_class, fname, field.fromUnicode(kwargs[fname]))
             else:
                 if field.required and not hasattr(new_class, fname):
+                    print provides, new_class, fname
                     raise ConfigurationError("Required field is missing", fname)
 
                 if not hasattr(new_class, fname):
@@ -357,9 +394,6 @@
 
     # prepare allowed interfaces and attributes
     allowed_interface.extend(provides)
-    if IPagelet not in provides:
-        allowed_interface.append(IPagelet)
-
     allowed_attributes.extend(kwargs.keys())
     allowed_attributes.extend(('__call__', 'browserDefault',
                                'update', 'render', 'publishTraverse'))
@@ -382,28 +416,39 @@
     defineChecker(new_class, Checker(required))
 
     # register pagelet
-    _context.action(
-        discriminator = ('z3ext.layout:registerPagelets', new_class),
-        callable = registerPagelets,
-        args = (for_, layer, new_class, manager, provides, name, _context.info))
+    for_.append(layer)
+    if type:
+        _context.action(
+            discriminator = ('z3ext.layout:registerPagelets', new_class),
+            callable = registerTypedPagelets,
+            args = (for_, new_class, type, name, _context.info))
+    else:
+        _context.action(
+            discriminator = ('z3ext.layout:registerPagelets', tuple(for_), layer, name),
+            callable = registerPagelets,
+            args = (for_, new_class, provides, name, _context.info))
 
 
-def registerPagelets(for_, layer, newClass, managers, provides, name, info):
-    if managers:
-        required = [for_, layer] + managers
-    else:
-        required = (for_, layer)
+def registerPagelets(required, newClass, provides, name, info):
+    handler('registerAdapter', newClass, required, IPagelet, name, info)
 
     for iface in provides:
+        if iface is IPagelet:
+            continue
+
         if IPageletType.providedBy(iface):
             handler('registerAdapter', newClass, required, iface, '', info)
-        else:
-            handler('registerAdapter', newClass, required, iface, name, info)
 
 
+def registerTypedPagelets(required, newClass, type, name, info):
+    for tp in type:
+        iface = getUtility(IPageletType, tp)
+        handler('registerAdapter', newClass, required, iface, name, info)
+
+
 def _handle_allowed_interface(
     _context, allowed_interface, permission, required):
-    # Allow access for all names defined by named interfaces 
+    # Allow access for all names defined by named interfaces
     if allowed_interface:
         for i in allowed_interface:
             _context.action(
@@ -423,8 +468,9 @@
             required[name] = permission
 
 def _handle_for(_context, for_):
-    if for_ is not None:
-        _context.action(
-            discriminator = None,
-            callable = provideInterface,
-            args = ('', for_))
+    for iface in for_:
+        if iface is not None:
+            _context.action(
+                discriminator = None,
+                callable = provideInterface,
+                args = ('', iface))



More information about the Checkins mailing list