a whole bunch of work mainly introducing viewlet stuff; and a few renames...

git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@646 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2005-10-31 15:44:01 +00:00
parent 9cfdbfd255
commit 3ea664a763
20 changed files with 466 additions and 105 deletions

11
browser/README.txt Normal file
View file

@ -0,0 +1,11 @@
Use Content Providers and Viewlets for setting up web pages
===========================================================
We first set up a test and working environment:
>>> from zope.app import zapi
>>> from zope.app.testing import ztapi
>>> from cybertools.browser.pageprovider import BaseView, PageProviderView
>>> from cybertools.browser.pageprovider import PageProvider

View file

@ -1,4 +1,33 @@
#
# Copyright (c) 2005 Helmut Merz helmutm@cy55.de
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
"""
cybertools browser package.
$Id$
"""
from zope.viewlet.interfaces import IViewletManager
class ILeft(IViewletManager):
""" Left slot.
"""
class IBody(IViewletManager):
""" Body (main) content slot.
"""

77
browser/pageprovider.py Normal file
View file

@ -0,0 +1,77 @@
#
# Copyright (c) 2005 Helmut Merz helmutm@cy55.de
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
"""
cybertools regions.
$Id$
"""
from zope.interface import implements
import zope.component
from zope.app.publisher.interfaces.browser import IBrowserView
from zope.app.publisher.browser import BrowserView
from zope.contentprovider.interfaces import IContentProvider
from zope.viewlet.manager import ViewletManagerBase
class BaseView(object):
""" Basic view class using a template and possibly doing some other
setup stuff.
"""
implements(IBrowserView)
def __call__(self):
# render the template associated with this view:
return self.index()
class PageProviderView(object):
""" Simple view class using a content provider for setting up a page.
"""
implements(IBrowserView)
def __call__(self):
context = self.context
request = self.request
name = 'cybertools.pageprovider'
provider = zope.component.queryMultiAdapter(
(context, request, self), IContentProvider, name)
provider.update()
return provider.render()
class PageProvider(ViewletManagerBase):
""" Simple implementation that provides a whole page.
"""
implements(IContentProvider)
def __init__(self, context, request, view):
self.context = context
self. request = request
self.view = view
self.__parent__ = view
def update(self):
return ViewletManagerBase.update(self)
def render(self):
return ViewletManagerBase.render(self)

View file

@ -15,10 +15,23 @@
zope.app.zopetop.templates
rotterdam default" />
<page for="*"
<!--<page for="*"
name="view_macros" template="view_macros.pt"
permission="zope.View"
layer="cyberview" />
layer="cyberview" />-->
<view for="*"
name="default.html"
class="cybertools.browser.pageprovider.PageProviderView"
permission="zope.View"
layer="cyberview"
/>
<defaultView
for="*"
name="default.html"
layer="cyberview"
/>
<resource name="cyberview.css" file="cyberview.css"
layer="cyberview" />
@ -32,21 +45,43 @@
<resource name="bg_cyberview.gif" image="bg_cyberview.gif"
layer="cyberview" />
<zope:interface interface="cybertools.browser.viewlets.ILeft"
type="zope.contentprovider.interfaces.IContentProviderType" />
<viewletManager
name="navMenu"
provides="cybertools.browser.viewlets.ILeft"
name="cybertools.pageprovider"
provides="zope.contentprovider.interfaces.IContentProvider"
class="cybertools.browser.pageprovider.PageProvider"
template="main.pt"
permission="zope.Public"
layer="cyberview"
/>
<viewletManager
name="cybertools.body"
provides="cybertools.browser.IBody"
permission="zope.Public"
layer="cyberview"
/>
<viewlet
name="body"
manager="cybertools.browser.IBody"
template="index.pt"
class="zope.app.container.browser.contents.Contents"
permission="zope.Public"
layer="cyberview"
/>
<viewletManager
name="cybertools.left"
provides="cybertools.browser.ILeft"
template="left_slot.pt"
permission="zope.Public"
layer="cyberview"
/>
<viewlet
name="navMenu"
manager="cybertools.browser.viewlets.ILeft"
template="menu_viewlet.pt"
name="navmenu"
manager="cybertools.browser.ILeft"
template="viewlet_menu.pt"
class="cybertools.browser.menu.MenuViewlet"
permission="zope.Public"
layer="cyberview"

