Putting a Page Together

« Return to page index

Plone Theme Reference

1. Content to Template

Content to Template

1.1. Content to Template

How content reaches a Page Template.

There are three ways in which content from your content items can reach a page.

  • directly from a content item
  • from the catalog
  • via a view component (using Python)

Getting content directly from a content item

A page template can pull data directly from the content item it is displaying. Here’s a snippet of the RSS template, calling the description field of a Collection content item:

<description>
    <metal:block define-slot="description">
       <tal:block content="context/Description">
          Default rss description goes here
       </tal:block>
    </metal:block>
</description>
  • context refers to the current content item
  • Description is the accessor of the description field

Accessors

An accessor is simply the method by which data in a field is extracted. In most cases the name of an accessor is the field name with the first letter capitalized and prefaced by 'get' (e.g., getStartTime). There's an exception to this rule. The title and description field, common to most content types, have 'Title' and 'Description' as their accessors (i.e. no 'get', but the first letter is capitalized).

Widgets

This snippet from the news item template does exactly the same thing but calls a specific display "widget" macro for the field rather than just the data.

<p class="documentDescription">
 <metal:field use-macro="python:here.widget('description',  mode='view')">
     .....
</metal:field>
</p>

Getting content from the catalog

Every content item is catalogued on creation and editing. Some of its fields are indexed for quick searching and sorting, while the values of others are stored in what's called the "brains" or "metadata" for quick access.

Pages pulling together a number of content types - a folder or collection listing for instance - often get their content from a catalog query and the brains, rather than waking up every content item in turn. You'll normally find a variable defined somewhere which holds the results of a catalog query:

folderContents here.queryCatalog(contentFilter);

Then the template will loop through the results and call values from the brains/metadata:

item_url item/getURL;
item_id item/getId;

These look pretty much like normal accessors, in fact they are the names of fields in the catalog brains/metadata. This can get confusing - if you try to access a field which isn't in the brains/metadata you'll get an error.

You can see what fields are available to you via

  • Site Setup > Zope Management Interface > portal_catalog > metadata tab

If you want to understand more about the catalog, there is a useful, general overview in the Zope book, and a more Plone-specific runthrough in The Definitive Guide to Plone (this book is for Plone 2 only, but the catalog section is still relevant to Plone 3).

Getting content via Python (using a view component)

It is often more efficient to use a view to process the data from the content item (or a group of content items) and then drop it into the page template. In this case, by "view" we mean a specific component defined in ZCML.

Here’s a snippet calling a view to render the sitemap:

<ul id="portal-sitemap"
    class="navTreeLevel0 visualNoMarker"
    tal:define="view context/@@sitemap_view;">
     <tal:sitemap replace="structure view/createSiteMap" />
</ul>
  • context/@@sitemap_view is assigned to a variable called (helpfully) 'view'
  • createSiteMap is a method of @@sitemap_view
  • @@ indicates that this is a view component

Here's the wiring in ZCML that creates @@sitemap_view:

<browser:page
     for="*"
(there’s no restriction on where I can be used)
     name="sitemap_view"
(this is my name)
     class=".sitemap.SitemapView"
(this is where you can find the code to deliver my content)
     permission="zope.Public"
(you can see me if you have the Public permission)
     allowed_interface=".interfaces.ISitemapView"
/>

In summary

  • the content is processed by a Python class
  • ZCML wires this class up into a component
  • the template calls this component

 

 

2. Templates and Components to Page

Templates and Components to Page

2.1. Templates and Components to Page

An overview of how templates, viewlets, and portlets mesh together to create a page.

Plone's page templates can be frustrating at first. There's no single template which seems to contain everything you need.

Content Views

Since each content type is likely to have a different combination of fields, each content type requires a separate template for display. As we saw in the templates and templating language section, these usually have _view appended to their name. You can find those for the standard Plone content types in

  • [your zope instance]/Products/CMFPlone/Skins/plone_content.

main_template

Knowing about content views only gets you so far, however. It is the main template (main_template.pt) which draws the content together with the page furniture and design. You can find this in

  • [your zope instance]/Products/CMFPlone/skins/plone_templates.

It is important to remember that the content view templates aren't complete in themselves, they merely provide a snippet of content which is dropped into a "slot" in the main_template - called 'main'.

If you feel unsure about slots, then have a look back at the templates and templating language section.

Around this main slot, the components - viewlets and portlets come into play - supplying the page furniture and decoration around the content. The main template simply pulls these in via viewlet managers and portlet managers.

Viewlets are so flexible that they can even be pulled into the content view. The abovecontentbody manager, for instance, is used in a number of content views, and handles, amongst other things, the presentation viewlet we looked at in previous sections.

In more detail

