[Zope3-checkins] SVN: Zope3/branches/roger-contentprovider/src/zope/contentprovider/ Added contentprovider package

Roger Ineichen roger at projekt01.ch
Thu Oct 6 12:24:44 EDT 2005


Log message for revision 38801:
  Added contentprovider package

Changed:
  A   Zope3/branches/roger-contentprovider/src/zope/contentprovider/
  A   Zope3/branches/roger-contentprovider/src/zope/contentprovider/DEPENDENCIES.cfg
  A   Zope3/branches/roger-contentprovider/src/zope/contentprovider/README.txt
  A   Zope3/branches/roger-contentprovider/src/zope/contentprovider/SETUP.cfg
  A   Zope3/branches/roger-contentprovider/src/zope/contentprovider/__init__.py
  A   Zope3/branches/roger-contentprovider/src/zope/contentprovider/configure.zcml
  A   Zope3/branches/roger-contentprovider/src/zope/contentprovider/directives.txt
  A   Zope3/branches/roger-contentprovider/src/zope/contentprovider/interfaces.py
  A   Zope3/branches/roger-contentprovider/src/zope/contentprovider/manager.py
  A   Zope3/branches/roger-contentprovider/src/zope/contentprovider/meta.zcml
  A   Zope3/branches/roger-contentprovider/src/zope/contentprovider/metaconfigure.py
  A   Zope3/branches/roger-contentprovider/src/zope/contentprovider/metadirectives.py
  A   Zope3/branches/roger-contentprovider/src/zope/contentprovider/tales.py
  A   Zope3/branches/roger-contentprovider/src/zope/contentprovider/zope.contentprovider-configure.zcml
  A   Zope3/branches/roger-contentprovider/src/zope/contentprovider/zope.contentprovider-meta.zcml

-=-
Added: Zope3/branches/roger-contentprovider/src/zope/contentprovider/DEPENDENCIES.cfg
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/contentprovider/DEPENDENCIES.cfg	2005-10-06 16:24:10 UTC (rev 38800)
+++ Zope3/branches/roger-contentprovider/src/zope/contentprovider/DEPENDENCIES.cfg	2005-10-06 16:24:43 UTC (rev 38801)
@@ -0,0 +1,8 @@
+zope.app
+zope.component
+zope.configuration
+zope.interface
+zope.publisher
+zope.schema
+zope.security
+zope.tales


Property changes on: Zope3/branches/roger-contentprovider/src/zope/contentprovider/DEPENDENCIES.cfg
___________________________________________________________________
Name: svn:eol-style
   + native

Added: Zope3/branches/roger-contentprovider/src/zope/contentprovider/README.txt
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/contentprovider/README.txt	2005-10-06 16:24:10 UTC (rev 38800)
+++ Zope3/branches/roger-contentprovider/src/zope/contentprovider/README.txt	2005-10-06 16:24:43 UTC (rev 38801)
@@ -0,0 +1,660 @@
+========
+Viewlets
+========
+
+This package provides a framework to develop componentized Web GUI
+applications. Instead of describing the content of a page using a single
+template or static system of templates and METAL macros, page regions can be
+defined and are filled dynamically with content (viewlets) based on the setup
+of the application.
+
+
+Getting Started
+---------------
+
+Let's say we have simple two-column page. In the smaller left column, there
+are boxes filled with various pieces of information, such as news, latest
+software releases, etc. This content, however, generally changes depending on
+the view and the object being viewed.
+
+
+Regions
+~~~~~~~
+
+Instead of hard-coding the pieces of content in the left column in the page
+template or using macros, we simply define a region for it. Regions are
+interfaces that act as content placeholders. Here is a common setup:
+
+  >>> import zope.interface
+  >>> class ILeftColumn(zope.interface.Interface):
+  ...     '''The left column of a Web site.'''
+
+  >>> from zope.app.viewlet import interfaces
+  >>> zope.interface.directlyProvides(ILeftColumn, interfaces.IRegion)
+
+  >>> import zope.component
+  >>> zope.component.provideUtility(ILeftColumn, interfaces.IRegion,
+  ...                               'webpage.LeftColumn')
+
+It is important that the region interface provides the ``IRegion``
+interface and that it is registered as a utility providing
+``IRegion``. If omitted, the framework will be unable to find the
+region later.
+
+
+Viewlet
+~~~~~~~
+
+Viewlets are snippets of content that can be placed into a region, such as the
+one defined above. As the name suggests, viewlets are views, but they are
+qualified not only by the context object and the request, but also the view
+they appear in. Also, the viewlet must *provide* the region interface it is
+filling; we will demonstrate a more advanced example later, where the purpose
+of this requirement becomes clear.
+
+Like regular views, viewlets can either use page templates to provide content
+or provide a simple ``__call__`` method. For our first viewlet, let's develop
+a more commonly used page-template-driven viewlet:
+
+  >>> import os, tempfile
+  >>> temp_dir = tempfile.mkdtemp()
+
+  >>> viewletFileName = os.path.join(temp_dir, 'viewlet.pt')
+  >>> open(viewletFileName, 'w').write('''
+  ...         <div class="box">
+  ...           <tal:block replace="viewlet/title" />
+  ...         </div>
+  ... ''')
+
+  >>> class ViewletBase(object):
+  ...     def title(self):
+  ...         return 'Viewlet Title'
+
+As you can see, the viewlet Python object is known as ``viewlet`` inside the
+template, while the view object is still available as ``view``. Next we build
+and register the viewlet using a special helper function:
+
+  # Create the viewlet class
+  >>> from zope.app.viewlet import viewlet
+  >>> Viewlet = viewlet.SimpleViewletClass(
+  ...     viewletFileName, bases=(ViewletBase,), name='viewlet')
+
+  # Generate a viewlet checker
+  >>> from zope.security.checker import NamesChecker, defineChecker
+  >>> viewletChecker = NamesChecker(('__call__', 'weight', 'title',))
+  >>> defineChecker(Viewlet, viewletChecker)
+
+  # Register the viewlet with component architecture
+  >>> from zope.publisher.interfaces.browser import IDefaultBrowserLayer
+  >>> from zope.app.publisher.interfaces.browser import IBrowserView
+  >>> zope.component.provideAdapter(
+  ...     Viewlet,
+  ...     (zope.interface.Interface, IDefaultBrowserLayer, IBrowserView),
+  ...     ILeftColumn,
+  ...     name='viewlet')
+
+As you can see from the security checker registration, a viewlet provides also
+a weight, which acts as a hint to determine the order in which the viewlets of
+a region should be displayed. The view the viewlet is used in can also be
+accessed via the ``view`` attribute of the viewlet class.
+
+
+Creating the View
+~~~~~~~~~~~~~~~~~
+
+Now that we have a region with a viewlet registered for it, let's use it by
+creating the front page of our Web Site:
+
+  >>> templateFileName = os.path.join(temp_dir, 'template.pt')
+  >>> open(templateFileName, 'w').write('''
+  ... <html>
+  ...   <body>
+  ...     <h1>My Web Page</h1>
+  ...     <div class="left-column">
+  ...       <div class="column-item"
+  ...            tal:repeat="viewlet viewlets:webpage.LeftColumn">
+  ...         <tal:block replace="structure viewlet" />
+  ...       </div>
+  ...     </div>
+  ...     <div class="main">
+  ...       Content here
+  ...     </div>
+  ...   </body>
+  ... </html>
+  ... ''')
+
+and registering it as a view (browser page) for all objects:
+
+  >>> from zope.app.pagetemplate.simpleviewclass import SimpleViewClass
+  >>> FrontPage = SimpleViewClass(templateFileName, name='main.html')
+
+  >>> zope.component.provideAdapter(
+  ...     FrontPage,
+  ...     (zope.interface.Interface, IDefaultBrowserLayer),
+  ...     zope.interface.Interface,
+  ...     name='main.html')
+
+That is all of the setup. Let's now render the view.
+
+
+Using the View
+~~~~~~~~~~~~~~
+
+Let's create a content object that can be viewed:
+
+  >>> class Content(object):
+  ...     zope.interface.implements(zope.interface.Interface)
+
+  >>> content = Content()
+
+Finally we look up the view and render it:
+
+  >>> from zope.publisher.browser import TestRequest
+  >>> request = TestRequest()
+
+  >>> view = zope.component.getMultiAdapter((content, request),
+  ...                                       name='main.html')
+  >>> print view().strip()
+  <html>
+    <body>
+      <h1>My Web Page</h1>
+      <div class="left-column">
+        <div class="column-item">
+  <BLANKLINE>
+          <div class="box">
+            Viewlet Title
+          </div>
+  <BLANKLINE>
+        </div>
+      </div>
+      <div class="main">
+        Content here
+      </div>
+    </body>
+  </html>
+
+
+Class-driven Viewlets
+~~~~~~~~~~~~~~~~~~~~~
+
+Let's now have a look into the steps involved to create a viewlet class from
+scratch. We also want to ensure that this viewlet always displays second and
+not before the first one. Here is a most simple implementation:
+
+  >>> from zope.app.publisher.browser import BrowserView
+  >>> class InfoViewlet(BrowserView):
+  ...     zope.interface.implements(interfaces.IViewlet, ILeftColumn)
+  ...     weight = 1
+  ...
+  ...     def __init__(self, context, request, view):
+  ...         super(InfoViewlet, self).__init__(context, request)
+  ...         self.view = view
+  ...
+  ...     def __call__(self):
+  ...         return u'<h3>Some Information.</h3>'
+
+  >>> defineChecker(InfoViewlet, viewletChecker)
+
+  >>> zope.component.provideAdapter(
+  ...     InfoViewlet,
+  ...     (zope.interface.Interface, IDefaultBrowserLayer, IBrowserView),
+  ...     ILeftColumn,
+  ...     name='infoViewlet')
+
+
+Note that you would commonly not state in the class itself that it
+implements a particular region, since it is usually done by the ZCML
+directive, which is introduced in `directives.zcml`.
+
+When we now render the view, the content of our info viewlet appears as well:
+
+  >>> print view().strip()
+  <html>
+    <body>
+      <h1>My Web Page</h1>
+      <div class="left-column">
+        <div class="column-item">
+  <BLANKLINE>
+          <div class="box">
+            Viewlet Title
+          </div>
+  <BLANKLINE>
+        </div>
+        <div class="column-item">
+          <h3>Some Information.</h3>
+        </div>
+      </div>
+      <div class="main">
+        Content here
+      </div>
+    </body>
+  </html>
+
+
+Changing the Weight
+~~~~~~~~~~~~~~~~~~~
+
+Let's ensure that the weight really affects the order of the viewlets. If we
+change the weights around,
+
+  >>> InfoViewlet.weight = 0
+  >>> Viewlet._weight = 1
+
+the order of the left column in the page template should change:
+
+  >>> print view().strip()
+  <html>
+    <body>
+      <h1>My Web Page</h1>
+      <div class="left-column">
+        <div class="column-item">
+          <h3>Some Information.</h3>
+        </div>
+        <div class="column-item">
+  <BLANKLINE>
+          <div class="box">
+            Viewlet Title
+          </div>
+  <BLANKLINE>
+        </div>
+      </div>
+      <div class="main">
+        Content here
+      </div>
+    </body>
+  </html>
+
+
+Looking Up a Viewlet by Name
+----------------------------
+
+In some cases you want to be able to look up a particular viewlet for a region,
+given a context and a view. For this use case, you can simply use a second
+TALES namespace called ``viewlet`` that selects the viewlet using the
+expression ``<path to region>/<viewlet name>``.
+
+Since everything else is already set up, we can simply register a new view:
+
+  >>> template2FileName = os.path.join(temp_dir, 'template2.pt')
+  >>> open(template2FileName, 'w').write('''
+  ... <html>
+  ...   <body>
+  ...     <h1>My Web Page - Take 2</h1>
+  ...     <div class="left-column">
+  ...       <div class="column-item">
+  ...         <tal:block
+  ...           replace="structure viewlet:webpage.LeftColumn/viewlet" />
+  ...       </div>
+  ...     </div>
+  ...   </body>
+  ... </html>
+  ... ''')
+
+  >>> SecondPage = SimpleViewClass(template2FileName, name='second.html')
+  >>> zope.component.provideAdapter(
+  ...     SecondPage,
+  ...     (zope.interface.Interface, IDefaultBrowserLayer),
+  ...     ILeftColumn,
+  ...     name='second.html')
+
+  >>> view = zope.component.getMultiAdapter((content, request),
+  ...                                       name='second.html')
+  >>> print view().strip()
+  <html>
+    <body>
+      <h1>My Web Page - Take 2</h1>
+      <div class="left-column">
+        <div class="column-item">
+  <BLANKLINE>
+          <div class="box">
+            Viewlet Title
+          </div>
+  <BLANKLINE>
+        </div>
+      </div>
+    </body>
+  </html>
+
+Note that this namespace returns the rendered viewlet and not the viewlet
+view, like the ``viewlets`` TALES namespace.
+
+
+Region Schemas
+--------------
+
+In some use cases you want to be able to provide variables to a viewlet that
+cannot be accessed via the view class or the context object. They are usually
+variables that are defined by the view template. Since we do not just want all
+of the view's template variables to be available (because it would be implicit
+and not all viewlets must be called from within page templates), we must
+specify the variables that the environment of the viewlet provides in the slot
+interface as fields.
+
+Let's say in your view you want to display a list of objects and you would
+like to allow various columns that are controlled by viewlets:
+
+  >>> class ObjectItems(object):
+  ...
+  ...     def objectInfo(self):
+  ...         return [{'name': 'README.txt', 'size': '1.2kB'},
+  ...                 {'name': 'logo.png', 'size': '100 x 100'}]
+
+  >>> contentsFileName = os.path.join(temp_dir, 'items.pt')
+  >>> open(contentsFileName, 'w').write('''
+  ... <html>
+  ...   <body>
+  ...     <h1>Contents</h1>
+  ...     <table>
+  ...       <tr tal:repeat="item view/objectInfo">
+  ...         <td tal:repeat="column viewlets:webpage.ObjectInfoColumn"
+  ...             tal:content="structure column" />
+  ...       </tr>
+  ...     </table>
+  ...   </body>
+  ... </html>
+  ... ''')
+
+  >>> Contents = SimpleViewClass(contentsFileName, bases=(ObjectItems,),
+  ...                            name='contents.html')
+
+  >>> zope.component.provideAdapter(
+  ...     Contents,
+  ...     (zope.interface.Interface, IDefaultBrowserLayer),
+  ...     zope.interface.Interface,
+  ...     name='contents.html')
+
+As you can see from the page template code, in order for the viewlets to be
+of any use, they need access to the ``item`` variable as defined in the page
+template. Thus, the region definition will state that the viewlet must have
+access to a variable called ``item`` that contains the value of ``item`` in
+the page template:
+
+  >>> import zope.schema
+  >>> class IObjectInfoColumn(zope.interface.Interface):
+  ...     '''Place holder for the columns of a contents view.'''
+  ...
+  ...     item = zope.schema.Dict(
+  ...         title=u'Object info dictionary',
+  ...         required=True)
+
+  >>> zope.interface.directlyProvides(
+  ...     IObjectInfoColumn, interfaces.IRegion)
+
+  >>> zope.component.provideUtility(
+  ...     IObjectInfoColumn, interfaces.IRegion,
+  ...     'webpage.ObjectInfoColumn')
+
+
+Next we implement two very simple viewlets, one displaying the name
+
+  >>> class NameColumnViewlet(BrowserView):
+  ...     zope.interface.implements(interfaces.IViewlet, IObjectInfoColumn)
+  ...     weight = 0
+  ...
+  ...     def __init__(self, context, request, view):
+  ...         super(NameColumnViewlet, self).__init__(context, request)
+  ...         self.view = view
+  ...
+  ...     def __call__(self):
+  ...         return '<b>' + self.item['name'] + '</b>'
+
+  >>> defineChecker(NameColumnViewlet, viewletChecker)
+
+  >>> zope.component.provideAdapter(
+  ...     NameColumnViewlet,
+  ...     (zope.interface.Interface, IDefaultBrowserLayer, IBrowserView),
+  ...     IObjectInfoColumn,
+  ...     name='name')
+
+... and the other displaying the size of the of objects in the list:
+
+  >>> class SizeColumnViewlet(BrowserView):
+  ...     zope.interface.implements(interfaces.IViewlet, IObjectInfoColumn)
+  ...     weight = 1
+  ...
+  ...     def __init__(self, context, request, view):
+  ...         super(SizeColumnViewlet, self).__init__(context, request)
+  ...         self.view = view
+  ...
+  ...     def __call__(self):
+  ...         return self.item['size']
+
+  >>> defineChecker(SizeColumnViewlet, viewletChecker)
+
+  >>> zope.component.provideAdapter(
+  ...     SizeColumnViewlet,
+  ...     (zope.interface.Interface, IDefaultBrowserLayer, IBrowserView),
+  ...     IObjectInfoColumn,
+  ...     name='size')
+
+
+Now let's have a look at the resulting view:
+
+  >>> view = zope.component.getMultiAdapter(
+  ...     (content, request), name='contents.html')
+  >>> print view().strip()
+  <html>
+    <body>
+      <h1>Contents</h1>
+      <table>
+        <tr>
+          <td><b>README.txt</b></td>
+          <td>1.2kB</td>
+        </tr>
+        <tr>
+          <td><b>logo.png</b></td>
+          <td>100 x 100</td>
+        </tr>
+      </table>
+    </body>
+  </html>
+
+
+Viewlet Managers
+----------------
+
+Until now we have always asserted that the viewlets returned by the TALES
+namespaces ``viewlets`` and ``viewlet`` always find the viewlets in the
+component architecture and then return them ordered by weight. This, however,
+is just the default policy. We could also register an alternative policy that
+has different rules on looking up, filtering and sorting the viewlets. The
+objects that implement those policies are known as viewlet managers.
+
+Viewlet managers are usually implemented as adapters from the context, request
+and view to the ``IViewletManager`` interface. They must implement two
+methods. The first one is ``getViewlets(region)``, which returns a list of
+viewlets for the specified region. The region argument is the region
+interface. The second method is ``getViewlet(name, region)``, which allows you
+to look up a specific viewlet by name and region.
+
+
+The Default Viewlet Manager
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Let's first have a close look at the default view manager, whose functionality
+we took for granted until now. Initializing the manager
+
+  >>> from zope.app.viewlet import manager
+  >>> defaultManager = manager.DefaultViewletManager(
+  ...     content, request, FrontPage(content, request))
+
+we can now get a list of viewlets:
+
+  >>> defaultManager.getViewlets(ILeftColumn)
+  [<InfoViewlet object at ...>,
+   <zope.app.viewlet.viewlet.SimpleViewletClass from ...viewlet.pt object ...>]
+
+The default manager also filters out all viewlets for which the current user
+is not authorized. So, if I create a viewlet that has no security
+declarations, then it is ignored:
+
+  >>> class UnauthorizedViewlet(Viewlet):
+  ...     pass
+
+  # Register the access to a permission that does not exist.
+  >>> unauthorizedChecker = NamesChecker(('__call__', 'weight', 'title',),
+  ...                                    permission_id='Unauthorized')
+  >>> defineChecker(UnauthorizedViewlet, unauthorizedChecker)
+
+  >>> zope.component.provideAdapter(
+  ...     UnauthorizedViewlet,
+  ...     (zope.interface.Interface, IDefaultBrowserLayer, IBrowserView),
+  ...     ILeftColumn,
+  ...     name='unauthorized')
+
+  >>> len(defaultManager.getViewlets(ILeftColumn))
+  2
+
+Also, when you try to look up the unauthorized viewlet by name you will get an
+exception telling you that you have insufficient priviledges to access the
+viewlet:
+
+  >>> defaultManager.getViewlet('unauthorized', ILeftColumn)
+  Traceback (most recent call last):
+  ...
+  Unauthorized: You are not authorized to access the viewlet
+                called `unauthorized`.
+
+When looking for a particular viewlet, you also get an exception, if none is
+found:
+
+  >>> defaultManager.getViewlet('unknown', ILeftColumn)
+  Traceback (most recent call last):
+  ...
+  ComponentLookupError: 'No viewlet with name `unknown` found.'
+
+
+An Alternative Viewlet Manager
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Let's now imagine that we would like to allow the user to choose the columns
+for the contents view. Here it would not be enough to implement a condition as
+part of the viewlet class, since the TD tag appearance is not controlled by
+the viewlet itself. In those cases it is best to implement a custom viewlet
+manager that only returns the viewlets that are specified in an option:
+
+  >>> showColumns = ['name', 'size']
+
+So our custom viewlet manager could look something like this:
+
+  >>> class ContentsViewletManager(manager.DefaultViewletManager):
+  ...
+  ...     def getViewlets(self, region):
+  ...         viewlets = zope.component.getAdapters(
+  ...             (self.context, self.request, self.view), region)
+  ...         viewlets = [(name, viewlet) for name, viewlet in viewlets
+  ...                     if name in showColumns]
+  ...         viewlets.sort(lambda x, y: cmp(showColumns.index(x[0]),
+  ...                                        showColumns.index(y[0])))
+  ...         return [viewlet for name, viewlet in viewlets]
+
+We just have to register it as an adapter:
+
+  >>> zope.component.provideAdapter(
+  ...     ContentsViewletManager,
+  ...     (zope.interface.Interface, IDefaultBrowserLayer, IBrowserView),
+  ...     interfaces.IViewletManager)
+
+  >>> view = zope.component.getMultiAdapter(
+  ...     (content, request), name='contents.html')
+  >>> print view().strip()
+  <html>
+    <body>
+      <h1>Contents</h1>
+      <table>
+        <tr>
+          <td><b>README.txt</b></td>
+          <td>1.2kB</td>
+        </tr>
+        <tr>
+          <td><b>logo.png</b></td>
+          <td>100 x 100</td>
+        </tr>
+      </table>
+    </body>
+  </html>
+
+But if I turn the order around,
+
+  >>> showColumns = ['size', 'name']
+
+it will provide the columns in a different order as well:
+
+  >>> print view().strip()
+  <html>
+    <body>
+      <h1>Contents</h1>
+      <table>
+        <tr>
+          <td>1.2kB</td>
+          <td><b>README.txt</b></td>
+        </tr>
+        <tr>
+          <td>100 x 100</td>
+          <td><b>logo.png</b></td>
+        </tr>
+      </table>
+    </body>
+  </html>
+
+On the other hand, it is as easy to remove a column:
+
+  >>> showColumns = ['name']
+  >>> print view().strip()
+  <html>
+    <body>
+      <h1>Contents</h1>
+      <table>
+        <tr>
+          <td><b>README.txt</b></td>
+        </tr>
+        <tr>
+          <td><b>logo.png</b></td>
+        </tr>
+      </table>
+    </body>
+  </html>
+
+
+UML Diagram
+-----------
+
+                      _________
+                     |         |
+                     | Context |
+                     |_________|
+                          ^
+                          |
+                          |*
+                      ____|____
+                     |         |
+                     |   View  |
+                     |_________|
+                          |
+                          |
+                          |* a view is composed of regions
+                      ____v____
+                     |         |
+                     |  Region |
+                     |_________|
+                          |
+                          |
+                          |* a region contains a list of viewlets
+                      ____v____
+                     |         |
+                     | Viewlet |
+                     |_________|
+
+Natively, Zope 3 allows us to associate one or more views to a given
+object. Those views are either registered for the provided interfaces of the
+object or the object itself. In a view, usually a template, one can define
+zero or more view regions. Upon rendering time, those view regions are populated
+with the viewlets that have been assigned to the region.
+
+
+Cleanup
+-------
+
+  >>> import shutil
+  >>> shutil.rmtree(temp_dir)
+


