[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