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:
parent
173fe3bd0c
commit
f0110c70dc
7 changed files with 125 additions and 45 deletions
|
@ -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
|
||||
---------------------
|
||||
|
|
|
@ -23,3 +23,8 @@
|
|||
</script>
|
||||
</metal:js>
|
||||
|
||||
|
||||
<metal:js define-macro="js-execute">
|
||||
<script tal:content="macro/jsCall"></script>
|
||||
</metal:js>
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
<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>
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue