[Commits] python.it commit r198 - in twisted/trunk/contrib/nevow/doc: . html txt txt/gettingstarted

commit a svn.python.it commit a svn.python.it
Mer 19 Lug 2006 11:52:23 CEST


Author: manlio
Date: Wed Jul 19 11:52:21 2006
New Revision: 198

Added:
   twisted/trunk/contrib/nevow/doc/
   twisted/trunk/contrib/nevow/doc/README
   twisted/trunk/contrib/nevow/doc/hier.py
   twisted/trunk/contrib/nevow/doc/html/
   twisted/trunk/contrib/nevow/doc/html/default.css
   twisted/trunk/contrib/nevow/doc/make.py
   twisted/trunk/contrib/nevow/doc/qdlocale.py
   twisted/trunk/contrib/nevow/doc/txt/
   twisted/trunk/contrib/nevow/doc/txt/gettingstarted/
   twisted/trunk/contrib/nevow/doc/txt/gettingstarted/helloworld.html
   twisted/trunk/contrib/nevow/doc/txt/gettingstarted/helloworld.py
   twisted/trunk/contrib/nevow/doc/txt/gettingstarted/helloworld.tac
   twisted/trunk/contrib/nevow/doc/txt/nevow-deployment.txt
   twisted/trunk/contrib/nevow/doc/txt/nevow-gettingstarted.txt
   twisted/trunk/contrib/nevow/doc/txt/nevow-glossary.txt
   twisted/trunk/contrib/nevow/doc/txt/nevow-intro.txt
   twisted/trunk/contrib/nevow/doc/txt/nevow-rendering.txt
   twisted/trunk/contrib/nevow/doc/txt/nevow-traversal.txt
   twisted/trunk/contrib/nevow/doc/txt/nevow-xml-templates.txt
   twisted/trunk/contrib/nevow/doc/txt2html.py
Log:
aggiunto fork alla documentazione di Nevow

Added: twisted/trunk/contrib/nevow/doc/README
==============================================================================
--- (empty file)
+++ twisted/trunk/contrib/nevow/doc/README	Wed Jul 19 11:52:21 2006
@@ -0,0 +1,8 @@
+Simple documentation system that supports navigation generation, 
+organizational hierarchy, internationalization, etc.
+Written by jamwt a jamwt.com.
+
+    1. Download docutils from http://docutils.sourceforge.net/.
+    2. Write simple fragment restructured text files in txt/.
+    3. Lay out heir.py to reflect the titles and hierarchy of the text fragments
+    4. cd to doc/ (the directory this README is in) and run 'python make.py'

Added: twisted/trunk/contrib/nevow/doc/hier.py
==============================================================================
--- (empty file)
+++ twisted/trunk/contrib/nevow/doc/hier.py	Wed Jul 19 11:52:21 2006
@@ -0,0 +1,23 @@
+title = { 
+        "en" : "Nevow Manual"
+        }
+
+hier = \
+( 
+{"nevow-intro":("Introduction",None)},
+{"nevow-gettingstarted":("Getting Started",None)},
+{"nevow-traversal":("Object Traversal",None)},
+{"nevow-rendering":("Object Publishing",None)},
+{"nevow-xml-templates":("XML Templates",None)},
+{"nevow-deployment":("Deploying Nevow Applications",None)},
+{"nevow-glossary":("Glossary",None)},
+
+#{"other":("Other",
+#    (
+#    {"blah":("Blah",
+#        (
+#        {"bar":("Bar",None)},
+#        ))},
+#    ))},
+
+)

Added: twisted/trunk/contrib/nevow/doc/html/default.css
==============================================================================
--- (empty file)
+++ twisted/trunk/contrib/nevow/doc/html/default.css	Wed Jul 19 11:52:21 2006
@@ -0,0 +1,209 @@
+/*
+ * Originally stolen from http://diveintopython.org
+ * - R. Sridhar
+ */
+
+body {
+  background-color: white;
+  color: #222;
+  font-family: "Book Antiqua", Georgia, Palatino, Times, "Times New Roman", serif;
+  line-height: 145%;
+}
+
+h1, h2, h3, h4, h5, h6, p#tagline, #menu, .Footer, #breadcrumb {
+  margin: 0;
+  padding: 0;
+  font-family: "Lucida Grande", Tahoma, "Trebuchet MS", Verdana, Lucida, Geneva, Helvetica, sans-serif;
+}
+
+.titlepage h1 {
+  margin-top: 1em;
+}
+
+h1 {
+  font-size: 180%;
+  background-color: white;
+  color: maroon;
+  text-shadow: 2px 2px 2px #990000;
+}
+
+h1 a {
+  background-color: white;
+  color: maroon;
+  text-decoration: none;
+}
+
+h2 {
+  margin-top: 1em;
+  font-size: 140%;
+  text-shadow: 2px 2px 2px #999999;
+}
+
+h3 {
+  margin-top: 1em;
+  font-size: 100%;
+}
+
+label, .divider {
+  display: none;
+}
+
+#Header {
+  border-bottom: 1px solid maroon;
+}
+
+p#tagline {
+  margin: 3px 0 6px 2px;
+  font-size: 90%;
+  font-weight: bold;
+  background-color: white;
+  color: maroon;
+}
+
+#breadcrumb {
+  font-size: 90%;
+}
+
+#navigation {
+  font-size: 90%;
+}
+
+.thispage {
+  font-weight: bold;
+}
+
+.Footer {
+  font-size: 90%;
+  border-top: 1px solid maroon;
+  background-color: white;
+  color: maroon;
+  width: 85%;
+}
+
+table.Footer {
+  margin-top: 1em;
+}
+
+#breadcrumb {
+  padding: 0 0 1em 2px;
+}
+
+.tip, .note, .warning, .caution, .important, .footnote {
+  margin: 1em 2em 1em 2em;
+}
+
+.furtherreading {
+  margin-top: 1em;
+}
+
+.screen, .programlisting, .example table {
+  margin: 1em 1em 0 1em;
+  padding: 0;
+}
+
+.example table {
+  margin-bottom: 1em;
+}
+
+.toc li {
+  list-style: none;
+}
+
+/* ----- Python code syntax coloring ----- */
+.computeroutput, .traceback, .pykeyword, .pystring, .pycomment, .pyfunction, .pyclass {
+  background-color: white;
+}
+
+.pykeyword, .pyfunction, .pyclass {
+  font-weight: bold;
+}
+
+.computeroutput {
+  color: teal;
+}
+
+.traceback {
+  color: red;
+}
+
+.pykeyword {
+  color: navy;
+}
+
+.pystring {
+  color: olive;
+}
+
+.pycomment {
+  color: green;
+  font-style: italic;
+}
+
+.pyfunction {
+  color: teal;
+}
+
+.pyclass {
+  color: blue;
+}
+
+/* ----- home page ----- */
+#wrapper {
+  float: left;
+  width: 66%;
+  border: 0;
+  background-color: white;
+  color: #222;
+  margin: 1em 2em 0 0;
+}
+
+#menu {
+  font-size: 90%;
+  margin-top: 1.5em;
+}
+
+#menu h2 {
+  background-color: white;
+  color: maroon;
+}
+  
+#menu ul {
+  list-style: none;
+}
+
+.selfad {
+  padding: 5px;
+  background-color: #ccc;
+  color: #222;
+  border: 1px solid #222;
+}
+
+.selfad p {
+  font-family: Tahoma, sans-serif;
+  font-size: 90%;
+  margin: 10px;
+  line-height: 140%;
+}
+
+#sponsoredlinks {
+  float: right;
+  margin-top: 20px;
+  margin-left: 20px;
+}
+
+.navbar a { 
+    font-size: 14px; margin-right: 25px;
+}
+
+.right { z-index: 99; position: absolute; right: 30px; }
+
+.docTitle { font-size: 20px; color: gray; }
+
+.directoryHeader { font-weight: bold;}
+
+.genNote { position: absolute; z-index: 99; right: 30px; font-style: italic;}
+
+.title { display: none; }
+
+.literal-block { margin: 0 2.5em; }
+

Added: twisted/trunk/contrib/nevow/doc/make.py
==============================================================================
--- (empty file)
+++ twisted/trunk/contrib/nevow/doc/make.py	Wed Jul 19 11:52:21 2006
@@ -0,0 +1,2 @@
+import os
+os.system("python txt2html.py txt html en")

Added: twisted/trunk/contrib/nevow/doc/qdlocale.py
==============================================================================
--- (empty file)
+++ twisted/trunk/contrib/nevow/doc/qdlocale.py	Wed Jul 19 11:52:21 2006
@@ -0,0 +1,14 @@
+locale = {
+    "en" : {
+        "defaultPage" : "index",
+        "next" : "Next",
+        "prev" : "Previous",
+        "home" : "Home",
+        "up" : "Up",
+        "top" : "Return to Top",
+        "toc" : "Table of Contents",
+        "updatedOn" : "Last updated on",
+        "sub" : "Subsections",
+    }
+}
+

Added: twisted/trunk/contrib/nevow/doc/txt/gettingstarted/helloworld.html
==============================================================================
--- (empty file)
+++ twisted/trunk/contrib/nevow/doc/txt/gettingstarted/helloworld.html	Wed Jul 19 11:52:21 2006
@@ -0,0 +1,9 @@
+<html>
+  <head>
+    <title>Hello, world!</title>
+  </head>
+  <body>
+    <p>Hello, world!</p>
+  </body>
+</html>
+

Added: twisted/trunk/contrib/nevow/doc/txt/gettingstarted/helloworld.py
==============================================================================
--- (empty file)
+++ twisted/trunk/contrib/nevow/doc/txt/gettingstarted/helloworld.py	Wed Jul 19 11:52:21 2006
@@ -0,0 +1,6 @@
+from nevow import loaders, rend
+
+class HelloWorld(rend.Page):
+    addSlash = True
+    docFactory = loaders.xmlfile('helloworld.html')
+

