Plone Appearance
Status: I will not finish this page; see Update below.
Pagecode: T->1 A->SAml H->trsa[t,a,si,di]d[t,a,si,di] C->SA[cccej]
Last changed: Monday 2010-03-01 [12:22 UTC]
Abstract:
This page is not about the many things under Plone's hood but about the visual/audio appearance of Plone to the user. In other words, this page is going to talk about XHTML, CSS, theming, skinning and the like. The reason why that is important respectively folks are interested in some individual site design -- something different than what ships with a Plone default installation -- is for the simple fact that individuals have personal likings or the site simply has to look like in a special way in order to comply to some corporate design agenda.
|
Table of Contents
|
Update: I now (May 2009) stopped working with/on Plone in favor of
Dolmen simply because working with Plone is no fun anymore. Plone has
become way to fat and confusing to work with over the years — I need
something that works with me, not against me.
There is a particular section on plone.org that is about visual design
in general.
Creating a Theme
This assumes that we already have a Buildout in place i.e. we start
here right after the Buildout step has been completed.
GenericSetup
What is GenericSetup? GenericSetup is a major step forward in
managing Plone site configuration, and as of Plone 2.5 GenericSetup
is a core part of how Plone handles its own site creation process.
Okay, that is all well and good. But what is it? Simply put,
GenericSetup is a Zope-based toolkit for managing site configuration.
Not much clearer? Maybe this would work better as a story:
Meet Guy Ablaze. Guy is a Plone site developer, who manages websites
built with Plone, and even develops add-on products for Plone using
Python. Guy never uses Plone just out of the box. Instead, he does a
lot of customization for every site he deploys. All of his sites have
custom skins, where the CSS and template modifications live. A lot of
his sites use custom content types. Rarely does he find that the
default site tabs are to his liking; he often replaces those with
custom tabs. And there are a myriad of little tweaks and adjustments
that he makes to each site, to get it working just so, to satisfy his
demanding customer's diverse requirements.
Guy knows that it is a good idea to be able to recreate a customer's
site without having to do a lot of twiddling in the ZMI, so he creates
install methods for each of the sites that he manages. These install
methods are written in Python. Each one is comprised of a bunch of
steps. One step is to install custom skins, containing the site's look
and feel. Another step might be to install some custom types, while a
third customizes the site tabs. And of course there are a bunch of
little steps that correspond to all of the miscellaneous tweaks that
he's made.
Guy is reasonably happy with this arrangement, but, you know, there
are some ways that it could be better. First, he finds that he has to
write a lot of repetitive boilerplate code in his various install
methods. Also, using Python instructions to describe how his site
should be configured does not really fit his brain. He would much
rather just be able to make a list of the types he wants and have them
automatically get installed. Also, it would be great if he could not
only import site configuration, but export site configuration. As in,
he could make some changes to the site, maybe using the Plone
interface, maybe using the ZMI, and then be able to spit that out to
be loaded somewhere else. And, wow, the mind boggles... would it not
be great to be able to compare site configurations? To be able to ask
What has been manually changed in my site since I did the original
installation? and get a meaningful answer? All of this and more is
what we get when we use GenericSetup!
Profiles
A profile is a set of XML (Extensible Markup Language) files that
describe the configuration of a particular Plone site. Note the
fundamental difference between a profile and an install method e.g. a
Buildout —
install methods define a set of steps that must be run to
get a result, while a profile actually describes the result itself.
This makes a lot more sense, semantically. It also brings site
configuration down from the lofty clouds of programmer-land, to a
realm where the non-programmer-type site managers might even be able
to look at the site configuration and understand its meaning.
What does a GenericSetup profile look like? Well, we can see a very
simple demonstration profile that has been recently added to the
GenericSetup software itself. If we want to see a much more complex
profile, we can look at the default Plone profile. I am not going into
detail, but I will rather point out a couple of things these profiles
have in common.
What we first notice, is that they both contain import_steps.xml and
export_steps.xml files. The import_steps.xml file defines all of the
steps that need to be taken when this configuration is loaded into our
site, while export_steps.xml describes the steps that should be taken
when we want to generate a new configuration profile from the live
site.
If we look a little bit more closely at the import_steps.xml file, we
will see that it contains a number of <import-step> tags, each of
which have an ID (Identifier), a version, a title, and a handler. Some
of them also contain one or more nested <dependency> tags. These
dependency tags allow us to specify that certain steps must be run
before other ones. For instance, it does us no good to configure the
actions tool (which is handled by the actions import step) before the
actions tool is instantiated (which is handled by the toolset import
step). Therefore, in the actions import step we will typically see the
following nested tag: <dependency step=toolset" />.
- Note
-
A tool is a singleton persistent object, found in the root of the
Plone site. Most tools have names starting with
portal_, such as
portal_membership, portal_setup or portal_types. They variously expose
shared functionality and act as containers for configuration state.
Most tools can be configured from the ZMI (Zope Management Interface),
and many of the Plone Site Setup control panels manage tool settings
under the hood.
Next, thing we see is that there are a bunch of other files. Each of
these other files deals with a specific aspect of our site's
configuration, and is usually related to a single step that was
included in the import and/or export steps. Common examples of these
additional files include:
- toolset.xml
-
Registers all of the tools available to the site. This must happen
before the tools are configured.
- skins.xml
-
A list of all of the skin paths that should be added to the skins tool
when our site is configured.
- skins(folder)
-
Contains all of the templates, images, and CSS (Cascading Style
Sheets) files for our skins.
- types.xml
-
A list of all the types that should be defined in the site's
portal_types tool.
- types (folder)
-
A folder containing other XML files, one for each type listed in
types.xml. Each file contains detailed configuration information
related to the specific custom content type for which it is named.
- workflows.xml
-
Registers all of the workflows for the product (those in the workflows
folder).
- workflows (folder)
-
Contains the workflow definitions. Each subfolder contains one
workflow. The workflows consist of a definition.xml file, and any
supporting scripts necessary for the workflow operation.
- And so on ...
There are many more already defined configuration files that
GenericSetup understands. And it is even possible to define and create
our own! An important point to note about profiles is —
Not all
profiles are created equal. In fact, there are two types of profiles
that GenericSetup understands
- Base Profiles and
- Extension Profiles
Base Profile
The first type is called a base profile. Base profiles, as anyone
would guess, provide the base level information that a site needs to
be created. In Plone 2.5 and onwards, Plone's default setup is itself
a GenericSetup base profile. Base profiles contain configuration
information such as tools, workflows, types, register plug-ins for
some packages. Most people building custom sites will never have to
create a base profile — and we should not create or alter our base
profile until we have some practice.
Extension Profile
Extension profiles are meant to be applied after base profiles. Any
number of extension profiles can be applied to a site, whereas only a
single base profile is ever applied. Extension profiles are meant to
describe new content types, custom skins, custom workflows, custom
tools, and add their configuration to what has already been set up in
the base profile. All of these are additive actions, that is they do
not make any changes to currently existing products. Changing
configuration in existing tools, modifying content types to respond to
different workflow, or any other modifications of the base profiles,
are less safe actions, and only should be undertaken when we know what
we are doing.
When a base profile has been activated, we can install additional
extension profiles. An extension profile is configured in the same way
as a base profile and uses the same handlers, but it will normally
only contain a subset of the settings that make up the site, either as
overrides for those from the base profile, or as new entries.
Extension profiles are useful for add-on products that need to be
installable independently of the rest of the configuration of the
site, as well as where the configuration will not deviate extensively
from the base profile.
To see an example of the profile that describes a current Plone site
and illustrates these concepts, one might export a snapshot and take a
look at what is done. The portal_setup tools section will now show a
few things in detail.
portal_setup tool
At first, let us clarify what we are talking about — the note from
above plus the image below should make it clear (also note, that we
are within a Plone Instance i.e. we are dealing with a particular
Plone Instance running on some Zope Instance. In case the reader is
still a bit uncertain about all the terms, the Glossary might be worth
a look).
The first thing to know about the setup tool is that it is stateful
i.e. that at any given time, the setup tool is working in relation to
an active profile. We can see which profile is currently active, as
well as set the active profile from any of the available profiles, on
the portal_setup properties tab in the ZMI (Zope Management
Interface).
The Plone Site profile that is currently active is the default Plone
base profile, the one that is used whenever we add a Plone site using
the ZMI. Once we know what profile is active, we can for example click
on the Import tab to see the import steps that are currently
registered. We can also export a profile using the Export tab. Then
there can be snapshots made which we might compare to each another
etc.
All that comes in handy when we are in the course of developing a new
site e.g. we start with Plones Site profile, export it and also take a
snapshot. Then we start customizing ... after a while, we take another
snapshot. Starting with two snapshots we can already start to compare
particular profiles, undo changes by importing a former exported
profile from its XML file or simply use the snapshot taken from an
earlier stage etc. Also, if someone else wants to help with
customizing, he would run a Builout first (given we provided him with
our buildout.cfg) then we would use the Export tab to create a XML
file and send it to him/her.
Miscellaneous
A section for different kinds of information about GenericSetup.
Gotcha
We might imagine that when we select a new profile to be the active
profile, and then we browse back to the import tab, that we would ONLY
see the import steps that were related to the active profile.
This is not the case! The import steps that a profile registers are
additive i.e. that whenever we select a new profile as the active
configuration, any new import steps are added to the set of already
registered import steps. Therefore, whenever we select a new profile
as the active profile, we will never see fewer import steps, we will
only (possibly) see more.
Why did they have to make this behavior so unintuitive? Why did they
not simply list the import steps for the currently active profile?
There is a method to this bahavior, however as we will see further
down ...
How Profiles are Applied
Okay, so we know now that profile import steps are additive. Let us
look at the implications of this. To do so, we will once again be
following the adventures of our good friend Guy Ablaze, who has now
drunk deeply of the GenericSetup kool-aid, having repented for and
moved beyond his former Python-based install method ways.
Say Guy adds a Plone site. When he does, of course the Plone Site base
profile is applied to his site, as it is for every Plone site. But
then he wants to install the membrane product. membrane, it turns out,
does not use the QuickInstaller / install method mechanism for
installation, but instead provides an extension profile. So he goes to
the portal_setup properties tab and selects membrane as the active
site configuration. Then he returns to the import tab and clicks the
Import all steps button.
GenericSetup will then iterate through every registered import step,
which includes all of the steps of the base profile and the two
additional steps defined by membrane's extension profile. For each
step, it will examine the active profile to see it contains any
applicable configuration. If config info for that import step exists,
then the step will run and the configuration will be applied. If there
is no config info for that step, then the step will be skipped and
nothing will happen.
This is an important point, with some interesting consequences. Let us
look at the membrane setup profile. You will notice that the
import_steps.xml file defines some new import steps. But you will
notice that it does NOT include a toolset import step, even though the
membrane profile DOES include a toolset.xml file. It is unnecessary to
add a toolset import step to the membrane profile, because this step
is already registered with the base profile. When the Import all steps
button is pressed, most of the registered steps will do nothing. But
the toolset step will find the toolset.xml file and will apply the
configuration there. Likewise, the additional import steps will find
corresponding configuration info, and these steps will be run.
If Guy were to switch back to Plone Site as the active profile and
then click on Import all steps, then it would (re)apply all of the
base configuration settings, but it would not find any configuration
info for the membrane-specific steps, and would therefore skip them.
The reader might realize, then, that it is a good idea to become
familiar with all of the import steps in the default Plone base
profile. These are all available to us when we create extension
profiles, and they do not even need to be added to our
import_steps.xml file. All we need to do to define new types is to
include a types.xml file and a properly constructed types folder.
Similar statements hold true for specifying actions, workflows, and
for registering skin paths.
-
In fact, if we are creating an extension profile that introduces no
custom import steps, then we do not even need an
import_steps.xml
file. That's right... if we create a profile that defines some new
types, maybe a workflow or two, a couple of custom actions, all of
those profile steps are already included in Plone's default set of
import steps. We only need to add an import_steps.xml file to our
profile when we are introducing steps that are not included in the
base profile.
Now, we can go back to the last section and re-read the bit about the
gotcha. If the reader has understood everything I have covered here,
he will understand why the setup tool behaves in the manner described.
Exports, Snapshots, and Comparisons
The first thing we notice upon clicking on the Export tab of the
portal_setup tool is how similar it is to the Import tab. It shows a
list of available steps (these are the export steps from
export_steps.xml, of course), as well as two buttons at the bottom.
One of the buttons says Export selected steps while the other reads
Export all steps.
These export steps are linked up to code that knows how to examine the
actual site setup and, from this, generate the appropriate XML files
for a GenericSetup profile that would replicate the current setup. If
we click on the Export all steps button, the browser should pop-up a
file download dialog window, asking where we want to save our
setup_tool-<time_stamp>.tar.gz file. This file, when extracted,
contains the XML files and directory structure for our GenericSetup
profile.
-
It is important to note that the active site configuration, as
specified on the properties tab of the setup tool, does NOT have an
direct impact on the export process. Whenever an export is run, all of
the specified steps are exported in full. In other words, if Guy
Ablaze were to make the membrane profile active and then run an
export, he would get (among other things) an export of ALL of the
tools that exist in the site, even though the membrane profile only
lists a single tool in the
toolset.xml file.
In addition to file system exports, it is also possible to create a
profile snapshot that lives entirely within the ZODB (Zope Object
Database). Finally, there is the Create a Snapshot button. Clicking
on this button will do an export, only instead of offering a tarball
for download, it will create a new folder inside the snapshots
folder in the setup tool. This new folder will contain a ZODB file and
folder objects which contain all of the XML that defines the site
configuration at the time the snapshot was taken (see image below).
Also useful in the setup tool is the Comparison tab — I already
mentioned the comparison feature above. On this tab we are able to
pick between any two profiles — including any snapshots — that we
have created, and generate diffs between them to see what has changed.
Here is an example of what this might look like.
In this example I have run a comparison between the NuPlone profile
and a snapshot that I created just before the comparison. Even more
useful is it to take snapshots during customizing a site — one can
not just rollback if needed but also compare different snapshots and
see what has changed in between them.
Under the Hood
How does it really work? What glues it all together? How would we
create our own, completely custom, import steps, in order to configure
this really cool thing that we will install in every Plone site we ever
touch from this day forward?
The import process is initiated when we tell the setup tool to run
some set of import steps. At this point, GenericSetup will iterate
through each of the steps, extracting the handler attribute
(specified in the step's XML tag in the import_steps.xml file from
which it was loaded). This handler is a callable, usually a function,
that accepts a single argument context, which is some flavor of what
GenericSetup calls an import context (the basic set of import and
export contexts can be found in the GenericSetup/context.py file).
-
By convention, this handler function, and all of the associated
adapters and other related import and export code, should live in
either a module or a package called exportimport in our Product's
package. For example, all of the Plone-specific import/export code
lives in the
Products.CMFPlone.exportimport package.
So what is this import handler supposed to do? Well, it is supposed to
know which XML files in the profile it cares about, and it should read
these. Then it should query for a multiadapter. This multiadapter
should adapt from some interface that marks the object that is being
configured, and from GenericSetup's ISetupEnviron, which is
implemented by the import context object. It should adapt to
GenericSetup's IBody interface. For example, the ZCML (Zope
Configuration Meta Language) that defines this adapter for the Plone
properties tool (which can be found in
CMFPlone/exportimport/configure.zcml) looks like this:
sa@pc1:~$ type gr
gr is aliased to `grep -rni --color'
sa@pc1:~$ gr -A2 -B3 IPropertiesTool /home/sa/work/git/plone_buildout/parts/plone/CMFPlone/exportimport/configure.zcml
14- <adapter
15- factory=".propertiestool.PlonePropertiesToolXMLAdapter"
16- provides="Products.GenericSetup.interfaces.IBody"
17: for="Products.CMFPlone.interfaces.IPropertiesTool
18- Products.GenericSetup.interfaces.ISetupEnviron"
19- />
sa@pc1:~$
The code that performs the adapter lookup in the importPloneProperties
handler looks like this importer = queryMultiAdapter((ptool,
context), IBody)
importer, then, will be an instance of the
PlonePropertiesToolXMLAdapter class, which implements GenericSetup's
IBody interface — I will leave it as an exercise to the reader to
look up that interface, but I will tell you that it defines a Zope 3
schema which includes a body text field. This is implemented (in the
XMLAdapterBase that the properties tool's adapter extends) as a
property, such that when we set the importer.body to be the XML read
in from the configuration file, this XML is parsed (using minidom) and
the configuration is applied.
So, if we want to have some fancy new ourthing tool that we want our
product to install, and we want to be able to manage the configuration
of that tool using XML files in a GenericSetup profile, what would you
do? Here are the steps:
- Add a
toolset.xml to our extension profile that lists our tool's
class, so it will be created during the toolset import step.
- Add a handler function in an appropriate place within our
product's exportimport package. This function should accept a
context argument, it should read in any XML file(s), and (in most
cases) it should set the body attribute to be the content of the
XML file.
- Create and register an adapter that adapts from an
IOurThing
interface and ISetupEnviron to IBody. If we are subclassing from
XMLAdapterBase, all we need to do is implement an _importNode
method that accepts the minidom node that is the root of the XML
tree in the configuration file. This should iterate through the
tree and perform all necessary configuration.
- Add our new import step to our extension profile's
import_steps.xml file.
- Add our new
ourthing.xml file to the extension profile.
Note that we have been looking at an XMLAdapterBase-based example.
XMLAdapterBase is a good starting point for situations where we have a
tool and a single XML file that contains the tool's configuration. Not
all import steps are like this, though, and there are other utility
classes that GenericSetup provides in its utils module. It is beyond
the scope of this page to cover them all in detail, but I will list a
couple that we should know about:
- ObjectManagerHelpers
-
When we need to import (or export) folderish objects that contain
other objects, we will probably find this useful.
- PropertyManagerHelpers
-
This provides some assistance when the configuration we need to
perform relates to Zope's PropertyManager API.
It is also important to say, while we have been focusing on the import
process, the export process works very similarly. Usually the same
adapter is used for exporting as for importing. In the XMLAdapterBase
situation, we would define an export handler that looked up the
adapter, read the body attribute (which would actually trigger
introspection of the site state and creation of the DOM (Document
Object Model) nodes and XML that represent that state), and then write
this out to the appropriate filename.
Applying Policies at Site Creation Time
Those who have been doing Plone product development for a while are
probably familiar with customization policies. Customization policies
are site configuration bundles, defined in the older python-based
semantics, that can be applied to a Plone site. One of the more handy
features of customization policies is that they could be made to show
up as an option when the Plone site was first created. If we did not
select one, we would get a default Plone site, but if we did, our site
would get a bunch of extra configuration applied.
Customization policies have not been supported in Plone 2.5 for a
while. There has been some justified grumbling about this — they were
not given a suitable deprecation period. The good news is that
GenericSetup provides the same ability, and that it is quite easy to
convert existing customization policies to GenericSetup profiles
(although these profiles will consist of just a single handler that
calls all of the pre-existing customization policy code). However, for
Plone 3 doing customization via GenericSetup is the way to go anyways
...
First let us look at how GenericSetup profiles are defined. This is
done using a profile_registry mechanism provided by GenericSetup,
which can be imported into our product as so from
Products.GenericSetup import profile_registry. Also defined are
some constants for specifying the type of profile you are registering
from Products.GenericSetup import BASE, EXTENSION.
Once we have done these imports, a simple call to the profile_registry
will register our profile. Here is what this call looks like for the
membrane product
profile_registry.registerProfile('default',
'membrane',
'Extension profile for membrane',
'profiles/default',
'membrane',
EXTENSION,
for_=IPloneSiteRoot)
I am not going to go into a detailed description of all of the
arguments (you can see the IProfileRegistry interface for that), but I
will draw our attention to the final for_ argument. This allows us to
specify an interface that denotes the type of portal that the profile
is meant to be used with. If we use the IPloneSiteRoot interface,
defined for this purpose, then when we add a new Plone site, our
profile will automatically show up as available to be applied when the
site is created.
In order to create an Extension Profile from a Customization Policy,
we would perform the following steps:
- Register an extension profile with the GenericSetup profile
registry (do not forget
for_ = IPloneSiteRoot).
- Add a single import step in
import_steps.xml, which calls a
runPolicy handler.
- Write the
runPolicy function, which should accept a context
argument, but which simply calls the same code that the
customization policy calls.
We should now have a working extension profile that is functionally
equivalent to the customization policy. There will not be any export
support, however — in order to get that, we will need to do
considerably more work in translating our older customization policy
into a true XML based configuration.
Changing Images and CSS
The look and feel of a Plone site is a big subject. A skin is a series
of CSS (Cascading Style Sheets), images, templates, and scripts that
come together to form the look and feel for a particular Plone
website. The idea of a skin is that we can change the skin and hence
change the look and feel of a site without having to change the
content.
Changing the Skin
We can change the default skin for a Plone site using the portal skin
form, which is accessible from the PCP (Plone Control Panel) i.e. we
can represent a Plone site in a few different ways by applying
different colors, style sheets, and templates to a site. The portal
skin form provides the following three choices:
- Default skin: This is the default skin to show to a user when they
access the site. There is only one skin that is given by default,
which is Plone's default skin — the one Plone ships with any
default installation.
- Skin flexibility: This sets whether we are going to allow users the
choice of choosing their own skin. If this is enabled, users can go
to their preferences and choose a new skin based on their personal
likings — this is enabled by default.
- Skin cookie persistence: If a user can select a skin, we can select
this to have the cookie last indefinitely. This means that a user
will always see a particular skin when logging into a Plone site.
However, this is disabled by default.
Changing the CSS Code
CSS determines the majority of the look and feel of a Plone site,
including the tabs, the images, the boxes, and the overall layout. The
fact that Plone's CSS is totally customizable means that from a few
style sheets users can completely customize many aspects of a site.
To quickly alter the CSS access the ZMI, one needs to click
portal_skins, then plone_styles, and then ploneCustom.css. This opens
the page for that object. This style sheet is actually straightforward
— in fact, it is empty. Plone is using the cascading property of CSS.
Because the HTML (Hypertext Markup Language) for Plone first imports
plone.css and then ploneCustom.css, any changes to the latter
overrides the standard style sheet. Why is this a good thing? It means
we can make small incremental changes to ploneCustom.css without
breaking or altering the core style sheet.
So, if we were to customize the ploneCustom.css object, we had to
click portal_skins, followed by plone_styles, then ploneCustom.css and
finally the click the Customize button. Again, this object has been
customized, and instead of being at
../portal_skins/plone_styles/ploneCustom.css, one will notice he is
now at ../portal_skins/custom/ploneCustom.css. Because file objects
can now be edited through the Web, we can directly edit the style
sheet through the Web.
As an example, to make the background have an image in the middle of
it (this is not necessarily the best user interface, but it is a clear
example of how to customize the CSS code). First, we need to upload an
image to Plone — we click portal_skins, click custom followed by the
scroll down menu at the right where we chose Image and the Add button
to select an Image.
We can choose any image. We then make sure that the ID (Identifier) of
the image is something meaningful like background.png for example.
Then we go to ../portal_skins/custom/ploneCustom.css and change the
text from /* DELETE THIS LINE AND PUT YOUR CUSTOM STUFF HERE */ to
the following:
body {
background-image: url(background.png);
background-repeat: no-repeat;
background-position: center;
}

Then we click Save Changes to commit the changes to this file. After
returning to our Plone site, we can see the new background image.
Plone Templating
Plone puts together three layers of technology to create a page.
Python and page templates create some HTML (Hypertext Markup
Language), which is sent to the browser. There, some CSS (Cascading
Style Sheets) render the nice page with which we are now familiar.
To understand how to generate and then edit a Plone template, we have
to first learn about some key underlying concepts. Some of these
concepts are particularly unique to Plone, and although they provide
great advantages, it does take some time to get used to them.
Understanding the Underlying Templating Machinery
Diving straight into how Plone templating works would likely leave the
first time reader confused, so we start by going through the
underlying templating machinery. In an ideal world, this is something
one should not have to worry about, but in practice it is usually the
first block people hit when trying to learn to use Plone.
Plone is rather unique in that everything in Plone is an object. Those
unfamiliar with the concept of an object, there is not much to know —
an object is just a thing that encapsulates some behavior.
Each object has methods that can called on the object. One example is
a computer mouse. A computer mouse could have methods such as move,
click, and right-click. In Plone, a document is an object of a
particular type. All this means is that the document is not just a
static bit of text — instead, it is something a little more
complicated and far more useful. A document in Plone has a description
method, for example, that will give us the description that the user
added. When using the templating system, we will see in more detail
that everything is an object. look first at some of the basic
principles of object publishing.
DTML and ZPT
Zope provides several mechanisms for HTML templating:
- DTML (Document Template Markup Language) and
- ZPT (Zope Page Templates)
DTML is a tag-based language which allows implementation of simple
scripting in the templates. DTML has provisions for variable
inclusion, conditions, and loops. However, DTML has major drawbacks:
DTML tags interspersed with HTML form non-valid HTML documents, and
careless inclusion of logic into templates results in very unreadable
code.
ZPT is a technology that fixes these shortcomings. ZPT templates can
be either well-formed XML documents or HTML documents, in which all
special markup is presented as attributes in the TAL (Template
Attribute Language) namespace. ZPT offers just a very limited set of
tools for conditional inclusion and repetition of XML elements, thus
the templates are usually quite simple, with most logic implemented in
Python code. One significant advantage of ZPT templates is that they
can be edited in most graphical HTML editors. ZPT also offers direct
support for internationalization.
As mentioned previously, Zope Page Templates are themselves XHTML
(Extensible HyperText Markup Language) documents which means they can
be viewed and edited using XHTML compliant tools (which is a big
benefit compared to other template languages used for web
applications). However, these page templates are not meant to be
rendered as is. Instead they are marked up with additional elements
and attributes in special XML namespaces (see below). This additional
information is used to describe how the page template should
ultimately be processed.
Here are some basic examples. To conditionally include a particular
element, like a div element, simply add the tal:condition attribute to
the element as follows:
<div tal:condition="...">
...
</div>
To control what appears inside an element, use the tal:content
attribute like this:
<h1><span tal:content="..."/></h1>
...
Finally, to introduce or replace values of attributes use the
tal:attributes attribute as follows: The power of python could also be
utilised to dynamically alter the href at runtime.
<a href="" tal:attributes="python: 'href http://someurl.com'">...</a>
Because Zope Page Templates are themselves XHTML not only can they be
edited using normal HTML editors but they can also be checked for
XHTML compliance in template form. As a result, we can be fairly
confident that these templates will be expanded into proper XHTML
automatically. This a very cursory explanation of Zope Page Templates.
The behavior of Zope Page Templates is almost completely described by
a template language (see below), fixed on TAL, TALES, and METAL
specifications.
TAL (Template Attribute Language)
The Template Attribute Language (TAL) is a templating language aimed
to generate HTML and XML pages. Its main goal is to simplify the
collaboration of programmers and designers by templates being proper
HTML (or XML, respectively) which can be worked on using common design
tools. TAL was created for Zope but can be used in any other
Python-based projects as well. For more information go here and here.
TALES (Template Attribute Language Expression Syntax)
The Template Attribute Language Expression Syntax (TALES) is the
recommended expression language used by TAL and METAL. For more
information go here and here.
METAL (Macro Expansion Template Attribute Language)
The Macro Expansion Template Attribute Language complements TAL,
providing macros which allow the reuse of code across template files.
Both were created for Zope but are used in other Python projects as
well. For more information go here and here.
Portlets
Navigation

KSS (Kinetic Style Sheets)
Is Plone 3's new AJAX (Asynchronous JavaScript and XML) framework,
called KSS, to add dynamic, JavaScript-driven, user interface
elements.
|