View file

@ -0,0 +1,23 @@
Using the CyberView Skin
========================
We first set up a test and working environment:
>>> from zope.app import zapi
>>> from zope.app.testing import ztapi
>>> from zope.app.component import site, interfaces
>>> from zope.testbrowser import Browser
>>> browser = Browser()
>>> browser.addHeader('Authorization', 'Basic mgr:mgrpw')
We can now open a page using the CyberView skin:
>>> browser.addHeader('Accept-Language', 'en-US')
>>> browser.open('http://localhost/++skin++CyberView')
>>> print browser.headers
Status: 200 Ok...
>>> browser.url
'http://localhost/++skin++CyberView'

44
browser/skin/index.pt Normal file
View file

@ -0,0 +1,44 @@
<table
id="sortable" class="listing" summary="Content listing"
cellpadding="2" cellspacing="0"
i18n:attributes="summary">
<thead>
<tr>
<th>&nbsp;</th>
<th i18n:translate="">Name</th>
<th i18n:translate="">Title</th>
<th i18n:translate="">Created</th>
<th i18n:translate="">Modified</th>
</tr>
</thead>
<tbody>
<tr tal:repeat="info view/listContentInfo">
<td>
<a
href="#"
tal:attributes="href string:${request/URL}/${info/url}"
tal:content="structure info/icon|default" />
</td>
<td class="ContentTitle">
<a href="subfolder_id"
tal:attributes="href info/url"
tal:content="info/id"
i18n:translate=""
>ID here</a>
</td>
<td><span tal:content="info/title|default"
i18n:translate="">&nbsp;</span></td>
<td><span tal:content="info/created|default"
i18n:translate="">&nbsp;</span></td>
<td><span tal:content="info/modified|default"
i18n:translate="">&nbsp;</span></td>
</tr>
</tbody>
</table>

View file

@ -2,9 +2,6 @@
Headline
</div>
<div tal:repeat="viewlet options/viewlets">
<div tal:content="structure python: viewlet(viewlet=viewlet)">
<!--<div tal:repeat="item python: menu.getMenuItems(context, request)">
<span tal:replace="item/title"/>
</div>-->
<div tal:content="structure python: viewlet(viewlet=viewlet)">Left Slot
</div>
</div>

53
browser/skin/main.pt Normal file
View file

@ -0,0 +1,53 @@
<metal:block define-macro="page"><metal:block define-slot="doctype"><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"></metal:block>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"
i18n:domain="zope">
<head metal:define-macro="head">
<title metal:define-slot="title"
tal:content="options/getTitle|view/getTitle|context/getTitle|default">
cyberconcepts IT-Consulting
</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link href="cyberview.css" rel="stylesheet" type="text/css"
tal:attributes="href context/++resource++cyberview.css" />
</head>
<body>
<div class="top">
<a href="#" name="top" tal:attributes="href string:${request/URL/1}">
<img src="cyberconcepts.gif" height="75"
alt="cyberconcepts IT-Consulting"
tal:attributes="src context/++resource++cyberconcepts.gif" />
</a>
<span metal:use-macro="context/@@standard_macros/logged_user">
Logged in as user
</span>
</div>
<table class="columns">
<tr>
<td class="left">
<!--
<span metal:use-macro="context/@@standard_macros/commontasks_box" />
<span metal:use-macro="context/@@standard_macros/metadata_box" />
<span metal:use-macro="context/@@standard_macros/views_box" />
<span metal:use-macro="context/@@standard_macros/actions_box" />
-->
<div tal:replace="structure provider:cybertools.left" />
</td>
<td class="main">
<!--
<span metal:use-macro="context/@@standard_macros/zmi_views" />
<span metal:use-macro="context/@@standard_macros/zmi_actions" />
<span metal:use-macro="context/@@standard_macros/content_header_bar" />
-->
<div tal:replace="structure provider:cybertools.body" />
</td>
</tr>
</table>
<!--
<span metal:use-macro="context/@@standard_macros/footer" />
-->
</body>
</html>
</metal:block>

View file

@ -42,6 +42,7 @@
<span metal:use-macro="context/@@standard_macros/content_header_bar" />
-->
<span metal:define-slot="body">Here comes the body</span>
<!--<p tal:content="provider:cybertools.pageprovider" />-->
</td>
</tr>
</table>

