Making a SilvaLayout Products

This Documentation gives a step by step guide for making Silva layouts using Silva 1.6 and Silva 2.x.

Making a Silva layout with Silva 1.6 and SilvaLayout 0.5.10

Setup

Before making the layout product download the SilvaLayout 0.5.10 product, restart your Zope instance, and then in the service_extensions tab of the Zope Management Interface (ZMI) install the SilvaLayout product.

Making the layout product

First make a directory with the name of your layout, for this example this will be called "NameOfLayout" in either the ./Products/ directory if you are using a Silva tarball or svn, or the ./products directory if you are using a Silva buildout.

Move into the layout directory and make the following files and directories.

  • __init__.py
  • configure.zcml
  • install.py
  • template.pt
  • css/
  • images/

In this example I am placing two directories in my layout product. It is not mandatory to have these directories for a layout product.

After creating the files and directories open the __init__.py file and add the following lines of code:

import install
from Products.Silva.ExtensionRegistry import extensionRegistry

import install
from Products.Silva.ExtensionRegistry import extensionRegistry

from Products.Silva.ExtensionRegistry import extensionRegistry
import install

def initialize(context):
    extensionRegistry.register(
        'NameOfLayout',
        'Name Of Layout',
        context, [], install, depends_on='SilvaLayout')

Save the __init__.py file and now open the install.py file and add the following code:

from os import path
from Globals import package_home

mapping = {}
installed_attr = '__name_of_layout__installed__'

def is_installed(context):
    return hasattr(context, installed_attr)

def install(context):
    configureMetadata(context)
    setattr(context, installed_attr, 1)

def uninstall(context):
    delattr(context, installed_attr)

def configureMetadata(context):
    product = package_home(globals())
    schema = path.join(product, 'schema')
    collection = context.service_metadata.getCollection()

    for types, setids in mapping.items():
        for setid in setids:
            if not setid in collection.objectIds():
                xmlfile = path.join(schema, setid+'.xml')
                definition = open(xmlfile, 'r')
        context.service_metadata.addTypesMapping(types, setids)

    context.service_metadata.initializeMetadata()

Save and close the install file.

Next open the configure.zcml file and add the following code:

<configure
  xmlns="http://namespaces.zope.org/zope"
  xmlns:browser="http://namespaces.zope.org/browser"
  xmlns:five="http://namespaces.zope.org/five"
  xmlns:i18n="http://namespaces.zope.org/i18n"
  >

  <include
    package="Products.SilvaLayout"
    />

  <browser:layer name="NameOfLayout" />

  <browser:page
    name="index.html"
    for="Products.Silva.interfaces.IContent"
    class="Products.SilvaLayout.browser.silvaview.Content"
    template="template.pt"
    permission="zope2.View"
    layer="NameOfLayout"
    />

  <browser:page
    name="index.html"
    for="Products.Silva.interfaces.IContainer"
    class="Products.Silva.browser.silvaview.Container"
    template="template.pt"
    permission="zope2.View"
    layer="NameOfLayout"
    />

  <browser:resourceDirectory
    name="css"
    directory="css"
    permission="zope2.View"
    layer="NameOfLayout"
    />

  <browser.resourceDirectory
    name="images"
    directory="images"
    permission="zope2.View"
    layer="NameOfLayout"
    />

  <browser:skin
    name="NameOfLayout"
    layer="NameOfLayout silvadefault default"
    />

</configure>

Save and close the configure.zcml.

Now open the template.pt file. The template file has been reduced to only a couple of useful bits of code. The template shows how to link to the css directory using an example stylesheet called main.css. The example also uses and image coming from the images directory. The template also makes uses of the tree.py module in SilvaLayout/browser/tree.py. This is a useful module for getting access to navigation trees. It comes with built in styles which can be overridden by users making their own tree css styles. Finally the template calls content from the view/render method, the method used for getting access to Silva Documents.:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"
    metal:define-macro="main">
  <head>
    <!-- title -->
    <title tal:content="structure view/title"/>
    <!-- meta data -->
    <meta tal:replace="structure context/@@contenttype" />
    <!-- Injector for content-specific css/js inclusion -->
    <link tal:replace="structure here/head_inject | nothing" />
    <!-- EXAMPLE LINK TAG -->
    <link rel="stylesheet" tal:attributes="href request/resourcebase/++resource++css/main.css"/>
  </head>
  <body>
    <!-- EXAMPLE IMAGE TAG -->
    <img tal:attributes="src request/resourcebase/++resource++images/name_of_image.gif" />
    <!-- EXAMPLE TREE -->
    <div tal:content="structure context/@@treeview/renderHTML">
      <!-- navtree goes here -->
    </div>
    <div id="contents">
      <span tal:content="structure view/render" /><br />
    </div>
  </body>