Added: twisted/trunk/contrib/nevow/doc/txt/gettingstarted/helloworld.tac
==============================================================================
--- (empty file)
+++ twisted/trunk/contrib/nevow/doc/txt/gettingstarted/helloworld.tac	Wed Jul 19 11:52:21 2006
@@ -0,0 +1,10 @@
+from twisted.application import internet
+from twisted.application import service
+from nevow import appserver
+import helloworld
+
+application = service.Application('helloworld')
+site = appserver.NevowSite(helloworld.HelloWorld())
+webServer = internet.TCPServer(8080, site)
+webServer.setServiceParent(application)
+

Added: twisted/trunk/contrib/nevow/doc/txt/nevow-deployment.txt
==============================================================================
--- (empty file)
+++ twisted/trunk/contrib/nevow/doc/txt/nevow-deployment.txt	Wed Jul 19 11:52:21 2006
@@ -0,0 +1,208 @@
+Nevow Deployment
+================
+
+Nevow includes two major phases for deciding what HTML to render. `Object
+Traversal`_ is the procedure by which a URL is mapped to a Python object which
+will perform the HTML generation. `Page Rendering`_ is the process by which data
+objects are combined with an HTML template to produce the final output.
+
+Before any of this can take place, however, we must have an environment in which
+our Python code can run in response to an HTTP request, and HTML can be returned
+to the browser for rendering. This is called the `Deployment Environment`_.
+
+There are various deployment options for Nevow page code:
+
+* `CGI`_: Simple deployment in almost any HTTP server
+* `WSGI`_: A more complete and flexible way for deploying on many HTTP servers
+* `Twisted.Web`_: A standalone application server process which includes a built-in HTTP server
+* `Zomne`_: A small CGI which hands off HTTP requests to a long-running application server process, similar to FastCGI or SCGI
+
+CGI
+---
+
+You can deploy Nevow on any webserver which uses the Common Gateway Interface.
+Using this method, your code is responsible for properly formatting and
+outputting the HTTP response headers, and Nevow is used only to generate the
+HTML body of your page. Here is the simplest possible CGI::
+
+  #!/usr/bin/env python
+
+  print "Content-type: text/plain\r\n\r\n",
+
+  from nevow import rend, loaders
+
+  class HelloWorld(rend.Page):
+      docFactory = loaders.stan("Hello, world!")
+
+  print HelloWorld().renderSynchronously()
+
+With this simple CGI you can use the Nevow template loaders and standard nevow
+template interpolation techniques in your CGIs. However, you do not get any
+`Object Traversal`_ features, and you have to generate HTTP headers yourself.
+`WSGI`_ is a slightly higher-level deployment option which does not suffer these
+problems.
+
+WSGI
+----
+
+WSGI is a proposed python interface for plugging web applications into various
+HTTP server architectures. It is described in `PEP 333`_, the Python Web
+Services Gateway Interface Python Enhancement Proposal. Nevow includes the
+nevow.wsgi module, which includes a createWSGIApplication function which takes a
+Page and returns a standard WSGI application callable. With the help of the
+run_with_cgi example gateway from the PEP (which I will omit here), our CGI
+example becomes shorter::
+
+  #!/usr/bin/env python
+
+  from nevow import rend, loaders, wsgi
+
+  class HelloWorld(rend.Page):
+      docFactory = loaders.stan("Hello, world!")
+
+  run_with_cgi(wsgi.createWSGIApplication(HelloWorld()))
+
+Of course, you can use any available WSGI gateway to publish your application
+object, such as one of the gateways which comes with the `PEAK`_ toolkit. For
+example, here is a simple python module which creates a WSGI application which
+we will then deploy with PEAK's SimpleHTTPServer gateway::
+
+  ## helloworld.py
+
+  from nevow import rend, loaders, wsgi
+
+  class HelloWorld(rend.Page):
+    docFactory = loaders.stan("Hello, world!")
+
+  application = wsgi.createWSGIApplication(HelloWorld())
+
+Save this file as "helloworld.py" somewhere on your PYTHONPATH and then run the
+following command::
+                      
+  peak launch WSGI import:helloworld.application
+
+This will bring up a SimpleHTTPServer running your Nevow code and launch a web
+browser to view the output. (TODO: I couldn't get this working immediately but I
+will seek assistance with PEAK and update the instructions once I do.)
+
+Twisted.Web
+-----------
+
+A convenient and powerful way to deploy Nevow applications is inside a process
+running the twisted.web HTTP server. With Python, Twisted, and Nevow installed,
+you have all you need to run a Web Application, with no other dependencies or
+external HTTP servers such as Apache required. Running your Nevow applications
+under twisted.web also gives you access to some of the more advanced "Live"
+features of Nevow, such as nevow.livepage and nevow.canvas. Currently, these
+modules require more control over the HTTP socket than CGI or WSGI can provide.
+(This may change in the future.)
+
+Deploying a Nevow application under twisted.web requires a little more
+boilerplate, but can be considerably easier to set up than other deployment
+options because there are no external dependencies. Note that normally you
+should declare your Page classes in modules external to the twisted
+configuration file, but everything is included in one file here for brevity.
+Here is the minimal configuration file required to use Nevow with twisted.web::
+
+  from nevow import rend, loaders, appserver
+
+  class HelloWorld(rend.Page):
+      docFactory = loaders.stan("Hello, world!")
+
+  from twisted.application import service, internet
+  application = service.Application("hello-world")
+  internet.TCPServer(8080, appserver.NevowSite(HelloWorld())).setServiceParent(application)
+
+Save this file as "helloworld.tac" and start the server using the command::
+
+  twistd -noy helloworld.tac
+
+Then visit your twisted.web server by viewing the url "http://localhost:8080/"
+in your browser. See the twistd man page for more information about what twistd
+is capable of, including daemonizing the HTTP server.
+
+Zomne
+-----
+
+**Warning** Zomne is experimental. It may blow up your computer and require your
+first born son as a sacrifice. Zomne also only works in UNIX-like environments
+where unix domain sockets are available, and may not work on windows.
+
+Zomne, or "Zombie Nevow", is a CGI written in C which can start up a
+long-running Application Server process if one is not already running. It then
+uses a simple custom protocol to transmit information about the HTTP request
+from the CGI process to the application server process.
+
+Zomne combines the ease of deployment of the CGI environment with the speed and
+flexibility of the twisted.web long-running application server process model.
+
+To use Zomne, you must first compile the CGI. cd into the directory created when
+unpacking the Nevow tarball, and compile the CGI::
+
+  % gcc zomne.c
+
+Move it into your cgi-bin::
+
+  % mv a.out /Library/WebServer/CGI-Executables/nevow.cgi
+
+Create a file which tells the cgi where to look for the application::
+
+  % cat > /Library/WebServer/CGI-Executables/.nevow.cgi.dir
+  /Users/dp/zomne-test
+  ^D
+
+The CGI name can be anything, as long as there is a file with a prepended "."
+and a postfixed ".dir" in the same directory which contains the full path of a
+zomne application directory. Next, create the application directory::
+
+  mkdir /Users/dp/zomne-test
+
+Finally, create the zomne.tac file which the zomne.cgi will execute to start the
+long-running application server process::
+
+  from nevow import rend, loaders, zomnesrv
+
+  class HelloWorld(rend.Page):
+      docFactory = loaders.stan("Hello, world!")
+
+  from twisted.application import service, internet
+  application = service.Application('nevow-zomne-test')
+  internet.UNIXServer('zomne.socket', zomnesrv.ZomneFactory(HelloWorld())).setServiceParent(application)
+
+Now, visiting the nevow.cgi URL through the web should render the Hello World
+page, after a pause while the server is starting up. Subsequent requests should
+be very fast, because the application server is already running, and the CGI
+merely has to forward the request to it.
+
+Another useful capability of the zomne CGI process is the ability to control
+environment variables the CGI will use. Create a directory named "zomne_environ"
+in the application directory, and fill it with text files whose name will be the
+environment key and whose contents will be the environment value::
+
+  % cd zomne-test
+  % mkdir zomne-environ
+  % cd zomne-environ
+  % cat > PYTHONPATH
+  /Users/dp/Projects/Nevow:/Users/dp/Projects/helloworld
+  ^D
+
+Conclusion
+==========
+
+Nevow may be deployed in a number of environments, from the most restrictive to
+the most permissive. Writing a CGI can be an easy way to try out the Nevow
+templating mechanism, but can be slow. A long-running application server process
+can be a good way to get good performance as well as additional features such as
+in-memory server-side sessions, advanced automatic form handling with formless,
+and live page updating features such as nevow.livepage and nevow.canvas.
+
+Which deployment option you choose will depend on the amount of control you have
+over your deployment environment, and what advanced features your application
+will require.
+
+.. _`Object Traversal`: nevow-glossary.html#object-traversal
+.. _`Page Rendering`: nevow-glossary.html#page-rendering
+.. _`Deployment Environment`: nevow-glossary.html#deployment-environment
+.. _`PEP 333`: http://www.python.org/peps/pep-0333.html
+.. _`PEAK`: http://peak.telecommunity.com/
+

