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 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 import component, interface
>>> from zope.publisher.browser import TestRequest >>> from zope.interface import Interface, implements
>>> from zope.publisher.interfaces.browser import IBrowserRequest >>> 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 The View Controller
------------------- -------------------
@ -24,18 +77,6 @@ because this already provides some predefined stuff:
>>> from cybertools.browser.liquid.controller import Controller >>> 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 = Controller(view, request)
>>> controller.view is view >>> controller.view is view
True True
@ -72,7 +113,7 @@ controller object to get an updated setting:
>>> controller.resourceBase >>> controller.resourceBase
'http://127.0.0.1/++skin++dummy/@@/' '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: ZPT macros:
>>> cssMacros = controller.macros['css'] >>> cssMacros = controller.macros['css']
@ -87,15 +128,34 @@ Calling a macro provided by Controller.macros[] returns the real ZPT macro:
>>> m1() >>> m1()
[...base_macros.pt...css...] [...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']) >>> len(controller.macros['css'])
5 5
>>> m5 = cssMacros[4] >>> m5 = cssMacros[4]
>>> print m5.name, m5.media, m5.resourceName >>> print m5.name, m5.media, m5.resourceName
css all node.css 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 The View Configurator
--------------------- ---------------------

View file

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

View file

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

View file

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

View file

@ -36,11 +36,12 @@ class Controller(BaseController):
macros = self.macros macros = self.macros
params = [('zope3_tablelayout.css', 'all'), params = [('zope3_tablelayout.css', 'all'),
('base.css', 'screen'), ('base.css', 'screen'),
('custom.css', 'all'), ('print.css', 'print')] ('custom.css', 'all'),
('print.css', 'print')]
for param in params: 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): def setupJs(self):
return 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" /> <metal:js use-macro="macro" />
</tal:js> </tal:js>
<tal:js repeat="macro controller/macros/js-execute">
<metal:js use-macro="macro" />
</tal:js>
<link rel="icon" type="image/png" <link rel="icon" type="image/png"
tal:attributes="href string:${resourceBase}favicon.png" /> tal:attributes="href string:${resourceBase}favicon.png" />
</head> </head>
<body tal:content="structure body"/> <body tal:content="structure body" />
</html> </html>
</metal:block> </metal:block>

View file

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