</html>

Applying the layout in Silva

Go to the Silva Management Interface (SMI) of your Silva root. Click on the properties tab, and then click on the settings... button, at the bottom of the page you can use the pulldown menu to select the newly built skin.

Making a layout for Silva 2.x trunk and SilvaLayout trunk

Follow the Setup steps in the previous example only switching the products to Silva trunk and SilvaLayout trunk.

Pointing out some differences

Without going into too much detail, the main difference between a Silva 1.6 layout and a 2.x layout is the exclusion of initialization code in a single __init__.py file. I say "single __init__.py" because this example uses a much deeper directory tree, each directory using an __init__.py file to register the directory with python. Another striking difference is the lack of an install.py file. In addition to a deeper directory tree each directory comes with its own configure.zcml. Finally there there is the addition of the skin.py file, which contains a class subclassing a default SilvaLayout interface.

Making the layout product

First make a directory with the name of your layout (NameLayout) in either the ./Products/ directory if you are using a Silva tarball or the ./products/ directory if you are using a Silva buildout.

Move into the layout directory and make the following files and directories

  • __init__.py
  • configure.zcml
  • browser/

Open the __init__.py and add the following:

#

Save and close the file. Then open the configure.zcml file and the following directives:

<configure
  xmlns="http://namespaces.zope.org/zope"
  xmlns:browser="http://namespaces.zope.org/browser"
  xmlns:five="http://namespaces.zope.org/five">

  <!-- make sure SilvaLayout is loaded first -->
  <include
    package="Products.SilvaLayout"
    />

  <!-- include views -->
  <include
    package=".browser"
    />

</configure>

Save and close the configure.zcml. Now enter the browser directory and make the following files and directory:

  • __init__.py
  • configure.zcml
  • NameOfLayoutTemplate/

open the __init__.py file and the following code:

#

Save the file and open the configure.zcml file and add:

<configure
  xmlns="http://namespaces.zope.org/zope"
  xmlns:browser="http://namespaces.zope.org/browser"
  xmlns:five="http://namespaces.zope.org/five">

  <include
    package=".NameOfLayoutTemplate"
    />

</configure>

Now enter the NameOfLayoutTemplate directory and add the following files and directories:

  • __init__.py
  • configure.zcml
  • skin.py
  • template.pt
  • css/
  • images/

Open __init__.py and add the following code:

#

Save the file and open the configure.zcml and add the following code:

<configure
  xmlns="http://namespaces.zope.org/zope"
  xmlns:browser="http://namespaces.zope.org/browser"
  xmlns:five="http://namespaces.zope.org/five">

  <browser:page
    name="index.html"
    for="Products.Silva.interfaces.IContent"
    class="Products.SilvaLayout.browser.silvaview.Content"
    template="template.pt"
    permission="zope2.View"
    layer=".skin.INameOfLayoutTemplate"
    />

  <browser:page
    name="index.html"
    for="Products.Silva.interfaces.IContainer"
    class="Products.SilvaLayout.browser.silvaview.Container"
    template="template.pt"
    permission="zope2.View"
    layer=".skin.INameOfLayoutTemplate"
    />

  <browser:resourceDirectory
    name="css"
    directory="css"
    permission="zope2.View"
    layer=".skin.INameOfLayoutTemplate"
    />

  <browser:resourceDirectory
    name="images"
    directory="images"
    permission="zope2.View"
    layer=".skin.INameOfLayoutTemplate"
    />

  <interface
    interface=".skin.INameOfLayoutTemplate"
    type="zope.publisher.interfaces.browser.IBrowserSkinType"
    name="NameLayout"
    />

</configure>

Save and close this file. Open the skin.py file and add the following code:

from Products.SilvaLayout.browser.silvadefault.skin import ISilvaDefault

class INameOfLayoutTemplate(ISilvaDefault):
    """Default skin for SilvaLayout.
    """

Save the skin.py file.

The template.pt remains the same as the previous example.

Applying the layout in Silva

Apply the layout in the same way as the previous example.

Note

This is only one way to make a layout, it is not necessary to follow this tree structure if you do not wish to.