Code

fixes to mailgw tests
[roundup.git] / doc / templating.txt
index c15e6ee2734e8c5f1be9133248c1fa7b91f7b60f..0a750d9ae9539d958dbd98ce1199dac8b8d17ac7 100644 (file)
@@ -2,7 +2,7 @@
 HTML Templating Mechanisms
 ==========================
 
-:Version: $Revision: 1.5 $
+:Version: $Revision: 1.14 $
 
 Current Situation and Issues
 ============================
@@ -15,7 +15,7 @@ Roundup currently uses an element-based HTML-tag-alike templating syntax::
    <display call="checklist('status')">
 
 The templates were initially parsed using recursive regular expression
-parsing, and since no template tag could be encapsulate itself, the parser
+parsing, and since no template tag could encapsulate itself, the parser
 worked just fine. Then we got the ``<require>`` tag, which could have other
 ``<require>`` tags inside. This forced us to move towards a more complete
 parser, using the standard python sgmllib/htmllib parser. The downside of this
@@ -23,10 +23,8 @@ switch is that constructs of the form::
 
    <tr class="row-<display call="plain('status')">">
 
-don't parse as we'd hope. It would be almost impossible to modify the sgmllib
-parser to parse the above "correctly", so a wholly new parser would be
-required. That is a large undertaking, and doesn't address another couple of
-issues that have arisen:
+don't parse as we'd hope. We can modify the parser to work, but that doesn't
+another couple of issues that have arisen:
 
 1. the template syntax is not well-formed, and therefore is a pain to parse
    and doesn't play well with other tools, and
@@ -55,7 +53,7 @@ Templates
 We should also take this opportunity to open up the flexibility of the
 templates through:
 
-1. allowing the instance to define a "page" template, which holds the overall
+1. allowing the tracker to define a "page" template, which holds the overall
    page structure, including header and footer
 
 
@@ -89,38 +87,114 @@ Other fun can be had when you start playing with stuff like:
    </tr>
   </table>
 