Added: twisted/trunk/contrib/nevow/doc/txt/nevow-gettingstarted.txt
==============================================================================
--- (empty file)
+++ twisted/trunk/contrib/nevow/doc/txt/nevow-gettingstarted.txt	Wed Jul 19 11:52:21 2006
@@ -0,0 +1,78 @@
+Getting Started with Nevow
+==========================
+
+Warning: This document has only just been started. It's not going to get you
+very far right now.
+
+Nevow is a reasonably large library and can be quite daunting at first. This
+document's aim is to guide the first time user in building a Nevow application.
+
+
+Our First Application
+---------------------
+
+Let's dive straight in, here's the code for our first (very, very simple)
+application. Create the following module, helloworld.py::
+
+
+    from nevow import loaders, rend
+    
+    class HelloWorld(rend.Page):
+        addSlash = True
+        docFactory = loaders.xmlfile('helloworld.html')
+        
+
+It looks quite simple but let's walk through it anyway.
+
+First, we import two Nevow modules. ``nevow.loaders`` contains template loaders
+of which the two most useful are ``xmlfile`` and ``stan``. ``xmlfile`` can load
+any well-formed XML (i.e. XHTML) file; ``stan`` loads a stan tree (more on these
+later). The other module, ``nevow.rend``, contains all Nevow's standard renders,
+many of which we'll meet in this document.
+
+We then define the ``HelloWorld`` class that subclasses ``rend.Page``, Nevow's
+main resource class. ``HelloWorld`` has two class attributes. ``addSlash`` tells
+rend.Page to redirect to a version of the request URL that ends in a '/' if
+necessary. You generally want to set this to ``True`` for the root resource.
+``docFactory`` tells the page instance where to get the template from. In this
+case we're providing a loader that parses an HTML file (not shown) from disk.
+
+Hmm, ok I hear you say but how do I see it. Well, Twisted provides a good web
+server which we can use. Twisted also includes a clever little application for
+starting Twisted applications. Here's the helloworld.tac file, a Twisted Application
+Configuration::
+
+    from twisted.application import internet
+    from twisted.application import service
+    from nevow import appserver
+    import helloworld
+    
+    application = service.Application('helloworld')
+    site = appserver.NevowSite(helloworld.HelloWorld())
+    webServer = internet.TCPServer(8080, site)
+    webServer.setServiceParent(application)
+
+
+Give it a go, run the following and connect to http://localhost:8080/ to see
+your application::
+
+    twistd -noy helloworld.tac
+    
+    
+You'll probably notice that you get log output on the console. This is just one
+of the good things that twistd does. It can also daemonize the application, shed
+privileges if run as root, etc.
+
+TAC files are covered in more detail in the Twisted documentation but let's
+quickly explain what all this does anyway.
+
+When twistd starts up it loads the .tac file (it's just Python) and looks for
+the attribute called ``application``. When twistd is all ready to go it starts
+the ``application``.
+
+The application is not much use unless it actually does something so the next
+thing we do is create a NevowSite instance, ``site``, and pass it a root
+resource, a ``HelloWorld`` instance. Finally, we create a TCP server that makes
+the site available on port 8080 and bind the server to the application to ensure
+the server is started when the application is started.
+

Added: twisted/trunk/contrib/nevow/doc/txt/nevow-glossary.txt
==============================================================================
--- (empty file)
+++ twisted/trunk/contrib/nevow/doc/txt/nevow-glossary.txt	Wed Jul 19 11:52:21 2006
@@ -0,0 +1,47 @@
+Nevow Glossary
+==============
+
+Object Traversal
+  The process by which a Python object is located to render HTML for a given
+  HTTP URL. For example, given the URL http://example.com/foo/bar, Object
+  Traversal will begin at the "Root Resource" object by asking it for an object
+  which is capable of rendering the page at ('foo', 'bar'). The "Root Resource"
+  returns an object and a list of unhandled path segments, and the traversal
+  continues across this new Resource object until all path segments have been
+  consumed.
+
+Page Rendering
+  The process by which a Python object, usually a rend.Page subclass, turns
+  itself into HTML. Page Rendering involves locating some page data, loading a
+  template document, and applying the template to the data, in the process
+  generating HTML.
+
+Deployment Environment
+  The environment in which a Nevow application is deployed. Generally involves
+  an HTTP server which is configured to route certain (or all) HTTP requests
+  through the Nevow Object Traversal and Page Rendering process. Deployment
+  environments include CGI, WSGI, and twisted.web.
+
+DOM
+  Document Object Model. A tree of objects which represent the structure of an
+  XHTML document in memory. Nevow uses a nonstandard DOM named "stan", which is
+  made up of simple Python lists, dicts, strings, and nevow.stan.Tag instances.
+
+Flattener
+  A Python function which knows how to translate from a rich type to a string
+  containing HTML. For example, the integer flattener calls str() on the
+  integer. The string flattener escapes characters which are unsafe in HTML,
+  such as <, >, and &.
+
+Tag
+  A class, defined at nevow.stan.Tag, which holds information about a single
+  HTML tag in a DOM. Tag instances have three attributes: tagName, attributes,
+  and children. tagName is a string indicating the tag name. attributes is a
+  dict indicating the HTML attributes of that node. children is a list
+  indicating the child nodes of that node.
+
+Tag Specials
+  A Tag attribute which is "special" to nevow. Tag specials include data,
+  render, pattern, slot, and macro. Tag Specials will never be output as HTML
+  attributes of tags, but will be used by the internal Nevow rendering process
+  to influence how the Tag is rendered.

Added: twisted/trunk/contrib/nevow/doc/txt/nevow-intro.txt
==============================================================================
--- (empty file)
+++ twisted/trunk/contrib/nevow/doc/txt/nevow-intro.txt	Wed Jul 19 11:52:21 2006
@@ -0,0 +1,237 @@
+Nevow: A Web Application Construction Kit
+=========================================
+
+Donovan Preston <dp a divmod.org>
+
+Summary
+-------
+
+Nevow is a next-generation web application templating system, based on the ideas
+developed in the Twisted Woven package. Its main focus is on separating the HTML
+template from both the business logic and the display logic, while allowing the
+programmer to write pure Python code as much as possible. It separates your code
+into 'data' and 'render' functions, a simplified implementation of traditional
+MVC. It has various parts which can be used individually or as a whole,
+integrated web solution:
+
+  - XHTML templates: contain no programming logic, only nodes tagged with nevow
+    attributes
+
+  - data/render methods: simplified MVC
+
+  - stan: An s-expression-like syntax for expressing xml in pure python
+
+  - formless: For describing the types of objects which may be passed to methods
+    of your classes, validating and coercing string input from either web or
+    command-line sources, and calling your methods automatically once validation
+    passes
+
+  - formless.webform: For rendering web forms based on formless type
+    descriptions, accepting form posts and passing them to formless validators,
+    and rendering error forms in the event validation fails
+
+  - livepage: Cross-browser JavaScript glue for sending client side events to
+    the server and server side events to the client after the page has loaded,
+    without causing the entire page to refresh
+
+Disk based templates
+~~~~~~~~~~~~~~~~~~~~
+
+Nevow includes the ability to load templates off disk. These templates may have
+processing directives which cause the execution of python methods at render
+time. The attribute technique was inspired by the attributes used by ZPT.
+However, no actual code may be embedded in the HTML template::
+
+  <html xmlns:nevow="http://nevow.com/ns/nevow/0.1">
+    <head>
+      <title>Greetings!</title>
+    </head>
+    <body>
+      <h1 style="font-size: large">Now I will greet you:</h1>
+      <span nevow:render="greet" />
+    </body>
+  </html>
+
+This template can then be loaded and rendered like so::
+
+  class Greeter(rend.Page):
+      docFactory = loaders.xmlfile("Greeting.html")
+
+      def render_greet(self, context, data):
+          return random.choice(["Hello", "Greetings", "Hi"]), " ", data
+
+  Greeter("My name is").renderString()
+
+data/render methods
+~~~~~~~~~~~~~~~~~~~
+
+To allow clean isolation between code which fetches data from a data source and
+code which renders the data into HTML, nevow allows you to write both 'data'
+methods and 'render' methods. These concepts are inspired by MVC, but simpler,
+since the framework can handle most of the controller aspect. An example::
+
+  <html xmlns:nevow="http://nevow.com/ns/nevow/0.1">
+    <body>
+      <span nevow:data="name" nevow:render="colorful" />
+      <span nevow:data="fun" nevow:render="colorful" />
+    </body>
+  </html>
+
+This template can be loaded and rendered using a class such as this::
+
+  class Colorful(rend.Page):
+    docFactory = loaders.xmlfile("Colorful.html")
+    
+    def render_colorful(self, context, data):
+      color = random.choice(['red', 'green', 'blue'])
+      return context.tag(style="color: %s" % color)
+
+    def data_name(self, context, data):
+      return "Your name here"
+
+    def data_fun(self, context, data):
+      return "Are we having fun yet?"
+
+Stan
+~~~~
+
+One of the most powerful things about nevow is stan, an s-expression-like syntax
+for producing XML fragments in pure Python syntax. Stan is not required for
+using nevow, but it is both a simple and powerful way to both lay out one's
+XHTML templates and express one's display logic. A brief example will illustrate
+its utility::
+
+      import random
+      from nevow import rend, tags
+    
+      class Greeter(rend.Page):
+          def greet(self, context, data):
+              return random.choice(["Hello", "Greetings", "Hi"]), " ", data
+    
+          docFactory = loaders.stan(
+          tags.html[
+          tags.head[ tags.title[ "Greetings!" ]],
+          tags.body[
+              tags.h1(style="font-size: large")[ "Now I will greet you:" ],
+              greet
+          ]
+      ])
+
+When the Greeter class is constructed, it is passed a Python object which will
+be used as that page's data::
+
+  Greeter("Your name here").renderString()
+
+Formless
+~~~~~~~~
+
+Python is dynamically typed, which means it has no built-in controls for
+enforcing the types of objects which are passed to one's methods. This is great
+for programmers, but not necessarily great if you are going to be passing
+user-entered input to those methods. Formless is a simple way to describe the
+types of objects that can be passed to one's methods, as well as coerce from
+string input to those types. Other code can then accept user input from a
+command line or from a web form, validate the input against the types described
+using formless, and call the method once validation has passed. A simple
+example::
+
+  from zope.interface import implements
+  from formless.annotate import TypedInterface, Integer, String
+
+  class ISimpleMethod(TypedInterface):
+      def simple(self, 
+          name=String(description="Your name."), 
+          age=Integer(description="Your age.")):
+          """Simple
+          
+          Please enter your name and age.
+          """
+
+  class Implementation(object):
+      implements(ISimpleMethod)
+
+      def simple(self, name, age):
+          print "Hello, %s, who is %s" % (name, age)
+
+Webform
+~~~~~~~
+
+Webform is a nevow module which will automatically render web forms and accept
+form posts based on types described using the classes in formless. Used in
+conjunction with the twisted.web HTTP server, the process is almost automatic::
+
+      from nevow import rend, tags
+      from formless import webform
+    
+      class WebForm(rend.Page):
+          document = rend.stan(
+          tags.html[
+          tags.body[
+              h1["Here is the form:"],
+              webform.renderForms('original')
+          ]
+      ])
+
+      resource = WebForm(Implementation())
+
+Exposing this resource instance to the web using twisted.web and visiting it
+will cause a form with two input boxes to be rendered. Posting the form will
+cause form validation to occur. Upon error, the user will be returned to the
+original page, with the form annotated with error messages. Upon success, the
+"simple" method of the Implementation instance will be called and passed a
+string and an integer.
+
+LivePage
+~~~~~~~~
+
+LivePage was a Woven technology which allowed programmers to receive server-side
+notification of client-side JavaScript events, and to send JavaScript to the
+client in response to a server-side event. New for Nevow 0.3, LivePage has been
+updated to support Mozilla, Firefox, IE6 Win, and Safari. Using LivePage is very
+easy::
+
+      from nevow.liveevil import handler
+
+      def greeter(client, nodeName):
+	  client.alert("Greetings. You clicked the %s node." % nodeName)
+
+      # Any string arguments after the event handler function will be evaluated
+      # as JavaScript in the context of the web browser and results passed to the
+      # Python event handler
+      handler = handler(greeter, 'node.name')
+
+      class Live(rend.Page):
+          docFactory = loaders.stan(
+          tags.html[
+          tags.body[
+              ol[
+                  li(onclick=handler, name="one")["One"]
+                  li(onclick=handler, name="two")["Two"]
+                  li(onclick=handler, name="three")["Three"]
+              ]
+          ]
+      ])
+
+More Information
+----------------
+
+Nevow is available from the `Nevow website`_. Starting with 0.3, it contains a
+simple WSGI implementation and can also be used to render CGIs. However, the
+recommended mode of operation is using the `Twisted web`_ server. Nevow is an
+active project, and many new bugfixes and features are committed to the Nevow
+SVN repository. Information about Nevow commits is available by subscribing to
+the `Nevow commits`_ mailing list. The Nevow SVN repository can be checked out
+using::
+
+  svn co svn://divmod.org/svn/Nevow/trunk Nevow
+
+Discussion of Nevow occurs on the `twisted.web mailing list`_. The Nevow
+developers are also often available for real-time help on the `#twisted.web
+channel`_ on irc.freenode.net.
+
+.. _`Nevow website`: http://nevow.com/
+.. _`Twisted web`: http://twistedmatrix.com/products/download
+.. _`Nevow commits`: http://divmod.org/users/mailman.twistd/listinfo/nevow-commits
+.. _`twisted.web mailing list`: http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-web
+.. _`#twisted.web channel`: irc://irc.freenode.net/#twisted.web
+

Added: twisted/trunk/contrib/nevow/doc/txt/nevow-rendering.txt
==============================================================================
--- (empty file)
+++ twisted/trunk/contrib/nevow/doc/txt/nevow-rendering.txt	Wed Jul 19 11:52:21 2006
@@ -0,0 +1,538 @@
+Nevow Object Publishing
+=======================
+
+In Nevow Object Traversal, we learned about the
+nevow.inevow.IResource.renderHTTP method, which is the most basic way to send
+HTML to a browser when using Nevow. However, it is not very convenient (or
+clean) to generate HTML tags by concatenating strings in Python code. In the
+Nevow Deployment documentation, we saw that it was possible to render a Hello
+World page using a nevow.rend.Page subclass and providing a "docFactory"::
+
+  >>> from nevow import rend, loaders
+  >>> class HelloWorld(rend.Page):
+  ...     docFactory = loaders.stan("Hello, world!")
+  ... 
+  >>> HelloWorld().renderSynchronously()
+  'Hello, world!'
+
+This example does nothing interesting, but the concept of a loader is important
+in Nevow. The rend.Page.renderHTTP implementation always starts rendering HTML
+by loading a template from the docFactory.
+
+* `The stan DOM`_
+* `Tag instances`_
+* `Functions in the DOM`_
+* `Accessing query parameters and form post data`_
+* `Generators in the DOM`_
+* `Methods in the DOM`_
+* `Data specials`_
+* `Render specials`_
+* `Pattern specials`_
+* `Slot specials`_
+* `Data directives`_
+* `Render directives`_
+* `Flatteners`_
+
+The stan DOM
+------------
+
+Nevow uses a DOM-based approach to rendering HTML. A tree of objects is first
+constructed in memory by the template loader. This tree is then processed one
+node at a time, applying functions which transform from various Python types to
+HTML strings.
+
+Nevow uses a nonstandard DOM named "stan". Unlike the W3C DOM, stan is made up
+of simple python lists, strings, and instances of the nevow.stan.Tag class.
+During the rendering process, "Flattener" functions convert from rich types to
+HTML strings. For example, we can load a template made up of some nested lists
+and Python types, render it, and see what happens::
+
+  >>> class PythonTypes(rend.Page):
+  ...     docFactory = loaders.stan(["Hello", 1, 1.5, True, ["Goodbye", 3]])
+  ... 
+  >>> PythonTypes().renderSynchronously()
+  'Hello11.5TrueGoodbye3'
+
+Tag instances
+-------------
+
+So far, we have only rendered simple strings as output. However, the main
+purpose of Nevow is HTML generation. In the stan DOM, HTML tags are represented
+by instances of the nevow.stan.Tag class. Tag is a very simple class, whose
+instances have an "attributes" dictionary and a "children" list. The Tag
+flattener knows how to recursively flatten attributes and children of the tag.
+To show you how Tags really work before you layer Nevow's convenience syntax on
+top, try this horrible example::
+
+  >>> from nevow import stan
+  >>> h = stan.Tag('html')
+  >>> d = stan.Tag('div')
+  >>> d.attributes['style'] = 'border: 1px solid black'
+  >>> h.children.append(d)
+  >>> class Tags(rend.Page):
+  ...     docFactory = loaders.stan(h)
+  ... 
+  >>> Tags().renderSynchronously()
+  '<html><div style="border: 1px solid black"></div></html>'
+
+So, we see how it is possible to programatically generate HTML by constructing
+and nesting stan Tag instances. However, it is far more convenient to use the
+overloaded operators Tag provides to manipulate them. Tag implements a __call__
+method which takes any keyword arguments and values and updates the attributes
+dictionary; it also implements a __getitem__ method which takes whatever is
+between the square brackets and appends them to the children list. A simple
+example should clarify things::
+
+  >>> class Tags2(rend.Page):
+  ...     docFactory = loaders.stan(stan.Tag('html')[stan.Tag('div')(style="border: 1px solid black")])
+  ... 
+  >>> Tags2().renderSynchronously()
+  '<html><div style="border: 1px solid black"></div></html>'
+
+This isn't very easy to read, but luckily we can simplify the example even
+further by using the nevow.tags module, which is full of "Tag prototypes" for
+every tag type described by the XHTML 1.0 specification::
+
+  >>> class Tags3(rend.Page):
+  ...     docFactory = loaders.stan(tags.html[tags.div(style="border: 1px solid black")])
+  ... 
+  >>> Tags3().renderSynchronously()
+  '<html><div style="border: 1px solid black"></div></html>'
+
+Using stan syntax is not the only way to construct template DOM for use by the
+Nevow rendering process. Nevow also includes loaders.xmlfile which implements a
+simple tag attribute language similar to the Zope Page Templates (ZPT) Tag
+Attribute Language (TAL). However, experience with the stan DOM should give you
+insight into how the Nevow rendering process really works. Rendering a template
+into HTML in Nevow is really nothing more than iterating a tree of objects and
+recursively applying "Flattener" functions to objects in this tree, until all
+HTML has been generated.
+
+Functions in the DOM
+--------------------
+
+So far, all of our examples have generated static HTML pages, which is not
+terribly interesting when discussing dynamic web applications. Nevow takes a
+very simple approach to dynamic HTML generation. If you put a Python function
+reference in the DOM, Nevow will call it when the page is rendered. The return
+value of the function replaces the function itself in the DOM, and the results
+are flattened further. This makes it easy to express looping and branching
+structures in Nevow, because normal Python looping and branching constructs are
+used to do the job::
+
+  >>> def repeat(ctx, data):
+  ...     return [tags.div(style="color: %s" % (color, ))
+  ...         for color in ['red', 'blue', 'green']]
+  ... 
+  >>> class Repeat(rend.Page):
+  ...     docFactory = loaders.stan(tags.html[repeat])
+  ... 
+  >>> Repeat().renderSynchronously()
+  '<html><div style="color: red"></div><div style="color: blue"></div><div style="color: green"></div></html>'
+
+However, in the example above, the repeat function isn't even necessary, because
+we could have inlined the list comprehension right where we placed the function
+reference in the DOM. Things only really become interesting when we begin
+writing parameterized render functions which cause templates to render
+differently depending on the input to the web application.
+
+The required signature of functions which we can place in the DOM is (ctx,
+data). The "context" object is essentially opaque for now, and we will learn how
+to extract useful information out of it later. The "data" object is anything we
+want it to be, and can change during the rendering of the page. By default, the
+data object is whatever we pass as the first argument to the Page constructor,
+**or** the Page instance itself if nothing is passed. Armed with this knowledge,
+we can create a Page which renders differently depending on the data we pass to
+the Page constructor::
+
+  class Root(page.Page):
+      docFactory = loaders.stan(tags.html[
+      tags.h1["Welcome."],
+      tags.a(href="foo")["Foo"],
+      tags.a(href="bar")["Bar"],
+      tags.a(href="baz")["Baz"]])
+
+      def childFactory(self, ctx, name):
+          return Leaf(name)
+  
+  
+  def greet(ctx, name):
+      return "Hello. You are visiting the ", name, " page."
+  
+  class Leaf(rend.Page):
+      docFactory = loaders.stan(tags.html[greet])
+
+Armed with this knowledge and the information in the Object Traversal
+documentation, we now have enough information to create dynamic websites with
+arbitrary URL hierarchies whose pages render dynamically depending on which URL
+was used to access them.
+
+Accessing query parameters and form post data
+---------------------------------------------
+
+Before we move on to more advanced rendering techniques, let us first examine
+how one could further customize the rendering of a Page based on the URL query
+parameters and form post information provided to us by a browser. Recall that
+URL parameters are expressed in the form::
+
+  http://example.com/foo/bar?baz=1&quux=2
+
+And form post data can be generated by providing a form to a browser::
+
+  <form action="" method="POST">
+    <input type="text" name="baz" />
+    <input type="text" name="quux" />
+    <input type="submit" />
+  </form>
+
+Accessing this information is such a common procedure that Nevow provides a
+convenience method on the context to do it. Let's examine a simple page whose
+output can be influenced by the query parameters in the URL used to access it::
+
+  def showChoice(ctx, data):
+      choice = ctx.arg('choice')
+      if choice is None:
+          return ''
+      return "You chose ", choice, "."
+
+  class Custom(rend.Page):
+      docFactory = loaders.stan(tags.html[
+      tags.a(href="?choice=baz")["Baz"],
+      tags.a(href="?choice=quux")["Quux"],
+      tags.p[showChoice]])
+
+The procedure is exactly the same for simple form post information::
+
+  def greet(ctx, data):
+      name = ctx.arg('name')
+      if name is None:
+          return ''
+      return "Greetings, ", name, "!"
+
+  class Form(rend.Page):
+      docFactory = loaders.stan(tags.html[
+      tags.form(action="", method="POST")[
+          tags.input(name="name"),
+          tags.input(type="submit")],
+      greet])
+
+Note that ctx.arg returns only the first argument with the given name. For
+complex cases where multiple arguments and lists of argument values are
+required, you can access the request argument dictionary directly using the
+syntax::
+
+  def arguments(ctx, data):
+      args = inevow.IRequest(ctx).args
+      return "Request arguments are: ", str(args)
+
+Generators in the DOM
+---------------------
+
+One common operation when building dynamic pages is iterating a list of data and
+emitting some HTML for each item. Python generators are well suited for
+expressing this sort of logic, and code which is written as a python generator
+can perform tests (if) and loops of various kinds (while, for) and emit a row of
+html whenever it has enough data to do so. Nevow can handle generators in the
+DOM just as gracefully as it can handle anything else::
+
+  >>> from nevow import rend, loaders, tags
+  >>> def generate(ctx, items):
+  ...     for item in items:
+  ...         yield tags.div[ item ]
+  ... 
+  >>> class List(rend.Page):
+  ...     docFactory = loaders.stan(tags.html[ generate ])
+  ... 
+  >>> List(['one', 'two', 'three']).renderSynchronously()
+  '<html><div>one</div><div>two</div><div>three</div></html>'
+
+As you can see, generating HTML inside of functions or generators can be very
+convenient, and can lead to very rapid application development. However, it is
+also what I would call a "template abstraction violation", and we will learn how
+we can keep knowledge of HTML out of our python code when we learn about
+patterns and slots.
+
+Methods in the DOM
+------------------
+
+Up until now, we have been placing our template manipulation logic inside of
+simple Python functions and generators. However, it is often appropriate to use
+a method instead of a function. Nevow makes it just as easy to use a method to
+render HTML::
+
+  class MethodRender(rend.Page):
+      def __init__(self, foo):
+          self.foo = foo
+
+      def render_foo(self, ctx, data):
+          return self.foo
+
+      docFactory = loaders.stan(tags.html[ render_foo ])
+
+Using render methods makes it possible to parameterize your Page class with more
+parameters. With render methods, you can also use the Page instance as a state
+machine to keep track of the state of the render. While Nevow is designed to
+allow you to render the same Page instance repeatedly, it can also be convenient
+to know that a Page instance will only be used one time, and that the Page
+instance can be used as a scratch pad to manage information about the render.
+
+Data specials
+-------------
+
+Previously we saw how passing a parameter to the default Page constructor makes
+it available as the "data" parameter to all of our render methods. This "data"
+parameter can change as the page render proceeds, and is a useful way to ensure
+that render functions are isolated and only act upon the data which is available
+to them. Render functions which do not pull information from sources other than
+the "data" parameter are more easily reusable and can be composed into larger
+parts more easily.
+
+Deciding which data gets passed as the data parameter is as simple as changing
+the "Data special" for a Tag. See the Glossary under "Tag Specials" for more
+information about specials. Assigning to the data special is as simple as
+assigning to a tag attribute::
+
+  >>> def hello(ctx, name):
+  ...     return "Hello, ", name
+  ... 
+  >>> class DataSpecial(rend.Page):
+  ...     docFactory = loaders.stan(tags.html[
+  ...     tags.div(data="foo")[ hello ],
+  ...     tags.div(data="bar")[ hello ]])
+  ... 
+  >>> DataSpecial().renderSynchronously()
+  '<html><div>Hello, foo</div><div>Hello, bar</div></html>'
+
+Data specials may be assigned any python value. Data specials are only in scope
+during the rendering of the tag they are assigned to, so if the "hello" renderer
+were placed in the DOM inside the html node directly, "Hello, None" would be
+output.
+
+Before data is passed to a render function, Nevow first checks to see if there
+is an IGettable adapter for it. If there is, it calls IGettable.get(), and
+passes the result of this as the data parameter instead. Nevow includes an
+IGettable adapter for python functions, which means you can set a Tag data
+special to a function reference and Nevow will call it to obtain the data when
+the Tag is rendered. The signature for data methods is similar to that of render
+methods, (ctx, data). For example::
+
+  def getName(ctx, data):
+      return ctx.arg('name')
+
+  def greet(ctx, name):
+      return "Greetings, ", name
+
+  class GreetName(rend.Page):
+      docFactory = loaders.stan(tags.html[
+      tags.form(action="")[
+          tags.input(name="name"),
+          tags.input(type="submit")],
+      tags.div(data=getName)[ greet ]])
+
+Data specials exist mainly to allow you to construct and enforce a
+Model-View-Controller style separation of the Model code from the View. Here we
+see that the greet function is capable of rendering a greeting view for a name
+model, and that the implementation of getName may change without the view code
+changing.
+
+Render specials
+---------------
+
+Previously, we have seen how render functions can be placed directly in the DOM,
+and the return value replaces the render function in the DOM. However, these
+free functions and methods are devoid of any contextual information about the
+template they are living in. The render special is a way to associate a render
+function or method with a particular Tag instance, which the render function can
+then examine to decide how to render::
+
+  >>> def alignment(ctx, data):
+  ...     align = ctx.tag.attributes.get('align')
+  ...     if align == 'right':    
+  ...         return ctx.tag["Aligned right"]
+  ...     elif align == 'center':
+  ...         return ctx.tag["Aligned center"]
+  ...     else:
+  ...         return ctx.tag["Aligned left"]
+  ... 
+  >>> class AlignmentPage(rend.Page):
+  ...     docFactory = loaders.stan(tags.html[
+  ...     tags.p(render=alignment),     
+  ...     tags.p(render=alignment, align="center"),
+  ...     tags.p(render=alignment, align="right")])
+  ... 
+  >>> AlignmentPage().renderSynchronously()
+  '<html><p>Aligned left</p><p align="center">Aligned center</p><p align="right">Aligned right</p></html>'
+
+Note how the alignment renderer has access to the template node as "ctx.tag". It
+can examine and change this node, and the return value of the render function
+replaces the original node in the DOM. Note that here we are returning the
+template node after changing it. We will see later how we can instead mutate the
+context and use slots so that the knowledge the renderer requires about the
+structure of the template is reduced even more.
+
+Pattern specials
+----------------
+
+When writing render methods, it is easy to inline the construction of Tag
+instances to generate HTML programatically. However, this creates a template
+abstraction violation, where part of the HTML which will show up in the final
+page output is hidden away inside of render methods instead of inside the
+template. Pattern specials are designed to avoid this problem. A node which has
+been tagged with a pattern special can then be located and copied by a render
+method. The render method does not need to know anything about the structure or
+location of the pattern, only it's name.
+
+We can rewrite our previous generator example so that the generator does not
+have to know what type of tag the template designer would like repeated for each
+item in the list::
+
+  >>> from nevow import rend, loaders, tags, inevow
+  >>> def generate(ctx, items):
+  ...     pat = inevow.IQ(ctx).patternGenerator('item')
+  ...     for item in items:
+  ...         ctx.tag[ pat(data=item) ]
+  ...     return ctx.tag
+  ... 
+  >>> def string(ctx, item):
+  ...     return ctx.tag[ str(item) ]
+  ...
+  >>> class List(rend.Page):
+  ...     docFactory = loaders.stan(tags.html[
+  ...     tags.ul(render=generate)[
+  ...         tags.li(pattern="item", render=string)]])
+  ... 
+  >>> List([1, 2, 3]).renderSynchronously()
+  '<html><ol><li>1</li><li>2</li><li>3</li></ol></html>'
+
+Note that we have to mutate the tag in place and repeatedly copy the item
+pattern, applying the item as the data special to the resulting Tag. It turns
+out that this is such a common operation that nevow comes out of the box with
+these two render functions::
+
+  >>> class List(rend.Page):
+  ...     docFactory = loaders.stan(tags.html[
+  ...     tags.ul(render=rend.sequence)[
+  ...         tags.li(pattern="item", render=rend.data)]])
+  ...
+  >>> List([1, 2, 3]).renderSynchronously()
+  '<html><ul><li>1</li><li>2</li><li>3</li></ul></html>'
+
+Slot specials
+-------------
+
+The problem with render methods is that they are only capable of making changes
+to their direct children. Because of the architecture of Nevow, they should not
+attempt to change grandchildren or parent nodes. It is possible to write one
+render method for every node you wish to change, but there is a better way. A
+node with a slot special can be "filled" with content by any renderer above the
+slot. Creating a slot special is such a frequent task that there is a prototype
+in nevow.tags which is usually used.
+
+Let us examine a renderer which fills a template with information about a
+person:
+          
+  >>> from nevow import loaders, rend, tags
+  ...
+  >>> person = ('Donovan', 'Preston', 'Male', 'California')
+  ... 
+  >>> def render_person(ctx, person):
+  ...     firstName, lastName, sex, location = person
+  ...     ctx.fillSlots('firstName', firstName)
+  ...     ctx.fillSlots('lastName', lastName)
+  ...     ctx.fillSlots('sex', sex)
+  ...     ctx.fillSlots('location', location)
+  ...     return ctx.tag
+  ...
+  >>> class PersonPage(rend.Page):
+  ...     docFactory = loaders.stan(tags.html(render=render_person)[
+  ...     tags.table[
+  ...         tags.tr[
+  ...             tags.td[tags.slot('firstName')],
+  ...             tags.td[tags.slot('lastName')],
+  ...             tags.td[tags.slot('sex')],
+  ...             tags.td[tags.slot('location')]]]])
+  ...
+  >>> PersonPage(person).renderSynchronously()
+  '<html><table><tr><td>Donovan</td><td>Preston</td><td>Male</td><td>California</td></tr></table></html>'
+
+Using patterns in combination with slots can lead to very powerful template
+abstraction. Nevow also includes another standard renderer called "mapping"
+which takes any data which responds to the "items()" message and inserts the
+items into appropriate slots::
+
+  >>> class DictPage(rend.Page):
+  ...     docFactory = loaders.stan(tags.html(render=rend.mapping)[
+  ...         tags.span[ tags.slot('foo') ], tags.span[ tags.slot('bar') ]])
+  ...
+  >>> DictPage(dict(foo=1, bar=2)).renderSynchronously()
+  '<html><span>1</span><span>2</span></html>'
+
+Data directives
+---------------
+
+So far, we have always placed data functions directly in the Data special
+attribute of a Tag. Sometimes, it is preferable to look up a data method from
+the Page class as the Page has being rendered. For example, a base class may
+define a template and a subclass may provide the implementation of the data
+method. We can accomplish this effect by using a data directive as a Tag's data
+special::
+
+  class Base(rend.Page):
+      docFactory = loaders.stan(tags.html[
+          tags.div(data=tags.directive('name'), render=rend.data)])
+
+  class Subclass(Base):
+      def data_name(self, ctx, data):
+          return "Your name"
+
+The data directive is resolved by searching for the IContainer implementation in
+the context. rend.Page implements IContainer.get by performing an attribute
+lookup on the Page with the prefix 'data_*'. You can provide your own IContainer
+implementation if you wish, and also you should know that IContainer
+implementations for list and dict are included in the nevow.accessors module.
+
+A common gotcha is that the closest IContainer is used to resolve data
+directives. This means that if a list is being used as the data during the
+rendering process, data directives below this will be resolved against the
+IContainer implementation in nevow.accessors.ListAccessor. If you are expecting
+a data directive to invoke a Page's data_* method but instead get a KeyError,
+this is why.
+
+Render directives
+-----------------
+
+Render directives are almost exactly the same, except they are resolved using
+the closest IRendererFactory implementation in the context. Render directives
+can be used to allow subclasses to override certain render methods, and also can
+be used to allow Fragments to locate their own prefixed render methods.
+
+Flatteners
+----------
+
+TODO This section isn't done yet.
+
+Nevow's flatteners use a type/function registry to determine how to render
+objects which Nevow encounters in the DOM during the rendering process.
+"Explicit is better than implicit", so in most cases, explicitly applying render
+methods to data will be better than registering a flattener, but in some cases
+it can be useful::
+
+  class Person(object):
+      def __init__(self, firstName, lastName):
+          self.firstName = firstName
+          self.lastName = lastName
+
+  def flattenPerson(person, ctx):
+      return flat.partialflatten(
+		ctx,
+		(person.firstName, " ", person.lastName))
+
+  from nevow import flat
+  flat.registerFlattener(flattenPerson, Person)
+
+  def insertData(ctx, data):
+      return data
+
+  class PersonPage(rend.Page):
+      docFactory = loaders.stan(tags.html[ insertData ])
+

Added: twisted/trunk/contrib/nevow/doc/txt/nevow-traversal.txt
==============================================================================
--- (empty file)
+++ twisted/trunk/contrib/nevow/doc/txt/nevow-traversal.txt	Wed Jul 19 11:52:21 2006
@@ -0,0 +1,301 @@
+Nevow Object Traversal
+======================
+
+*Object traversal* is the process Nevow uses to determine what object to use to
+render HTML for a particular URL. When an HTTP request comes in to the web
+server, the object publisher splits the URL into segments, and repeatedly calls
+methods which consume path segments and return objects which represent that
+path, until all segments have been consumed. At the core, the Nevow traversal
+API is very simple. However, it provides some higher level functionality layered
+on top of this to satisfy common use cases.
+
+* `Object Traversal Basics`_
+* `locateChild in depth`_
+* `childFactory method`_
+* `child_* methods and attributes`_
+* `Dots in child names`_
+* `The default trailing slash handler`_
+* `ICurrentSegments and IRemainingSegments`_
+
+Object Traversal Basics
+-----------------------
+
+The *root resource* is the top-level object in the URL space; it conceptually
+represents the URI "/". The Nevow *object traversal* and *object publishing*
+machinery uses only two methods to locate an object suitable for publishing and
+to generate the HTML from it; these methods are described in the interface
+``nevow.inevow.IResource``::
+
+
+  class IResource(compy.Interface):
+      def locateChild(self, ctx, segments):
+          """Locate another object which can be adapted to IResource
+          Return a tuple of resource, path segments
+          """
+
+      def renderHTTP(self, ctx):
+          """Render a request
+          """
+
+``renderHTTP`` can be as simple as a method which simply returns a string of HTML.
+Let's examine what happens when object traversal occurs over a very simple root
+resource::
+
+  from zope.interface import implements
+
+  class SimpleRoot(object):
+      implements(inevow.IResource)
+
+      def locateChild(self, ctx, segments):
+          return self, ()
+
+      def renderHTTP(self, ctx):
+          return "Hello, world!"
+
+This resource, when passed as the root resource to ``appserver.NevowSite`` or
+``wsgi.createWSGIApplication``, will immediately return itself, consuming all path
+segments. This means that for every URI a user visits on a web server which is
+serving this root resource, the text "Hello, world!" will be rendered. Let's
+examine the value of ``segments`` for various values of URI:
+
+/foo/bar
+  ('foo', 'bar')
+
+/
+  ('', )
+
+/foo/bar/baz.html
+  ('foo', 'bar', 'baz.html')
+
+/foo/bar/directory/
+  ('foo', 'bar', 'directory', '')
+
+So we see that Nevow does nothing more than split the URI on the string '/' and
+pass these path segments to our application for consumption. Armed with these
+two methods alone, we already have enough information to write applications
+which service any form of URL imaginable in any way we wish. However, there are
+some common URL handling patterns which Nevow provides higher level support for.
+
+``locateChild`` in depth
+------------------------
+
+One common URL handling pattern involves parents which only know about their
+direct children. For example, a ``Directory`` object may only know about the
+contents of a single directory, but if it contains other directories, it does
+not know about the contents of them. Let's examine a simple ``Directory`` object
+which can provide directory listings and serves up objects for child directories
+and files::
+
+  from zope.interface import implements            
+
+  class Directory(object):
+      implements(inevow.IResource)
+
+      def __init__(self, directory):
+          self.directory = directory
+
+      def renderHTTP(self, ctx):
+          html = ['<ul>']
+          for child in os.listdir(self.directory):
+              fullpath = os.path.join(self.directory, child)
+              if os.path.isdir(fullpath):
+                  child += '/'
+              html.extend(['<li><a href="', child, '">', child, '</a></li>'])
+          html.append('</ul>')
+          return ''.join(html)
+
+      def locateChild(self, ctx, segments):
+          name = segments[0]
+          fullpath = os.path.join(self.directory, name)
+          if not os.path.exists(fullpath):
+              return None, () # 404
+
+          if os.path.isdir(fullpath):
+              return Directory(fullpath), segments[1:]
+          if os.path.isfile(fullpath):
+              return static.File(fullpath), segments[1:]
+
+Because this implementation of ``locateChild`` only consumed one segment and
+returned the rest of them (``segments[1:]``), the object traversal process will
+continue by calling ``locateChild`` on the returned resource and passing the
+partially-consumed segments. In this way, a directory structure of any depth can
+be traversed, and directory listings or file contents can be rendered for any
+existing directories and files.
+
+So, let us examine what happens when the URI "/foo/bar/baz.html" is traversed,
+where "foo" and "bar" are directories, and "baz.html" is a file.
+
+Directory('/').locateChild(ctx, ('foo', 'bar', 'baz.html'))
+    Returns Directory('/foo'), ('bar', 'baz.html')
+
+Directory('/foo').locateChild(ctx, ('bar', 'baz.html'))
+    Returns Directory('/foo/bar'), ('baz.html, )
+
+Directory('/foo/bar').locateChild(ctx, ('baz.html'))
+    Returns File('/foo/bar/baz.html'), ()
+
+No more segments to be consumed; ``File('/foo/bar/baz.html').renderHTTP(ctx)`` is
+called, and the result is sent to the browser.
+                        
+``childFactory`` method
+-----------------------
+
+Consuming one URI segment at a time by checking to see if a requested resource
+exists and returning a new object is a very common pattern. Nevow's default
+implementation of ``IResource``, ``nevow.rend.Page``, contains an implementation of
+``locateChild`` which provides more convenient hooks for implementing object
+traversal. One of these hooks is ``childFactory``. Let us imagine for the sake of
+example that we wished to render a tree of dictionaries. Our data structure
+might look something like this::
+
+    tree = dict(
+        one=dict(
+            foo=None,
+            bar=None),
+        two=dict(
+            baz=dict(
+                quux=None)))
+
+Given this data structure, the valid URIs would be:
+
+* /
+* /one
+* /one/foo
+* /one/bar
+* /two
+* /two/baz
+* /two/baz/quux
+
+Let us construct a ``rend.Page`` subclass which uses the default ``locateChild``
+implementation and overrides the ``childFactory`` hook instead::
+
+  class DictTree(rend.Page):
+      def __init__(self, dataDict):
+          self.dataDict = dataDict
+
+      def renderHTTP(self, ctx):
+          if self.dataDict is None:
+              return "Leaf"
+          html = ['<ul>']
+          for key in self.dataDict.keys():
+              html.extend(['<li><a href="', key, '">', key, '</a></li>'])
+          html.append('</ul>')
+          return ''.join(html)
+
+      def childFactory(self, ctx, name):
+          if name not in self.dataDict:
+              return None # 404
+          return DictTree(self.dataDict[name])
+
+As you can see, the ``childFactory`` implementation is considerably shorter than the
+equivalent ``locateChild`` implementation would have been.
+
+``child_*`` methods and attributes
+----------------------------------
+
+Often we may wish to have some hardcoded URLs which are not dynamically
+generated based on some data structure. For example, we might have an
+application which uses an external CSS stylesheet, an external JavaScript file,
+and a folder full of images. The ``rend.Page`` ``locateChild`` implementation provides a
+convenient way for us to express these relationships by using ``child``-prefixed
+methods::
+
+  class Linker(rend.Page):
+      def renderHTTP(self, ctx):
+          return """<html>
+    <head>
+      <link href="css" rel="stylesheet" />
+      <script type="text/javascript" src="scripts" />
+    <body>
+      <img src="images/logo.png" />
+    </body>
+  </html>"""
+
+      def child_css(self, ctx):
+          return static.File('/Users/dp/styles.css')
+
+      def child_scripts(self, ctx):
+          return static.File('/Users/dp/scripts.js')
+
+      def child_images(self, ctx):
+          return static.File('/Users/dp/images/')
+
+One thing you may have noticed is that all of the examples so far have returned
+new object instances whenever they were implementing a traversal API. However,
+there is no reason these instances cannot be shared. One could for example
+return a global resource instance, an instance which was previously inserted in
+a dict, or lazily create and cache dynamic resource instances on the fly. The
+``rend.Page`` ``locateChild`` implementation also provides a convenient way to express
+that one global resource instance should always be used for a particular url,
+the ``child``-prefixed attribute::
+
+  class FasterLinker(Linker):
+      child_css = static.File('/Users/dp/styles.css')
+      child_scripts = static.File('/Users/dp/scripts.js')
+      child_images = static.File('/Users/dp/images/')
+
+Dots in child names
+-------------------
+
+When a URL contains dots, which is quite common in normal URLs, it is simple
+enough to handle these URL segments in ``locateChild`` or ``childFactory`` -- one of the
+passed segments will simply be a string containing a dot. However, it is not
+immediately obvious how one would express a URL segment with a dot in it when
+using ``child``-prefixed methods. The solution is really quite simple::
+
+  class DotChildren(rend.Page):
+      return '<html><head><script type="text/javascript" src="scripts.js" /></head></html>'
+
+  setattr(DotChildren, 'child_scripts.js', static.File('/Users/dp/scripts.js'))
+
+The same technique could be used to install a child method with a dot in the
+name.
+
+The default trailing slash handler
+----------------------------------
+
+When a URI which is being handled ends in a slash, such as when the '/' URI is
+being rendered or when a directory-like URI is being rendered, the string ''
+appears in the path segments which will be traversed. Again, handling this case
+is trivial inside either ``locateChild`` or ``childFactory``, but it may not be
+immediately obvious what ``child``-prefixed method or attribute will be looked up.
+The method or attribute name which will be used is simply ``child`` with a single
+trailing underscore.
+
+The ``rend.Page`` class provides an implementation of this method which can work in
+two different ways. If the attribute ``addSlash`` is True, the default trailing
+slash handler will return ``self``. In the case when ``addSlash`` is True, the default
+``rend.Page.renderHTTP`` implementation will simply perform a redirect which adds
+the missing slash to the URL.
+
+The default trailing slash handler also returns self if ``addSlash`` is false, but
+emits a warning as it does so. This warning may become an exception at some
+point in the future.
+
+``ICurrentSegments`` and ``IRemainingSegments``
+-----------------------------------------------
+
+During the object traversal process, it may be useful to discover which segments
+have already been handled and which segments are remaining to be handled. This
+information may be obtained from the ``context`` object which is passed to all the
+traversal APIs. The interfaces ``nevow.inevow.ICurrentSegments`` and
+``nevow.inevow.IRemainingSegments`` are used to retrieve this information. To
+retrieve a tuple of segments which have previously been consumed during object
+traversal, use this syntax::
+
+  segs = ICurrentSegments(ctx)
+
+The same is true of ``IRemainingSegments``. ``IRemainingSegments`` is the same value
+which is passed as ``segments`` to ``locateChild``, but may also be useful in the
+implementations of ``childFactory`` or a ``child``-prefixed method, where this
+information would not otherwise be available.
+ 
+Conclusion
+==========
+
+Nevow makes it easy to handle complex URL hierarchies. The most basic object
+traversal interface, ``nevow.inevow.IResource.locateChild``, provides powerful and
+flexible control over the entire object traversal process. Nevow's canonical
+``IResource`` implementation, ``rend.Page``, also includes the convenience hooks
+``childFactory`` along with ``child``-prefixed method and attribute semantics to
+simplify common use cases.

Added: twisted/trunk/contrib/nevow/doc/txt/nevow-xml-templates.txt
==============================================================================
--- (empty file)
+++ twisted/trunk/contrib/nevow/doc/txt/nevow-xml-templates.txt	Wed Jul 19 11:52:21 2006
@@ -0,0 +1,255 @@
+Nevow XML Templates
+===================
+
+Stan syntax is cool, but eventually you are going to want to integrate your
+Python code with a template designed by an HTML monkey. Nevow accomplishes this
+by providing an xmlfile loader which uses the built-in Python SAX libraries to
+generate a tree of stan behind the scenes. The general rule is anything that is
+possible in stan should be possible in a pure XML template; of course, the XML
+syntax is generally going to be much more verbose.
+
+* `loaders.xmlfile`_
+* `Nevow's xmlns declaration`_
+* `Nevow's Tag Attribute Language`_
+* `nevow:render`_
+* `Built-in renderers`_
+* `nevow:data`_
+* `nevow:pattern`_
+* `nevow:slot`_
+* `nevow:attr`_
+* `xmlstr, htmlfile, and htmlstr`_
+
+loaders.xmlfile
+---------------
+
+Wherever you have seen a loaders.stan being created in any of the example code,
+a loaders.xmlfile can be substituted instead. At the most basic, xmlfile merely
+requires the name of an xml template::
+
+  class HelloXML(rend.Page):
+      docFactory = loaders.xmlfile('hello.xml')
+
+Placing the following xml in the hello.xml file will cause HelloXML to display a
+static page when it is rendered::
+
+  <html>Hello, world!</html>
+
+The following additional keyword arguments may be given to xmlfile to configure
+it:
+
+templateDirectory
+  The path to the directory which contains the template file. Defaults to ''.
+
+ignoreDocType    
+  If True, discard any DOCTYPE declaration when building the DOM from this
+  template. When false, preserve the DOCTYPE, causing it to show up in the final
+  output. Useful for when you are inserting an XML fragment into a larger page
+  and do not wish to generate invalid XML as output. Defaults to False.
+
+ignoreComment
+  If True, discard XML comments, causing them to disappear from the output. If
+  False, preserve comments and render them in the final output unchanged.
+  Defaults to False.
+
+pattern
+  If present, the given pattern name will be looked up and used as the root of
+  the template. If not present, the entire document will be used as the
+  template. Useful for embedding fragments of an XML document in a larger page.
+  Defaults to None.
+
+Nevow's xmlns declaration
+-------------------------
+
+In order for Nevow to notice and process any XML directives in the template
+file, you must declare the Nevow xmlns at the top of your XML document. Nevow's
+xmlns is::
+
+  http://nevow.com/ns/nevow/0.1
+
+The syntax for declaring that your xml document uses this namespace is::
+
+  <html xmlns:nevow="http://nevow.com/ns/nevow/0.1"></html>
+
+You may replace the text "nevow" in the above example with any name you choose.
+For example, many people use "n" because it is shorter to type. If you do so, be
+sure to replace all occurrences of the nevow namespace in the examples with the
+namespace name you choose.
+
+Nevow's Tag Attribute Language
+------------------------------
+
+The markup you will add to your XHTML file in order to invoke Nevow code
+consists mostly of namespaced tag attributes. This approach was influenced
+heavily by the Zope Page Templates (ZPT) Tag Attribute Language (TAL). However,
+I felt that TAL did not go far enough in removing control flow and branching
+possibilities from the XML template. Nevow's main philosophy is that it should
+be as easy as possible to move from the XML document into Python code, and that
+the Python code should have ultimate control over manipulating the structure of
+the XML template.
+
+The key is that it is easy to expose Python methods that you write to your XML
+template, and it is easy for the XML templates to mark nodes which it wishes the
+Python method to manipulate. In this way, if either the Python implementation
+changes or the location or content of the marked nodes change in the XML
+template, the other side will be isolated from these changes.
+
+Nevow's XML templating has two attributes which invoke Python code:
+
+* nevow:render -- Invokes a Python method and replaces the template node with the result
+* nevow:data -- Invokes a Python method and sets the data special for the node to the result
+
+It has one attribute which marks nodes as manipulatable by Python code:
+
+* nevow:pattern -- Gives a node a name so that Python code may clone and mutate copies of this node
+
+It also has two namespaced tags:
+
+* nevow:slot -- Works in the same way as the slot attribute
+* nevow:attr -- Indicates that an attribute of the parent tag should be manipulated by Python code in some way
+
+nevow:render
+------------
+
+When the nevow:render attribute is encountered, the xmlfile loader sets the
+render special to a directive constructed with the attribute value. When the
+template is rendered, this means that the appropriate render_* method will be
+looked up on the IRendererFactory (generally the Page instance)::
+
+  <html><div nevow:render="foo" /></html>
+
+With the render_foo method::
+
+  def render_foo(self, ctx, data):
+      return "Hello"
+
+Will result in the document::
+
+  <html>Hello</html>
+
+Note that the return value of the render method replaces the template node in
+the DOM, so if you want the template node to remain, you should use ctx.tag.
+
+Built-in renderers
+------------------
+
+Nevow comes with various built in renderers on the Page class.
+
+data
+  Renders the current data as-is inside the current node.
+
+string
+  Renders the current data as a string inside the current node.
+
+sequence
+  Iterates the current data, copying the "item" pattern for each item. Sets the
+  the data special of the new node to the item, and inserts the result in the
+  current node. See the nevow.rend.sequence docstring for information about
+  other used patterns, including "header", "divider", "footer" and "empty".
+
+mapping
+  Calls .items() on the current data, and calls ctx.fillSlots(key, value) for
+  every key, value pair in the result. Returns the template tag.
+
+xml
+  Inserts the current data into the template after wrapping it in an xml
+  instance. Not very useful in practice.
+
+nevow:data
+----------
+
+When the nevow:data attribute is encountered, the xmlfile loader sets the data
+special of the current node to a directive constructed with the attribute value.
+When the template is rendered, this means that the appropriate data_* method
+will be looked up on the current IContainer (generally the Page instance). The
+data_* method will be called, and the result will be set as the data special of
+the current Tag::
+
+  <html><div nevow:data="name" nevow:render="data" /></html>
+
+With the data_name method::
+
+  def data_name(self, ctx, data):
+      return "Hello!"
+
+Will result in the document::
+
+  <html><div>Hello!</div></html>
+
+Note that with a data attribute on a node but no renderer, the result of the
+data method will be set as the data special for that tag, and child render
+methods will be passed this data.
+
+nevow:pattern
+-------------
+
+When the nevow:pattern attribute is encountered, the xmlfile loader sets the
+pattern special of the current node to the attribute value as a string.
+Renderers which are above this node may then make copies of it using the
+nevow.inevow.IQ of the current context. With the template::
+
+  <html nevow:render="stuff"><div nevow:pattern="somePattern" nevow:render="data" /></html>
+
+And the renderer::
+
+  def render_stuff(self, ctx, data):
+      pat = inevow.IQ(ctx).patternGenerator('somePattern')
+      return [pat(data=1), pat(data=2)]
+
+Will result in the document::
+
+  <html><div>1</div><div>2</div></html>
+
+nevow:slot
+----------
+
+When the nevow:slot tag is encountered, the xmlfile loader constructs a
+nevow.stan.slot instance, passing the name attribute value as the slot name. The
+children of the slot node are added as children of the new slot instance. This
+is useful if you wish to put patterns inside the slot. With the template::
+
+  <html nevow:render="stuff"><nevow:slot name="slotName" /></html>
+
+And the render method::
+
+  def render_stuff(self, ctx, data):
+      ctx.fillSlots('slotName', "Hello.")
+      return ctx.tag
+
+This document will be produced::
+
+  <html>Hello.</html>
+
+nevow:attr
+----------
+
+When the nevow:attr tag is encountered, the contents of the nevow:attr node will
+be assigned to the attribute of the parent tag with the name of the value of the
+name attribute. Perhaps an example will be a little clearer::
+
+  <html><a><nevow:attr name="href">HELLO!</nevow:attr>Goodbye</a></html>
+
+This document will be produced::
+
+  <html><a href="HELLO!">Goodbye</a></html>
+
+While this syntax is somewhat awkward, every other type of nevow tag and
+attribute may be used inside the nevow:attr node. This makes setting attributes
+of tags uniform with every other method of manipulating the XML template.
+
+xmlstr, htmlfile, and htmlstr
+-----------------------------
+
+xmlstr is a loader which is identical to xmlfile except it takes a string of XML
+directly.
+
+htmlfile and htmlstr should generally be avoided. They are similar to xmlfile
+and xmlstr, except they use twisted.web.microdom in beExtremelyLenient mode to
+attempt to parse badly-formed HTML (non-XHTML) templates. See the nevow.loaders
+docstrings for more information.
+
+Conclusions
+===========
+
+Nevow's xmlfile tag attribute language allows you to integrate
+externally-designed XHTML templates into the Nevow rendering process.
+

Added: twisted/trunk/contrib/nevow/doc/txt2html.py
==============================================================================
--- (empty file)
+++ twisted/trunk/contrib/nevow/doc/txt2html.py	Wed Jul 19 11:52:21 2006
@@ -0,0 +1,210 @@
+import sys
+import os
+import time
+
+from nevow import flat, tags as T
+
+import hier
+
+PROGNAME = sys.argv[0]
+USAGE = "%s text_directory html_directory language_code" % PROGNAME
+
+def error(msg,exitcode=0,usage=False):
+    sys.stderr.write("%s: %s\n" % (PROGNAME,msg))
+
+    if usage:
+        sys.stderr.write("\nusage: %s\n" % USAGE)
+    
+    if exitcode:
+        sys.exit(exitcode)
+
+if len(sys.argv) != 4:
+    error("Incorrect number of arguments",1,True)
+
+LANGUAGE = sys.argv[3]
+
+import qdlocale as locale
+try:
+    conf = locale.locale[LANGUAGE]
+except:
+    error("Could not load locale configuration for '%s'" % LANGUAGE,4)
+
+try:
+    _dc = hier.title[LANGUAGE]
+except:
+    error("No title specified for locale '%s'" % LANGUAGE,5)
+
+try:
+    from docutils.core import publish_string
+except ImportError:
+    error("Error during import: Docutils is required.",99)
+
+TEMPLATE = \
+'''~~~~~~~~~~
+$title
+~~~~~~~~~~
+
+$header
+
+-----------
+
+^^^^^^^^^
+$title
+^^^^^^^^^
+
+%s
+
+-----------
+
+$footer
+'''
+
+
+def navBar(name,flathier):
+    ind = [nm for nm,node in flathier].index(name)
+    
+    # Set previous/next.
+    if ind:
+        prev = flathier[ind - 1]
+    else:
+        prev = None
+
+    if ind != len(flathier) - 1:
+        next = flathier[ind + 1]
+    else:
+        next = None
+
+    # Find parent
+    parent = None
+    while ind:
+        ind -= 1
+        if not flathier[ind][1][-1]:
+            continue
+        child_pages = [page.keys()[0] for page in flathier[ind][1][-1]]
+        if name in child_pages:
+            parent = flathier[ind][0],flathier[ind][1]
+
+    return flat.flatten(
+        [T.a(name="top",id="top"),
+        T.div(_class="navbar")[
+            T.span(_class="docTitle")[hier.title[LANGUAGE]],
+            T.span(_class="right")[
+                prev and [conf["prev"], ": ",
+                T.a(href=[prev[0],".html"])["[", prev[1][0],"]",]] or "",
+                parent and [conf["up"],": ",
+                T.a(href=[parent[0],".html"])["[", parent[1][0],"]",]] or "",
+                conf["home"],": ",
+                T.a(href=[flathier[0][0],".html"])["[",flathier[0][1][0],"]"],
+                next and [conf["next"], ": ",
+                    T.a(href=[next[0],".html"])["[", next[1][0],"]",]] or ""
+            ],
+                    ]])
+
+def genDirectory(prefix,tree):
+    elements = []
+    x = 0
+    for page in tree:
+        x += 1
+        nodenum = prefix + str(x)
+        name,node = page.items()[0]
+        desc,subtree = node
+        elements.append(
+            T.li[T.a(href=name + ".html")[" ".join((nodenum,desc))]])
+        if subtree:
+            elements.append(genDirectory(nodenum + ".",subtree))
+    return T.ul[ elements ]
+
+def footer(node):
+    name,tree = node
+    if not tree:
+        directory = ""
+    else:
+        directory = [T.div(_class="directoryHeader")[conf["sub"]],
+            T.blockquote[
+            genDirectory(name != conf["toc"] and (name.split(" ")[0] + ".") or "" ,tree),
+            ],T.hr()]
+
+    return flat.flatten([directory,
+    T.a(href="#top")["[",conf["top"],"]"],T.span(_class="genNote")
+        [conf["updatedOn"], ' ' ,time.strftime("%a, %d %b %Y",time.localtime(time.time()))]]) 
+
+def generateHtml(text,name,node,flathier):
+    title, tree = node
+
+    # Apply our basic template before docstring work.
+    text = TEMPLATE % text
+    html = publish_string(text, writer_name = 'html')
+
+    # Insert the title.
+    html = html.replace("$title",title,3)
+
+    # Navigation bar
+    nb = navBar(name,flathier)
+    html = html.replace("<p>$header</p>",nb)
+
+    foot = footer(node)
+
+    # We need to use rfind to make sure we replace the *last* 
+    # $footer instance
+    ind = html.rfind("<p>$footer</p>")
+
+    html = html[:ind] + foot +  html[ind + 14:]
+
+    return html
+
+def startNode(name):
+    sys.stdout.write("%-70s" % ("Processing '%s':" % name))
+    sys.stdout.flush()
+
+def endNode():
+    sys.stdout.write("[OK]\n")
+
+def failNode():
+    sys.stdout.write("[ERROR]\n")
+
+def flattenHier(hier,flat=None,prefix=""):
+    if not flat:
+        name,node = hier[0].items()[0]
+        return flattenHier(node[-1],[(name,node)])
+
+    x = 0
+    for node in hier:
+        x += 1
+        nodenum = prefix + (str(x))
+
+        name,node = node.items()[0]
+
+        # Convert to list so we can change the title
+        node = list(node)
+        node[0] = " ".join((nodenum,node[0]))
+        flat.append((name,node))
+        tree = node[-1]
+        if tree:
+            flattenHier(tree,flat,prefix + ("%d." % x))
+
+    return flat
+
+def go():
+
+    txtdir, htmldir = sys.argv[1:3]
+    
+    flathier = flattenHier(({conf["defaultPage"]:(conf["toc"],hier.hier)},))
+
+    for name,node in flathier[1:]:
+        startNode(name)
+        try:
+            data = open(os.path.join(txtdir,name + ".txt")).read()
+        except IOError:
+            failNode()
+            error("'%s' is in hier but '%s.txt' cannot be opened in '%s'" % (name,name,txtdir))
+            continue
+
+        html = generateHtml(data,name,node,flathier)
+        open(os.path.join(htmldir,name + ".html"),"w").write(html)
+        endNode()
+
+    html = generateHtml("",conf["defaultPage"],flathier[0][1],flathier)
+    open(os.path.join(htmldir,conf["defaultPage"] + ".html"),"w").write(html)
+
+if __name__ == "__main__":
+    go()


Maggiori informazioni sulla lista Commits