# 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.