|
|
||||||||||||||||||
|
|
||||||||||||||||||
![]() |
![]() |
Issue 4 - Revision 9 / July 9, 2003
|
|||
|
Zope 3 Skins for Developers - Step-by-Step - - - - - - - - - - - - By Paul Everitt | July 9, 2003 Abstract In the previous article, we gave the general background on the Rotterdam skin for Zope 3. Rotterdam is focused on a certain audience (site developers) and makes certain decisions to please this audience. This focus is reasonable because Zope 3 expects people to create their own user interfaces, including new management interfaces. Thus, how do you create a Zope 3 skin? The next articles will begin the process of building such a new interface. In this article we cover the following objectives:
Future installments in this series of articles will cover the Zope 3 API, as seen from the perspective of a skin developer and site developer. Dangerous CurvesFirst, a fair warning. Zope 3 is, at the time of this writing, still firmly in the domain of component developers. While it is valuable for web designers to evaluate the new model for creating user interfaces, it can also be difficult. Thus, a certain amount of pioneer spirit is required. Getting StartedFor this article, let's imagine we are building a content management interface for our new intranet at "Zeitgeist Management, Incorporated" (ZMInc), a management consulting company. We are the site developers and we need to build an interface for browsing and adding documents. This article will use the milestone 3 release of Zope X3, available at http://dev.zope.org/Members/jim/ZopeX3-0.0m3.tgz. The text of the announcement is available at http://mail.zope.org/pipermail/zope-announce/2003-July/001173.html. Note that the X3 M3 release requires Python 2.2.3 and PyXML 0.8.1 or higher. The INSTALL.txt file in the doc directory of the download provides a very good explanation of installation. Once you have Zope 3 running, you can point your browser at the http://localhost:8080/ URL to browse your site or the http://localhost:8080/@@contents.html URL to login and manage the contents. Important Notes
As veteran Zope 2 people know, ZPT was created to smooth the workflow between web designer and site developer. The web designer could create the mockups and the site developer could sprinkle in the "magic" to render dynamic pages, without breaking the HTML. For this article we will follow the same workflow by creating some mockups of the ZMInc site pages. The first page we will create is the home page. Let's call it home.html and save it in ~/sandboxes/samplesite/home.html. Using our favorite HTML editor, we create a mockup home page that looks like the following:
This mockup uses files:
and
The HTML file is simple:
<html>
<head>
<title>ZMInc Corporate Site</title>
</head>
<body>
<img src="zminclogo.png"/>
<h1>Welcome to ZMInc</h1>
</body>
</html>
To follow along, copy these two files to your ~/sandboxes/samplesite directory. Why Skins?As you will see in this series of articles, Zope 3's skins and layers facility is powerful but complex. At times you may scratch your head, overwhelmed, and wonder, "Why is this so complicated?" Fortunately there is a good reason: the problem itself is complicated. Thus, to appreciate the full beauty of the Zope 3 skin system, we must first understand the byzantine problems it tries to solve. Imagine a typical website page on a web application:
You need a box to hold the personalized content for the logged-in user:
Clearly these two variations are very similar. There should be some reuse between them. Next you want a page that lets you edit the page instead of just view the content:
Again, much of the page remains the same between all three pages. Now, imagine further variations between pages in your website:
Finally, put yourself in Zope 3's shoes and understand how massive of a challenge it has. In addition to the variations above, Zope 3 faces:
Zope 3 has to solve this arbitrary extensibility problem while staying within some contraints:
This is where the packages/skins/layers facility comes from. Packages are simple: they provide the physical distribution of the files in a skin. Thus let's focus on skins and layers:
In the diagram above, we see the four skins that ship with Zope X3 Milestone 3: Basic, Debug, Rotterdam, and ZopeTop. Each skin gets its resources (templates, images, CSS files, etc.) from one or more layers:
In each of these layers we can find files that act as available, published resources:
Thus we see the two levels of decomposition that solve the problems listed above. A skin is a user interface. Each skin creates or reuses resources defined in one or more layers. Simple, right? Alas, there is still rain in store for this parade. That is, there are other variables in the variations. For instance, ZPTs provide their own set of machinery for reuse through METAL. Thus, we also have an informal system of macros and slots:
And alas, there's still more: Python package locations, include directives, configuration files, interfaces. Other variables, such as "usage" are still being discussed. Indeed it is a bit overwhelming. For this article we will focus on skins and layers, with just a bit of METAL. Turn The Mockup Into a SkinLet's get started on Zope 3 development by turning this mockup into a 'zminc' skin for ZMInc. Doing so will involve the following steps:
Since Zope 3 has a goal to be more Pythonic, the first step to creating a skin is to turn the samplesite directory into a Python package. Fortunately this is very simple:
Next, for the Zope 3 server to know that this new Python package exists, we have to modify our PYTHONPATH environment variable to include the parent directory of our new package. In this case we need to add our ~/sandboxes directory:
Although Python has this package in its path, your Zope 3 server doesn't yet have it registered. Fortunately this, too, is easy:
And one final step: the samplesite package needs a configuration file. Now that Zope 3 knows your package is there, it will want to find out how to configure your package. In Zope 2, simply leaving a package in the right place was enough, but led to numerous headaches. Following the "explicit not implicit" dictum of Zope 3, we wire in our package with a configure.zcml file:
And that's it! Of course, that's only "it" if all goes well. If your Zope 3 server is running, shut it down and restart it. If the server starts with no error messages, then congratulations, you now have added a new skin to your Zope 3 site. Of course there isn't much to the skin yet. In fact, our mockup pages aren't even used. Still, we can view our work by visiting the following URL: http://localhost:8080/++skin++zminc/You should see a page that looks like the following screenshot:
As you can see, this screenshot doesn't look anything like the mockup. Why? Although you indicated that your package was a skin, you didn't do all the steps yet to build the skin. We'll do that below. Why Did That Work?Ok, now to the theory. Your samplesite package included a configuration file that added a new skin called zminc. Thus, the ++skin++zminc part of the URL, which told Zope 3 to use a different "namespace" for the root folder. However, when you see a Zope3 URL without any ++skin++ in it, you know that you are using the default skin, as configured in the configure.zcml file for Zope 3's skins subpackage. But where did all the stuff on the screen come from? Answer: the layers="default" attribute in our samplesite/configure.zcml configuration file. The directive looks like this: <browser:skin name="zminc" layers="default" /> This directive says:
We'll cover the theory of skins and layers in the next section. For now, simply understand that setting the layer to "default" says, "This skin gets all its stuff from the built-in Zope 3 stuff." Also, this point answers the question at the end of the previous section. Note: Though we say "built-in" layer, this doesn't mean Rotterdam, which is the default skin, not the default layer. What does this default layer look like? You can see it in the "Basic" skin (Basic is a very simple skin included in Zope 3) by going to the following URL: http://localhost:8080/++skin++basic/ As you can see, this looks exactly the same as your skin, since the Basic skin also only uses the default layer. In fact, we can confirm this little fact by visiting another URL in our Zope 3 site: http://localhost:8080/++skin++zminc/@@contents.htmlThis URL will require a username and password, set in the principals.zcml file you created as part of the installation process. Compare the above URL to: http://localhost:8080/++skin++basic/@@contents.htmlAgain, these URLs look the same, as both skins rely on the same layers. Where is Rotterdam? As we mentioned, the Rotterdam skin is the default skin. But you can always reach it by specifying the skin name in the URL: http://localhost:8080/++skin++Rotterdam/@@contents.htmlAfter these stes, we now have the simple management interface from the Basic skin, mirrored into our zminc skin. How does this "mirroring" happen? With skins and layers, our next topic. Skins and LayersZope 3 is designed to have modular, replaceable user interfaces. These interfaces are commonly referred to as "skins". Each skin is made up of layers, which provide the modularity by organizing related resources such as templates and images. The CMF explored the ideas of skins and layers quite effectively. The main problem the CMF tried to solve with layers was customization. Templates were the first thing that people wanted to change. If the CMF or a CMF developer then shipped a new version with changes, the upgrade would unfortunately overwrite the work done by the site developer. Thus, a CMF skin was built from layers, or locations where resources such as templates and graphics could be found. The resources from the software went in one layer and the customized resources went in another layer. Add-on products defined their own layers. Over time, though, a new benefit appeared from this skin approach. You could build a new skin by pointing at all the existing layers and implementing a simple change. This is what we did above: the "zminc" skin was configured to include the "default" layer. How do we find out which layers are available? The built-in skins and layers can be found in the skin configuration file at ~/sandboxes/Zope3/src/zope/app/browser/skins/configure.zcml. Here's what it looks like: <zopeConfigure xmlns='http://namespaces.zope.org/zope' xmlns:browser='http://namespaces.zope.org/browser' > <browser:skin name="" layers="rotterdam default" /> <include package=".basic" /> <include package=".zopetop" /> <include package=".rotterdam" /> <include package=".debug" /> </zopeConfigure> Confusingly, the Zope 3 skin configuration file doesn't define layers. Instead, it simply points at skin packages, each of which contain the configuration file that defines that particular skin. Each directive that defines a resource can specify a layer for that resource. Doing so makes a layer spring into existance. (This is one place where Zope 3 doesn't obey its "Explicit is better than implicit" maxim.) Unfortunately, this indirection is one of several that a skin developer will see, so let's repeat the discussion:
For this ZMInc article, the layers we are interested in are as follows:
We will review these layers in a moment. But first, let's get back to work on building our interface. Using Our Own LogoTo show layers in action, let's make our zminc skin re-use all of the Rotterdam skin. We will then change the Zope 3 logo to use our own ZMInc logo. First we need to include the Rotterdam layer in our skin. Remember, Rotterdam is defined in the configuration file at sandboxes/Zope3/src/zope/app/browser/skins/rotterdam/configure.zcml. To re-use these resources:
Look familiar? It is, essentially, the exact same skin as the Rotteram skin. To customize it, let's make two changes: use a new layer in our skin and add a resource for our own logo.
Here is a screenshot from a portion of the screen:
The Zope 3 logo object's contents are now filled with the ZMInc logo file's contents. (Purists will note that this change serves a JPEG file with a .gif file extension.) This change was surprisingly simple: the skin declaration added a new layer at the beginning and a new resource was added, replacing the one by the same name from the Rotterdam skin. This was a simple, but important customization. And we did it using ZCML instead of editing "software". In fact, this is exactly the purpose of Zope 3's configuration system, which wires all the assets together. Quick ReviewBefore taking a big step into using our mockup, let's review some of the new concepts and terminology we have introduced so far:
Packages, skins, and layers. Pretty simple, eh? Onward. Integrating Our MockupWe don't want ZMInc to look like Rotterdam, which is Zope 3's default skin. We want it to look like our mockup. How can we change the "master template" that lays out all the pages in our skin? First let's see how Rotterdam does it. There isn't anything obvious in the skins/rotterdam/configure.zcml or in the skins/rotterdam directory to identify the "master template". Through trial and error -- in this case, inserting an H1 element until it appears in the interface -- we identify template.pt as the "master template". Working the problem backwards, when look at the declaration for template.pt in skins/rotterdam/configure.zcml and see:
<browser:page
for="*"
name="skin_macros"
permission="zope.View"
layer="rotterdam"
template="template.pt"
/>
The item we are interested in is name="skin_macros". Thus, we have an important rule: Rule: The browser:page in a skin with the name="skin_macros" is the "master template" for that skin.This means that, to use our "home.html" mockup page as the "master template" for the zminc skin, we need to add this to our samplesites/configure.zcml file:
<browser:page
for="*"
name="skin_macros"
permission="zope.View"
layer="zminc"
template="home.html"
/>
That's the first part of the handshake for the skin mechanism. There are two more parts. For the second part, we need our newly-designated master template (test.html) to define the ZPT macro that identifies itself as the handler for the page. In short, this means wrapping the master template in a "define-macro".
As you can see, the interface is radically different. That is, the site looks like our mockup, except the image is broken. (We'll fix the image in a moment.) In fact, all pages on the site now look the same. Visit the URL at http://localhost:8080/++skin++zminc/@@contents.html to see. Why? Because we now have a master template that doesn't contain any ZPT. Thus, there is nothing dynamic in the site. We can fix that with a simple change:
Since Zope 3 runs in debugging mode, you don't need to restart the server for changes to templates. When you revisit the pages in your site, you will see that the browser shows different titles for each page. What makes this work? The third part of the handshake. The various template pages, written by the developers of Zope 3 and Zope 3 products, agree to conventions for the names of certain macro slots. The title above is an example. We'll explore more about this protocol as we build out our entire interface. Finally, we need to fix the broken image by giving the proper URL using ZPT's attribute replacement. Here is a final version of the home.html template:
<metal:block define-macro="page">
<html>
<head>
<title metal:define-slot="title">ZMInc Corporate Site</title>
</head>
<body>
<img src="zminclogo.png"
tal:attributes="src context/++resource++zope3logo.gif"/>
<h1>Welcome to ZMInc</h1>
</body>
</html>
</metal:block>
After you refresh your browser, the image will appear. Unfortunately, as shown above, the original idea of page templates -- that they would be valid HTML that could be directly edited in an HTML layout tool -- is no longer true. The <metal:block> element that encloses the template breaks this feature. Hopefully Zope 3 will evolve a solution to this problem. ConclusionCreating user interfaces for Zope 3 is a good exercise in learning the new development methodology. In this article we saw quite a few new concepts and concluded with a skin that is ready to be built into a user interface. For the next article, we will begin introducing more of the features for a full ZMInc site.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ZopeMag is committed to bringing you the best in Zope Documentation. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
![]() |
Reproduction of material from any of ZopeMag's pages without prior written permission is strictly prohibited. Copyright 2003 - 2005 ZopeMag |
|