Property changes on: Zope3/branches/roger-contentprovider/src/zope/contentprovider/README.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: Zope3/branches/roger-contentprovider/src/zope/contentprovider/SETUP.cfg
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/contentprovider/SETUP.cfg	2005-10-06 16:24:10 UTC (rev 38800)
+++ Zope3/branches/roger-contentprovider/src/zope/contentprovider/SETUP.cfg	2005-10-06 16:24:43 UTC (rev 38801)
@@ -0,0 +1,5 @@
+# Tell zpkg how to install the ZCML slugs.
+
+<data-files zopeskel/etc/package-includes>
+  zope.app.viewlet-*.zcml
+</data-files>


Property changes on: Zope3/branches/roger-contentprovider/src/zope/contentprovider/SETUP.cfg
___________________________________________________________________
Name: svn:eol-style
   + native

Added: Zope3/branches/roger-contentprovider/src/zope/contentprovider/__init__.py
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/contentprovider/__init__.py	2005-10-06 16:24:10 UTC (rev 38800)
+++ Zope3/branches/roger-contentprovider/src/zope/contentprovider/__init__.py	2005-10-06 16:24:43 UTC (rev 38801)
@@ -0,0 +1,17 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Viewlet exceptions
+
+$Id$
+"""


Property changes on: Zope3/branches/roger-contentprovider/src/zope/contentprovider/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: Zope3/branches/roger-contentprovider/src/zope/contentprovider/configure.zcml
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/contentprovider/configure.zcml	2005-10-06 16:24:10 UTC (rev 38800)
+++ Zope3/branches/roger-contentprovider/src/zope/contentprovider/configure.zcml	2005-10-06 16:24:43 UTC (rev 38801)
@@ -0,0 +1,19 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:tales="http://namespaces.zope.org/tales"
+    i18n_domain="zope"
+    >
+
+  <interface interface=".interfaces.ITALESViewletsExpression" />
+  <tales:expressiontype
+      name="viewlets"
+      handler=".tales.TALESViewletsExpression"
+      />
+
+  <interface interface=".interfaces.ITALESViewletExpression" />
+  <tales:expressiontype
+      name="viewlet"
+      handler=".tales.TALESViewletExpression"
+      />
+
+</configure>
\ No newline at end of file


Property changes on: Zope3/branches/roger-contentprovider/src/zope/contentprovider/configure.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: Zope3/branches/roger-contentprovider/src/zope/contentprovider/directives.txt
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/contentprovider/directives.txt	2005-10-06 16:24:10 UTC (rev 38800)
+++ Zope3/branches/roger-contentprovider/src/zope/contentprovider/directives.txt	2005-10-06 16:24:43 UTC (rev 38801)
@@ -0,0 +1,183 @@
+=========================
+The ``viewlet`` Directive
+=========================
+
+The viewlet directive allows you to quickly register a new paglet without much
+hassle, like it was shown in the `README.txt` file. Here is a sample
+directive::
+
+  >>> from zope.configuration import xmlconfig
+  >>> context = xmlconfig.string('''
+  ... <configure i18n_domain="zope">
+  ...   <include package="zope.app.viewlet" file="meta.zcml" />
+  ... </configure>
+  ... ''')
+
+  >>> context = xmlconfig.string('''
+  ... <configure xmlns="http://namespaces.zope.org/browser" i18n_domain="zope"
+  ...            package="zope.app.viewlet.tests">
+  ...   <viewlet
+  ...       name="testviewlet"
+  ...       for="*"
+  ...       region=".test_doc.ITestRegion"
+  ...       template="test_viewlet.pt"
+  ...       permission="zope.Public"
+  ...       />
+  ... </configure>
+  ... ''', context=context)
+
+As you can see, the directive looks very similar to the page directive and you
+are right. The viewlet directive does not permit you to specify a `menu` and
+`title`, since it is not sensible to have a menu item for a viewlet. However,
+it does support two more qualifying attributes, `view` and `region`. While view
+is nearly never specified (very common default), the `region` attribute *must*
+be specified. An optional `weight` attribute (not shown above) allows you to
+change the position of a particular viewlet relative to the others. The
+default value is zero.
+
+If we now look into the adapter registry, we will find the viewlet:
+
+  >>> class Content(object):
+  ...     pass
+  >>> content = Content()
+
+  >>> from zope.publisher.browser import TestRequest
+  >>> request = TestRequest()
+
+  >>> from zope.app.publisher.browser import BrowserView
+  >>> view = BrowserView(content, request)
+
+  >>> import zope.interface
+  >>> from zope.app.viewlet.tests.test_doc import ITestRegion
+
+  >>> import zope.component
+  >>> from zope.app.viewlet.interfaces import IViewlet
+  >>> viewlet = zope.component.getMultiAdapter(
+  ...     (content, request, view), ITestRegion, name='testviewlet')
+  >>> viewlet()
+  u'<div>testviewlet macro content</div>\n'
+
+Let's now ensure that we can also specify a viewlet class:
+
+  >>> context = xmlconfig.string('''
+  ... <configure xmlns="http://namespaces.zope.org/browser" i18n_domain="zope"
+  ...            package="zope.app.viewlet.tests">
+  ...   <viewlet
+  ...       name="testviewlet2"
+  ...       for="*"
+  ...       region=".test_doc.ITestRegion"
+  ...       template="test_viewlet.pt"
+  ...       class=".test_doc.TestViewlet"
+  ...       permission="zope.Public"
+  ...       />
+  ... </configure>
+  ... ''', context=context)
+
+  >>> viewlet = zope.component.getMultiAdapter(
+  ...     (content, request, view), ITestRegion, name='testviewlet2')
+  >>> viewlet()
+  u'<div>testviewlet macro content</div>\n'
+
+Okay, so the template-driven cases wrok. But just specifying a class should
+also work:
+
+  >>> context = xmlconfig.string('''
+  ... <configure xmlns="http://namespaces.zope.org/browser" i18n_domain="zope"
+  ...            package="zope.app.viewlet.tests">
+  ...   <viewlet
+  ...       name="testviewlet3"
+  ...       for="*"
+  ...       region=".test_doc.ITestRegion"
+  ...       class=".test_doc.TestViewlet2"
+  ...       permission="zope.Public"
+  ...       />
+  ... </configure>
+  ... ''', context=context)
+
+  >>> viewlet = zope.component.getMultiAdapter(
+  ...     (content, request, view), ITestRegion, name='testviewlet3')
+  >>> viewlet()
+  u'called'
+
+It should also be possible to specify an alternative attribute of the class to
+be rendered upon calling the viewlet:
+
+  >>> context = xmlconfig.string('''
+  ... <configure xmlns="http://namespaces.zope.org/browser" i18n_domain="zope"
+  ...            package="zope.app.viewlet.tests">
+  ...   <viewlet
+  ...       name="testviewlet4"
+  ...       for="*"
+  ...       region=".test_doc.ITestRegion"
+  ...       class=".test_doc.TestViewlet"
+  ...       attribute="doSomething"
+  ...       permission="zope.Public"
+  ...       />
+  ... </configure>
+  ... ''', context=context)
+
+  >>> viewlet = zope.component.getMultiAdapter(
+  ...     (content, request, view), ITestRegion, name='testviewlet4')
+  >>> viewlet()
+  u'something'
+
+
+Error Scenarios
+---------------
+
+Neither the class or template have been specified:
+
+  >>> context = xmlconfig.string('''
+  ... <configure xmlns="http://namespaces.zope.org/browser" i18n_domain="zope"
+  ...            package="zope.app.viewlet.tests">
+  ...   <viewlet
+  ...       name="testviewlet"
+  ...       region=".test_doc.ITestRegion"
+  ...       permission="zope.Public"
+  ...       />
+  ... </configure>
+  ... ''', context=context)
+  Traceback (most recent call last):
+  ...
+  ZopeXMLConfigurationError: File "<string>", line 4.2-8.8
+      ConfigurationError: Must specify a class or template
+
+The specified attribute is not ``__call__``, but also a template has been
+specified:
+
+  >>> context = xmlconfig.string('''
+  ... <configure xmlns="http://namespaces.zope.org/browser" i18n_domain="zope"
+  ...            package="zope.app.viewlet.tests">
+  ...   <viewlet
+  ...       name="testviewlet"
+  ...       region=".test_doc.ITestRegion"
+  ...       template="test_viewlet.pt"
+  ...       attribute="faux"
+  ...       permission="zope.Public"
+  ...       />
+  ... </configure>
+  ... ''', context=context)
+  Traceback (most recent call last):
+  ...
+  ZopeXMLConfigurationError: File "<string>", line 4.2-10.8
+      ConfigurationError: Attribute and template cannot be used together.
+
+Now, we are not specifying a template, but a class that does not have the
+specified attribute:
+
+  >>> context = xmlconfig.string('''
+  ... <configure xmlns="http://namespaces.zope.org/browser" i18n_domain="zope"
+  ...            package="zope.app.viewlet.tests">
+  ...   <viewlet
+  ...       name="testviewlet"
+  ...       region=".test_doc.ITestRegion"
+  ...       class=".test_doc.TestViewlet"
+  ...       attribute="faux"
+  ...       permission="zope.Public"
+  ...       />
+  ... </configure>
+  ... ''', context=context)
+  Traceback (most recent call last):
+  ...
+  ZopeXMLConfigurationError: File "<string>", line 4.2-10.8
+    ConfigurationError: The provided class doesn't have the specified attribute


Property changes on: Zope3/branches/roger-contentprovider/src/zope/contentprovider/directives.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: Zope3/branches/roger-contentprovider/src/zope/contentprovider/interfaces.py
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/contentprovider/interfaces.py	2005-10-06 16:24:10 UTC (rev 38800)
+++ Zope3/branches/roger-contentprovider/src/zope/contentprovider/interfaces.py	2005-10-06 16:24:43 UTC (rev 38801)
@@ -0,0 +1,115 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Viewlet interfaces
+
+$Id$
+"""
+__docformat__ = 'restructuredtext'
+
+import zope.component
+import zope.interface
+import zope.schema
+from zope.tales import interfaces
+
+from zope.app.i18n import ZopeMessageIDFactory as _
+from zope.app.publisher.interfaces.browser import IBrowserView
+
+
+class ViewletRegionLookupError(zope.component.ComponentLookupError):
+    """Viewlet region object not found."""
+
+
+class IRegion(zope.interface.interfaces.IInterface):
+    """Type interface for viewlet regions.
+
+    Region interfaces specify the environment variables that are available to
+    the viewlet. How those variables are provided is up to the implementation.
+    """
+
+
+class IViewlet(IBrowserView):
+    """A piece of content of a page.
+
+    Viewlets are objects that can fill the region specified in a page, most
+    often page templates. They are selected by the context, request and
+    view. All viewlets of a particular region must also provide the region
+    interface.
+    """
+
+    view = zope.interface.Attribute(
+        'The view the viewlet is used in.')
+
+    weight = zope.schema.Int(
+        title=_(u'weight'),
+        description=_(u"""
+            Key for sorting viewlets if the viewlet collector is supporting
+            this sort mechanism."""),
+        required=False,
+        default=0)
+
+
+class IViewletManager(zope.interface.Interface):
+    """An object that provides access to the viewlets.
+
+    The viewlets are of a particular context, request and view configuration
+    are accessible via a particular manager instance. Viewlets are looked up
+    by the region they appear in and the name of the viewlet.
+    """
+
+    context = zope.interface.Attribute(
+        'The context of the view the viewlet appears in.')
+
+    view = zope.interface.Attribute(
+        'The view the viewlet is used in.')
+
+    request = zope.interface.Attribute(
+        'The request of the view the viewlet is used in.')
+
+    def getViewlets(region):
+        """Get all available viewlets of the given region.
+
+        This method is responsible for sorting the viewlets as well.
+        """
+
+    def getViewlet(self, name, region):
+        """Get a particular viewlet of a region selected by name."""
+
+
+class ITALESViewletsExpression(interfaces.ITALESExpression):
+    """TAL namespace for getting a list of viewlets.
+
+    To call viewlets in a view use the the following syntax in a page
+    template::
+
+      <tal:block repeat="viewlet viewlets:path.to.my.IRegion">
+        <tal:block replace="structure viewlet" />
+      </tal:block>
+
+    where ``path.to.my.IRegion`` is a region object that provides
+    ``viewlet.interfaces.IRegion``.
+    """
+
+
+class ITALESViewletExpression(interfaces.ITALESExpression):
+    """TAL namespace for getting a single viewlet.
+
+    To call a named viewlet in a view use the the following syntax in a page
+    template::
+
+      <tal:block replace="structure viewlet:path.to.my.IRegion/name" />
+
+    where ``path.to.my.IRegion`` is a region object that provides
+    ``viewlet.interfaces.IRegion`` and ``name`` is the name of the page
+    template.
+    """


Property changes on: Zope3/branches/roger-contentprovider/src/zope/contentprovider/interfaces.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: Zope3/branches/roger-contentprovider/src/zope/contentprovider/manager.py
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/contentprovider/manager.py	2005-10-06 16:24:10 UTC (rev 38800)
+++ Zope3/branches/roger-contentprovider/src/zope/contentprovider/manager.py	2005-10-06 16:24:43 UTC (rev 38801)
@@ -0,0 +1,74 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Viewlet implementation
+
+$Id$
+"""
+__docformat__ = 'restructuredtext'
+
+import zope.component
+import zope.interface
+import zope.security
+
+from zope.app.viewlet import interfaces
+
+
+class DefaultViewletManager(object):
+    """The Default Viewlet Manager
+
+    This implementation looks up all viewlets from the adapter registry and
+    sorts the viewlet list by weight. Viewlets that are not accessible in the
+    context of this request will also be filtered.
+    """
+    zope.interface.implements(interfaces.IViewletManager)
+
+    def __init__(self, context, request, view):
+        self.context = context
+        self.request = request
+        self.view = view
+
+
+    def getViewlets(self, region):
+        """See zope.app.viewlet.interfaces.IViewletManager"""
+        # Find all viewlets for this region
+        viewlets = zope.component.getAdapters(
+            (self.context, self.request, self.view), region)
+        # Sort out all viewlets that cannot be accessed by the principal
+        viewlets = [viewlet for name, viewlet in viewlets
+                    if zope.security.canAccess(viewlet, '__call__')]
+        # Sort the viewlets by weight.
+        viewlets.sort(lambda x, y: cmp(x.weight, y.weight))
+
+        return viewlets
+
+
+    def getViewlet(self, name, region):
+        """See zope.app.viewlet.interfaces.IViewletManager"""
+        # Find the viewlet
+        viewlet = zope.component.queryMultiAdapter(
+            (self.context, self.request, self.view), region, name=name)
+
+        # If the viewlet was not found, then raise a lookup error
+        if viewlet is None:
+            raise zope.component.interfaces.ComponentLookupError(
+                'No viewlet with name `%s` found.' %name)
+
+        # If the viewlet cannot be accessed, then raise an unauthorized error
+        if not zope.security.canAccess(viewlet, '__call__'):
+            raise zope.security.interfaces.Unauthorized(
+                'You are not authorized to access the viewlet '
+                'called `%s`.' %name)
+
+        # Return the rendered viewlet.
+        return viewlet


Property changes on: Zope3/branches/roger-contentprovider/src/zope/contentprovider/manager.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: Zope3/branches/roger-contentprovider/src/zope/contentprovider/meta.zcml
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/contentprovider/meta.zcml	2005-10-06 16:24:10 UTC (rev 38800)
+++ Zope3/branches/roger-contentprovider/src/zope/contentprovider/meta.zcml	2005-10-06 16:24:43 UTC (rev 38801)
@@ -0,0 +1,14 @@
+<configure
+    xmlns:meta="http://namespaces.zope.org/meta">
+
+  <meta:directives namespace="http://namespaces.zope.org/browser">
+
+    <meta:directive
+        name="viewlet"
+        schema=".metadirectives.IViewletDirective"
+        handler=".metaconfigure.viewletDirective"
+        />
+
+  </meta:directives>
+
+</configure>


Property changes on: Zope3/branches/roger-contentprovider/src/zope/contentprovider/meta.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: Zope3/branches/roger-contentprovider/src/zope/contentprovider/metaconfigure.py
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/contentprovider/metaconfigure.py	2005-10-06 16:24:10 UTC (rev 38800)
+++ Zope3/branches/roger-contentprovider/src/zope/contentprovider/metaconfigure.py	2005-10-06 16:24:43 UTC (rev 38801)
@@ -0,0 +1,128 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Viewlet metadconfigure
+
+$Id$
+"""
+__docformat__ = 'restructuredtext'
+
+import os
+
+from zope.security import checker
+
+from zope.configuration.exceptions import ConfigurationError
+from zope.interface import Interface, classImplements
+from zope.publisher.interfaces.browser import IDefaultBrowserLayer
+
+from zope.app.component.interface import provideInterface
+from zope.app.component import metaconfigure
+from zope.app.publisher.browser import viewmeta
+from zope.app.publisher.interfaces.browser import IBrowserView
+
+from zope.app.viewlet import viewlet, interfaces
+
+
+def viewletDirective(_context, name, permission, region,
+                     for_=Interface, layer=IDefaultBrowserLayer,
+                     view=IBrowserView,
+                     class_=None, template=None, attribute='__call__', weight=0,
+                     allowed_interface=None, allowed_attributes=None):
+
+    required = {}
+
+    # Get the permission; mainly to correctly handle CheckerPublic.
+    permission = viewmeta._handle_permission(_context, permission)
+
+    # Either the class or template must be specified.
+    if not (class_ or template):
+        raise ConfigurationError("Must specify a class or template")
+
+    # Make sure that all the non-default attribute specifications are correct.
+    if attribute != '__call__':
+        if template:
+            raise ConfigurationError(
+                "Attribute and template cannot be used together.")
+
+        # Note: The previous logic forbids this condition to evere occur.
+        if not class_:
+            raise ConfigurationError(
+                "A class must be provided if attribute is used")
+
+    # Make sure that the template exists and that all low-level API methods
+    # have the right permission.
+    if template:
+        template = os.path.abspath(str(_context.path(template)))
+        if not os.path.isfile(template):
+            raise ConfigurationError("No such file", template)
+        required['__getitem__'] = permission
+
+    # Make sure the has the right form, if specified.
+    if class_:
+        if attribute != '__call__':
+            if not hasattr(class_, attribute):
+                raise ConfigurationError(
+                    "The provided class doesn't have the specified attribute "
+                    )
+        if template:
+            # Create a new class for the viewlet template and class.
+            new_class = viewlet.SimpleViewletClass(
+                template, bases=(class_, ), weight=weight)
+        else:
+            if not hasattr(class_, 'browserDefault'):
+                cdict = {
+                    'browserDefault':
+                    lambda self, request: (getattr(self, attribute), ())
+                    }
+            else:
+                cdict = {}
+
+            cdict['_weight'] = weight
+            cdict['__name__'] = name
+            cdict['__page_attribute__'] = attribute
+            new_class = type(class_.__name__,
+                             (class_, viewlet.SimpleAttributeViewlet), cdict)
+
+        if hasattr(class_, '__implements__'):
+            classImplements(new_class, IBrowserPublisher)
+
+    else:
+        # Create a new class for the viewlet template alone.
+        new_class = viewlet.SimpleViewletClass(
+            template, name=name, weight=weight)
+
+    # Make sure the new class implements the region
+    classImplements(new_class, region)
+
+    for attr_name in (attribute, 'browserDefault', '__call__',
+                      'publishTraverse', 'weight'):
+        required[attr_name] = permission
+
+    viewmeta._handle_allowed_interface(
+        _context, allowed_interface, permission, required)
+    viewmeta._handle_allowed_attributes(
+        _context, allowed_interface, permission, required)
+
+    viewmeta._handle_for(_context, for_)
+    metaconfigure.interface(_context, view)
+    metaconfigure.interface(_context, region, interfaces.IRegion)
+
+    checker.defineChecker(new_class, checker.Checker(required))
+
+    # register viewlet
+    _context.action(
+        discriminator = ('viewlet', for_, layer, view, region, name),
+        callable = metaconfigure.handler,
+        args = ('provideAdapter',
+                (for_, layer, view), region, name, new_class,
+                 _context.info),)