You might find it helpful to look at an example in context.

Have a look at:

  • Products/CMFPlone/Skins/plone_templates/main_template

and

  • Products/CMFPlone/Skins/plone_content/document_view

About document_view (a content view template)

1. Although document_view looks like a complete HTML page, ignore this. Just note that right at the top it calls the main_template.

metal:use-macro="here/main_template/macros/master"

The code that gets used from document_view is actually the bit between these tags:

<metal:main fill-slot="main"> …… </metal:main>

This gets dropped into a slot in the main_template:

<metal:bodytext metal:define-slot="main" 
                tal:content="nothing">
... 
</metal:bodytext>

2. Going back to the fill-slot in the document_view you’ll see a few tags calling the relevant fields from the content type – like this:

<metal:field 
       use-macro="python:here.widget('title', mode='view')">
</metal:field>

You’ll also see a few tags like calling viewlet managers which, in turn, will summon up groups of viewlets:

<div tal:replace="structure provider:plone.abovecontentbody" />

These enable you to drop extra bits of page furniture around the specific content from the fields (e.g., the presentation mode link).

About the main template

1. Jump back to main_template and you’ll see similar calls to other viewlet managers managing groups of viewlets for more page furniture:

<div tal:replace="structure provider:plone.portaltop" />

2. And calls to portlet managers to pull up the portlets defined for that particular page:

<tal:block replace="structure provider:plone.leftcolumn" />

3. You’ll also see a number of additional slots (define-slot), which could also be filled (fill-slot) from the content view template if you wanted. Here's one you could use to add a bit of css:

<metal:styleslot define-slot="style_slot" />

Jump back to your content view template and simply add an additional fill-slot (outside of the main fill-slot):

<metal:mystyleslot fill-slot="style_slot">
 ..... 
</metal:mystyleslot>

We'll go into other ways of providing styles in more detail in the next section.

2.2. How to show full content in folder views

This how-to only makes sense for folders, smart folder, or other similar views with a reasonably small number of items. It shows how to display the full view of content in listings by using the macros already defined for the content types. The same approach can be used to define viewlets for layout products like compositepack.

I was looking for a layout product for the front page of a site I am working on, and the existing products did not meet my needs out of the box because they only showed summary views of content rather than the full view. Instead of writing viewlets for different content types from scratch, I used the existing view macros of the content types as follows, in a new folder view I called folder_full_view (this is just a code snippet):

        <tal:listing condition="folderContents">

                <div tal:repeat="item folderContents">
                <tal:block tal:define="here item/getObject;
                                       actions nothing;
                                       view here/defaultView;
                                       object_title item/pretty_title_or_id"
                           tal:on-error="nothing">                  
                   <div metal:use-macro="here/?view/macros/main"/>

                </tal:block>
                </div>

        </tal:listing>

The setting of actions to nothing is so that the action icons are not displayed for every content item. The on-error="nothing" may not be necessary for you. I have it because I allow the catalog to return results for which there is no View permission.

Similarly, for the CompositePack product, I defined a viewlet

<div class="viewlet default_view">
<tal:block on-error="nothing"
     tal:define="here nocall: context;
                 actions nothing;
                 view here/defaultView;
                 object_title here/pretty_title_or_id">
  <metal:block use-macro="context/global_defines/macros/defines" />
  <div metal:use-macro="context/?view/macros/main"/>
</tal:block>
</div>

so that complete content can be displayed in a layout.

 

Use these ideas at your own risk. Seems to work for me so far.

2.3. How to scale images using PiL in Page Templates

A quick description of how to scale images from an image field using the Python Image Library in your Page Templates using TAL.

PROBLEM:

I have a custom type with an ImageField.  I'm customizing a folder listing of these types and I wanted a thumbnail of each image shown in the folder listing.  This is very straightforward using PiL (Python Imaging Library), if you know what to do.  I was also presented with the problem of working with brains rather than the object itself.

ASSUMPTIONS:

  • You have PiL installed and working.
  • You know how to make a custom Archetype

OVERVIEW:

When you get the folder contents for a folder listing, brains objects are returned and iterated over to produce the list.  This is of course, much more efficient than waking up each object.  The problem being, you cannot get to your Image field in a brain (that I know of).  The following is a snippet from 'folder_listing.pt' showing this.

<tal:foldercontents define="contentFilter contentFilter|request/contentFilter|nothing;

                            contentsMethod python:test(here.portal_type=='Topic', here.queryCatalog, here.getFolderContents);

                            folderContents folderContents|python:contentsMethod(contentFilter);">



	<tal:entry tal:repeat="item folderContents">

	<tal:block tal:define="item_url item/getURL|item/absolute_url;">