View file

@ -0,0 +1,2 @@
<div tal:define="menu options/viewlet/getMenu"
tal:content="python: menu.getMenuItems(context, request)" />

14
ftests.py Executable file
View file

@ -0,0 +1,14 @@
# $Id$
import unittest, doctest
from zope.testing.doctestunit import DocFileSuite
from zope.app.testing.functional import FunctionalDocFileSuite
def test_suite():
flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
browser = FunctionalDocFileSuite('browser/skin/cyberview.txt', optionflags=flags)
return unittest.TestSuite((browser,))
if __name__ == '__main__':
unittest.main(defaultTest='test_suite')

133
lazynamespace/README.txt Normal file
View file

@ -0,0 +1,133 @@
Setting up and using LazyNamespace objects
==========================================
A LazyNamespace contains variables that are only calculated when really
needed, and these are calculated only once during the lifetime of the
LazyNamespace objects they live in.
This is especially useful when rendering web pages as during this
rendering often the same data are used again and again, whereas you don't
know at the beginning of the rendering process which data you will really
need.
We first need a function that will be used to provide a value
for a variable we want to use in the LazyNamespace. This function will expect
one parameter that will be set to the LazyNamespace object when the function
is called.
Our demonstration function will increment a counter on a context object
(provided via the vars parameter) and return this counter so that we can easily
follow the calls to the function:
>>> def getNumber(vars):
... context = vars.context
... context.counter += 1
... return context.counter
We now register the function with our LazyNamespace class under the name
we later want to use for accessing the variable:
>>> from cybertools.lazynamespace.lazynamespace import LazyNamespace
>>> LazyNamespace.registerVariable('number', getNumber)
We also need a context object - that one which carries the above mentioned
counter:
>>> from zope.interface import Interface, implements
>>> class Number(object):
... implements(Interface)
... counter = 0
>>> context = Number()
This object is now used as the context parameter when creating a LazyNamespace
object:
>>> lns = LazyNamespace(context)
So let's look if the LazyNamespace object can give us a value for the variable
we have registered:
>>> lns.number
1
The getNumber() function has been called that apparently has
incremented the counter.
What happens if we access the variable again?
>>> lns.number
1
Same result, no incrementation, as it is now stored in the LazyNamespace
object and retrieved without recalculation. Really lazy...
We can even use the same function for more than one variable. When we first
access the new variable the function is called again:
>>> LazyNamespace.registerVariable('number2', getNumber)
>>> lns.number2
2
Our first variable is not affected by this:
>>> lns.number
1
Typically you will use a LazyNamespace class for adapters. When you want
to use a LazyNamespace when rendering a browser web page you may use
a LazyBrowserNamespace:
LazyBrowserNamespace
~~~~~~~~~~~~~~~~~~~~
A LazyBrowserNamespace is meant to be used as a multi-adapter on a context
object, a request, and a view.
>>> from cybertools.lazynamespace.lazynamespace import LazyBrowserNamespace
>>> from cybertools.lazynamespace.interfaces import ILazyNamespace
>>> import zope.component
>>> from zope.publisher.interfaces.browser import IDefaultBrowserLayer
>>> from zope.app.publisher.interfaces.browser import IBrowserView
>>> zope.component.provideAdapter(LazyBrowserNamespace,
... (Interface, IDefaultBrowserLayer, IBrowserView),
... ILazyNamespace)
We can now get at a LazyBrowserNamespace adapter using our context object
from above and supplying a request and a view in addition.
>>> from zope.publisher.browser import TestRequest
>>> request = TestRequest()
>>> class View(object):
... implements(IBrowserView)
... def __init__(self, context, request):
... pass
>>> view = View(context, request)
>>> from zope.app import zapi
>>> lbns = zapi.getMultiAdapter((context, request, view), ILazyNamespace)
The LazyBrowserNamespace is independent of the LazyNamespace class and
provides its own registry. So we won't find our variable from above
there:
>>> lbns.number
Traceback (most recent call last):
...
KeyError: 'number'
So we again register a variable, now with the LazyBrowserNamespace:
>>> LazyBrowserNamespace.registerVariable('number', getNumber)
>>> lbns.number
3
>>> lbns.number
3
The old stuff from above is not affected:
>>> lns.number
1

