finished registration of macros (for resources, global js calls, etc.) on new view structure with main.pt

git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@1315 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2006-08-18 12:06:18 +00:00
parent 173fe3bd0c
commit f0110c70dc
7 changed files with 125 additions and 45 deletions

View file

@ -1,15 +1,68 @@
Browser View Tools
==================
We first set up a test and working environment:
>>> from zope.app import zapi
>>> from zope.app.testing import ztapi
>>> from zope import component, interface
>>> from zope.publisher.browser import TestRequest
>>> from zope.interface import Interface, implements
>>> from zope.publisher.interfaces.browser import IBrowserRequest
The Generic View class
----------------------
GenericView is intended as the base class for application-specific views.
The GenericView class itself provides only basic functionality, so you
will have to subclass it. (An example can be found in loops.browser - see
the common and node modules there.)
Let's start with a dummy content object and create a view on it:
>>> class SomeObject(object):
... implements(Interface)
>>> obj = SomeObject()
>>> from cybertools.browser.view import GenericView
>>> class View(GenericView): pass
>>> from zope.publisher.browser import TestRequest
>>> request = TestRequest()
>>> view = View(obj, request)
Via the `template` and `macro` attributes one may control the presentation of
the view - in fact the rendering of a certain content object is achieved
by providing an appropriate macro for its view.
The view also may provide a special skin and a menu.
All these attributes default to None:
>>> view.template is None
True
>>> view.macro is None
True
>>> view.skin is None
True
>>> view.menu is None
True
The `item` attribute may be used to delegate to another view; it defaults to
self:
>>> view.item is view
True
There is a method for setting the skin that will be called when the controller
attribute is set, see below:
>>> view.setSkin(None)
When the view is called, the standard main template (main.pt) is rendered;
this template in turn calls the view's pageBody() method to render the
body.
This pageBody() method returns the rendered body by accessing another view
(default: BodyTemplateView) that provides a corresponding template in its
bodyTemplate attribute.
The View Controller
-------------------
@ -24,18 +77,6 @@ because this already provides some predefined stuff:
>>> from cybertools.browser.liquid.controller import Controller
Before creating a controller we have to set up a context object and
a view:
>>> class SomeObject(object): pass
>>> obj = SomeObject()
>>> from cybertools.browser.view import GenericView
>>> class View(GenericView):
... pass
>>> from zope.publisher.browser import TestRequest
>>> request = TestRequest()
>>> view = View(obj, request)
>>> controller = Controller(view, request)
>>> controller.view is view
True
@ -72,7 +113,7 @@ controller object to get an updated setting:
>>> controller.resourceBase
'http://127.0.0.1/++skin++dummy/@@/'
The controller may be used as a provider for content elements using
The controller may be used as a provider for HTML elements using
ZPT macros:
>>> cssMacros = controller.macros['css']
@ -87,15 +128,34 @@ Calling a macro provided by Controller.macros[] returns the real ZPT macro:
>>> m1()
[...base_macros.pt...css...]
The pre-set collection of macros for a certain slot may be extended:
The pre-set collection of macros for a certain slot may be extended
(this may be done by overriding the view's setupController() method, e.g.):
>>> controller.macros.register('css', resourceName='node.css', media='all')
>>> controller.macros.register('css', 'node.css', resourceName='node.css', media='all')
>>> len(controller.macros['css'])
5
>>> m5 = cssMacros[4]
>>> print m5.name, m5.media, m5.resourceName
css all node.css
If an identifier is given (the second parameter) a certain macro is only
registered once; note: the first setting will not be overridden!
>>> controller.macros.register('css', 'node.css', resourceName='node.css')
>>> len(controller.macros['css'])
5
We can also access slots that are not predefined:
>>> controller.macros['js.execute']
[]
>>> jsCall = 'dojo.require("dojo.widget.Editor")'
>>> controller.macros.register('js-execute', jsCall, jsCall=jsCall)
>>> dojoCall = controller.macros['js-execute'][0]
>>> dojoCall()
[...base_macros.pt...macro/jsCall...]
The View Configurator
---------------------

View file

@ -23,3 +23,8 @@
</script>
</metal:js>
<metal:js define-macro="js-execute">
<script tal:content="macro/jsCall"></script>
</metal:js>

View file

@ -21,7 +21,7 @@
<page for="*"
name="body.html"
class="cybertools.browser.view.GenericView"
class="cybertools.browser.view.BodyTemplateView"
permission="zope.View"/>
<page name="controller"

View file

@ -69,12 +69,10 @@ class Macros(dict):
def __init__(self, controller):
self.controller = controller
self['css'] = []
self['js'] = []
self.identifiers = set()
def register(self, slot, template=None, name=None, position=None,
identifier=None, **kw):
def register(self, slot, identifier=None, template=None, name=None,
position=None, **kw):
if identifier:
# make sure a certain resource is only registered once
if identifier in self.identifiers:
@ -85,12 +83,15 @@ class Macros(dict):
if name is None:
name = slot
macro = Macro(template, name, **kw)
if slot not in self:
self[slot] = []
entry = self.setdefault(slot, [])
if position is None:
self[slot].append(macro)
entry.append(macro)
else:
self[slot].insert(position, macro)
entry.insert(position, macro)
def __getitem__(self, key):
return self.get(key, [])
class Macro(object):

View file

@ -36,11 +36,12 @@ class Controller(BaseController):
macros = self.macros
params = [('zope3_tablelayout.css', 'all'),
('base.css', 'screen'),
('custom.css', 'all'), ('print.css', 'print')]
('custom.css', 'all'),
('print.css', 'print')]
for param in params:
macros.register('css', resourceName=param[0], media=param[1])
macros.register('css', identifier=param[0],
resourceName=param[0], media=param[1])
def setupJs(self):
return
#self.macros['js'] = []
self.macros.register('js', resourceName='zope3.js')
#self.macros.register('js', resourceName='zope3.js')

View file

@ -20,11 +20,15 @@
<metal:js use-macro="macro" />
</tal:js>
<tal:js repeat="macro controller/macros/js-execute">
<metal:js use-macro="macro" />
</tal:js>
<link rel="icon" type="image/png"
tal:attributes="href string:${resourceBase}favicon.png" />
</head>
<body tal:content="structure body"/>
<body tal:content="structure body" />
</html>
</metal:block>

View file

@ -29,18 +29,27 @@ from zope.publisher.interfaces.browser import ISkin
from zope.app.pagetemplate import ViewPageTemplateFile
mainTemplate = ViewPageTemplateFile('main.pt')
class UnboundTemplateFile(ViewPageTemplateFile):
def __get__(self, instance, type):
return self
class GenericView(object):
class BodyTemplateView(object):
""" Dummy view used for providing a body template.
"""
index = ViewPageTemplateFile('main.pt')
bodyTemplate = UnboundTemplateFile('liquid/body.pt')
menu = macro = skin = None
class GenericView(object):
index = mainTemplate
template = macro = menu = skin = None
def setController(self, controller):
# make the (one and only controller) available via the request
@ -66,10 +75,14 @@ class GenericView(object):
def setupController(self):
pass
@Lazy
def item(self):
return self
def pageBody(self):
template = component.getMultiAdapter((self.context, self.request),
bodyTemplate = component.getMultiAdapter((self.context, self.request),
name='body.html').bodyTemplate
return template(self)
return bodyTemplate(self)
def setSkin(self, skinName):
skin = None
@ -79,8 +92,4 @@ class GenericView(object):
applySkin(self.request, skin)
self.skin = skin
@Lazy
def item(self):
return self