As you can see, while iterating over 'item' you're accessing brains-y things in a brains-y way, like 'item/getURL'.  But you'll notice that you cannot do 'item/my_image' because it's not in the brain.  What to do?! you may wail.  Well, you could wake up the objects, get the image field, and then call the image scaling on it in a pythonic way, but this is a performance hit, puts python in your TAL, whcih you should avoid.

Instead you'll just be crafty.  You already have 'item_url' and you know the name of your image field (my-image) so put those together and you'll get right at the image.  Try this in your browser:

http://full/url/to/your/object/my-image

and you should see your image! Translating this into TAL, you would go:

<img src="#" tal:attributes="src string:${item_url}/my-image" />

Now to add the image scaling bit, and this is where I went wrong.  Much of the Plone documentation about PiL assume you're working with an ATImage object, but you're not.  You're working with an AT ImageField.  An AT ImageField only defines ONE image scale size by default:

sizes = {'thumb': (80,80)}

 whereas ATImage defines a bunch:

sizes = {'large'   : (768, 768),

           'preview' : (400, 400),

           'mini'    : (200, 200),

           'thumb'   : (128, 128),

           'tile'    :  (64, 64),

           'icon'    :  (32, 32),

           'listing' :  (16, 16),

          },

To make matters worse, notice that the sizes defined for the same size key are different.  Bad dog.  No cookie.  Anyhow, what this means is that in order to access the size you want, you have to define it in your schema in advance, like so:

    ImageField(

        name='my-image',

        widget=ImageWidget(

            label="My Image",

            description="An image!",

        ),

        storage=AttributeStorage(),

        sizes= {'large'   : (768, 768),

           'preview' : (400, 400),

           'mini'    : (200, 200),

           'thumb'   : (128, 128),

           'tile'    :  (64, 64),

           'icon'    :  (32, 32),

           'listing' :  (16, 16),

          },

    ),

Ok, so now that you have defined the sizes you want in your custom type's schema, you're ready to use it in your Page Template.  Remember the way we accessed it before?

<img src="#" tal:attributes="src string:${item_url}/my-image" />

To access the sizes defined in your schema, just add the name to the end of your image, preceded by an underscore.

<img src="#" tal:attributes="src string:${item_url}/my-image_mini" />

It's that easy, and it should be.  You shouldn't have to access and therefore wake up your objects!  There are also other ways to get at PiL's image scaling, but this I found was easiest and didn't throw any bizarro "Unauthorized" or "TypeError: a float is required" errors.

Enjoy!
~Spanky

ALSO SEE:

http://plone.org/documentation/manual/archetypes-developer-manual/fields/fields-referencehttp://plone.org/documentation/tutorial/richdocument/pil

3. CSS and JavaScript to Page

CSS and JavaScript to Page

3.1. CSS and JavaScript to Page

How style sheets and JavaScript reach the page.

Style sheets and JavaScript files are included in the skin section of the Plone Default theme, so the process of customizing or rewriting in general follows the concept of order of precedence described in the Skin section of this manual (i.e. placing a replacement in a higher layer in the Skin).

If you create your own style sheet, you can either put it in the custom folder of portal_skins through the web or in the skins directory of your theme on the file system.

If you like, and are feeling ambitious, you can turn your stylesheet into a resource type component by putting it in the browser directory and registering it in ZCML. Indeed, this is done for you if you create your own theme product using the paster plone3_template. There are pros and cons to the latter approach, look back at the Skin or Components section if you want to explore these further.

Resource Registries

Before the CSS and JavaScript reach the page they go through an extra step. You'll note that there are quite a few style sheets and JavaScript files available (and not all are always required). So a Registry tool picks and chooses them as required and merges only those it needs for speed and efficiency.

There's a detailed tutorial on how to use these registries in the following section.

including how to use conditions to specify that you only want a particular resource loaded in a particular context (for instance with a document view).

Registering style sheets and JavaScript

  • Through the web you can add or remove style sheets and JavaScript by going to the Zope Management Interface > portal_css or portal_JavaScripts.
  • On the file system, registering style sheets and JavaScript is part of the Configuration. So you'll need to look in profiles/default/jssregistry.xml and cssregistry.xml.

DTML

Some of the default Plone style sheet files have a .dtml extension, and the CSS inside is wrapped in

/* <dtml-with base_properties> */
 .......
/* </dtml-with> */

DTML is another Zope templating language, which in this case is deployed so that particular variables can be picked up from a properties sheet (base_properties.props) - for example:

#portal-column-one {
    vertical-align: top;
    width: <dtml-var columnOneWidth missing="16em">;
    border-collapse: collapse;
    padding: 0;
}