Property changes on: Zope3/branches/roger-contentprovider/src/zope/contentprovider/metaconfigure.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: Zope3/branches/roger-contentprovider/src/zope/contentprovider/metadirectives.py
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/contentprovider/metadirectives.py	2005-10-06 16:24:10 UTC (rev 38800)
+++ Zope3/branches/roger-contentprovider/src/zope/contentprovider/metadirectives.py	2005-10-06 16:24:43 UTC (rev 38801)
@@ -0,0 +1,50 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Viewlet metadirective
+
+$Id$
+"""
+__docformat__ = 'restructuredtext'
+
+from zope.configuration.fields import GlobalInterface
+from zope.schema import Int
+
+from zope.app.publisher.browser import metadirectives
+
+
+class IViewletDirective(metadirectives.IPagesDirective,
+                        metadirectives.IViewPageSubdirective):
+    """A directive to register a new viewlet.
+
+    Viewlet registrations are very similar to page registrations, except that
+    they are additionally qualified by the region and view they are used for. An
+    additional `weight` attribute is specified that is intended to coarsly
+    control the order of the viewlets.
+    """
+
+    region = GlobalInterface(
+        title=u"region",
+        description=u"The region interface this viewlet is for.",
+        required=True)
+
+    view = GlobalInterface(
+        title=u"view",
+        description=u"The interface of the view this viewlet is for. "
+                    u"(default IBrowserView)""",
+        required=False)
+
+    weight = Int(
+        title=u"weight",
+        description=u"Integer key for sorting viewlets in the same region.",
+        required=False)