View file

@ -9,11 +9,13 @@
<!-- Content declarations -->
<utility provides=".interfaces.IRelationsRepository"
factory=".utilities.RelationsRepository" />
<utility provides=".interfaces.IRelationsRegistry"
factory=".utilities.RelationsRegistry" />
<adapter
for="zope.interface.Interface
zope.app.publisher.interfaces.browser.IBrowserRequest"
provides=".interfaces.ILazyNamespace"
factory=".lazynamespace.LazyNamespace"
permission="zope.Public"
/>
<!-- Register various browser related components, including all views -->
<!--include package=".browser" /-->

View file

@ -25,7 +25,7 @@ $Id$
from zope.interface import Interface, Attribute
class ILazyVars(Interface):
class ILazyNamespace(Interface):
""" Generic adapter that provides lazy setting and returning
of variables.
"""
@ -34,9 +34,9 @@ class ILazyVars(Interface):
""" Class method: register a variable 'name' on class 'class_' that
will be provided by calling the function given.
The function should have one parameter that is set to the LazyVars
object when the function is called. Thus the method has access
to the instance variables (and other methods) of the LazyVars
object.
The function should have one parameter that is set to the
LazyNamespace object when the function is called. Thus the method
has access to the instance variables (and other methods) of the
LazyVars object.
"""

View file

@ -25,11 +25,11 @@ $Id$
from zope.interface import implements
import interfaces
class LazyVars(object):
""" Basic adapter providing lazy variables.
class LazyNamespace(object):
""" Basic adapter providing a lazy namespace.
"""
implements(interfaces.ILazyVars)
implements(interfaces.ILazyNamespace)
variables = {}
@ -44,4 +44,19 @@ class LazyVars(object):
value = self.variables[attr](self)
setattr(self, attr, value)
return value
class LazyBrowserNamespace(LazyNamespace):
""" A multi-adapter providing a lazy namespace for to be used for
browser views.
"""
variables = {} # LazyBrowserNamespace class should get its own registry.
def __init__(self, context, request, view):
self.context = context
self.request = request
self.view = view

View file

@ -1,72 +0,0 @@
Setting up and using LazyVars objects
=====================================
Lazy variables are only calculated when really needed, and they are
calculated only once during the lifetime of the LazyVars objects they
live in.
This is especially useful when rendering web pages as during this
rendering often the same data are used again and again, whereas you don't
know at the beginning of the rendering process which data you will really
need.
We first need a function that will be used to provide a value
for our lazy variable. This function will expect one parameter that will
be set to the LazyVars object when the function is called.
Our demonstration function will increment a counter on a context object
(provided via the vars parameter) and return this counter so that we can easily
follow the calls to the function:
>>> def getNumber(vars):
... context = vars.context
... context.counter += 1
... return context.counter
We now register the function with our LazyVars class under the name we later
want to use for accessing the variable:
>>> from cybertools.lazyvars.lazyvars import LazyVars
>>> LazyVars.registerVariable('number', getNumber)
We also need a context object - that one which carries the above mentioned
counter:
>>> class Number(object):
... counter = 0
>>> context = Number()
This object is now used as the context parameter when creating a LazyVars
object:
>>> lv = LazyVars(context)
So let's look if the LazyVars object can give us a value for the variable
we have registered:
>>> lv.number
1
The getNumber() function has been called that apparently has
incremented the counter.
What happens if we access the variable again?
>>> lv.number
1
Same result, no incrementation, as it is now stored in the LazyVars object and
retrieved without recalculation. Really lazy...
We can even use the same function for more than one variable. When we first
access the new variable the function is called again:
>>> LazyVars.registerVariable('number2', getNumber)
>>> lv.number2
2
Our first variable is not affected by this:
>>> lv.number
1

View file

@ -40,8 +40,9 @@ class TestMenu(unittest.TestCase):
def test_suite():
return unittest.TestSuite((
unittest.makeSuite(TestMenu),
DocFileSuite('../doc/menu.txt'),
unittest.makeSuite(TestMenu),
DocFileSuite('browser/README.txt'),
DocFileSuite('doc/menu.txt'),
))
if __name__ == '__main__':

View file

@ -1,4 +0,0 @@
"""
$Id$
"""