We wouldn't recommend using this technique as it is likely to be phased out, but it is as well to know that it is there. You can sometimes get caught out if you're customizing an existing style sheet and accidentally delete the top or bottom "dtml-with" statement.

3.2. Using the Resource Registries to Control CSS and JavaScript

Plone has two neat tools for managing Cascading Stylesheets and JavaScript in a handy way. This tutorial explains some whys and hows and even has a minimal practical example of how it works.

3.2.1. Why do we even have these registries?

Why were the Resource Registries written, what do they do, and why are they useful?

The ResourceRegistries spring out of ( as most features in Plone ) frustrations with the state of the world before their existence: If you wanted to add a CSS style sheet or a Javascript library to your Plone site, beyond using the ploneCustom.css-file, you would have to override the header templates. This was painful from a maintenance point of view, and it also didn't allow it happening more than once. There was no way of Products supplying their own css files without massive conflicts if more than one Product attempted the same. Having several style sheets and Javascript files to make things more manageable on the filesystem was painful too.

With the existence of ResourceRegistries we were also able to split up Plone's CSS and Javascript into more manageable parts that can be turned on or off at the click of a button. We couldn't do this in earlier versions of Plone as splitting the style sheets would increase the number of separate http-requests needed to display a page incredibly.

The resource registries should:

  • Make it easier to work with and supply your own Cascading Style Sheets and JavaScripts in Plone
  • Make it possible/easier to add conditions to your Cascading Style Sheets and JavaScripts so they only apply when you want them to
  • Make it easy for Product authors to supply Cascading Style Sheets and JavaScripts for their products without  getting conflicts with other products
  • Reduce the number of http-requests needed to display a Plone page in a browser
  • Pack Cascading Style Sheets and JavaScripts to reduce the download sizes of files to users, and the bandwidth usage from serving a Plone site
  • Make it easy to change priorities amongst Cascading Style Sheets and JavaScripts
  • Make it easy to disable all or parts of Plone's default Cascading Style Sheets and JavaScripts

What are the registries?

The Resource Registries currently consist of two Plone tools living in the ZMI in the root of your Plone site. They have been part of the Plone bundle/installers since Plone 2.1. (They can be used with Plone 2.0.x as well. There is a special readme-file in the product for installation instructions for Plone 2.0.x)

How do the registries work?

Each registry has an ordered list of resources, CSS or JavaScript files, each with its own set of attributes. Entries in the registries will be linked automatically in Plone pages in the standard templates when the browser requests a page. The registries have been configured to have very sensible defaults — so for almost all use-cases (probably 90%+) it is merely the matter of adding the id of a resource you want to use.

NOTE: For experimentation, for example when reading this document, make sure to check the "debug/development mode" checkbox on the top of the configuration panel. (Read more about why in part 2.)

 

3.2.2. Conditions, merging, caching and debugging

some more details on how the ResourceRegistries function

Conditions

When a user agent (i.e a browser) makes a page request, all the resources registered in the registry are evaluated against their condition field. If the condition is true, the resource is served to the browser. If the condition evaluates to false, the resource is not served.

This gives you the ability to conditionally serve different style sheets or scripts based on logic like whether the user is logged in, whether you are in the "Human Resources"-section of your intranet of if the content-type is a news-item.

Conditions have to be TALES expressions. You can use global template variables inside them.

Merging

Whenever you click the save-button in a registry, a new set of css or javascript files are created. The registry will try to assemble the different resources into bigger lumps/files to server to the browser. This is to reduce the number of http-requests necessary and can improve performance considerably.

The rules for merging resources

  1. The registry will only try to merge resources that are adjacent in the list. Otherwise there's risk that the order of operations in the browser would be affected (order of code in JavaScript and the order of the cascade in CSS). This would possibly affect rendering or execution in the browser in a negative way, and is therefore not available.
  2. Two adjacent resources are only merged if their condition is exactly the same (more about conditions in the next chapter)
  3. Two adjacent resources are not merged if they don't have the 'allow merging' checkbox checked

The magically assembled 'Files' are assigned a new random number as their name. So you'll find entries like <link rel="stylesheet" href="plone2341.css" /> in your html source. You can inspect how the resources will be merged if you click the second tab in the registry; "composition". It will present you with a list of 'magic' files, like 'plone2341.css', and nested within them the component resources they are constructed from. You can click each entry to inspect what it will look like when served.

The CSS-composition UI

 

The css-registry composition UI

Each merged resource will have a small snippet in the source identifying its origin so that you can get hold of the full unmodified source if you need.

The comment stuff usually looks like the following.