Property changes on: Zope3/branches/roger-contentprovider/src/zope/contentprovider/metadirectives.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: Zope3/branches/roger-contentprovider/src/zope/contentprovider/tales.py
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/contentprovider/tales.py	2005-10-06 16:24:10 UTC (rev 38800)
+++ Zope3/branches/roger-contentprovider/src/zope/contentprovider/tales.py	2005-10-06 16:24:43 UTC (rev 38801)
@@ -0,0 +1,114 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Viewlet tales expression registrations
+
+$Id$
+"""
+__docformat__ = 'restructuredtext'
+import zope.interface
+import zope.component
+from zope.tales import expressions
+
+from zope.app.viewlet import interfaces, manager
+
+
+def getRegion(str):
+    """Get a region from the string.
+
+    This function will create the dummy region implementation as well.
+    """
+    region = zope.component.queryUtility(interfaces.IRegion, name=str)
+    if region is None:
+        raise interfaces.ViewletRegionLookupError(
+            'Viewlet region interface not found.', str)
+    return region
+
+
+def getRegionFieldData(region, context):
+    """Get a dictionary of values for the region fields."""
+    data = {}
+    for name, field in zope.schema.getFields(region).items():
+        data[name] = context.vars.get(name, field.default)
+    return data
+
+
+class TALESViewletsExpression(expressions.StringExpr):
+    """Collect viewlets via a TAL namespace called `viewlets`."""
+
+    zope.interface.implements(interfaces.ITALESViewletsExpression)
+
+    def __call__(self, econtext):
+        context = econtext.vars['context']
+        request = econtext.vars['request']
+        view = econtext.vars['view']
+
+        # get the region from the expression
+        region = getRegion(self._s)
+
+        # Find the viewlets
+        viewletManager = zope.component.queryMultiAdapter(
+            (context, request, view), interfaces.IViewletManager)
+        if viewletManager is None:
+            viewletManager = manager.DefaultViewletManager(
+                context, request, view)
+
+        viewlets = viewletManager.getViewlets(region)
+
+        # Insert the data gotten from the context
+        data = getRegionFieldData(region, econtext)
+        for viewlet in viewlets:
+            viewlet.__dict__.update(data)
+
+        return viewlets
+
+
+class TALESViewletExpression(expressions.StringExpr):
+    """Collects a single viewlet via a TAL namespace called viewlet."""
+
+    zope.interface.implements(interfaces.ITALESViewletExpression)
+
+    def __init__(self, name, expr, engine):
+        if not '/' in expr:
+            raise KeyError('Use `iface/viewletname` for defining the viewlet.')
+
+        parts = expr.split('/')
+        if len(parts) > 2:
+            raise KeyError("Do not use more then one / for defining iface/key.")
+
+        # get interface from key
+        self._iface = parts[0]
+        self._name = parts[1]
+
+    def __call__(self, econtext):
+        context = econtext.vars['context']
+        request = econtext.vars['request']
+        view = econtext.vars['view']
+
+        # get the region from the expression
+        region = getRegion(self._iface)
+
+        # Find the viewlets
+        viewletManager = zope.component.queryMultiAdapter(
+            (context, request, view), interfaces.IViewletManager)
+        if viewletManager is None:
+            viewletManager = manager.DefaultViewletManager(
+                context, request, view)
+
+        viewlet = viewletManager.getViewlet(self._name, region)
+
+        # Insert the data gotten from the context
+        data = getRegionFieldData(region, econtext)
+        viewlet.__dict__.update(data)
+
+        return viewlet()


Property changes on: Zope3/branches/roger-contentprovider/src/zope/contentprovider/tales.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: Zope3/branches/roger-contentprovider/src/zope/contentprovider/zope.contentprovider-configure.zcml
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/contentprovider/zope.contentprovider-configure.zcml	2005-10-06 16:24:10 UTC (rev 38800)
+++ Zope3/branches/roger-contentprovider/src/zope/contentprovider/zope.contentprovider-configure.zcml	2005-10-06 16:24:43 UTC (rev 38801)
@@ -0,0 +1 @@
+<include package="zope.contentprovider" />
\ No newline at end of file


Property changes on: Zope3/branches/roger-contentprovider/src/zope/contentprovider/zope.contentprovider-configure.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: Zope3/branches/roger-contentprovider/src/zope/contentprovider/zope.contentprovider-meta.zcml
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/contentprovider/zope.contentprovider-meta.zcml	2005-10-06 16:24:10 UTC (rev 38800)
+++ Zope3/branches/roger-contentprovider/src/zope/contentprovider/zope.contentprovider-meta.zcml	2005-10-06 16:24:43 UTC (rev 38801)
@@ -0,0 +1 @@
+<include package="zope.contentprovider" file="meta.zcml" />


Property changes on: Zope3/branches/roger-contentprovider/src/zope/contentprovider/zope.contentprovider-meta.zcml
___________________________________________________________________
Name: svn:eol-style
   + native



More information about the Zope3-Checkins mailing list