+Note: even if we don't switch templating as a whole, this document may be
+applied to the ZRoundup frontend.
+
+PageTemplates in a Nutshell
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+PageTemplates consist of three technologies:
+
+TAL - Template Attribute Language
+  This is the syntax which is woven into the HTML using the ``tal:`` tag
+  attributes. A TAL parser pulls out the TAL commands from the attributes
+  runs them using some expression engine.
+
+TALES - TAL Expression Syntax
+  The expression engine used in this case is TALES, which runs the expressions
+  that form the tag attribute values. TALES expressions come in three
+  flavours:
+
+  Path Expressions - eg. ``item/status/checklist``
+   These are object attribute / item accesses. Roughly speaking, the path
+   ``item/status/checklist`` is broken into parts ``item``, ``status``
+   and ``checklist``. The ``item`` part is the root of the expression.
+   We then look for a ``status`` attribute on ``item``, or failing that, a
+   ``status`` item (as in ``item['status']``). If that
+   fails, the path expression fails. When we get to the end, the object we're
+   left with is evaluated to get a string - methods are called, objects are
+   stringified. Path expressions may have an optional ``path:`` prefix, though
+   they are the default expression type, so it's not necessary.
+
+  String Expressions - eg. ``string:hello ${user/name}``
+   These expressions are simple string interpolations (though they can be just
+   plain strings with no interpolation if you want. The expression in the
+   ``${ ... }`` is just a path expression as above.
+
+  Python Expressions - eg. ``python: 1+1``
+   These expressions give the full power of Python. All the "root level"
+   variables are available, so ``python:item.status.checklist()`` would be
+   equivalent to ``item/status/checklist``, assuming that ``checklist`` is
+   a method.
+
+PageTemplates
+  The PageTemplates module glues together TAL and TALES.
+
 
 Implementation
 ~~~~~~~~~~~~~~
 
 I'm envisaging an infrastructure layer where each template has the following
-variables defined:
+"root level" (that is, directly accessible in the TALES namespace) variables
+defined:
+
+*klass*
+  The current class of item being displayed as an HTMLClass instance. Name is
+  mangled so it can be used in Python expressions.
 
-*class*
-  the current class of node being displayed
 *item*
-  the current node from the database, if we're viewing a specific node
+  The current item from the database, if we're viewing a specific item, as an
+  HTMLItem instance. If it doesn't exist, then we're on a new item page.
+
 (*classname*)
-  the current node is also available under its classname, so a *user* node
-  would also be available under the name *user*.
+  this is one of two things:
+
+  1. the *item* is also available under its classname, so a *user* item
+     would also be available under the name *user*. This is also an HTMLItem
+     instance.
+  2. if there's no *item* then the current class is available through this
+     name, thus "user/name" and "user/name/menu" will still work - the latter
+     will pull information from the form if it can.
+
+  this is a dangerous attribute, and may cause us pain the long run (its name
+  may clash with other top-level variables ... it already clashed with the
+  proposed *user* variable). It might be safer to go with just *class* and
+  *item*, actually...
+
 *form*
-  the current CGI form information
-*instance*
-  the current instance
+  The current CGI form information as a mapping of form argument name to value
+
+*request*
+  Includes information about the current request, including:
+   - the url
+   - the current index information (``filterspec``, ``filter`` args,
+     ``properties``, etc) parsed out of the form. 
+   - methods for easy filterspec link generation
+   - *user*, the current user item as an HTMLItem instance
+
+*tracker*
+  The current tracker
+
 *db*
-  the current open database
+  The current open database
+
 *config*
-  the current instance config
-*util*
-  utility methods
+  The current instance config
 
-Accesses through a class (either through *class* or *db.<classname>*):
+*modules*
+  python modules made available (XXX: not sure what's actually in there tho)
 
-    class HTMLItem:
+Accesses through a class (either through *klass* or *db.<classname>*)::
+
+    class HTMLClass:
         def __getattr__(self, attr):
             ''' return an HTMLItem instance '''
         def classhelp(self, ...)
         def list(self, ...)
+        def filter(self):
+            ''' Return a list of items from this class, filtered and sorted
+                by the current requested filterspec/filter/sort/group args
+            '''
 
 Accesses through an *item*::
 
@@ -128,9 +202,11 @@ Accesses through an *item*::
         def __getattr__(self, attr):
             ''' return an HTMLItem instance '''
         def history(self, ...)
-        def classhelp(self, ...)
         def remove(self, ...)
 
+Note: the above could cause problems if someone wants to have properties
+called "history" or "remove"...
+
 String, Number, Date, Interval HTMLProperty
  a wrapper object which may be stringified for the current plain() behaviour
  and has methods emulating all the current display functions, so
@@ -165,6 +241,7 @@ String, Number, Date, Interval HTMLProperty
     class IntervalHTMLProperty(HTMLProperty):
         def plain(self, ...)
         def field(self, ...)
+        def pretty(self, ...)
 
 Link HTMLProperty
  the wrapper object would include the above as well as being able to access
@@ -194,33 +271,89 @@ Multilink HTMLProperty
         def checklist(self, ...)
         def list(self, ...)
  
-*util*
- the util object will handle::
+*request*
+ the request object will handle::
 
-    class Util:
+    class Request:
         def __init__(self, ...)
         def filterspec(self, ...)
-        def note(self, ...)
-        def submit(self, ...)
 
-Action
-======
+Accesses through the *user* attribute of *request*::
+
+    class HTMLUser(HTMLItem):
+        def hasPermission(self, ...)
+
+(note that the other permission check implemented by the security module may
+ be implemented easily in a tal:condition, so isn't needed here)
+
+Template files
+~~~~~~~~~~~~~~
+
+Each instance will have the opportunity to supply the following templates:
+
+page
+ This is the overall page look template, and includes at some point a TAL
+ command that includes the variable "content". This variable causes the actual
+ page content to be generated.
+
+[classname].[template type]
+ Templates that have this form are applied to item data. There are three forms
+ of special template types:
+
+ [classname].index
+  This template is used when the URL specifies only the class, and not an item
+  designator.  It displays a list of [classname] items from the database, and
+  a "filter refinement" form.
+  Would perform a TAL ``repeat`` command using the list supplied by
+  ``class/filter``. This deviates from the current situation in that currently
+  the index template specifies a single row, and the filter part is
+  automatically generated.
+
+ [classname].item
+  This template is used when the URL specifies an item designator. It's the
+  default template used (when no template is explicitly given). It displays
+  a single item from the database using the *classname* variable (that
+  is, the variable of the same name as the class being displayed. If 
+
+ These two special template types may be overridden by the :template CGI
+ variable.
+
+Note that the "newitem" template doesn't exist any more because the item
+templates may determine whether the page has an existing item to render. The
+new item page would be accessed by "/tracker/url/issue?:template=item".
+The old "filter" template has been subsumed by the index template.
+
+
+Integrating Code
+~~~~~~~~~~~~~~~~
+
+We will install PageTemplates, TAL and ZTUtils in site-packages. If there is a
+local Zope installation, it will use its own PageTemplates code (Zope modifies
+the module search path to give precedence to its own module library).
+
+We will then install the trivial MultiMapping and ComputedAttribute modules in
+the Roundup package, and have some import trickery that determines whether
+they are required, and if so they will be imported as if they were at the
+"top level" of the module namespace.
+
+New CGI client structure
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Handling of a request in the CGI client will take three phases:
 
-1. Investigate how PageTemplates would be integrated into Roundup:
+1. Determine user, pre-set "content" to authorisation page if necessary
+2. Render main page, with callback to "content"
+3. Render content - if not pre-set, then determine which content to render
 
-   - we could go for a fully-divorced-from-Zope approach, which would involve
-     bundling PageTemplates/TAL/ZTUtils in with Roundup, with all the
-     Zope-specific bits removed.
-   - we could try to coexist with a Zope installation, but there the problem
-     would be that Zope includes its own copy of PageTemplates/TAL/ZTUtils and
-     we'd be installing a version in site-packages, which would be bad.
 
-   The latter may allow nicer integration with Zope itself, giving Zope
-   Roundup users access to acquired information in their templates. We could
-   get around that by modifying the ZRoundup interface to use the "real Zope"
-   ZPT. Maybe.
+Use Cases
+~~~~~~~~~
 
-2. Implement the Roundup infrastructure described in the `implementation`_
-   above.
+Meta/parent bug
+  Can be done with addition to the schema and then the actual parent heirarchy
+  may be displayed with a new template page ":dependencies" or something.
 
+Submission wizard
+  Can be done using new templates ":page1", ":page2", etc and some additional
+  actions on the CGI Client class in the instance.