Component 0.2
+++++++++++++

.. contents::

Downloads and Websites
======================

* Homepage: http://wiki.webwareforpython.org/component.html
* Download: http://webwareforpython.org/downloads/Component-0.2.tar.gz
* Source repository: http://svn.webwareforpython.org/Component/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/Component/trunk Component

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

License and Prerequesites
=========================

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

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

Component is a toolkit for `Webware For Python`_.  Webware is the only
prerequisite.

.. _Webware For Python: http://webwareforpython.org

What Are They?
==============

Many enhancements in Webware require subclassing ``WebKit.Page``.  But
each of these enhancements is incompatible with the others, because
you have to choose an specific inheritance hierarchy to use them.  You
can't subclass ``SecurePage`` and ``SidebarPage`` and ``MVCPage`` all
at once.

One solution is Mixins, using multiple inheritance to add various
functions.  This technique is available in Webware through
``MiscUtils.MixIn``.  However, there are many places where Mixins are
mutually incompatible -- for instance, code often has to intercept the
``awake()`` method, but delegating to each Mixin requires that they
all know about each other.

Components are essentially a way of creating Mixins that all know
about each other.

What's a Component Good For?
----------------------------

Components are useful if you have code that should know about the
request and response, and possible intercept it.  If the code doesn't
need to know about the request at all, you should just create a normal
Python library, and call into it explicitly.  Components can also be a
convenient way to add new convenience methods to your servlet.

Using CPage
===========

In order to use components, all your servlets must inherit from
``Component.CPage``.  This subclass of ``WebKit.Page`` adds some new
convenient methods, but mostly just adds component support.

New methods:

``writeHeader()``:
    Called automatically in ``writeBodyParts``.  If you are not using
    a template, this can be used to write the HTML that goes at the
    top of every page (the text written goes just *after* ``<body>``).

``writeFooter()``:
    ``writeHeader`` compliment.

``setView(view_name)``:
    ``CPage`` adds the idea of *views*.  The default view is
    ``writeContent`` -- that's the innermost method that is called.
    This can be used with actions so that the action method performs
    some work, then changes the view to display a different body.
    This way actions occur before content display, but can effect
    later display without losing the normal Python templating
    mechanism (``writeHead``, etc).  Templating components (like
    ZPTKit) may use this concept of view to indicate a template to
    use.

``view()``:
    Returns the view, as a string.

``sendResponseAndEnd(status, headers={}, body=None)``:
    For error responses.  This can be used like::

      def awake(self, trans):
          CPage.awake(self, trans)
          try:
              self.id = int(
                  self.request().extraURLPath().split('/')[1])
          except (ValueError, IndexError):
              self.sendResponseAndEnd(500)

    A simple error body is created if you don't pass one in.

``preAction`` and ``postAction`` are modified to do nothing (in
``WebKit.Page`` they output a little HTML).

Using Components
================

``CPage`` looks for any components you have in the ``.components``
class variable (which should be a list).  One very simple component is
included, ``NotifyComponent``.  As an example you can use this
component like::

    from Component import CPage
    from Component.notify import NotifyComponent

    class SitePage(CPage):

        components = [NotifyComponent()]

        def writeHeader(self):
            self.writeMessages()

If the component was configured, it would probably take arguments to
its constructor (this simple component has no configuration).  A
component can add new methods to the servlet.  In this case it adds a
``.message(text)`` method, which adds your message to the session, and
a ``.writeMessages()`` method which writes the messages and clears them
from the session.  (Also a ``.messageText()`` method if you don't want
to write the messages immediately.)

It's up to the component to add methods or attributes to the servlet.
It can also respond to "events" -- one example (and one of the only
current events) is the ``awake`` event, where it could intercept the
request.  An example of this is in LoginKit_, where the component
checks the servlet for permission settings, and may abort the
transaction with a login screen (or a Forbidden response) during
``awake()``.

.. _LoginKit: http://svn.w4py.org/LoginKit

Writing Components
==================

Read the source -- there are many docstrings in ``Component.py``.