/* ----- base.css ----- */
@media screen {
/* http://yourhost/plone/portal_css/base.css?original=1 */
/* */

 

Caching and HTTP

The merged resources are automatically served with HTTP-headers optimized for being cached a long time. Since the auto-generated number is being changed every time you save the registry settings, the browser will request the new 'files' and not use its old cached values anyway. The scheme is actually rather clever.

The potential problem with the caching scheme is that the registry doesn't know if you change the files in the skins directories unless you touch the "save" button in the registry. This  is only an issue while you are working on your CSS (or JavaScripts) to get them right, but can cause massive confusion if you make changes and only see cached styles/scripts in the browser. To avoid this issue, we have added a handy "debug and development" mode to the registries.

Debug and development mode

To enable the debug and development mode, check the corresponding checkbox in the registry configuration page and click "save".

This:

  • Disables merging of resources (great for finding bugs and specific declarations with the inspectors and development tools like Firebug)
  • Sets HTTP-headers for not caching so that you get a fresh copy every time
  • Disables compression

 

These settings affect performance in an adverse way, so make sure to disable the debug mode when your Plone goes live.

3.2.3. Resource Parameters

The parameters for a registry entry in the CSS (and JavaScript) registry.

Each entry in the CSS and JavaScript registries has some parameters that can be tweaked.

id
The id of the style sheet or JavaScript to be used. In Plone 3.3 onwards you can specify an externally hosted resource by entering the full URL here.
expression
A TALES expression to be evaluated to check if the style sheet or JavaScript should be included in output or not. You can use global template variables here.
conditionalcomment (available from Plone version 3.3 onwards)
A small string to be included in a conditional comment around the resource. For example, entering simply 'IE' in the field will result in a conditional comment of:
<!--[if IE]>...<![endif]--
This behavior is currently enabled for the CSS and JavaScript registries. The KSS registry is the only registry that does not have full support for conditional comments. For more information see: http://msdn.microsoft.com/en-us/library/ms537512.aspx
media
The media for which the style sheet should apply, normally empty or 'all'. other possible values are 'screen', 'print' etc. Read more about the media settings of CSS at w3.org
rel
Link relation. defaults to 'stylesheet', and should almost always stay that way. For designating alternative style sheets. This is used for the toggle between large, medium and small fonts in default Plone. Don't change this one unless you know what you are doing.
title
the title of an alternate stylesheet.
rendering
How the stylesheet is linked from the html page. This is an advanced setting. Leave it set to the default 'import' unless you know the effects of different ways of rendering and linking stylesheets
import
the default. normal css import
link
works better for old browsers and is needed for alternate stylesheets
inline
render the stylesheet inline instead of linking it externally. Shouldn't be used at all! It isn't possible to create sites which validate if you do.
For more information see: http://developer.mozilla.org/en/docs/Properly_Using_CSS_and_JavaScript_in_XHTML_Documents
compression
Whether and how much the resource should be compressed
none
the original content will not be changed
safe
the content will be compressed in a way which should be safe for any workarounds for browser bugs. Conditional code for Internet Explorer is preserved since ResourceRegistries 1.2.3 and 1.3.1.

full
the content will be compressed with some additional rules.For css all comments and most newlines are removed, this may break special browser hacks, so use with care. For JavaScript this encodes variables with special prefixes according to the rules described here (Special Characters):
http://dean.edwards.name/packer/usage/ The source code needs to be written according to those rules, otherwise it's more than likely that it will break.
safe-encode
- only available for JavaScript
- 'full-encode' - only available for JavaScript. Additionally encodes keywords. This heavily compresses the JavaScript, but it needs to be decoded on the fly in the browser on each load. Depending on the size of the scripts this could lead to timeouts in Firefox. Use with special care!
applyPrefix
- only available for CSS. 
- If your stylesheet uses relative URLs in a url() statement, e.g. to refer to another stylesheet or image, you may experience problems when using the registry in non-debug-mode, as portal_css alters the URL seen by the browser. If so, set this option to True or tick the "Replace relative paths in url() statements with absolute paths?" option in the portal_css management screen to replace any relative path inside a url() statement with an absolute path (prefixed with the Plone site root path) during the resource merging stage. This does not modify the original stylesheet. It may have a slight performance impact, but it should not be an issue if resources get cached properly. It has no effect in debug mode.
 

3.2.4. Practical: Adding a Style Sheet to the Registry Through the Web

Basic operations of the CSS-and Javascript-registries – and a truly minimal example of how to use them in real life. As a simple example of the most basic functionality, we'll add and register a minimal stylesheet that adds to the background of your Plone a terrible red color.

To use one of the registries, you have to

  1. Have a resource (for example a File) in your Skin with some CSS or JavaScript in it (this could, for instance, be in the custom folder of portal_skins).
  2. Make an entry in the corresponding registry (for example portal_css) with the id of the resource.

Make a Style Sheet

  • Go to Site Setup > Zope Management Interface and navigate to portal_skins/custom
  • From the add-item menu, select File
  • Give your new file an id of 'css-demo.css'
  • Paste the following content into the file:
    body{ background-color : red }
  • …and save it

Add it to the CSS Registry

The registries are two tools that live only in the Zope Management Interface (ZMI); they have no interface in the Plone user-interface itself. However, you can easily find them when browsing the ZMI of your Plone site - look for portal_css and portal_javascript

  • Go to Site Setup > Zope Management Interface and click portal_css.  Once selected, the CSS Registry ( the one we use for this example - the JavaScript one is almost exactly the same) will present an interface displaying all the registered resources (in the case of the CSS Registry, the resources are CSS files).
  • Make sure that you tick the debug mode checkbox. This will ensure that you see your changes immediately.
  • Scroll to the bottom of the form, where there is a form for adding a style sheet

  • In the id field, enter 'css-demo.css'  (leave the other values as they are by default for now)
  • Voila! – view your Plone site and you'll easily notice its (admittedly quite horrifying) shiny red background color!

The Technical Explanation

Each entry in the registries has an id that references a resource that can be found in the current Plone acquisition context. Technically it could be a tool or a utility or anything that has a name and is available, but most commonly it will be a File object ( for static CSS and JS) or a DTML Method (for dynamic variable replacement). The Resource Registries makes no difference as to what the object is, as long as it can be found and called, rendered or printed as a string.

3.2.5. Practical: Adding a Style Sheet to the Registry in your own Theme Product

Style sheets and JavaScript are added to the registries on installation of your theme product, via Generic Setup. You simply need to write the Generic Setup XML.

Create your Style Sheet

  • Create a normal CSS file [mytheme.css] using your favourite CSS editor.
  • You now have two options:
    • The simplest place to put your style sheet is in the skins directory of your theme product. Paster will have created a styles directory for you  (skins/plonetheme_mytheme_styles).
    • Paster will also have created a stylesheets directory for you in the browser directory of your theme product and will have registered this as a resource in the configure.zcml file. You can, if you like, put your style sheet in that directory instead.

Write your Generic Setup File

The relevant files for the configuration of your registries are profiles/default/cssregistry.xml and profiles/default/jsregistry.xml. Paster should have created these for you, but if they aren't there, just make them yourself.

An entry for a style sheet in the skins directory of your theme product, will look like this:

<?xml version="1.0"?>
<object name="portal_css" meta_type="Stylesheets Registry">
 <stylesheet title="" cacheable="True" compression="safe" cookable="True"
    enabled="1" expression="" id="mytheme.css" media="screen"
    rel="stylesheet" rendering="import"/>
</object>

Note that the parameters are just the same as the through-the-web form. You need only give the ID of the style sheet; Plone will find it as it is part of the skin.

An entry for a style sheet in the browser directory of your theme product will look like this:

<?xml version="1.0"?>
<object name="portal_css">
 <stylesheet title=""
    id="++resource++plonetheme.mytheme.stylesheets/mytheme.css"
    media="screen" rel="stylesheet" rendering="import"
    cacheable="True" compression="safe" cookable="True"
    enabled="1" expression=""/>
</object>

Note the special ++resource++plonetheme.mytheme.stylesheets syntax to refer to the directory registered as a resource in browser/configure.zcml

Once written, you can reimport the cssregistry.xml file using the portal_setup tool in the ZMI to make this change take effect. Make sure you choose the correct profile (your theme product) before importing the CSS step. Re-installing your theme product will also work, though you should be careful to guard against GenericSetup clashes. It's safer to import the individual step if your theme has been installed previously.

Plone Version 3.3 Onwards

In Plone 3.3 onwards you can also tell the CSS Registry to put conditional comments around your stylesheet:

<stylesheet title="" cacheable="False" compression="none" cookable="False"
 rel="stylesheet" expression="" id="IEFixes.css" media="all" enabled="1"
 rendering="import" conditionalcomment="IE" />

You can also specify an external resource:

<javascript cacheable="False" compression="none" cookable="False"
 enabled="True" expression="" id="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"
 inline="False" insert-before="jquery-integration.js" />

 If you are using SSL and specifying an external resource, you may find it necessary to specify both an http and an ssl entry in the registry. You can use the expression parameter to decide which one will be used:

<javascript cacheable="False" compression="none" cookable="False"
 enabled="True" expression="python:request.get('ACTUAL_URL','').startswith('https://')"
 id="https://jqueryjs.googlecode.com/files/jquery-1.2.6.min.js"
 inline="False" insert-before="jquery-integration.js" />

<javascript cacheable="False" compression="none" cookable="False"
 enabled="True" expression="python:request.get('ACTUAL_URL','').startswith('http://')"
 id="http://jqueryjs.googlecode.com/files/jquery-1.2.6.min.js"
 inline="False" insert-before="jquery-integration.js" />

3.2.6. Example Conditions

Some examples of limiting Style Sheets by the condition parameter, to help you get started.

In these examples we've given the condition as it would appear in profiles/default/jsregistry.xml and cssregistry.xml. If you are working through the web, then the text within the inverted commas "...." can simply be dropped into the condition box for the relevant CSS or JavaScript file in portal_css or portal_javascripts.

Content Type

If your CSS or JavaScript is only relevant to a particular content type:

expression = "python:object.meta_type == 'ATFolder'" 

View

You can check a specific browser view for a property (this example is from Products.Maps):

<javascript 
    cacheable="True" 
    ...
    expression="object/@@maps_googlemaps_enabled_view/enabled 
                                                | nothing" />

Here's how to look up one of the global views (see the Using Other Information about your Site Section for more about these views). This example delivers the Plone RTL Style Sheet:

<stylesheet 
    ...
    expression="python:portal.restrictedTraverse
                             ('@@plone_portal_state').is_rtl()"
    id="RTL.css" 
    .../>

Role

The following will check whether the visitor is logged in or not - in this case it delivers the standard member.css if the visitor is not anonymous:

<stylesheet 
    ...
    expression="not: portal/portal_membership/isAnonymousUser"
    id="member.css" 
    .../>

This example does the same, but uses the plone_portal_state view

expression="python: not here.restrictedTraverse
                        ('@@plone_portal_state').anonymous()"

Section and/or place in the site

Note that the body tag of every page has a section and template CSS class. So you may not need to use the resource registries at all.

However, if you want to change styles for a folder that isn't at the top level of your site, or, if you want to supply some JavaScript at a specific point in the site, then you will need to write a script and call this via the resource-registry expression. The section class on the body tag in main_template is generated by a Python script getSectionFromURL. This is a good starting point for your own script.

Here's an example expression and script. This will return True for a folder of your site with the shortname 'news' and any object within it. In this case - unlike the default Plone setup - the news folder is one level down from the top level:

expression="python: here.getSectionInTree(object,1)=='news'"
## Script (Python) "getSectionInTree"
##bind container=container
##bind context=context
##bind namespace=
##bind script=script
##bind subpath=traverse_subpath
##parameters=object, position
##title=Returns a section name
##
contentPath = object.portal_url.getRelativeContentPath(context)
if not contentPath:
    return ''
else:
    if len(contentPath)-1 >= position:
         return contentPath[position]
    else:
         return ''

 

3.3. How to Add New Class Styles to Kupu

This document explains how to add and define new custom class styles for use in kupu.

 Pre-requisites: CSS knowledge

1. Go to Site Setup in your Plone site.

2. Select the kupu visual editor add-on product configuration icon, as seen below:

Site-setup kupu

 

3. Scroll down to the paragraph styles box.

Kupu paragraph styles

4. Add your new paragraph style in the box. Format is title|tag or title|tag|className, one per line. For example:

Smalltext|p|smalltext

5. Open your ZMI.

6. Make sure that your site is in debug mode when first making changes. This will allow you to see your changes right away. 

7. Go to http://yoursite/portal_skins/plone_styles/ploneCustom.css/manage_main.

8. Click the customize button.

9. Enter your new paragraph style where it says “add your custom stuff here”.

.smalltext {font-size: 70%;}

Note: scroll down the page for available elements. See base_properties for definitions of those elements.

 

4. Using Other Information about your Site on a Page

How to get information about the state of your site and other global variables.

At some point or other you'll find you need to use the title of your site in a template; or you'll want your template to deliver something depending on the roles or permissions of your visitor or user. There are two approaches for obtaining this information:

1. Browser Views (recommended)

The first, newer, and recommended approach is to use the methods available in one of three browser views:

  • @@plone_portal_state
  • @@plone_context_state
  • @@plone_tools

These are kept in

  • [your egg location]/plone/app/layout/globals OR
  • [your egg location]/plone.app.layout-[version]/plone/app/layout/globals

You can find a description of each method in interfaces.py in that directory, but the main methods are outlined below. This excerpt from the main_template in the core Plone Default templates in Plone 4, demonstrates how these views, or their individual methods, are made available to every page:

<html xmlns="http://www.w3.org/1999/xhtml"
      ...
      tal:define="portal_state context/@@plone_portal_state;
                  context_state context/@@plone_context_state;
                  ...
                  lang portal_state/language;
                  ...
                  portal_url portal_state/portal_url;
                  ..."
     ...
>

Here's an excerpt from the newsitem_view template in the core Plone Default templates illustrating how the @@plone_context_state can be used to establish whether an item is editable or not:

        <p tal:define="is_editable context/@@plone_context_state/is_editable"
           tal:condition="python: not len_text and is_editable"
           i18n:translate="no_body_text"
           class="discreet">
            This item does not have any body text, click the edit tab to change it.
        </p>


2.  Global Defines (deprecated)

The second approach has been around for a long time, but is being phased out (as it is slower) in Plone 3 and has been pretty much removed in Plone 4. This is to use a set of variables that are available to every single page.

In Plone 3:

These are called by main_template:

<metal:block use-macro="here/global_defines/macros/defines" />

If you want to investigate them further, you'll find them in

  • [your products directory]/CMFPlone/browser/ploneview.py.

These variables are used in a number of the default Plone templates in Plone 3 and so they are listed below alongside their equivalent in the available views.

In Plone 4:

The global_defines macro is not used at all and the variables have been entirely replaced in all Plone templates. However, should it be required, the global_defines macro is still available in the core Plone Default skin layers in the plone_deprecated folder.  For more information on making a Plone 3 theme compatible with Plone 4, consult the upgrade guide.

Available Views and Methods

About the site

View @@plone_portal_state

Method What you get global defines
portal Portal Object portal
portal_title The title of your site portal_title
portal_url The URL of your site portal_url
navigation_root_path Path of the navigation root
navigation_root_url The URL of the navigation root navigation_root_url
default_language The default language of the site
language The current language
locale The current locale
is_rtl Whether the site is being viewed in an RTL language isRTL
member The current authenticated member member
anonymous Whether or not the current visitor is anonymous
isAnon
friendly_types Get a list of types that can be deployed by a user

About the current context

View @@plone_context_state

Method

what you get

global defines

current_page_url

The URL of the current page

current_page_url

current_base_url

The actual URL of the current page

 


canonical_object

The current object itself

 


canonical_object_url

The URL of the current object

 


view_url

The URL used for viewing the object

 


view_template_id

The id of the view template

 


is_view_template

True if the current URL refers to the standard view

 


object_url

The URL of the current object

 


object_title

The 'prettified' title of the current object

 


workflow_state

The workflow state of the current object

wf_state

parent

The direct parent of the current object

 


folder

The current folder

 


is_folderish

True if this is a folderish object

isFolderish

is_structural_folder

True if this is a structural folder

isStructuralFolder

is_default_page

True if this is the default page in a folder

 


is_portal_root

True if this is the portal root or the default page in the portal root

 


is_editable

True if the current object is editable

is_editable

is_locked

True if the current object is locked

isLocked

 actions
(Plone 4)
The filtered actions in the context. You can restrict the actions to just one category.  
 portlet_assignable
(Plone 4)
 Whether or not the context is capable of having locally assigned portlets.  

Tools

view @@plone_tools

method

what you get

global defines

actions

The portal actions tool

atool

catalog

The portal_catalog tool

 


membership

The portal_membership tool

mtool

properties

The portal_properties tool

 


syndication

The portal_syndication tool

syntool

types

The portal_types tool

 


url

The portal_url tool

utool

workflow

The portal_workflow tool

wtool

 

5. Using jQuery and jQuery Tools

Plone includes the jQuery and jQuery Tools JavaScript libraries out of the box, which you can use in your own scripts right away.

jQuery is a popular JavaScript Library that simplifies HTML document traversal, event handling, animating, and Ajax interactions. jQuery Tools is a collection of user-interface components including overlays, tabs, accordions and tooltips.

jQuery has been shipped with Plone since 3.1. jQuery Tools was added with Plone 4.0.

Using jQuery

jQuery has excellent documentation available at http://api.jquery.com. Note, though, that it is never wise to depend on the availability of the "$" alias for the jQuery function since other libraries may redefine it.

So, Instead of:

$(document).ready(function(){
   $("a").click(function(event){
     alert("Thanks for visiting!");
   });
 });

you should embed and jQuery code that uses the "$" alias in a wrapper like:

(function($) {
 $(document).ready(function(){
   $("a").click(function(event){
     alert("Thanks for visiting!");
   });
 });
})(jQuery);

Using jQuery Tools

jQuery Tools is a jQuery plugin, and Plone 4 includes the tabs, tooltip, scrollable, overlay and expose toolset. The remainder of the jQuery Tools kit plugins are available by enabling the plone.app.jquerytools.plugins.js resource Plone's JavaScript registry.

The integration with jQuery Tools is provided through the package plone.app.jquerytools, which includes a set of overlay helpers for common AJAX overlay needs. This kit is used to provide many of Plone's overlayed forms. See the plone.app.jquerytools pypi page for documentation and examples.