[Checkins] SVN: z3ext.layout/ initial import

Nikolay Kim fafhrd at datacom.kz
Fri Mar 21 04:31:56 EDT 2008


Log message for revision 84827:
  initial import

Changed:
  A   z3ext.layout/
  A   z3ext.layout/branches/
  A   z3ext.layout/tags/
  A   z3ext.layout/trunk/
  A   z3ext.layout/trunk/AUTHOR.txt
  A   z3ext.layout/trunk/CHANGES.txt
  A   z3ext.layout/trunk/LICENSE.txt
  A   z3ext.layout/trunk/bootstrap.py
  A   z3ext.layout/trunk/buildout.cfg
  A   z3ext.layout/trunk/setup.py
  A   z3ext.layout/trunk/src/
  A   z3ext.layout/trunk/src/z3ext/
  A   z3ext.layout/trunk/src/z3ext/__init__.py
  A   z3ext.layout/trunk/src/z3ext/layout/
  A   z3ext.layout/trunk/src/z3ext/layout/README.txt
  A   z3ext.layout/trunk/src/z3ext/layout/__init__.py
  A   z3ext.layout/trunk/src/z3ext/layout/configure.zcml
  A   z3ext.layout/trunk/src/z3ext/layout/interfaces.py
  A   z3ext.layout/trunk/src/z3ext/layout/layout.py
  A   z3ext.layout/trunk/src/z3ext/layout/layoutcontent.pt
  A   z3ext.layout/trunk/src/z3ext/layout/layoutpage.pt
  A   z3ext.layout/trunk/src/z3ext/layout/layoutviewspace.pt
  A   z3ext.layout/trunk/src/z3ext/layout/layoutworkspace.pt
  A   z3ext.layout/trunk/src/z3ext/layout/meta.zcml
  A   z3ext.layout/trunk/src/z3ext/layout/pagelet.py
  A   z3ext.layout/trunk/src/z3ext/layout/pagelet.txt
  A   z3ext.layout/trunk/src/z3ext/layout/tests.py
  A   z3ext.layout/trunk/src/z3ext/layout/zcml.py

-=-

Property changes on: z3ext.layout/trunk
___________________________________________________________________
Name: svn:ignore
   + bin
develop-eggs
eggs
parts
coverage
.installed.cfg


Added: z3ext.layout/trunk/AUTHOR.txt
===================================================================
--- z3ext.layout/trunk/AUTHOR.txt	                        (rev 0)
+++ z3ext.layout/trunk/AUTHOR.txt	2008-03-21 08:31:56 UTC (rev 84827)
@@ -0,0 +1 @@
+Nikolay Kim (fafhrd91 <at> gmail <dot> com)

Added: z3ext.layout/trunk/CHANGES.txt
===================================================================
--- z3ext.layout/trunk/CHANGES.txt	                        (rev 0)
+++ z3ext.layout/trunk/CHANGES.txt	2008-03-21 08:31:56 UTC (rev 84827)
@@ -0,0 +1,79 @@
+=======
+CHANGES
+=======
+
+1.4 (2008-03-21)
+----------------
+
+- Added z3ext:pagelet directive
+
+- Code cleanup
+
+- Moved to svn.zope.org
+
+
+1.3.2 (2008-03-06)
+------------------
+
+- Removed context layouts
+
+
+1.3.1 (2008-02-21)
+------------------
+
+- Code cleanup
+
+- Remove code related to zope.formlib
+
+
+1.3.0 (2008-02-20)
+------------------
+
+- Removed code related to z3c.form
+
+
+1.2.1 (2008-02-18)
+------------------
+
+- Added 'redirect' method to IBrowserPagelet, this is usefull
+  when we need redirect during 'update' method and we don't 
+  need render pagelet at all.
+
+- Added adapter to IPagelet for (context, request),
+  this adapter gets browser:defaultView for context and if it IPagelet return it
+
+
+1.2.0 (2008-02-13)
+------------------
+
+- Remove all code related to persistent templates
+
+
+1.1.2 (2008-02-12)
+------------------
+
+- Added 'title' and 'description' fields layout directive
+
+- check ILayoutTemplateTAL for ISite
+
+
+1.1.0 (2008-02-08)
+------------------
+
+- Added compatibility with z3c.template layouts
+
+- Added ILayoutTemplateTAL interface, other packages
+  can define adapter to this interface and change layout template
+  TAL program (layout customization)
+
+
+1.0.1 (2008-02-02)
+------------------
+
+- Added required dependencies
+
+
+1.0.0 (2008-01-15)
+------------------
+
+- Initial release

Added: z3ext.layout/trunk/LICENSE.txt
===================================================================
--- z3ext.layout/trunk/LICENSE.txt	                        (rev 0)
+++ z3ext.layout/trunk/LICENSE.txt	2008-03-21 08:31:56 UTC (rev 84827)
@@ -0,0 +1,54 @@
+Zope Public License (ZPL) Version 2.1
+-------------------------------------
+
+A copyright notice accompanies this license document that
+identifies the copyright holders.
+
+This license has been certified as open source. It has also
+been designated as GPL compatible by the Free Software
+Foundation (FSF).
+
+Redistribution and use in source and binary forms, with or
+without modification, are permitted provided that the
+following conditions are met:
+
+1. Redistributions in source code must retain the
+   accompanying copyright notice, this list of conditions,
+   and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the accompanying
+   copyright notice, this list of conditions, and the
+   following disclaimer in the documentation and/or other
+   materials provided with the distribution.
+
+3. Names of the copyright holders must not be used to
+   endorse or promote products derived from this software
+   without prior written permission from the copyright
+   holders.
+
+4. The right to distribute this software or to use it for
+   any purpose does not give you the right to use
+   Servicemarks (sm) or Trademarks (tm) of the copyright
+   holders. Use of them is covered by separate agreement
+   with the copyright holders.
+
+5. If any files are modified, you must cause the modified
+   files to carry prominent notices stating that you changed
+   the files and the date of any change.
+
+Disclaimer
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS''
+  AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+  NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+  AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+  NO EVENT SHALL THE COPYRIGHT HOLDERS BE
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+  DAMAGE.

