|
|
|
1 2 3 4 5 6 7 8 9 10 11 | import grok
class Sample(grok.Application, grok.Container):
pass
class Index(grok.View):
pass # see app_templates/index.pt
class MyMacros(grok.View):
"""The macro holder"""
grok.context(Sample) # The default model this view is bound to.
|
In the associated page template app_templates/mymacros.pt we define the macros we like to have available. You define macros with the METAL attribute:
metal:define-macro="<macro-name>"
and the slots therein with:
metal:define-slot=<slot-name>
Let's define a very plain page macro in app_templates/mymacros.pt:
<html metal:define-macro="mypage">
<head></head>
<body>
The content:
<div metal:define-slot="mycontent">
Put your content here...
</div>
</body>
</html>
Here we defined a single macro mypage with only one slot mycontent.
If we restart our Zope instance (don't forget to put some index.pt into app_templates/) and have created our application as test, we now can go to the following URL:
http://localhost:8080/test/mymacros
and see the output:
The content: Put your content here...
Allright.
In index.pt we now want to use the macro defined in mymacros.pt. Using a macro means to let it render a part of another page template, especially, filling the slots defined in mymacros.pt with content defined in index.pt. You call macros with the METAL attribute:
metal:use-macro="<macro-location>"
Our app_templates/index.pt can be that simple:
<html metal:use-macro="context/@@mymacros/macros/mypage">
</html>
Watching:
http://localhost:8080/test/index
should now give the same result as above, although we didn't call mymacros in browser, but index. That's what macros are made for.
When we fill the slots, we get different content rendered within the same macro. You can fill slots using:
metal:fill-slot="<slot-name>"
where the slot-name must be defined in the macro. Now, change index.pt to:
<html metal:use-macro="context/@@mymacros/macros/mypage">
<body>
<!-- slot 'mycontent' was defined in the macro above -->
<div metal:fill-slot="mycontent">
My content from index.pt
</div>
</body>
</html>
and you will get the output:
The content: My content from index.pt
The pattern of the macro reference (the <macro-location>) used here is:
context/<view-name>/macros/<macro-name>
whereas context references the object being viewed, which in our case is the Sample application. In plain English we want Zope to look for a view for a Sample application object (test) which is called mymacros and contains a macro called mypage.
The logic behind this is, that views are always registered for certain object types. Registering a view with some kind of object (using grok.context() for example), means, that we promise, that this view can render objects of that type. (It is up to you to make sure, that the view can handle rendering of that object type).
It is not a bad idea to register views for interfaces (instead of implementing classes), because it means, that a view will remain usable, while an implementation of an interface can change. [FIXME: Is this a lie?] This is done in the section Defining 'all-purpose' macros.
In the case of grok.View views, they subclass the Zope 3 BrowserPage objects which provide an attribute template, which is the associated page template. The associated page template in turn has got an attribute macros, which is a dictionary containing all the macros defined in the page template with their names as keys (or None).
This means, that you can also reference a macro of a grok.View using:
context/<view-name>/template/macros/<macro-name>
Grok shortens this path for you by mapping the macros dictionary keys to the associated grok.View. If you define a macro mymacro in a template associated with a grok.View called myview, this view will map mymacro as an attribute, so that you can ask for the attribute mymacro of the view, where as it is in fact an attribute of the associated template.
Such, you can write in short for the above pattern:
context/<view-name>/macros/<macro-name>
View names always start with the 'eyes' (@@) which is a shortcut for ++view++<view-name>.
1 2 3 4 5 | from zope.interface import Interface
import grok
class Master(grok.View):
grok.context(Interface)
|
and reference the macros of the associated pagetemplate like this:
context/@@master/macros/<macro-name>
Because the macros in Master now are 'bound' (in fact their view is bound) to Interface and every Grok application, model or container implements some interface, the Master macros will be accessible from nearly every other context. Master promises to be a view for every object, which implements Interface.
To give your pages standard Zope3 look, you can do something like this in your page template:
<html metal:use-macro="context/@@standard_macros/page">
<head>
<title metal:fill-slot="title">
Document Title
</title>
<metal:headers fill-slot="headers">
<!-- Additional headers here... -->
</metal:headers>
</head>
<body>
<div metal:fill-slot="body">
Your content here...
</div>
</body>
</html>
© Copyright 2007-2008, The Grok Community
Hosting provided by Quintagroup
