++++++++++
ZPTKit 0.4
++++++++++

.. contents::

ZPTKit is copyright 2005 `Imaginary Landscape, LLC`__.

.. __: http://imagescape.com

Downloads and Websites
----------------------

* Homepage: http://imagescape.com/software/ZPTKit/
* Download: http://imagescape.com/software/ZPTKit/ZPTKit-0.4.tar.gz
* Source repository: http://svn.webwareforpython.org/ZPTKit/trunk
* Discussion: `webware-discuss@lists.sourceforge.net`__

.. __: http://lists.sourceforge.net/lists/listinfo/webware-discuss

The repository is a Subversion_ repository.  To check out a copy::

   $ svn co http://svn.webwareforpython.org/ZPTKit/trunk ZPTKit

.. _Subversion: http://subversion.tigris.org/

License and Prerequesites
-------------------------

ZPTKit is licensed under an `MIT-style license`__.  This gives you
permission to most anything you want with ZPTKit.

.. __: http://www.opensource.org/licenses/mit-license.php

ZPTKit is a toolkit for `Webware For Python`_.  It builds upon several
other pieces of code:

* Webware_.  This should be compatible at least to 0.8.1 and probably
  earlier.  This is also compatible with `Paste
  <http://pythonpaste.org>`_ (both ``paste.webkit`` and
  ``paste.wareweb``).

* `Zope Page Templates`_.  Right now there's several implementations
  of ZPT That have been either reimplemented from the spec or split
  from Zope.  ZPTKit uses the package from http://zpt.sourceforge.net/
  -- in the future it may move to a package derived from the Zope 3
  tree.

* Component_.  This is a subclass of ``WebKit.Page``, and adds extra
  features for integrating new features into your servlet (like a
  template manager).  You must subclass your servlets from
  ``Component.CPage`` to use ZPTKit.

.. _Zope Page Templates: http://www.zope.org/DevHome/Wikis/DevSite/Projects/ZPT/FrontPage
.. _Webware:
.. _Webware For Python: http://webwareforpython.org
.. _Component: http://svn.webwareforpython.org/Component

Status & News
-------------

ZPTKit is used in production environments, but has not had a wide base
of users.  As such, it should probably be considered beta quality --
while in a certain use case it performs well, it's likely that new
users will provide new use cases.

Also, ZPTKit builds on Component, and Component is still at a beta
quality.  By the `Stable Dependencies Principle`__, ZPTKit can not be
more stable than Component.

.. __: http://c2.com/cgi/wiki?StableDependenciesPrinciple

Changes in ZPTKit 0.4
~~~~~~~~~~~~~~~~~~~~~

* Nothing to report yet!

Changes in ZPTKit 0.3
~~~~~~~~~~~~~~~~~~~~~

* Improve support for templates in subdirectories of the search path
* Removed special handling of RFC-822 headers in emails; now only the
  markup form of headers is allowed
* Improved rendering of tables with htmlrender
* Make more compatible with setuptools (setuptools is not required)
* Added `Paste Script <http://pythonpaste.org/script/>`_ package 
  template
* Added ``.renderTemplate()`` method, that does normal rendering
  but returning the result instead of writing it to the output stream
* Added ``add_template_path()`` method to servlet, which allows 
  per-request addition of items to the path
* Added ``egg/PackageName/template_name.pt``, which allows you to load
  templates out of other packages (based on `Eggs 
  <http://peak.telecommunity.com/DevCenter/PythonEggs>`_)

Changes in ZPTKit 0.2
~~~~~~~~~~~~~~~~~~~~~

(Note: no public APIs were changed.)

* Fixed problem where macro templates were not being cached.
* Caches all templates more aggressively.  These two fixes should have 
  a considerable impact on performance.
* Cleanup and simplification.
* Distutils-based distribution.
* Some small improvements to the HTML->text renderer.

Features
--------

* Compiles templates as needed.
* Caches and pools compiled templates.
* Can find templates in several directories (typically used so that
  you can shadow individual templates to change the look of an
  application).
* Send emails from ZPT templates, including a text form of an email.
  Conversion to text is done after the template is rendered, and does
  word wrapping on the rendered form.
* Serves static files from several directories (so that static files
  like CSS can be put alongside templates, and also shadowed).
* Shows exceptions with extended ZPT information.
* Model-View-Controller style (where the ZPT template is the view).