Added: z3ext.layout/trunk/bootstrap.py
===================================================================
--- z3ext.layout/trunk/bootstrap.py	                        (rev 0)
+++ z3ext.layout/trunk/bootstrap.py	2008-03-21 08:31:56 UTC (rev 84827)
@@ -0,0 +1,52 @@
+##############################################################################
+#
+# Copyright (c) 2006 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.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+
+$Id$
+"""
+
+import os, shutil, sys, tempfile, urllib2
+
+tmpeggs = tempfile.mkdtemp()
+
+ez = {}
+exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+                     ).read() in ez
+ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+import pkg_resources
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+if sys.platform == 'win32':
+    cmd = '"%s"' % cmd # work around spawn lamosity on windows
+
+ws = pkg_resources.working_set
+assert os.spawnle(
+    os.P_WAIT, sys.executable, sys.executable,
+    '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout',
+    dict(os.environ,
+         PYTHONPATH=
+         ws.find(pkg_resources.Requirement.parse('setuptools')).location
+         ),
+    ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout')
+import zc.buildout.buildout
+zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+shutil.rmtree(tmpeggs)


Property changes on: z3ext.layout/trunk/bootstrap.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3ext.layout/trunk/buildout.cfg
===================================================================
--- z3ext.layout/trunk/buildout.cfg	                        (rev 0)
+++ z3ext.layout/trunk/buildout.cfg	2008-03-21 08:31:56 UTC (rev 84827)
@@ -0,0 +1,18 @@
+[buildout]
+develop = .
+parts = test coverage-test coverage-report
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = z3ext.layout [test]
+
+[coverage-test]
+recipe = zc.recipe.testrunner
+eggs = z3ext.layout [test]
+defaults = ['--coverage', '../../coverage']
+
+[coverage-report]
+recipe = zc.recipe.egg
+eggs = z3c.coverage
+scripts = coverage=coverage-report
+arguments = ('coverage', 'coverage/report')

Added: z3ext.layout/trunk/setup.py
===================================================================
--- z3ext.layout/trunk/setup.py	                        (rev 0)
+++ z3ext.layout/trunk/setup.py	2008-03-21 08:31:56 UTC (rev 84827)
@@ -0,0 +1,76 @@
+##############################################################################
+#
+# Copyright (c) 2007 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.
+#
+##############################################################################
+"""Setup for z3ext.layout package
+
+$Id$
+"""
+import sys, os
+from setuptools import setup, find_packages
+
+def read(*rnames):
+    return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
+
+version='1.4'
+
+
+setup(name='z3ext.layout',
+      version=version,
+      description="A package implementing advanced Page Template patterns.",
+      long_description=(
+          'Detailed Documentation\n' +
+          '======================\n'
+          + '\n\n' +
+          read('src', 'z3ext', 'layout', 'README.txt')
+          + '\n\n' +
+          read('CHANGES.txt')
+          ),
+      classifiers=[
+        'Development Status :: 5 - Production/Stable',
+        'Environment :: Web Environment',
+        'Intended Audience :: Developers',
+        'License :: OSI Approved :: Zope Public License',
+        'Programming Language :: Python',
+        'Natural Language :: English',
+        'Operating System :: OS Independent',
+        'Topic :: Internet :: WWW/HTTP',
+        'Framework :: Zope3'],
+      author='Nikolay Kim',
+      author_email='fafhrd91 at gmail.com',
+      url='http://z3ext.net/',
+      license='ZPL 2.1',
+      packages=find_packages('src'),
+      package_dir = {'':'src'},
+      namespace_packages=['z3ext'],
+      install_requires = ['setuptools',
+			  'zope.event', 
+			  'zope.schema',
+			  'zope.component',
+			  'zope.interface',
+			  'zope.security',
+			  'zope.publisher',
+			  'zope.configuration',
+			  'zope.pagetemplate',
+			  'zope.app.component',
+			  'zope.app.publisher',
+			  'zope.app.pagetemplate',
+                          'z3c.autoinclude',
+			  'z3ext.statusmessage',
+                          ],
+      extras_require = dict(test=['zope.app.container',
+                                  'zope.app.testing',
+                                  'zope.testing',
+                                  ]),
+      include_package_data = True,
+      zip_safe = False
+      )


Property changes on: z3ext.layout/trunk/setup.py
___________________________________________________________________
Name: svn:executable
   + *
Name: svn:keywords
   + Id

Added: z3ext.layout/trunk/src/z3ext/__init__.py
===================================================================
--- z3ext.layout/trunk/src/z3ext/__init__.py	                        (rev 0)
+++ z3ext.layout/trunk/src/z3ext/__init__.py	2008-03-21 08:31:56 UTC (rev 84827)
@@ -0,0 +1,6 @@
+# namespace package boilerplate
+try:
+    __import__('pkg_resources').declare_namespace(__name__)
+except ImportError, e:
+    from pkgutil import extend_path
+    __path__ = extend_path(__path__, __name__)


Property changes on: z3ext.layout/trunk/src/z3ext/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3ext.layout/trunk/src/z3ext/layout/README.txt
===================================================================
--- z3ext.layout/trunk/src/z3ext/layout/README.txt	                        (rev 0)
+++ z3ext.layout/trunk/src/z3ext/layout/README.txt	2008-03-21 08:31:56 UTC (rev 84827)
@@ -0,0 +1,323 @@
+================
+Template layouts
+================
+
+Layouts is different way of building skin templates without METAL.
+
+We need load zcml file
+
+  >>> import z3ext.layout
+  >>> from zope.configuration import xmlconfig
+  >>> context = xmlconfig.file('meta.zcml', z3ext.layout)
+
+  >>> import os, tempfile
+  >>> from zope import interface, component
+  >>> from z3ext.layout import tests, interfaces
+  >>> from z3ext.layout.pagelet import BrowserPagelet
+
+Let's define main layout for our skin, it like 'page' macros from basicskin or 
+rotterdam. It will contains <html>, <head> and <body> tags. 
+It's like main_template in CMF or 'page' macro in basicskin/rotterdam
+
+  >>> temp_dir = tempfile.mkdtemp()
+  >>> layoutportal = os.path.join(temp_dir, 'layoutportal.pt')
+  >>> open(layoutportal, 'w').write('''<html>
+  ... <head><title>My portal</title></head>
+  ...   <body><div id="portal" tal:content="structure view/render">
+  ...   </div>
+  ... </body>
+  ... </html>''')
+
+Let's define 'portal' layout
+
+  >>> context = xmlconfig.string("""
+  ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
+  ...   <z3ext:layout
+  ...     name="portal"
+  ...     for="zope.app.component.interfaces.ISite"
+  ...     template="%s" />
+  ... </configure>"""%layoutportal, context)
+
+Here another layout.
+
+  >>> layoutworkspace = os.path.join(temp_dir, 'layoutworkspace.pt')
+  >>> open(layoutworkspace, 'w').write('''
+  ... <div id="workspace" tal:content="structure view/render"></div>''')
+
+  >>> context = xmlconfig.string("""
+  ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
+  ...   <z3ext:layout
+  ...     name="workspace"
+  ...     layout="portal"
+  ...     for="zope.app.component.interfaces.ISite"
+  ...     template="%s" />
+  ... </configure>"""%layoutworkspace, context)
+
+You should notice that we used layout="portal" it indicates that 
+'workspace' layout uses 'portal' layout as parent. so 'workspace' will be rendered
+inside 'portal' layout
+
+Now we need very simple view that uses BrowserPagelet
+
+  >>> class IMyView(interface.Interface):
+  ...     pass
+
+  >>> class MyView(BrowserPagelet):
+  ...     interface.implements(IMyView)
+  ...
+  ...     def render(self):
+  ...       return self.context.__name__
+
+  >>> from zope.publisher.browser import TestRequest
+  >>> request = TestRequest()
+  >>> view = MyView(root, request)
+
+It return context __name__
+
+  >>> view.__call__()
+  'root'
+
+By default BrowserPagelet uses layout without name, Let's create one, it will
+use 'workspace' layout as parent.
+
+  >>> layoutcontent = os.path.join(temp_dir, 'layoutcontent.pt')
+  >>> open(layoutcontent, 'w').write('''
+  ... <div id="content" tal:content="structure view/render"></div>''')
+
+  >>> context = xmlconfig.string("""
+  ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
+  ...   <z3ext:layout
+  ...     layout="workspace"
+  ...     for="zope.app.component.interfaces.ISite"
+  ...     template="%s" />
+  ... </configure>"""%layoutcontent, context)
+
+  >>> print view()
+  <html>
+  <head><title>My portal</title></head>
+    <body><div id="portal">
+  <div id="workspace">
+  <div id="content">root</div>
+  </div>
+  </div>
+  </body>
+  </html>
+  <BLANKLINE>
+
+All 3 our layout rendered. view rendered inside nameless layout then in
+-> 'workspace' layout -> 'portal' layout
+
+Now let's create several more content objects
+
+  >>> folder1 = tests.Folder()
+  >>> root['folder1'] = folder1
+
+  >>> print MyView(folder1, request)()
+  <html>
+  <head><title>My portal</title></head>
+    <body><div id="portal">
+  <div id="workspace">
+  <div id="content">folder1</div>
+  </div>
+  </div>
+  </body>
+  </html>
+  <BLANKLINE>
+
+And another one.
+
+  >>> folder1_1 = tests.Folder()
+  >>> root['folder1']['folder1_1'] = folder1_1
+
+  >>> folder1_1_1 = tests.Folder()
+  >>> root['folder1']['folder1_1']['folder1_1_1'] = folder1_1_1
+
+  >>> print MyView(folder1_1_1, request)()
+  <html>
+  <head><title>My portal</title></head>
+    <body><div id="portal">
+  <div id="workspace">
+  <div id="content">folder1_1_1</div>
+  </div>
+  </div>
+  </body>
+  </html>
+  <BLANKLINE>
+
+This is all quite easy. Let's use more complex example. For example 
+later other developers decide change how portal looks for folder1 object
+they want that all folder1 and all it's childs(folder1_1, folder1_1_1) have 
+same look.
+
+Let's add '<table>' with couple columns
+
+  >>> layoutcolumns = os.path.join(temp_dir, 'layoutcolumns.pt')
+  >>> open(layoutcolumns, 'w').write('''
+  ... <table id="columns">
+  ...   <tr>
+  ...     <td id="column1">Column1</td>
+  ...     <td id="column2" tal:content="structure view/render"></td>
+  ...     <td id="column3">Column3</td>
+  ...   </tr>
+  ... </table>''')
+
+We register new layout for different interafce
+
+  >>> context = xmlconfig.string("""
+  ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
+  ...   <z3ext:layout
+  ...     name="workspace"
+  ...     layout="portal"
+  ...     for="z3ext.layout.tests.IFolder1"
+  ...     template="%s" />
+  ... </configure>"""%layoutcolumns, context)
+
+  >>> interface.directlyProvides(folder1, tests.IFolder1)
+
+  >>> print MyView(folder1, request)()
+  <html>
+  <head><title>My portal</title></head>
+    <body><div id="portal">
+  <table id="columns">
+    <tr>
+      <td id="column1">Column1</td>
+      <td id="column2">
+  <div id="content">folder1</div>
+  </td>
+      <td id="column3">Column3</td>
+    </tr>
+  </table>
+  </div>
+  </body>
+  </html>
+  <BLANKLINE>
+
+folder1 uses new 'workspace' layout, but what about other folders
+
+  >>> print MyView(folder1_1, request)()
+  <html>
+  <head><title>My portal</title></head>
+    <body><div id="portal">
+  <table id="columns">
+    <tr>
+      <td id="column1">Column1</td>
+      <td id="column2">
+  <div id="content">folder1_1</div>
+  </td>
+      <td id="column3">Column3</td>
+    </tr>
+  </table>
+  </div>
+  </body>
+  </html>
+  <BLANKLINE>
+
+  >>> print MyView(folder1_1_1, request)()
+  <html>
+  <head><title>My portal</title></head>
+    <body><div id="portal">
+  <table id="columns">
+    <tr>
+      <td id="column1">Column1</td>
+      <td id="column2">
+  <div id="content">folder1_1_1</div>
+  </td>
+      <td id="column3">Column3</td>
+    </tr>
+  </table>
+  </div>
+  </body>
+  </html>
+  <BLANKLINE>
+
+Now we also change how folder1_1 looks, we can replace nameless layout.
+Also we can use nameless layout as parent with layout="."
+
+  >>> layoutcontent1_1 = os.path.join(temp_dir, 'layoutcontent1_1.pt')
+  >>> open(layoutcontent1_1, 'w').write('''
+  ... <div id="content1_1">
+  ...   <h1>Folder1_1</h1>
+  ...   <div tal:content="structure view/render"></div>
+  ... </div>''')
+
+  >>> context = xmlconfig.string("""
+  ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
+  ...   <z3ext:layout
+  ...     layout="."
+  ...     for="z3ext.layout.tests.IFolder1_1"
+  ...     template="%s" />
+  ... </configure>"""%layoutcontent1_1, context)
+
+  >>> interface.directlyProvides(folder1_1, tests.IFolder1_1)
+  
+  >>> print MyView(folder1_1, request)()
+  <html>
+  <head><title>My portal</title></head>
+    <body><div id="portal">
+  <table id="columns">
+    <tr>
+      <td id="column1">Column1</td>
+      <td id="column2">
+  <div id="content">
+  <div id="content1_1">
+    <h1>Folder1_1</h1>
+    <div>folder1_1</div>
+  </div>
+  </div>
+  </td>
+      <td id="column3">Column3</td>
+    </tr>
+  </table>
+  </div>
+  </body>
+  </html>
+  <BLANKLINE>
+
+It still uses nameless layout that we defined for 'root'. 
+
+And same for folder1_1_1
+
+  >>> layoutcontent1_1_1 = os.path.join(temp_dir, 'layoutcontent1_1_1.pt')
+  >>> open(layoutcontent1_1_1, 'w').write('''
+  ... <div id="content1_1_1">
+  ...   <h1>Folder1_1_1</h1>
+  ...   <div tal:content="structure view/render"></div>
+  ... </div>''')
+
+  >>> context = xmlconfig.string("""
+  ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
+  ...   <z3ext:layout
+  ...     layout="."
+  ...     for="z3ext.layout.tests.IFolder1_1_1"
+  ...     template="%s" />
+  ... </configure>"""%layoutcontent1_1_1, context)
+
+  >>> interface.directlyProvides(folder1_1_1, tests.IFolder1_1_1)
+
+  >>> print MyView(folder1_1_1, request)()
+  <html>
+  <head><title>My portal</title></head>
+    <body><div id="portal">
+  <table id="columns">
+    <tr>
+      <td id="column1">Column1</td>
+      <td id="column2">
+  <div id="content">
+  <div id="content1_1">
+    <h1>Folder1_1</h1>
+    <div>
+  <div id="content1_1_1">
+    <h1>Folder1_1_1</h1>
+    <div>folder1_1_1</div>
+  </div>
+  </div>
+  </div>
+  </div>
+  </td>
+      <td id="column3">Column3</td>
+    </tr>
+  </table>
+  </div>
+  </body>
+  </html>
+  <BLANKLINE>

Added: z3ext.layout/trunk/src/z3ext/layout/__init__.py
===================================================================
--- z3ext.layout/trunk/src/z3ext/layout/__init__.py	                        (rev 0)
+++ z3ext.layout/trunk/src/z3ext/layout/__init__.py	2008-03-21 08:31:56 UTC (rev 84827)
@@ -0,0 +1 @@
+# This file is necessary to make this directory a package.


Property changes on: z3ext.layout/trunk/src/z3ext/layout/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3ext.layout/trunk/src/z3ext/layout/configure.zcml
===================================================================
--- z3ext.layout/trunk/src/z3ext/layout/configure.zcml	                        (rev 0)
+++ z3ext.layout/trunk/src/z3ext/layout/configure.zcml	2008-03-21 08:31:56 UTC (rev 84827)
@@ -0,0 +1,55 @@
+<configure
+   xmlns="http://namespaces.zope.org/zope"
+   xmlns:zcml="http://namespaces.zope.org/zcml"
+   xmlns:z3ext="http://namespaces.zope.org/z3ext">
+
+  <autoinclude package="z3ext.layout" />
+
+  <!-- adapter provides IPagelet for (context, request) -->
+  <adapter factory=".pagelet.queryPagelet" />
+
+  <!-- default layouts -->
+  <z3ext:layout
+     layout="viewspace"
+     for="zope.app.component.interfaces.ISite"
+     title="Default layout (z3ext.layout)"
+     description="Default layout, registered for IDefaultBrowserLayer."
+     template="layoutcontent.pt" />
+
+  <z3ext:layout
+     name="viewspace"
+     layout="workspace"
+     title="Viewspace layout (z3ext.layout)"
+     description="Default viewpsace layout, registered for IDefaultBrowserLayer."
+     for="zope.app.component.interfaces.ISite"
+     template="layoutviewspace.pt" />
+
+  <z3ext:layout
+     name="workspace"
+     layout="portal"
+     title="Workspace layout (z3ext.layout)"
+     description="Default workspace layout, registered for IDefaultBrowserLayer."
+     for="zope.app.component.interfaces.ISite"
+     template="layoutworkspace.pt" />
+
+  <z3ext:layout
+     name="portal"
+     title="Portal layout (z3ext.layout)"
+     description="Default portal layout, registered for IDefaultBrowserLayer"
+     for="zope.app.component.interfaces.ISite"
+     template="layoutpage.pt" />
+
+  <!-- Registering documentation with API doc -->
+  <configure
+     xmlns:zcml="http://namespaces.zope.org/zcml"
+     xmlns:apidoc="http://namespaces.zope.org/apidoc"
+     zcml:condition="have apidoc">
+
+    <apidoc:bookchapter
+       id="z3ext-layout"
+       title="z3ext.layout - Template Layouts"
+       doc_path="README.txt"
+       parent="z3ext" />
+  </configure>
+
+</configure>

Added: z3ext.layout/trunk/src/z3ext/layout/interfaces.py
===================================================================
--- z3ext.layout/trunk/src/z3ext/layout/interfaces.py	                        (rev 0)
+++ z3ext.layout/trunk/src/z3ext/layout/interfaces.py	2008-03-21 08:31:56 UTC (rev 84827)
@@ -0,0 +1,76 @@
+##############################################################################
+#
+# Copyright (c) 2007 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.
+#
+##############################################################################
+""" z3ext.layout interfaces
+
+$Id$
+"""
+from zope import interface
+from zope.publisher.interfaces.browser import IBrowserPage
+
+
+class ILayoutLayer(interface.Interface):
+    """ A layer that contains all registration of this package. """
+
+
+class IPagelet(IBrowserPage):
+    """ pagelet """
+
+    isRedirected = interface.Attribute('is redirected')
+
+    def redirect(url=''):
+        """Redirect URL, if `update` method needs redirect,
+        it should call `redirect` method, __call__ method should
+        check isRendered before render or layout."""
+
+    def update():
+        """Update the pagelet data."""
+
+    def render():
+        """Render the pagelet content w/o o-wrap."""
+
+
+class ILayout(IBrowserPage):
+    """ layout """
+
+    title = interface.Attribute('Layout title')
+
+    description = interface.Attribute('Layout description')
+
+    template = interface.Attribute('Layout template')
+
+    def update():
+        """Update the layout data """
+
+    def render():
+        """Render the layout """
+
+
+class ILayoutTemplateFile(interface.Interface):
+    """ layout template file """
+
+
+class ILayoutCreatedEvent(interface.Interface):
+    """ notification about new layout """
+
+    name = interface.Attribute('Name')
+
+    view = interface.Attribute('View')
+
+    context = interface.Attribute('Context')
+
+    layer = interface.Attribute('Layer')
+
+    layoutclass = interface.Attribute('Generated class for layout')
+
+    keywords = interface.Attribute('Keywords')


Property changes on: z3ext.layout/trunk/src/z3ext/layout/interfaces.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3ext.layout/trunk/src/z3ext/layout/layout.py
===================================================================
--- z3ext.layout/trunk/src/z3ext/layout/layout.py	                        (rev 0)
+++ z3ext.layout/trunk/src/z3ext/layout/layout.py	2008-03-21 08:31:56 UTC (rev 84827)
@@ -0,0 +1,119 @@
+##############################################################################
+#
+# Copyright (c) 2007 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.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+from zope import interface
+from zope.publisher import browser
+from zope.component import getMultiAdapter
+
+from zope.app.pagetemplate.engine import TrustedAppPT
+from zope.pagetemplate.pagetemplatefile import PageTemplateFile
+
+from z3ext.layout.pagelet import queryLayout
+from z3ext.layout.interfaces import ILayout, ILayoutTemplateFile
+
+
+class ViewMapper(object):
+
+    def __init__(self, ob, request):
+        self.ob = ob
+        self.request = request
+
+    def __getitem__(self, name):
+        return getMultiAdapter((self.ob, self.request), name=name)
+
+
+class LayoutTemplateFile(TrustedAppPT, PageTemplateFile): 
+    interface.implements(ILayoutTemplateFile)
+
+    expand = False
+
+    def __init__(self, filename, _prefix=None, content_type=None):
+        _prefix = self.get_path_from_prefix(_prefix)
+        super(LayoutTemplateFile, self).__init__(filename, _prefix)
+        if content_type is not None:
+            self.content_type = content_type
+
+    def pt_getContext(self, layout, **_kw):
+        view = layout.view
+
+        # instance is a View component
+        namespace = super(LayoutTemplateFile, self).pt_getContext(**_kw)
+        namespace['view'] = view
+        namespace['request'] = layout.request
+        namespace['context'] = view.context
+        namespace['layout'] = layout
+        namespace['layoutcontext'] = layout.context
+        namespace['mainview'] = layout.mainview
+        namespace['maincontext'] = layout.maincontext
+        namespace['views'] = ViewMapper(view.context, layout.request)
+        return namespace
+
+    def __call__(self, layout, *args, **kw):
+        namespace = self.pt_getContext(layout, args=args, options=kw)
+        return self.pt_render(namespace)
+
+
+class Layout(browser.BrowserPage):
+    interface.implements(ILayout)
+
+    mainview = None
+    maincontext = None
+
+    def __init__(self, view, context, request):
+        self.view = view
+        self.context = context
+        self.request = request
+
+        self.__parent__ = view.context
+
+    def update(self):
+        pass
+
+    def render(self):
+        return self.template(self)
+
+    def __call__(self, layout=None, view=None, *args, **kw):
+        if view is None:
+            view = self.view
+        self.mainview = view
+        self.maincontext = view.context
+
+        layoutview = self.view
+        if layout is not None:
+            self.view = layout
+
+        self.update()
+
+        if self.layout is None:
+            return self.render()
+
+        if self.__name__ != self.layout:
+            layout = queryLayout(view, self.request, name=self.layout)
+            if layout is not None:
+                return layout(layout=self, view=view, *args, **kw)
+        else:
+            if layoutview.context is not self.context.__parent__:
+                context = self.context.__parent__
+            else:
+                context = getattr(self.context.__parent__, '__parent__')
+
+            layout = queryLayout(self, self.request, context, name=self.layout)
+            if layout is not None:
+                return layout(view=view, *args, **kw)
+
+        layout = queryLayout(self.context, self.request, name=self.layout)
+        return layout(maincontext=maincontext, *args, **kw)


Property changes on: z3ext.layout/trunk/src/z3ext/layout/layout.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3ext.layout/trunk/src/z3ext/layout/layoutcontent.pt
===================================================================
--- z3ext.layout/trunk/src/z3ext/layout/layoutcontent.pt	                        (rev 0)
+++ z3ext.layout/trunk/src/z3ext/layout/layoutcontent.pt	2008-03-21 08:31:56 UTC (rev 84827)
@@ -0,0 +1,2 @@
+<div id="z-content" tal:content="structure view/render">
+</div>

Added: z3ext.layout/trunk/src/z3ext/layout/layoutpage.pt
===================================================================
--- z3ext.layout/trunk/src/z3ext/layout/layoutpage.pt	                        (rev 0)
+++ z3ext.layout/trunk/src/z3ext/layout/layoutpage.pt	2008-03-21 08:31:56 UTC (rev 84827)
@@ -0,0 +1,14 @@
+<metal:block metal:use-macro="context/@@standard_macros/page">
+  <div id="z3ext-portal" metal:fill-slot="columns">
+    <tal:block tal:content="structure provider:statusMessage" />
+    <tal:block tal:content="structure view/render" />
+  </div>
+  <div id="z3ext-portal" metal:fill-slot="workspace">
+    <tal:block tal:content="structure provider:statusMessage" />
+    <tal:block tal:content="structure view/render" />
+  </div>
+  <div id="z3ext-portal" metal:fill-slot="body">
+    <tal:block tal:content="structure provider:statusMessage" />
+    <tal:block tal:content="structure view/render" />
+  </div>
+</metal:block>

Added: z3ext.layout/trunk/src/z3ext/layout/layoutviewspace.pt
===================================================================
--- z3ext.layout/trunk/src/z3ext/layout/layoutviewspace.pt	                        (rev 0)
+++ z3ext.layout/trunk/src/z3ext/layout/layoutviewspace.pt	2008-03-21 08:31:56 UTC (rev 84827)
@@ -0,0 +1 @@
+<div id="z-portal-viewspace" tal:content="structure view/render"></div>

Added: z3ext.layout/trunk/src/z3ext/layout/layoutworkspace.pt
===================================================================
--- z3ext.layout/trunk/src/z3ext/layout/layoutworkspace.pt	                        (rev 0)
+++ z3ext.layout/trunk/src/z3ext/layout/layoutworkspace.pt	2008-03-21 08:31:56 UTC (rev 84827)
@@ -0,0 +1 @@
+<div id="z-portal-workspace" tal:content="structure view/render"></div>

Added: z3ext.layout/trunk/src/z3ext/layout/meta.zcml
===================================================================
--- z3ext.layout/trunk/src/z3ext/layout/meta.zcml	                        (rev 0)
+++ z3ext.layout/trunk/src/z3ext/layout/meta.zcml	2008-03-21 08:31:56 UTC (rev 84827)
@@ -0,0 +1,17 @@
+<configure
+   xmlns="http://namespaces.zope.org/zope"
+   xmlns:meta="http://namespaces.zope.org/meta">
+
+  <meta:directives namespace="http://namespaces.zope.org/z3ext">
+    <meta:directive
+       name="layout"
+       schema=".zcml.ILayoutDirective"
+       handler=".zcml.layoutDirective" />
+
+    <meta:directive
+       name="pagelet"
+       schema=".zcml.IPageletDirective"
+       handler=".zcml.pageletDirective" />
+  </meta:directives>
+
+</configure>

Added: z3ext.layout/trunk/src/z3ext/layout/pagelet.py
===================================================================
--- z3ext.layout/trunk/src/z3ext/layout/pagelet.py	                        (rev 0)
+++ z3ext.layout/trunk/src/z3ext/layout/pagelet.py	2008-03-21 08:31:56 UTC (rev 84827)
@@ -0,0 +1,91 @@
+##############################################################################
+#
+# Copyright (c) 2007 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.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+from zope import interface, component
+from zope.publisher.browser import BrowserPage
+from zope.component import getMultiAdapter, queryMultiAdapter
+from zope.pagetemplate.interfaces import IPageTemplate
+from zope.app.publisher.browser import queryDefaultViewName
+
+from z3ext.layout.interfaces import IPagelet, ILayout
+
+
+ at interface.implementer(IPagelet)
+ at component.adapter(interface.Interface, interface.Interface)
+def queryPagelet(context, request):
+    name = queryDefaultViewName(context, request, 'index.html')
+    if name:
+        view = getMultiAdapter((context, request), name=name)
+        if IPagelet.providedBy(view):
+            return view
+
+
+def queryLayout(view, request, context=None, iface=ILayout, name=''):
+    if context is None:
+        context = view.context
+
+    while context is not None:
+        layout = queryMultiAdapter((view, context, request), iface, name)
+        if layout is not None:
+            return layout
+
+        context = getattr(context, '__parent__', None)
+
+    return None
+
+
+class BrowserPagelet(BrowserPage):
+    interface.implements(IPagelet)
+
+    layoutname = u''
+
+    index = None
+    template = None
+
+    def update(self):
+        pass
+
+    def render(self):
+        template = queryMultiAdapter((self, self.request), IPageTemplate)
+
+        if template is None:
+            template = self.template or self.index
+            if template is None:
+                raise LookupError("Can't find IPageTemplate for pagelet.")
+            return template()
+
+        return template(self)
+
+    def __call__(self):
+        self.update()
+
+        if self.isRedirected:
+            return u''
+
+        layout = queryLayout(self, self.request, name=self.layoutname)
+        if layout is None:
+            return self.render()
+        else:
+            return layout()
+
+    isRedirected = False
+
+    def redirect(self, url=''):
+        if url:
+            self.request.response.redirect(url)
+
+        self.isRedirected = True


Property changes on: z3ext.layout/trunk/src/z3ext/layout/pagelet.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3ext.layout/trunk/src/z3ext/layout/pagelet.txt
===================================================================
--- z3ext.layout/trunk/src/z3ext/layout/pagelet.txt	                        (rev 0)
+++ z3ext.layout/trunk/src/z3ext/layout/pagelet.txt	2008-03-21 08:31:56 UTC (rev 84827)
@@ -0,0 +1,222 @@
+=================
+Pagelet directive
+=================
+
+Show how we can use the pagelet directive. Register the meta configuration for 
+the directive.
+
+  >>> import os, sys, tempfile
+  >>> from zope import interface, component
+  >>> from zope.configuration import xmlconfig
+  >>> import z3ext.layout
+  >>> context = xmlconfig.file('meta.zcml', z3ext.layout)
+
+We need also a custom pagelet class:
+
+  >>> from z3ext.layout.pagelet import BrowserPagelet
+  >>> class MyPagelet(BrowserPagelet):
+  ...     """Custom pagelet"""
+
+Make them available under the fake package ``custom``:
+
+  >>> sys.modules['custom'] = type(
+  ...     'Module', (), 
+  ...     {'MyPagelet': MyPagelet})()
+
+Register a pagelet within the directive with minimal attributes:
+
+  >>> context = xmlconfig.string("""
+  ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
+  ...   <z3ext:pagelet
+  ...       name="index.html"
+  ...       class="custom.MyPagelet"
+  ...       permission="zope.Public"
+  ...       />
+  ... </configure>
+  ... """, context)
+
+Let's get the pagelet
+
+  >>> import zope.component
+  >>> from zope.publisher.browser import TestRequest
+  >>> pagelet = zope.component.queryMultiAdapter((object(), TestRequest()), 
+  ...     name='index.html')
+
+and check them:
+
+  >>> pagelet
+  <z3ext.layout.zcml.PageletClass from <class 'MyPagelet'> ...>
+
+  >>> pagelet.context
+  <object object at ...>
+
+Register the pagelet with a different name and more attributes provided from
+the directive. We also use a custom attribute called label here.
+Also we don't use BrowserPagelet as parent class, pagelet directive automaticly
+adds BrowserPagetlet to bases classes. Let's define some more components...
+
+  >>> class SecondPagelet(object):
+  ...     label = u''
+
+  >>> import zope.interface
+  >>> class IContent(zope.interface.Interface):
+  ...     """Content interface."""
+
+  >>> class Content(object):
+  ...     zope.interface.implements(IContent)
+
+register the new classes in the custom module...
+
+  >>> sys.modules['custom'].IContent = IContent
+  >>> sys.modules['custom'].Content = Content
+  >>> sys.modules['custom'].SecondPagelet = SecondPagelet
+
+and use them in the directive:
+
+  >>> context = xmlconfig.string("""
+  ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
+  ...   <z3ext:pagelet
+  ...       name="custom.html"
+  ...       class="custom.SecondPagelet"
+  ...       for="custom.IContent"
+  ...       permission="zope.Public"
+  ...       label="my Label" />
+  ... </configure>
+  ... """, context)
+
+Get the pagelet for the new content object
+
+  >>> import zope.component
+  >>> pagelet = zope.component.queryMultiAdapter((Content(), TestRequest()), 
+  ...     name='custom.html')
+
+and check them:
+
+  >>> pagelet
+  <z3ext.layout.zcml.PageletClass from <class 'SecondPagelet'> ...>
+
+  >>> pagelet.label
+  u'my Label'
+
+We also can provide another interface then the IPagelet within the directive.
+Such a interface must be inherited from IPagelet.
+
+  >>> class NewPagelet(BrowserPagelet):
+  ...     """New pagelet"""
+  >>> sys.modules['custom'] = type(
+  ...     'Module', (), 
+  ...     {'NewPagelet': NewPagelet})()
+
+
+Now register the pagelet within a interface.
+
+  >>> class INewPagelet(interface.Interface):
+  ...     """New pagelet interface."""
+  >>> sys.modules['custom'] = type(
+  ...     'Module', (), 
+  ...     {'INewPagelet': INewPagelet, 'NewPagelet': NewPagelet})()
+
+  >>> context = xmlconfig.string("""
+  ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
+  ...   <z3ext:pagelet
+  ...       name="new.html"
+  ...       class="custom.NewPagelet"
+  ...       permission="zope.Public"
+  ...       provides="custom.INewPagelet" />
+  ... </configure>
+  ... """, context)
+
+And if we get the pagelet, we can see that the object provides the new 
+pagelet interface:
+
+  >>> pagelet = zope.component.queryMultiAdapter((object(), TestRequest()), 
+  ...     name='new.html')
+  >>> pagelet
+  <z3ext.layout.zcml.PageletClass from <class 'NewPagelet'> ...>
+
+  >>> INewPagelet.providedBy(pagelet)
+  True
+
+We can create pagelet without specific class
+
+  >>> context = xmlconfig.string("""
+  ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
+  ...   <z3ext:pagelet
+  ...       name="noclass.html"
+  ...       permission="zope.Public" />
+  ... </configure>
+  ... """, context) 
+
+  >>> pagelet = zope.component.queryMultiAdapter((object(), TestRequest()), 
+  ...     name='noclass.html')
+  >>> pagelet
+  <z3ext.layout.zcml.PageletClass from None ...>
+
+
+We can create pagelet with template:
+
+  >>> context = xmlconfig.string("""
+  ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
+  ...   <z3ext:pagelet
+  ...       name="unknown.html"
+  ...       template="unknown.pt"
+  ...       permission="zope.Public" />
+  ... </configure>
+  ... """, context)
+  Traceback (most recent call last):
+  ...
+  ZopeXMLConfigurationError: File "<string>", line 3.2-6.33
+  ConfigurationError: ('No such file', ...unknown.pt')
+
+  >>> temp_dir = tempfile.mkdtemp()
+  >>> template = os.path.join(temp_dir, 'pagelet.pt')
+  >>> open(template, 'w').write('''<div>My pagelet</div>''')
+
+  >>> context = xmlconfig.string("""
+  ... <configure xmlns:z3ext="http://namespaces.zope.org/z3ext">
+  ...   <z3ext:pagelet
+  ...       name="template.html"
+  ...       template="%s"
+  ...       permission="zope.Public" />
+  ... </configure>
+  ... """%template, context)
+
+  >>> pagelet = zope.component.queryMultiAdapter((object(), TestRequest()), 
+  ...     name='template.html')
+  >>> pagelet
+  <z3ext.layout.zcml.PageletClass from None ...>
+
+  >>> pagelet.template
+  <BoundPageTemplateFile of <z3ext.layout.zcml.PageletClass from None ...>>
+
+Pagelet rendering
+
+  >>> print pagelet.render()
+  <div>My pagelet</div>
+  <BLANKLINE>
+
+We should use page template as template for pagelet or we should
+provide IPageTemplate adapter for pagelet
+
+  >>> pagelet = zope.component.queryMultiAdapter((object(), TestRequest()), 
+  ...     name='noclass.html')
+  >>> pagelet.render()
+  Traceback (most recent call last):
+  ...
+  LookupError: Can't find IPageTemplate for pagelet.
+
+  >>> from zope.pagetemplate.interfaces import IPageTemplate
+  >>> from zope.app.pagetemplate import ViewPageTemplateFile
+  >>> pt = ViewPageTemplateFile(template)
+  >>> def getPT(context, request):
+  ...     return pt
+  >>> component.getSiteManager().registerAdapter(
+  ...     getPT, (pagelet.__class__, interface.Interface), IPageTemplate, '')
+
+  >>> print pagelet.render()
+  <div>My pagelet</div>
+  <BLANKLINE>
+  
+Now we need to clean up the custom module.
+
+  >>> del sys.modules['custom']

Added: z3ext.layout/trunk/src/z3ext/layout/tests.py
===================================================================
--- z3ext.layout/trunk/src/z3ext/layout/tests.py	                        (rev 0)
+++ z3ext.layout/trunk/src/z3ext/layout/tests.py	2008-03-21 08:31:56 UTC (rev 84827)
@@ -0,0 +1,64 @@
+##############################################################################
+#
+# Copyright (c) 2008 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.
+#
+##############################################################################
+""" 
+
+$Id$
+"""
+import unittest, doctest
+from zope import interface
+from zope.testing.doctestunit import DocFileSuite
+from zope.app.testing import setup
+from zope.app.container.sample import SampleContainer
+
+class IFolder1(interface.Interface):
+    pass
+
+class IFolder1_1(interface.Interface):
+    pass
+
+class IFolder1_1_1(interface.Interface):
+    pass
+
+
+class Folder(SampleContainer):
+    pass
+
+
+class MyLayout(object):
+
+    title = u'My layout'
+
+
+def setUp(test):
+    root = setup.placefulSetUp(site=True)
+    root.__name__ = 'root'
+    test.globs['root'] = root
+
+
+def tearDown(test):
+    setup.placefulTearDown()
+
+
+def test_suite():
+    return unittest.TestSuite((
+            doctest.DocFileSuite(
+                'README.txt',
+                setUp=setUp, tearDown=tearDown,
+                optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+                ),
+            doctest.DocFileSuite(
+                'pagelet.txt',
+                optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+                ),
+            ))


Property changes on: z3ext.layout/trunk/src/z3ext/layout/tests.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3ext.layout/trunk/src/z3ext/layout/zcml.py
===================================================================
--- z3ext.layout/trunk/src/z3ext/layout/zcml.py	                        (rev 0)
+++ z3ext.layout/trunk/src/z3ext/layout/zcml.py	2008-03-21 08:31:56 UTC (rev 84827)
@@ -0,0 +1,369 @@
+##############################################################################
+#
+# Copyright (c) 2007 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.
+#
+##############################################################################
+""" 
+
+$Id$
+"""
+import os.path
+from zope import schema, interface, event
+from zope.component.interface import provideInterface
+from zope.component.zcml import handler, adapter, utility
+from zope.security.checker import defineChecker, Checker, CheckerPublic
+from zope.configuration.fields import Path, Tokens, GlobalObject, GlobalInterface
+from zope.configuration.exceptions import ConfigurationError
+from zope.publisher.interfaces.browser import IDefaultBrowserLayer
+from zope.app.component.metadirectives import IBasicViewInformation
+from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
+
+from interfaces import IPagelet
+from interfaces import ILayout, ILayoutCreatedEvent
+
+from pagelet import BrowserPagelet
+from layout import Layout, LayoutTemplateFile
+
+
+class IPageletDirective(IBasicViewInformation):
+    """A directive to register a new pagelet.
+
+    The pagelet directive also supports an undefined set of keyword arguments
+    that are set as attributes on the pagelet after creation.
+    """
+
+    for_ = GlobalObject(
+        title = u"Context",
+        description = u"The content interface or class this pagelet is for.",
+        required = False)
+
+    name = schema.TextLine(
+        title = u"The name of the pagelet.",
+        description = u"The name shows up in URLs/paths. For example 'foo'.",
+        required = True)
+
+    provides = Tokens(
+        title = u"The interface this pagelets provides.",
+        description = u"""A pagelet can provide an interface.  This would be used for
+        views that support other views.""",
+        required = False,
+        value_type = GlobalInterface(),
+        default = [IPagelet,])
+
+    class_ = GlobalObject(
+        title=u"Class",
+        description=u"A class that provides attributes used by the pagelet.",
+        required=False,
+        )
+
+    template = Path(
+        title = u'Pagelet template.',
+        description = u"Refers to a file containing a page template (should "\
+                                    "end in extension ``.pt`` or ``.html``).",
+        required=False)
+
+    layout = schema.TextLine(
+        title = u'The name of the layout.',
+        description = u"The name is used to look up the layout.",
+        default=u'',
+        required=False)
+
+# Arbitrary keys and values are allowed to be passed to the pagelet.
+IPageletDirective.setTaggedValue('keyword_arguments', True)
+
+
+class ILayoutDirective(interface.Interface):
+
+    template = Path(
+        title=u'Layout template.',
+        description=u"Refers to a file containing a page template (should "
+                     "end in extension ``.pt`` or ``.html``).",
+        required=False,
+        )
+
+    name = schema.TextLine(
+        title=u"The name of the layout.",
+        description=u"The name is used to look up the layout.",
+        default=u'',
+        required=False)
+
+    layer = GlobalObject(
+        title = u'Layer',
+        description = u'The layer for which the template should be available',
+        required = False,
+        default=IDefaultBrowserLayer,
+        )
+
+    contentType = schema.BytesLine(
+        title = u'Content Type',
+        description=u'The content type identifies the type of data.',
+        default='text/html',
+        required=False,
+        )
+
+    provides = GlobalInterface(
+        title=u"Interface the layout provides",
+        description=u"This attribute specifies the interface the layout"
+                      " instance will provide.",
+        default=ILayout,
+        required=False,
+        )
+
+    for_ = GlobalObject(
+        title = u'Context',
+        description = u'The object for which the layout should be available',
+        default=interface.Interface,
+        required = False)
+
+    view = GlobalObject(
+        title = u'View',
+        description = u'The view for which the layout should be available',
+        default=interface.Interface,
+        required = False)
+
+    class_ = GlobalObject(
+        title=u"Class",
+        description=u"A class that provides attributes used by the layout.",
+        required=False,
+        )
+
+    layout = schema.TextLine(
+        title = u'Layout',
+        description = u'Custom layout name.',
+        required = False)
+
+    title = schema.TextLine(
+        title = u'Layout title',
+        required = False)
+
+    description = schema.TextLine(
+        title = u'Layout description',
+        required = False)
+
+# Arbitrary keys and values are allowed
+ILayoutDirective.setTaggedValue('keyword_arguments', True)
+
+
+def layoutDirective(
+    _context, template='', for_=None, view=None, name = u'',
+    layer = IDefaultBrowserLayer, provides = ILayout,
+    contentType='text/html', class_ = None, layout = '', 
+    title='', description='', **kwargs):
+
+    if for_ is interface.Interface:
+        raise ConfigurationError('for should be valid interface or object')
+
+    if not layout:
+        layout = None
+    elif layout == '.':
+        layout = ''
+
+    # Make sure that the template exists
+    if template:
+        template = os.path.abspath(str(_context.path(template)))
+        if not os.path.isfile(template):
+            raise ConfigurationError("No such file", template)
+
+    # Check
+    if (for_ is None) and (view is None):
+        raise ConfigurationError("FOR or VIEW are required.")
+
+    # Build a new class that we can use different permission settings if we
+    # use the class more then once.
+    cdict = {}
+    cdict['__name__'] = name
+    cdict['layout'] = layout
+    cdict['title'] = title
+    cdict['description'] = description
+
+    if template:
+        cdict['template'] = LayoutTemplateFile(template, content_type=contentType)
+
+    cdict.update(kwargs)
+
+    class_name = 'Layout<%s>'%name
+
+    if class_ is None:
+        bases = (Layout,)
+    else:
+        bases = (class_, Layout)
+
+    newclass = type(str(class_name), bases, cdict)
+
+    # Set up permission mapping for various accessible attributes
+    required = {}
+
+    for iface in (provides, ILayout):
+        for iname in iface:
+            required[iname] = CheckerPublic
+
+    required = {'__call__': CheckerPublic,
+                'browserDefault': CheckerPublic,
+                'publishTraverse': CheckerPublic}
+
+    # provide the custom provides interface if not allready provided
+    if not provides.implementedBy(newclass):
+        interface.classImplements(newclass, provides)
+
+    # security checker
+    defineChecker(newclass, Checker(required))
+
+    if for_ is not None:
+        # register the template
+        if name:
+            adapter(_context, (newclass,),
+                    provides, (interface.Interface, for_, layer), name=name)
+        else:
+            adapter(_context, (newclass,),
+                    provides, (interface.Interface, for_, layer))
+
+        # send ILayoutCreatedEvent event
+        _context.action(
+            discriminator = ('z3ext.layout', name, interface.Interface, for_, layer),
+            callable = sendNotification,
+            args = (name, interface.Interface, for_, layer, newclass, kwargs),
+            order = 99999999)
+
+    if view is not None:
+        # register the template
+        if name:
+            adapter(_context, (newclass,),
+                    provides, (view, interface.Interface, layer), name=name)
+        else:
+            adapter(_context, (newclass,),
+                    provides, (view, interface.Interface, layer))
+
+        # send ILayoutCreatedEvent event
+        _context.action(
+            discriminator = ('z3ext.layout', name, view, interface.Interface, layer),
+            callable = sendNotification,
+            args = (name, view, interface.Interface, layer, newclass, kwargs),
+            order = 99999999)
+
+
+class LayoutCreatedEvent(object):
+    interface.implements(ILayoutCreatedEvent)
+
+    def __init__(self, name, view, context, layer, layoutclass, keywords):
+        self.name = name
+        self.view = view
+        self.context = context
+        self.layer = layer
+        self.layoutclass = layoutclass
+        self.keywords = keywords
+
+
+def sendNotification(name, view, context, layer, layoutclass, keywords):
+    event.notify(LayoutCreatedEvent(
+            name, view, context, layer, layoutclass, keywords))
+
+
+# pagelet directive
+def pageletDirective(
+    _context, name, permission, class_=None, for_=interface.Interface,
+    layer=IDefaultBrowserLayer, provides=[IPagelet,],
+    allowed_interface=[], allowed_attributes=[],
+    template=u'', layout=u'', **kwargs):
+
+    # Security map dictionary
+    required = {}
+
+    # Get the permission; mainly to correctly handle CheckerPublic.
+    if permission == 'zope.Public':
+        permission = CheckerPublic
+
+    # Make sure that the template exists
+    if template:
+        template = os.path.abspath(str(_context.path(template)))
+        if not os.path.isfile(template):
+            raise ConfigurationError("No such file", template)
+        kwargs['template'] = ViewPageTemplateFile(template)
+
+    # check interfaces
+    ifaces = list(interface.Declaration(provides).flattened())
+    if IPagelet not in ifaces:
+        provides.append(IPagelet)
+
+    # Build a new class that we can use different permission settings if we
+    # use the class more then once.
+    cdict = {}
+    cdict.update(kwargs)
+    cdict['__name__'] = name
+    cdict['layoutname'] = layout
+
+    if class_ is not None:
+        if issubclass(class_, BrowserPagelet):
+            bases = (class_,)
+        else:
+            bases = (class_, BrowserPagelet)
+    else:
+        bases = (BrowserPagelet,)
+
+    new_class = type('PageletClass from %s'%class_, bases, cdict)
+
+    # prepare allowed interfaces and attributes
+    allowed_interface.extend(provides)
+    allowed_attributes.extend(kwargs.keys())
+    allowed_attributes.extend(('__call__', 'browserDefault',
+                               'update', 'render', 'publishTraverse'))
+
+    # Set up permission mapping for various accessible attributes
+    _handle_allowed_interface(
+        _context, allowed_interface, permission, required)
+    _handle_allowed_attributes(
+        _context, allowed_attributes, permission, required)
+
+    # Register the interfaces.
+    _handle_for(_context, for_)
+
+    # provide the custom provides interface if not allready provided
+    for iface in provides:
+        if not iface.implementedBy(new_class):
+            interface.classImplements(new_class, iface)
+
+    # Create the security checker for the new class
+    defineChecker(new_class, Checker(required))
+
+    # register pagelet
+    _context.action(
+        discriminator = ('z3ext:pagelet', for_, layer, name),
+        callable = handler,
+        args = ('registerAdapter',
+                new_class, (for_, layer), IPagelet, name, _context.info))
+
+
+def _handle_allowed_interface(
+    _context, allowed_interface, permission, required):
+    # Allow access for all names defined by named interfaces 
+    if allowed_interface:
+        for i in allowed_interface:
+            _context.action(
+                discriminator = None,
+                callable = provideInterface,
+                args = (None, i))
+
+            for name in i:
+                required[name] = permission
+
+def _handle_allowed_attributes(
+    _context, allowed_attributes, permission, required):
+
+    # Allow access for all named attributes 
+    if allowed_attributes:
+        for name in allowed_attributes:
+            required[name] = permission
+
+def _handle_for(_context, for_):
+    if for_ is not None:
+        _context.action(
+            discriminator = None,
+            callable = provideInterface,
+            args = ('', for_))


Property changes on: z3ext.layout/trunk/src/z3ext/layout/zcml.py
___________________________________________________________________
Name: svn:keywords
   + Id



More information about the Checkins mailing list