To-Do
-----

* Better configuration, for sending ZPT-based emails outside of a
  servlet or web request (e.g., from TaskKit based on a schedule).
* There's always improvements to be made in the HTML->text converter.
* ``If-Modified-Since`` support in ResourceComponent (though this
  file might simply go away at some point).

Using ZPTKit
------------

First, make sure you are subclassing from ``Component.CPage``;
typically you change your ``SitePage``::

    from Component import CPage
    from ZPTKit import ZPTComponent

    class SitePage(CPage):
        components = [ZPTComponent(zpt_paths)]
        def writeHTML(self):
            self.writeTemplate()
        # Needed for Webware 0.8.1 and earlier:
        def handleAction(self, action):
            CPage.handleAction(self, action)
            self.defaultAction()

``CPage`` is compatible with ``WebKit.Page``.  You must fill in
``zpt_paths`` on your own, using whatever configuration mechanism you
choose.  This can be a single path (where all templates are found) or
a list of paths; if a list, then the paths will be searched in order
for each template.

Your template will now have several new methods and attributes:

``writeTemplate()``:
    Renders and writes the template that you've set with ``setView``,
    and writes it to the response.

``template(filename)``:
    Retrieve the named template.  You can render it by calling it.

``sendMail(filename, to_address, from_address, **options)``:
    Send an email with the given to and from address, and ``options``.

``options``:
    A dictionary of ``options``.  You can also set and get values from
    this custom dictionary with attributes.  The values will be made
    available in your template under ``options/attribute_name``.  In
    Zope you typically pass values into a template as keyword
    arguments, and they show up as ``options``; this way top-level
    attributes remain fairly fixed.  This is empty until you add
    values to it.

``context``:
    Another custom dictionary, which has all the values available to
    the template, including ``options``.  This also includes
    ``request``, a dictionary-like object that holds values from the
    request, ``test(cond, if_true, if_false=None)`` for inline
    conditionals, and ``here``, which represents the current directory
    (for use when calling macros in a template).

``CPage`` adds the concept of "view", which ZPTKit interprets as the
name of a template (by default ``CPage`` interprets it as the name of
a servlet method).  This way you can have multiple templates for a
single servlet, with each template as a view.  E.g.::

    class Register(SitePage):
        def actions(self):
            return ['save']
        def save(self):
            ... process form ...
            if successful:
                self.setView('RegisterSuccessful.pt')

By default the view matches the servlet's name, so ``Register.pt`` is
called.  In this case if the form is successfully submitted we instead
use ``RegisterSuccessful.pt``.

Templates
---------

ZPTKit templates are normal Zope Page Templates.  In most cases they
will look very similar.  You can use macros as normal, for instance.

One difference is that there is no ``container`` variable.  You can
use ``here`` to refer to other templates (like
``here/standard_template.pt``), but only to templates (in Zope you can
access scripts and functions the same way).

Instead the variable ``servlet`` is added, which is a reference to the
calling servlet.  So if you have a complicated callback, you can refer
to ``python: servlet.method(arg1, ...)`` and the value will be
substituted in (be sure to use ``structure`` if that value includes
markup).

Providing Template With Eggs
----------------------------

You must add something like to your ``setup.py`` file::

    setup(....
        entry_points="""
        [zptkit.template_dir]
        main = mypackage.templates:template_location
        """, ...)

Then in ``mypackage/templates.py`` put something like::

    template_location = 'mypackage/templates/'

Then when someone tries to load ``egg/MyPackage/foo.pt`` it will look
in ``mypackage/templates/foo.pt``.  Also ``egg/MyPackage/main/foo.pt``
will work (using the name you used in ``entry_points``) -- ``main`` is
the default.

ResourceComponent
-----------------

``ResourceComponent`` is also provided to allow static files (like CSS
or images) to go alongside templates.  You must turn ``ExtraPathInfo``
on in ``Application.config``, and add a component *just* to your
``index.py`` (or ``Main.py``) servlet::

    from ZPTKit.resourcecomponent import ResourceComponent

    class index(SitePage):
        components = SitePage.components + [
            ResourceComponent(zpt_paths)]

Then ``zpt_paths`` will be searched for files if no servlet is found
by a given name (and it will produce 404s if no file is found either).
The normal processing of the ``index`` servlet will be aborted in
either case, so long as there is any ``request.extraURLPath()``.
