[Checkins] SVN: zope2book/trunk/ Restify SimpleExamples chapter.

Tres Seaver tseaver at palladion.com
Tue Feb 10 16:15:33 EST 2009


Log message for revision 96422:
  Restify SimpleExamples chapter.

Changed:
  D   zope2book/trunk/SimpleExamples.stx
  A   zope2book/trunk/source/SimpleExamples.rst
  U   zope2book/trunk/source/index.rst

-=-
Deleted: zope2book/trunk/SimpleExamples.stx
===================================================================
--- zope2book/trunk/SimpleExamples.stx	2009-02-10 21:14:24 UTC (rev 96421)
+++ zope2book/trunk/SimpleExamples.stx	2009-02-10 21:15:33 UTC (rev 96422)
@@ -1,970 +0,0 @@
-Creating Basic Zope Applications
-
-  XXX: add new screen shots
-
-  XXX: convert guest book to zpt
-
-  This chapter will take you, step by step, through building a basic web
-  application in Zope.  As we go through the chapter, we will examine some of
-  Zope's main concepts at work.  Using Zope *Folder*, *Script (Python)*, and
-  *Page Template* objects, we'll create a simple website for an imaginary
-  zoo: the "Zope Zoo", of course!
-
-  We will develop the website as a Zope "instance-space" application.  A
-  discussion of instance space is at the end of this chapter, but for now it
-  is enough to know that instance-space applications are the easiest and
-  fastest kind to build, because we can do everything in our favorite web
-  browser.
-
-  Goals for the Zope Zoo Web Site
-
-    As with any project, we first need to clarify our goals for the Zope Zoo
-    application.  The application's primary goal is to create a website for
-    the world-renowned Zope Zoo.  Furthermore, we want to make the website
-    easy to use and manage.  Here are some things we'll do:
-
-    o Enable web users to navigate the site easily, as if they were moving
-      around a real zoo.
-
-    o Keep all our shared web layout tools, like a Cascading Style Sheet
-      (CSS), in a single, easy-to-manage location.
-
-    o Design the website so that future site-wide changes are quick and easy
-      to implement.
-
-    o Take advantage of Zope to create a dynamic website in which web pages
-      build themselves "on the fly" when requested so that they are always up
-      to date.
-
-    o Provide a simple file library of various documents that describe the
-      animals.
-
-    o A guest book must be created so that zoo visitors can give you feedback
-      and comments about your site.
-
-  Beginning with a Folder
-
-    Zope *Folder* objects provide natural containers and organizers for web
-    applications.  A good way to start building an application is to create a
-    new *Folder* to hold all the objects and subfolders related to the
-    application.
-
-    Consider, for example, a Zope folder named *Invoices* to hold an
-    application for managing invoices through the Web.  The *Invoices* folder
-    could contain both the logic objects - or "methods" - which allow you to
-    add and edit invoices, as well as the actual data of the invoices.  The
-    *Invoices* folder thus becomes a small Zope application.
-
-    We begin building our Zope Zoo website application by creating a Zope
-    *Folder* object to hold it all together in one place.
-
-    Step 1: Create *ZopeZoo* Folder
-
-      If you haven't already, start your Zope installation and log into the
-      Zope Management Interface (ZMI) using your favorite browser.  (If you
-      are not familiar with the ZMI, refer to the "Installing and Starting
-      Zope":InstallingZope.stx chapter.)
-
-      1. Navigate to Zope's top-level *root* folder.
-
-      2. Use the *Add* list to create a new *Folder*.
-
-      3. Give the new folder the *Id* 'ZopeZoo'.
-
-      4. Check *Create public interface*.
-
-      5. Click *Add*.
-
-      (For now, we will ignore the optional *Title* fields.)
-
-  Designing a Navigable Zoo
-
-    One of our goals is to enable easy user movement around the website.  A
-    key to this easy movement is a navigation interface that is consistent
-    among the site's pages.  In other words, every web page in the site should
-    present a similar set of hyperlinks, in a similar place on the page, on
-    which users can rely to guide them through the site.
-
-    We also want to make sure the navigation links are always correct,
-    regardless of how the structure of the site changes.  The solution is to
-    design a meaningful site structure, and then create the Zope methods that
-    will dynamically present the current structure to web users in the form of
-    navigation links.
-
-    First, let's define the site structure.  If the Zope Zoo was real, we
-    might model the website's organization on the zoo's physical or logical
-    design.  For our purposes, we will pretend that the zoo houses three
-    classes of animals.  We'll organize the website by adding folders inside
-    our *ZopeZoo* folder.
-
-    Step 2: Create Site Organization
-
-      (NOTE: Do not create public interfaces for the folders in this step.)
-
-      1. Enter the *ZopeZoo* folder and create three subfolders with *Ids*:
-         'Reptiles', 'Mammals' and 'Fish'.
-
-      2. Inside the *Mammals* folder, add one folder named 'Whales'.
-
-      3. Navigate to the *Reptiles* folder and create two folders there:
-         'Lizards' and 'Snakes'.
-
-    In Zope's Navigator frame on the left side, you should see an icon for the
-    *ZopeZoo* folder.  (If you don't see it, click *Refresh* in the
-    Navigator).  To view the *ZopeZoo* folder hierarchy - i.e. our nascent web
-    site's structure - expand the *ZopeZoo* folder by clicking the little plus
-    sign next to the icon.  Similarly expand the zoo subfolders.  You'll see
-    something like the figure below.
-
-    "Zoo folder structure.":img:5-1:Figures/zoo1.png
-
-    Now we create the basic presentation objects:  The main template and the
-    style sheet *z_zoo.css*.  To get started, we ask a web designer to create
-    a HTML mockup and a CSS file that together represent the web page layout
-    shared throughout the site.
-
-    For the style sheet we create a simple *File* object in Zope.  No need to
-    make it dynamic.
-
-    Step 3: Create the Style Sheet
-
-      1. Go to the top level of our zoo website, the *ZopeZoo* folder.
-
-      2. Select *File* from the *Add* list.
-
-      3. Give the file an *Id* of 'z_zoo.css'.
-
-      4. Click *Add*.
-
-      5. Select *z_zoo.css* to get its *Edit* view.
-
-      6. Copy and paste these style definitions into the *File Data* area::
-
-        body, p, th, td {
-          font-family: Verdana, Arial, Helvetica, sans-serif;
-          font-size: 10pt;
-        }
-        h1 {
-          color: #6699cc;
-          font-family: Verdana, Arial, Helvetica, sans-serif;
-          font-size: 18pt;
-          font-weight: bold;
-        }
-        p {
-          color: #660000;
-        }
-        .status_message{
-          background: #ffffaa;
-          border-style: solid;
-          border-width: thin;
-          font-weight: bold;
-          padding: 4pt;
-        }
-        th {
-          background: #dee7ec;
-          text-align: left;
-        }
-
-      At this stage, the HTML page the web designer created for us is valid
-      XHTML 1.0 Strict and could also live in a static *File* object.  But in
-      the next steps we will convert the page into a dynamic template by
-      adding TAL and METAL statements, so we need a *Page Template* object.
-      For now we use the *index_html* method already added by selecting
-      *Create public interface* in step 1.
-
-    Step 4: Create the Main Template
-
-      1. Select *index_html* to get its *Edit* view.
-
-      2. Replace all of the stock template code with this::
-
-        <!DOCTYPE html PUBLIC
-            "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
-        <html>
-        <head>
-
-        <title>PAGE TITLE OR ID</title>
-        <link rel="stylesheet" href="z_zoo.css" type="text/css" />
-
-        </head>
-        <body>
-
-        <div>&gt; <a href="ABSOLUTE_URL">PARENT TITLE OR ID</a> </div>
-
-        <ul>
-          <li><a href="ABSOLUTE_URL">SUB-OBJECT TITLE OR ID</a></li>
-        </ul>
-
-        <h1>PAGE TITLE OR ID</h1>
-
-        <p class="status_message">STATUS MESSAGE</p>
-
-        <p>THIS IS WHERE THE PAGE'S CONTENT GOES.</p>
-
-        </body>
-        </html>
-
-      Our web designer marked placeholders for dynamic elements with UPPERCASE
-      letters.  Using the *Test* tab of the new template, we can see the
-      static HTML page.  Don't blame the web designer for the spartan layout.
-      It's for the sake of an easy example.  If you don't understand the XHTML
-      and CSS code you might want to learn more about HTML first.  This
-      chapter shows you how to make that code dynamic.
-
-    Step 5: Dynamic Title and Headline
-
-      1. Go to the *Edit* tab of *index_html*.
-
-      2. Find these two lines::
-
-        <title>PAGE TITLE OR ID</title>
-        ...
-        <h1>PAGE TITLE OR ID</h1>
-
-      3. Change them to look like that::
-
-        <title tal:content="context/title_or_id">PAGE TITLE OR ID</title>
-        ...
-        <h1 tal:content="context/title_or_id">PAGE TITLE OR ID</h1>
-
-      The *path expression* 'context/title_or_id' returns the *title* of the
-      context object or - if that doesn't exist - its *id*.  We work in the
-      context of the *ZopeZoo* folder, which has no title.  So clicking again
-      on the *Test* tab you'll see that title and headline are replaced by the
-      id *ZopeZoo*.  (You might want to open the *Test* tab in a new window to
-      see the title of the browser window.)  After completing the next step
-      you'll be able to navigate to subfolders and see title and headline
-      change depending on the context.
-
-    Step 6: Generate Subfolder Menu Dynamically
-
-      1. Find the example menu item::
-
-        <ul>
-          <li><a href="ABSOLUTE_URL">SUB-OBJECT TITLE OR ID</a></li>
-        </ul>
-
-      2. Extend it like this::
-
-        <ul tal:condition="python: context.objectValues(['Folder'])">
-          <li tal:repeat="item python: context.objectValues(['Folder'])">
-            <a href="ABSOLUTE_URL"
-               tal:attributes="href item/absolute_url"
-               tal:content="item/title_or_id">SUB-OBJECT TITLE OR ID</a></li>
-        </ul>
-
-      The *Python expression* 'context.objectValues(['Folder'])' returns all
-      the subfolders in our context.  The 'tal:condition' statement checks if
-      any subfolders exist.  If not, the complete 'ul' element is removed.
-      That means we have reached a *leaf* of the navigation tree and don't
-      need a subfolder menu.
-       
-      Otherwise, the same expression in the 'tal:repeat' statement of the 'li'
-      element will return a list of subfolders.  The 'li' element will be
-      repeated for each *item* of this list.  In step 3 we created three
-      subfolders in the *ZopeZoo* folder, so using again the *Test* tab we
-      will see three list items, each with the correct id and link URL.  For
-      now there are no links back, so use the back button of your browser if
-      you can't wait exploring the site.
-
-    Step 7: Generate Breadcrumbs Dynamically
-
-      1. Look for this line::
-
-        <div>&gt; <a href="ABSOLUTE_URL">PARENT TITLE OR ID</a> </div>
-
-      2. Replace it by::
-
-        <div><tal:loop tal:repeat="item python: request.PARENTS[-2::-1]">&gt;
-          <a href="ABSOLUTE_URL"
-             tal:attributes="href item/absolute_url"
-             tal:content="item/title_or_id">PARENT TITLE OR
-                                            ID</a> </tal:loop></div>
-
-      Using a trail of bread crumbs for navigation is quite an old idea, you
-      might remember Hansel and Gretel tried that to find their way home.  In
-      our days, breadcrumbs are used for site navigation and show the path
-      back to the root (or home) of the site.
-
-      The folder that contains the current object is also called its *parent*.
-      As long as we have not reached the root object, each folder has again a
-      *parent* folder.  'request.PARENTS' is a list of all these parents from
-      the current object down to the root object of the Zope application.
-      'request.PARENTS[-2::-1]' returns a copy of that list in reverse order,
-      starting with the second last element.  We don't need the last value
-      because 'ZopeZoo' is located in the second level of our Zope application
-      and we just want to navigate within the zoo.
-
-      We use again a 'tal:repeat' statement to display the list.  Because we
-      don't want to repeat the 'div' element, we add a dummy TAL element that
-      doesn't show up in the rendered HTML page.  Now our site navigation is
-      complete and you can explore the sections of the zoo.
-
-    Step 8: Dynamic Status Bar
-
-      1. Go to this line::
-
-        <p class="status_message">STATUS MESSAGE</p>
-
-      2. Extend it by two tal attributes::
-
-        <p class="status_message"
-           tal:condition="options/status_message | nothing"
-           tal:content="options/status_message">STATUS MESSAGE</p>
-
-      We need the status bar later in this chapter.  For now all we need is to
-      make it invisible.  'options/status_message' will later be used for some
-      messages.  But most pages don't have that variable at all and this path
-      expression would raise an error.  'options/status_message | nothing'
-      catches that error and falls back to the special  value *nothing*.  This
-      is a common pattern to test if a value exists **and** is true.
-
-    Step 9: Improve Style Sheet Link
-
-      1. Find this line in the HTML head::
-
-        <link rel="stylesheet" href="z_zoo.css" type="text/css" />
-
-      2. Replace it by::
-
-        <link rel="stylesheet" href="z_zoo.css" type="text/css"
-              tal:attributes="href context/z_zoo.css/absolute_url" />
-
-      While the relative URI of the *href* attribute works thanks to
-      acquisition, this isn't a good solution.  Using the *index_html* method
-      for different folders, the browser can't know that all the *z_zoo.css*
-      files are in fact one and the same.  Besides the CSS file the basic
-      layout often contains a logo and other images, so making sure they are
-      requested only once makes your site faster and you waste less bandwidth.
-      The *path expression* 'context/z_zoo.css/absolute_url' returns the
-      absolute url of the CSS file.  Using it in the *href* attribute we have
-      a unique URI independent of the current context.
-
-    Step 10: Factor out Basic Look and Feel
-
-      1. Rename *index_html* to 'z_zoo.pt'.
-
-      2. Wrap a 'metal:define-macro' statement around the whole page and add
-         two 'metal:define-slot' statements for headline and content.  After
-         all these changes our main template - now called *z_zoo.pt* - looks
-         like this::
-
-        <metal:macro metal:define-macro="page"><!DOCTYPE html PUBLIC
-            "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
-        <html>
-        <head>
-
-        <title tal:content="context/title_or_id">PAGE TITLE OR ID</title>
-        <link rel="stylesheet" href="z_zoo.css" type="text/css"
-              tal:attributes="href context/z_zoo.css/absolute_url" />
-
-        </head>
-        <body>
-
-        <div><tal:loop tal:repeat="item python: request.PARENTS[-2::-1]">&gt;
-          <a href="ABSOLUTE_URL"
-             tal:attributes="href item/absolute_url"
-             tal:content="item/title_or_id">PARENT TITLE OR
-                                            ID</a> </tal:loop></div>
-
-        <ul tal:condition="python: context.objectValues(['Folder'])">
-          <li tal:repeat="item python: context.objectValues(['Folder'])">
-            <a href="ABSOLUTE_URL"
-               tal:attributes="href item/absolute_url"
-               tal:content="item/title_or_id">SUB-OBJECT TITLE OR ID</a></li>
-        </ul>
-
-        <metal:slot metal:define-slot="headline">
-
-          <h1 tal:content="context/title_or_id">PAGE TITLE OR ID</h1>
-
-        </metal:slot>
-
-        <p class="status_message"
-           tal:condition="options/status_message | nothing"
-           tal:content="options/status_message">STATUS MESSAGE</p>
-
-        <metal:slot metal:define-slot="content">
-
-          <p>THIS IS WHERE THE PAGE'S CONTENT GOES.</p>
-
-        </metal:slot>
-
-        </body>
-        </html>
-        </metal:macro>
-
-      3. Add again a new *Page Template* with the *id* 'index_html'.
-
-      4. Replace the example code of *index_html* with these two lines::
-
-        <metal:macro metal:use-macro="context/z_zoo.pt/macros/page">
-        </metal:macro>
-
-      Transforming our main template into an external macro and including it
-      again using the 'metal:use-macro' statement doesn't change the resulting
-      HTML page in any way.  But in the next step we can add code we only want
-      to use in *index_html* without changing the main template.
-
-      The 'metal:define-macro' statement in *z_zoo.pt* marks the complete
-      template as reuseable macro, giving it the *id* *page*.  The expression
-      'context/z_zoo.pt/macros/page' in *index_html* points to that macro.
-
-      For later use we also added two 'metal:define-slot' statements within
-      the macro.  That allows to override *headline* and *body* while reusing
-      the rest of the macro.
-
-    Step 11: Add Special Front Page Code
-
-      1. Go to the *Edit* tab of the new *index_html*.
-
-      2. Replace it by this code::
-
-        <metal:macro metal:use-macro="context/z_zoo.pt/macros/page">
-        <metal:slot metal:fill-slot="headline">
-
-          <h1>Welcome to the Zope Zoo</h1>
-
-        </metal:slot>
-        <metal:slot metal:fill-slot="content">
-
-          <p>Here you will find all kinds of cool animals. You are in the
-            <b tal:content="context/title_or_id">TITLE OR ID</b> section.</p>
-
-        </metal:slot>
-        </metal:macro>
-
-      The *index_html* should serve as the welcome screen for zoo visitors.
-      In order to do so, we override the default slots.  Take a look at how
-      your site appears by clicking on the *View* tab of the *ZopeZoo* folder.
-
-      You can use the navigation links to travel through the various sections
-      of the Zoo.  Use this navigation interface to find the reptiles section.
-      Zope builds this page to display a folder by looking for the default
-      folder view method, *index_html*.  It walks up the zoo site folder by
-      folder until it finds the *index_html* method in the *ZopeZoo* folder.
-      It then calls this method on the *Reptiles* folder.
-
-  Modifying a Subsection of the Site
-
-    What if you want the reptile page to display something besides the welcome
-    message?  You can replace the *index_html* method in the reptile section
-    with a more appropriate display method and still take advantage of the
-    main template including navigation.
-
-    Step 12: Create *index_html* for the Reptile House
-
-      1. Go to the *Reptile* folder.
-
-      2. Add a new *Page Template* named 'index_html'.
-
-      3. Give it some content more appropriate to reptiles::
-
-        <metal:macro metal:use-macro="context/z_zoo.pt/macros/page">
-        <metal:slot metal:fill-slot="headline">
-
-          <h1>The Reptile House</h1>
-
-        </metal:slot>
-        <metal:slot metal:fill-slot="content">
-
-          <p>Welcome to the Reptile House.</p>
-
-          <p>We are open from 6pm to midnight Monday through Friday.</p>
-
-        </metal:slot>
-        </metal:macro>
-
-      Now take a look at the reptile page by going to the *Reptile* folder and
-      clicking the *View* tab.
-
-      Since the *index_html* method in the *Reptile* folder uses the same
-      macro as the main *index_html*, the reptile page still includes your
-      navigation system.
-
-      Click on the *Snakes* link on the reptile page to see what the Snakes
-      section looks like.  The snakes page looks like the *Reptiles* page
-      because the *Snakes* folder acquires its *index_html* display method
-      from the *Reptiles* folder instead of from the *ZopeZoo* folder.
-
-  Creating a File Library
-
-    File libraries are common on websites since many sites distribute files
-    of some sort.  The old fashioned way to create a file library is to upload
-    your files, then create a web page that contains links to those files.
-    With Zope you can dynamically create links to files.  When you upload,
-    change or delete files, the file library's links can change automatically.
-
-    Step 13: Creating Library Folder and some Files
-
-      1. Add a new *Folder* to *ZopeZoo* with *Id* 'Files' and *Title* 'File
-         Library'.
-
-      2. Within that folder, add two *File* objects called 'DogGrooming' and
-         'HomeScienceExperiments'.
-
-      We don't need any content within the files to test the library.  Feel
-      free to add some more files and upload some content.
-
-    Step 14: Adding *index_html* Script and Template
-
-      1. Within the *Files* folder, add this new *Script (Python)* with the
-         *Id* 'index_html'::
-
-        ## Script (Python) "index_html"
-        ##parameters=
-        ##
-        library_items = []
-        items = context.objectValues(['File'])
-        for item in items:
-            library_items.append(
-                    { 'title': item.title_or_id(),
-                      'url': item.absolute_url(),
-                      'modified': item.bobobase_modification_time().aCommon()
-                      } )
-
-        options = { 'library_items': tuple(library_items) }
-
-        return options
-
-      2. Also add a new *Page Template* named 'index_html.pt' with this
-         content::
-
-        <metal:macro metal:use-macro="context/z_zoo.pt/macros/page">
-        <metal:slot metal:fill-slot="content">
-
-          <table>
-            <tr>
-              <th width="300">File</th>
-              <th>Last Modified</th>
-            </tr>
-            <tr>
-              <td><a href="URL">TITLE</a></td>
-              <td>MON DD, YYYY H:MM AM</td>
-            </tr>
-          </table>
-
-        </metal:slot>
-        </metal:macro>
-
-      This time the logic for our 'index_html' method will be more complex, so
-      we should separate logic from presentation.  We start with two
-      unconnected objects:  A *Script (Python)* to generate the results and a
-      *Page Template* to present them as HTML page.
-
-      The script loops over 'context.objectValues(['File'])', a list of all
-      *File* objects in our *Files* folder, and appends for each file the
-      needed values to the library_items list.  Again the dynamic values are
-      UPPERCASE in our mockup, so what we need are the file *title*, the *url*
-      and the last *modified* date in a format like this: Mar 1, 1997 1:45 pm.
-      Most Zope objects have the *bobobase_modification_time* method that
-      returns a *DateTime* object.  Looking at the API of *DateTime*, you'll
-      find that the *aCommon* method returns the format we want.
-
-      Later we will have more return values, so we store them in the *options*
-      dictionary.  Using the *Test* tab of the script you will see the
-      returned dictionary contains all the dynamic content needed by our
-      template.
-
-      The template uses again the *page* macro of *z_zoo.pt*.  Unlike before
-      there is only one 'metal:fill-slot' statement because we don't want to
-      override the *headline* slot.  Go to the *Test* tab of the template to
-      see how our file library will look like.
-
-    Step 15: Bringing Things Together
-
-      1. Replace the last line of the *index_html* script by this one::
-
-        return getattr(context, 'index_html.pt')(**options)
-
-      2. Look for this example table row in *index_html.pt*::
-
-            <tr>
-              <td><a href="URL">TITLE</a></td>
-              <td>MON DD, YYYY H:MM AM</td>
-            </tr>
-
-      3. Replace it by that code::
-
-            <tr tal:repeat="item options/library_items">
-              <td><a href="URL"
-                     tal:attributes="href item/url"
-                     tal:content="item/title">TITLE</a></td>
-              <td tal:content="item/modified">MON DD, YYYY H:MM AM</td>
-            </tr>
-
-      Now our script calls the *index_html.pt* after doing all the computing
-      and passes the resulting *options* dictionary to the template, which
-      creates the HTML presentation of *options*.  The *Test* tab of the
-      template no longer works because it now depends on the script.  Go to
-      the *Test* tab of the script to see the result: The file library!
-
-      If you add another file, Zope will dynamically adjust the file library
-      page.  You may also want to try changing the titles of the files,
-      uploading new files, or deleting some of the files.
-
-    Step 16: Making the Library Sortable
-
-      1. Find the table headers in *index_html.pt*::
-
-              <th width="300">File</th>
-              <th>Last Modified</th>
-
-      2. Replace them with these dynamic table headers::
-
-              <th width="300"><a href="SORT_TITLE_URL"
-                     tal:omit-tag="not: options/sort_title_url"
-                     tal:attributes="href options/sort_title_url"
-                     >File</a></th>
-              <th><a href="SORT_MODIFIED_URL"
-                     tal:omit-tag="not: options/sort_modified_url"
-                     tal:attributes="href options/sort_modified_url"
-                     >Last Modified</a></th>
-
-      3. Extend *index_html* to make it look like this::
-
-        ## Script (Python) "index_html"
-        ##parameters=sort='title'
-        ##
-        library_items = []
-        items = context.objectValues(['File'])
-        if sort == 'title':
-            sort_on = ( ('title_or_id', 'cmp', 'asc'), )
-            sort_title_url = ''
-            sort_modified_url = '%s?sort=modified' % context.absolute_url()
-        else:
-            sort_on = ( ('bobobase_modification_time', 'cmp', 'desc'), )
-            sort_title_url = '%s?sort=title' % context.absolute_url()
-            sort_modified_url = ''
-        items = sequence.sort(items, sort_on)
-        for item in items:
-            library_items.append(
-                    { 'title': item.title_or_id(),
-                      'url': item.absolute_url(),
-                      'modified': item.bobobase_modification_time().aCommon()
-                      } )
-
-        options = { 'sort_title_url': sort_title_url,
-                    'sort_modified_url': sort_modified_url,
-                    'library_items': tuple(library_items) }
-
-        return getattr(context, 'index_html.pt')(**options)
-
-      The changes in the template are quite simple.  If an url is provided,
-      the column header becomes a link.  If not, the 'not:' expression of the
-      'tal:omit-tag' statement is true and the 'a' tag is omitted.  The script
-      will always provide an url for the column that isn't currently sorted.
-
-      Basically we have to extend the logic, so most changes are in the
-      script.  First of all we define an optional parameter *sort*.  By
-      default it is 'title', so if no value is passed in we sort by title.
-      Sort criteria and urls depend on the sort parameter.  We use the sort
-      function of the built in *sequence* module to apply the sort criteria to
-      the *items* list.
-
-      Now view the file library and click on the *File* and *Last Modified*
-      links to sort the files.  If there is a *sort* variable and if it has a
-      value of *modified* then the files are sorted by modification time.
-      Otherwise the files are sorted by *title*.
-
-  Building a Guest Book
-
-      A guest book is a common and useful web application that allows
-      visitors to your site to leave messages.  Figure [5-6] shows
-      what the guest book you're going to write looks like.
-
-      "Zoo guest book.":img:5-6:Figures/5-6.png
-
-      Start by creating a folder called *GuestBook* in the root folder.
-      Give this folder the title 'The Zope Zoo Guest Book'.  The
-      *GuestBook* folder will hold the guest book entries and methods to
-      view and add entries. The folder will hold everything the guest
-      book needs. After the guest book is done you will be able to copy
-      and paste it elsewhere in your site to create new guest books.
-
-      You can use Zope to create a guest book several ways, but for
-      this example, you'll use one of the simplest.  The *GuestBook*
-      folder will hold a bunch of Files, one file for each guest book
-      entry.  When a new entry is added to the guest book, a new file
-      is created in the *GuestBook* folder.  To delete an unwanted
-      entry, just go into the *GuestBook* folder and delete the
-      unwanted file using the management interface.
-
-      Let's create a method that displays all of the entries.  Call this
-      method *index_html* so that it is the default view of the
-      *GuestBook* folder::
-
-        <dtml-var standard_html_header>
-
-        <h2><dtml-var title_or_id></h2>
-
-        <!-- Provide a link to add a new entry, this link goes to the
-        addEntryForm method -->
-
-        <p>
-          <a href="addEntryForm">Sign the guest book</a>
-        </p>
-
-        <!-- Iterate over each File in the folder starting with
-        the newest documents first. -->
-
-        <dtml-in expr="objectValues('File')"
-                 sort="bobobase_modification_time" reverse>
-
-        <!-- Display the date, author and contents of each file -->
-
-          <p>
-          <b>On <dtml-var bobobase_modification_time fmt="aCommon">, 
-             <dtml-var guest_name html_quote null="Anonymous"> said:</b><br>
-
-          <dtml-var sequence-item html_quote newline_to_br>
-
-          <!-- Make sure we use html_quote so the users can't sneak any
-          HTML onto our page -->
-
-        </p>
-
-        </dtml-in>
-
-        <dtml-var standard_html_footer>
-
-      This method loops over all the files in the folder and displays
-      each one. Notice that this method assumes that each file will have
-      a *guest_name* property. If that property doesn't exist or is empty,
-      then Zope will use *Anonymous* as the guest name. When you create a
-      entry file you'll have to make sure to set this property.
-
-      Next, let's create a form that your site visitors will use to add new
-      guest book entries. In the *index_html* method above we already
-      created a link to this form. In your *GuestBook* folder create a new
-      DTML Method named *addEntryForm*::
-
-        <dtml-var standard_html_header>
-
-        <p>Type in your name and your comments and we'll add it to the
-        guest book.</p>
-
-        <form action="addEntryAction" method="POST">
-        <p> Your name: 
-          <input type="text" name="guest_name" value="Anonymous">
-        </p>
-        <p> Your comments: <br>
-          <textarea name="comments" rows="10" cols="60"></textarea>
-        </p>
-
-        <p>
-          <input type="submit" value="Send Comments">
-        </p>  
-        </form>
-
-        <dtml-var standard_html_footer>
-
-      Now when you click on the *Sign Guest Book* link on the guest book page
-      you'll see a form allowing you to type in your comments.  This form
-      collects the user's name and comments and submits this information to a
-      method named *addEntryAction*.
-
-      Now create an *addEntryAction* DTML Method in the *GuestBook* folder to
-      handle the form. This form will create a new entry document and return
-      a confirmation message::
-
-        <dtml-var standard_html_header>
-
-        <dtml-call expr="addEntry(guest_name, comments)">
-
-        <h1>Thanks for signing our guest book!</h1>
-
-        <p><a href="<dtml-var URL1>">Return</a>
-        to the guest book.</p>
-
-        <dtml-var standard_html_footer>
-
-      XXX: show how to send the form data straight to the form and then return
-      to the guestbook page with the validated entry
-
-      This method creates a new entry by calling the *addEntry* method
-      and returns a message letting the user know that their entry has
-      been added.
-
-      The last remaining piece of the puzzle is to write the script that
-      will create a file and sets its contents and properties. We'll do
-      this in Python since it is much clearer than doing it in DTML. Create
-      a Python-based Script in the *GuestBook* folder called *addEntry*
-      with parameters *guest_name* and *comments*::
-
-        ## Script (Python) "addEntry"
-        ##parameters=guest_name, comments
-        ##
-        """
-        Create a guest book entry.
-        """
-        # create a unique file id
-        id='entry_%d' % len(context.objectIds())
-
-        # create the file
-        context.manage_addProduct['OFSP'].manage_addFile(id,
-                                                 title="", file=comments)
-
-        # add a guest_name string property
-        doc=getattr(context, id)
-        doc.manage_addProperty('guest_name', guest_name, 'string')
-
-      This script uses Zope API calls to create a File and to create a
-      property on it. This script performs the same sort of actions in
-      a script that you could do manually; it creates a file, edits it
-      and sets a property.
-
-      XXX: also explain objectIds, OFSP
-
-      The guest book is now almost finished. To use the simple guest
-      book, just visit 'http://localhost:8080/ZopeZoo/GuestBook/'.
-
-      One final thing is needed to make the guest book complete. More
-      than likely your security policy will not allow anonymous site
-      visitors to create files. However the guest book application
-      should be able to be used by anonymous visitors. In Chapter 7,
-      User and Security, we'll explore this scenario more fully. The
-      solution is to grant special permission to the *addEntry* method
-      to allow it to do its work of creating a file. You can do
-      this by setting the *Proxy role* of the script to
-      *Manager*. This means that when the script runs it will work as
-      though it was run by a manager regardless of who is actually
-      running the method. To change the proxy roles go to the *Proxy*
-      view of the *addEntry* script, as shown in [5-7].
-
-      "Setting proxy roles for the *addEntry* script.":img:5-7:Figures/5-7.png
-
-      Now select *Manager* from the list of proxy roles and click
-      *Change*.
-
-      Congratulations, you've just completed a functional web
-      application. The guest book is complete and can be copied to
-      different sites if you want.
-
-    Extending the Guest Book to Generate XML
-
-      All Zope objects can create XML. It's fairly easy to create XML with
-      DTML. XML is just a way of describing information. The power of
-      XML is that it lets you easily exchange information across the
-      network. Here's a simple way that you could represent your guest book in
-      XML::
-
-        <?xml version="1.0"?>
-        <guestbook>
-          <entry>
-            <author>Tom</author>
-            <comments>My comments</comments>
-          </entry>
-          <entry>
-            <author>Anonymous</author>
-            <comments>I like your web page</comments>
-          </entry>
-          <entry>
-            <author>Laura</author>
-            <comments>Please no blink tags</comments>
-          </entry>
-        </guestbook>
-
-      This XML document may not be that complex but it's easy to
-      generate. Create a DTML Method named "entries.xml" in your guest
-      book folder with the following contents::
-
-        <?xml version="1.0"?>
-        <guestbook>
-          <dtml-in expr="objectValues('File')">
-          <entry>
-            <author><dtml-var guest_name null="Anonymous"></author>
-            <comments><dtml-var sequence-item html_quote></comments>
-          </entry>
-          </dtml-in>
-        </guestbook>
-
-      As you can see, DTML is equally adept at creating XML as it is at
-      creating HTML. Simply embed DTML tags among XML tags and you're
-      set. The only tricky thing that you may wish to do is to set the
-      content-type of the response to *text/xml*, which can be done with
-      this DTML code::
-
-        <dtml-call expr="RESPONSE.setHeader('content-type', 'text/xml')">
-
-      The whole point of generating XML is producing data in a format
-      that can be understood by other systems. Therefore you will
-      probably want to create XML in an existing format understood by
-      the systems you want to communicate with.  In the case of the
-      guest book a reasonable format may be the RSS (Rich Site Summary) XML
-      format. RSS is a format developed by Netscape for its
-      *my.netscape.com* site, which has since gained popularity among
-      other web logs and news sites.  The Zope.org website uses DTML to
-      build a dynamic RSS document.
-
-      Congratulations! You've XML-enabled your guest book in just a
-      couple minutes. Pat yourself on the back. If you want extra credit,
-      research RSS enough to figure out how to change *entries.xml* to
-      generate RSS.
-
-  Building "Instance-Space" Applications
-
-    In Zope, there are a few ways to develop a web application.  The
-    simplest and fastest way, and the one we've been concentrating on
-    thus far in this book, is to build an application in *instance
-    space*.  To understand the term "instance space", we need to once
-    again put on our "object orientation hats".
-
-    When you create Zope objects by selecting them from the Zope "Add"
-    list, you are creating *instances* of a *class* defined by someone
-    else (see the "Object Orientation":ObjectOrientation.stx chapter
-    if you need to brush up on these terms).  For example, when you
-    add a Script (Python) object to your Zope database, you are
-    creating an instance of the Script (Python) class.  The Script
-    (Python) class was written by a Zope Corporation engineer.  When
-    you select "Script (Python)" from the Add list, and you fill in
-    the form to give an id and title and whatnot, and click the submit
-    button on the form, Zope creates an *instance* of that class in
-    the Folder of your choosing.  Instances such as these are inserted
-    into your Zope database and they live there until you delete them.
-
-    In the Zope application server, most object instances serve to
-    perform presentation duties, logic duties, or content duties.  You
-    can "glue" these instances together to create basic Zope
-    applications.  Since these objects are really instances of a
-    class, the term "instance space" is commonly used to describe the
-    Zope root folder and all of its subfolders.  "Building an
-    application in instance space" is defined as the act of creating
-    Zope object instances in this space and modifying them to act a
-    certain way when they are executed.
-
-    Instance-space applications are typically created from common Zope
-    objects.  Script (Python) objects, Folders, DTML Methods, Page
-    Templates, and other Zope services can be glued together to build
-    simple applications.
-
-  Instance-Space Applications vs. Products
-
-    In contrast to building applications in instance space, you may
-    also build applications in Zope by building them as *Products*.
-    Building an application as a Product differs from creating
-    applications in instance space inasmuch as the act of creating a
-    Product typically allows you to *extend* Zope with new "addable"
-    objects that appear in Zope's "Add" list.  Building a Product also
-    typically allows you to more easily distribute an application to
-    other people, and allows you to build objects that may more
-    closely resemble your "problem space".  We explore one way to
-    create Products in the chapter entitled "Extending
-    Zope":CustomZopeObjects.stx.  Building a Product is typically more
-    complicated than building an "instance-space" application, so we
-    get started here by describing how to build instance-space
-    applications.  When you find that it becomes difficult to
-    maintain, extend, or distribute an instance-space application
-    you've written, it's probably time to reconsider rewriting it as a
-    Product.
-
-  The Next Step
-
-    This chapter shows how simple web applications can be made.  Zope
-    has many more features in addition to these, but these simple
-    examples should get you started on create well managed, complex
-    websites.
-
-    In the next chapter, we'll see how the Zope security system lets
-    Zope work with many different users at the same time and allows
-    them to collaborate together on the same projects.

Copied: zope2book/trunk/source/SimpleExamples.rst (from rev 96419, zope2book/trunk/SimpleExamples.stx)
===================================================================
--- zope2book/trunk/source/SimpleExamples.rst	                        (rev 0)
+++ zope2book/trunk/source/SimpleExamples.rst	2009-02-10 21:15:33 UTC (rev 96422)
@@ -0,0 +1,991 @@
+Creating Basic Zope Applications
+================================
+
+.. todo:
+   
+   - add new screen shots
+   - convert guest book to zpt
+
+This chapter will take you, step by step, through building a basic web
+application in Zope.  As we go through the chapter, we will examine some of
+Zope's main concepts at work.  Using Zope *Folder*, *Script (Python)*, and
+*Page Template* objects, we'll create a simple website for an imaginary
+zoo: the "Zope Zoo", of course!
+
+We will develop the website as a Zope "instance-space" application.  A
+discussion of instance space is at the end of this chapter, but for now it
+is enough to know that instance-space applications are the easiest and
+fastest kind to build, because we can do everything in our favorite web
+browser.
+
+Goals for the Zope Zoo Web Site
+-------------------------------
+
+As with any project, we first need to clarify our goals for the Zope Zoo
+application.  The application's primary goal is to create a website for
+the world-renowned Zope Zoo.  Furthermore, we want to make the website
+easy to use and manage.  Here are some things we'll do:
+
+- Enable web users to navigate the site easily, as if they were moving
+  around a real zoo.
+
+- Keep all our shared web layout tools, like a Cascading Style Sheet
+  (CSS), in a single, easy-to-manage location.
+
+- Design the website so that future site-wide changes are quick and easy
+  to implement.
+
+- Take advantage of Zope to create a dynamic website in which web pages
+  build themselves "on the fly" when requested so that they are always up
+  to date.
+
+- Provide a simple file library of various documents that describe the
+  animals.
+
+- A guest book must be created so that zoo visitors can give you feedback
+  and comments about your site.
+
+Beginning with a Folder
+-----------------------
+
+Zope *Folder* objects provide natural containers and organizers for web
+applications.  A good way to start building an application is to create a
+new *Folder* to hold all the objects and subfolders related to the
+application.
+
+Consider, for example, a Zope folder named *Invoices* to hold an
+application for managing invoices through the Web.  The *Invoices* folder
+could contain both the logic objects - or "methods" - which allow you to
+add and edit invoices, as well as the actual data of the invoices.  The
+*Invoices* folder thus becomes a small Zope application.
+
+We begin building our Zope Zoo website application by creating a Zope
+*Folder* object to hold it all together in one place.
+
+Step 1: Create *ZopeZoo* Folder
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you haven't already, start your Zope installation and log into the Zope
+Management Interface (ZMI) using your favorite browser.  (If you are not
+familiar with the ZMI, refer to the `Installing and Starting Zope
+<InstallingZope.html>`_ chapter.)
+
+1. Navigate to Zope's top-level *root* folder.
+
+2. Use the *Add* list to create a new *Folder*.
+
+3. Give the new folder the *Id* 'ZopeZoo'.
+
+4. Check *Create public interface*.
+
+5. Click *Add*.
+
+(For now, we will ignore the optional *Title* fields.)
+
+Designing a Navigable Zoo
+-------------------------
+
+One of our goals is to enable easy user movement around the website.  A key
+to this easy movement is a navigation interface that is consistent among
+the site's pages.  In other words, every web page in the site should
+present a similar set of hyperlinks, in a similar place on the page, on
+which users can rely to guide them through the site.
+
+We also want to make sure the navigation links are always correct,
+regardless of how the structure of the site changes.  The solution is to
+design a meaningful site structure, and then create the Zope methods that
+will dynamically present the current structure to web users in the form of
+navigation links.
+
+First, let's define the site structure.  If the Zope Zoo was real, we might
+model the website's organization on the zoo's physical or logical design.
+For our purposes, we will pretend that the zoo houses three classes of
+animals.  We'll organize the website by adding folders inside our *ZopeZoo*
+folder.
+
+Step 2: Create Site Organization
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. note:
+   
+   Do not create public interfaces for the folders in this step.
+
+1. Enter the *ZopeZoo* folder and create three subfolders with *Ids*:
+   'Reptiles', 'Mammals' and 'Fish'.
+
+2. Inside the *Mammals* folder, add one folder named 'Whales'.
+
+3. Navigate to the *Reptiles* folder and create two folders there:
+   'Lizards' and 'Snakes'.
+
+In Zope's Navigator frame on the left side, you should see an icon for the
+*ZopeZoo* folder.  (If you don't see it, click *Refresh* in the Navigator).
+To view the *ZopeZoo* folder hierarchy - i.e. our nascent web site's
+structure - expand the *ZopeZoo* folder by clicking the little plus sign
+next to the icon.  Similarly expand the zoo subfolders.  You'll see
+something like the figure below.
+
+.. figure:: ../Figures/zoo1.png
+
+   Zoo folder structure
+
+Now we create the basic presentation objects:  The main template and the
+style sheet *z_zoo.css*.  To get started, we ask a web designer to create a
+HTML mockup and a CSS file that together represent the web page layout
+shared throughout the site.
+
+For the style sheet we create a simple *File* object in Zope.  No need to
+make it dynamic.
+
+Step 3: Create the Style Sheet
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Go to the top level of our zoo website, the *ZopeZoo* folder.
+
+2. Select *File* from the *Add* list.
+
+3. Give the file an *Id* of 'z_zoo.css'.
+
+4. Click *Add*.
+
+5. Select *z_zoo.css* to get its *Edit* view.
+
+6. Copy and paste these style definitions into the *File Data* area::
+
+    body, p, th, td {
+      font-family: Verdana, Arial, Helvetica, sans-serif;
+      font-size: 10pt;
+    }
+    h1 {
+      color: #6699cc;
+      font-family: Verdana, Arial, Helvetica, sans-serif;
+      font-size: 18pt;
+      font-weight: bold;
+    }
+    p {
+      color: #660000;
+    }
+    .status_message{
+      background: #ffffaa;
+      border-style: solid;
+      border-width: thin;
+      font-weight: bold;
+      padding: 4pt;
+    }
+    th {
+      background: #dee7ec;
+      text-align: left;
+    }
+
+At this stage, the HTML page the web designer created for us is valid XHTML
+1.0 Strict and could also live in a static *File* object.  But in the next
+steps we will convert the page into a dynamic template by adding TAL and
+METAL statements, so we need a *Page Template* object.  For now we use the
+*index_html* method already added by selecting *Create public interface* in
+step 1.
+
+Step 4: Create the Main Template
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Select *index_html* to get its *Edit* view.
+
+2. Replace all of the stock template code with this::
+
+    <!DOCTYPE html PUBLIC
+        "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
+    <html>
+    <head>
+
+    <title>PAGE TITLE OR ID</title>
+    <link rel="stylesheet" href="z_zoo.css" type="text/css" />
+
+    </head>
+    <body>
+
+    <div>&gt; <a href="ABSOLUTE_URL">PARENT TITLE OR ID</a> </div>
+
+    <ul>
+      <li><a href="ABSOLUTE_URL">SUB-OBJECT TITLE OR ID</a></li>
+    </ul>
+
+    <h1>PAGE TITLE OR ID</h1>
+
+    <p class="status_message">STATUS MESSAGE</p>
+
+    <p>THIS IS WHERE THE PAGE'S CONTENT GOES.</p>
+
+    </body>
+    </html>
+
+Our web designer marked placeholders for dynamic elements with UPPERCASE
+letters.  Using the *Test* tab of the new template, we can see the static
+HTML page.  Don't blame the web designer for the spartan layout.  It's for
+the sake of an easy example.  If you don't understand the XHTML and CSS
+code you might want to learn more about HTML first.  This chapter shows you
+how to make that code dynamic.
+
+Step 5: Dynamic Title and Headline
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Go to the *Edit* tab of *index_html*.
+
+2. Find these two lines::
+
+    <title>PAGE TITLE OR ID</title>
+    ...
+    <h1>PAGE TITLE OR ID</h1>
+
+3. Change them to look like that::
+
+    <title tal:content="context/title_or_id">PAGE TITLE OR ID</title>
+    ...
+    <h1 tal:content="context/title_or_id">PAGE TITLE OR ID</h1>
+
+The *path expression* 'context/title_or_id' returns the *title* of the
+context object or - if that doesn't exist - its *id*.  We work in the
+context of the *ZopeZoo* folder, which has no title.  So clicking again on
+the *Test* tab you'll see that title and headline are replaced by the id
+*ZopeZoo*.  (You might want to open the *Test* tab in a new window to see
+the title of the browser window.)  After completing the next step you'll be
+able to navigate to subfolders and see title and headline change depending
+on the context.
+
+Step 6: Generate Subfolder Menu Dynamically
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Find the example menu item::
+
+    <ul>
+      <li><a href="ABSOLUTE_URL">SUB-OBJECT TITLE OR ID</a></li>
+    </ul>
+
+2. Extend it like this::
+
+    <ul tal:condition="python: context.objectValues(['Folder'])">
+      <li tal:repeat="item python: context.objectValues(['Folder'])">
+        <a href="ABSOLUTE_URL"
+           tal:attributes="href item/absolute_url"
+           tal:content="item/title_or_id">SUB-OBJECT TITLE OR ID</a></li>
+    </ul>
+
+The *Python expression* 'context.objectValues(['Folder'])' returns all the
+subfolders in our context.  The 'tal:condition' statement checks if any
+subfolders exist.  If not, the complete 'ul' element is removed.  That
+means we have reached a *leaf* of the navigation tree and don't need a
+subfolder menu.
+ 
+Otherwise, the same expression in the 'tal:repeat' statement of the 'li'
+element will return a list of subfolders.  The 'li' element will be
+repeated for each *item* of this list.  In step 3 we created three
+subfolders in the *ZopeZoo* folder, so using again the *Test* tab we will
+see three list items, each with the correct id and link URL.  For now there
+are no links back, so use the back button of your browser if you can't wait
+exploring the site.
+
+Step 7: Generate Breadcrumbs Dynamically
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Look for this line::
+
+    <div>&gt; <a href="ABSOLUTE_URL">PARENT TITLE OR ID</a> </div>
+
+2. Replace it by::
+
+    <div><tal:loop tal:repeat="item python: request.PARENTS[-2::-1]">&gt;
+      <a href="ABSOLUTE_URL"
+         tal:attributes="href item/absolute_url"
+         tal:content="item/title_or_id">PARENT TITLE OR
+                                        ID</a> </tal:loop></div>
+
+Using a trail of bread crumbs for navigation is quite an old idea, you
+might remember Hansel and Gretel tried that to find their way home.  In our
+days, breadcrumbs are used for site navigation and show the path back to
+the root (or home) of the site.
+
+The folder that contains the current object is also called its *parent*.
+As long as we have not reached the root object, each folder has again a
+*parent* folder.  'request.PARENTS' is a list of all these parents from the
+current object down to the root object of the Zope application.
+'request.PARENTS[-2::-1]' returns a copy of that list in reverse order,
+starting with the second last element.  We don't need the last value
+because 'ZopeZoo' is located in the second level of our Zope application
+and we just want to navigate within the zoo.
+
+We use again a 'tal:repeat' statement to display the list.  Because we
+don't want to repeat the 'div' element, we add a dummy TAL element that
+doesn't show up in the rendered HTML page.  Now our site navigation is
+complete and you can explore the sections of the zoo.
+
+Step 8: Dynamic Status Bar
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Go to this line::
+
+    <p class="status_message">STATUS MESSAGE</p>
+
+2. Extend it by two tal attributes::
+
+    <p class="status_message"
+       tal:condition="options/status_message | nothing"
+       tal:content="options/status_message">STATUS MESSAGE</p>
+
+We need the status bar later in this chapter.  For now all we need is to
+make it invisible.  'options/status_message' will later be used for some
+messages.  But most pages don't have that variable at all and this path
+expression would raise an error.  'options/status_message | nothing'
+catches that error and falls back to the special  value *nothing*.  This is
+a common pattern to test if a value exists **and** is true.
+
+Step 9: Improve Style Sheet Link
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Find this line in the HTML head::
+
+    <link rel="stylesheet" href="z_zoo.css" type="text/css" />
+
+2. Replace it by::
+
+    <link rel="stylesheet" href="z_zoo.css" type="text/css"
+          tal:attributes="href context/z_zoo.css/absolute_url" />
+
+While the relative URI of the *href* attribute works thanks to acquisition,
+this isn't a good solution.  Using the *index_html* method for different
+folders, the browser can't know that all the *z_zoo.css* files are in fact
+one and the same.  Besides the CSS file the basic layout often contains a
+logo and other images, so making sure they are requested only once makes
+your site faster and you waste less bandwidth.  The *path expression*
+'context/z_zoo.css/absolute_url' returns the absolute url of the CSS file.
+Using it in the *href* attribute we have a unique URI independent of the
+current context.
+
+Step 10: Factor out Basic Look and Feel
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Rename *index_html* to 'z_zoo.pt'.
+
+2. Wrap a 'metal:define-macro' statement around the whole page and add
+   two 'metal:define-slot' statements for headline and content.  After
+   all these changes our main template - now called *z_zoo.pt* - looks
+   like this::
+
+    <metal:macro metal:define-macro="page"><!DOCTYPE html PUBLIC
+        "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
+    <html>
+    <head>
+
+    <title tal:content="context/title_or_id">PAGE TITLE OR ID</title>
+    <link rel="stylesheet" href="z_zoo.css" type="text/css"
+          tal:attributes="href context/z_zoo.css/absolute_url" />
+
+    </head>
+    <body>
+
+    <div><tal:loop tal:repeat="item python: request.PARENTS[-2::-1]">&gt;
+      <a href="ABSOLUTE_URL"
+         tal:attributes="href item/absolute_url"
+         tal:content="item/title_or_id">PARENT TITLE OR
+                                        ID</a> </tal:loop></div>
+
+    <ul tal:condition="python: context.objectValues(['Folder'])">
+      <li tal:repeat="item python: context.objectValues(['Folder'])">
+        <a href="ABSOLUTE_URL"
+           tal:attributes="href item/absolute_url"
+           tal:content="item/title_or_id">SUB-OBJECT TITLE OR ID</a></li>
+    </ul>
+
+    <metal:slot metal:define-slot="headline">
+
+      <h1 tal:content="context/title_or_id">PAGE TITLE OR ID</h1>
+
+    </metal:slot>
+
+    <p class="status_message"
+       tal:condition="options/status_message | nothing"
+       tal:content="options/status_message">STATUS MESSAGE</p>
+
+    <metal:slot metal:define-slot="content">
+
+      <p>THIS IS WHERE THE PAGE'S CONTENT GOES.</p>
+
+    </metal:slot>
+
+    </body>
+    </html>
+    </metal:macro>
+
+3. Add again a new *Page Template* with the *id* 'index_html'.
+
+4. Replace the example code of *index_html* with these two lines::
+
+    <metal:macro metal:use-macro="context/z_zoo.pt/macros/page">
+    </metal:macro>
+
+Transforming our main template into an external macro and including it
+again using the 'metal:use-macro' statement doesn't change the resulting
+HTML page in any way.  But in the next step we can add code we only want to
+use in *index_html* without changing the main template.
+
+The 'metal:define-macro' statement in *z_zoo.pt* marks the complete
+template as reuseable macro, giving it the *id* *page*.  The expression
+'context/z_zoo.pt/macros/page' in *index_html* points to that macro.
+
+For later use we also added two 'metal:define-slot' statements within the
+macro.  That allows to override *headline* and *body* while reusing the
+rest of the macro.
+
+Step 11: Add Special Front Page Code
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Go to the *Edit* tab of the new *index_html*.
+
+2. Replace it by this code::
+
+    <metal:macro metal:use-macro="context/z_zoo.pt/macros/page">
+    <metal:slot metal:fill-slot="headline">
+
+      <h1>Welcome to the Zope Zoo</h1>
+
+    </metal:slot>
+    <metal:slot metal:fill-slot="content">
+
+      <p>Here you will find all kinds of cool animals. You are in the
+        <b tal:content="context/title_or_id">TITLE OR ID</b> section.</p>
+
+    </metal:slot>
+    </metal:macro>
+
+The *index_html* should serve as the welcome screen for zoo visitors.  In
+order to do so, we override the default slots.  Take a look at how your
+site appears by clicking on the *View* tab of the *ZopeZoo* folder.
+
+You can use the navigation links to travel through the various sections of
+the Zoo.  Use this navigation interface to find the reptiles section.  Zope
+builds this page to display a folder by looking for the default folder view
+method, *index_html*.  It walks up the zoo site folder by folder until it
+finds the *index_html* method in the *ZopeZoo* folder.  It then calls this
+method on the *Reptiles* folder.
+
+Modifying a Subsection of the Site
+----------------------------------
+
+What if you want the reptile page to display something besides the welcome
+message?  You can replace the *index_html* method in the reptile section
+with a more appropriate display method and still take advantage of the main
+template including navigation.
+
+Step 12: Create *index_html* for the Reptile House
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Go to the *Reptile* folder.
+
+2. Add a new *Page Template* named 'index_html'.
+
+3. Give it some content more appropriate to reptiles::
+
+    <metal:macro metal:use-macro="context/z_zoo.pt/macros/page">
+    <metal:slot metal:fill-slot="headline">
+
+      <h1>The Reptile House</h1>
+
+    </metal:slot>
+    <metal:slot metal:fill-slot="content">
+
+      <p>Welcome to the Reptile House.</p>
+
+      <p>We are open from 6pm to midnight Monday through Friday.</p>
+
+    </metal:slot>
+    </metal:macro>
+
+Now take a look at the reptile page by going to the *Reptile* folder and
+clicking the *View* tab.
+
+Since the *index_html* method in the *Reptile* folder uses the same macro
+as the main *index_html*, the reptile page still includes your navigation
+system.
+
+Click on the *Snakes* link on the reptile page to see what the Snakes
+section looks like.  The snakes page looks like the *Reptiles* page because
+the *Snakes* folder acquires its *index_html* display method from the
+*Reptiles* folder instead of from the *ZopeZoo* folder.
+
+Creating a File Library
+-----------------------
+
+File libraries are common on websites since many sites distribute files of
+some sort.  The old fashioned way to create a file library is to upload
+your files, then create a web page that contains links to those files.
+With Zope you can dynamically create links to files.  When you upload,
+change or delete files, the file library's links can change automatically.
+
+Step 13: Creating Library Folder and some Files
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Add a new *Folder* to *ZopeZoo* with *Id* 'Files' and *Title* 'File
+   Library'.
+
+2. Within that folder, add two *File* objects called 'DogGrooming' and
+   'HomeScienceExperiments'.
+
+We don't need any content within the files to test the library.  Feel
+free to add some more files and upload some content.
+
+Step 14: Adding *index_html* Script and Template
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Within the *Files* folder, add this new *Script (Python)* with the
+   *Id* 'index_html'::
+
+    ## Script (Python) "index_html"
+    ##parameters=
+    ##
+    library_items = []
+    items = context.objectValues(['File'])
+    for item in items:
+        library_items.append(
+                { 'title': item.title_or_id(),
+                  'url': item.absolute_url(),
+                  'modified': item.bobobase_modification_time().aCommon()
+                  } )
+
+    options = { 'library_items': tuple(library_items) }
+
+    return options
+
+2. Also add a new *Page Template* named 'index_html.pt' with this
+   content::
+
+    <metal:macro metal:use-macro="context/z_zoo.pt/macros/page">
+    <metal:slot metal:fill-slot="content">
+
+      <table>
+        <tr>
+          <th width="300">File</th>
+          <th>Last Modified</th>
+        </tr>
+        <tr>
+          <td><a href="URL">TITLE</a></td>
+          <td>MON DD, YYYY H:MM AM</td>
+        </tr>
+      </table>
+
+    </metal:slot>
+    </metal:macro>
+
+This time the logic for our 'index_html' method will be more complex, so we
+should separate logic from presentation.  We start with two unconnected
+objects:  A *Script (Python)* to generate the results and a *Page Template*
+to present them as HTML page.
+
+The script loops over 'context.objectValues(['File'])', a list of all
+*File* objects in our *Files* folder, and appends for each file the needed
+values to the library_items list.  Again the dynamic values are UPPERCASE
+in our mockup, so what we need are the file *title*, the *url* and the last
+*modified* date in a format like this: Mar 1, 1997 1:45 pm.  Most Zope
+objects have the *bobobase_modification_time* method that returns a
+*DateTime* object.  Looking at the API of *DateTime*, you'll find that the
+*aCommon* method returns the format we want.
+
+Later we will have more return values, so we store them in the *options*
+dictionary.  Using the *Test* tab of the script you will see the returned
+dictionary contains all the dynamic content needed by our template.
+
+The template uses again the *page* macro of *z_zoo.pt*.  Unlike before
+there is only one 'metal:fill-slot' statement because we don't want to
+override the *headline* slot.  Go to the *Test* tab of the template to see
+how our file library will look like.
+
+Step 15: Bringing Things Together
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Replace the last line of the *index_html* script by this one::
+
+    return getattr(context, 'index_html.pt')(**options)
+
+2. Look for this example table row in *index_html.pt*::
+
+      <tr>
+        <td><a href="URL">TITLE</a></td>
+        <td>MON DD, YYYY H:MM AM</td>
+      </tr>
+
+3. Replace it by that code::
+
+      <tr tal:repeat="item options/library_items">
+        <td><a href="URL"
+               tal:attributes="href item/url"
+               tal:content="item/title">TITLE</a></td>
+        <td tal:content="item/modified">MON DD, YYYY H:MM AM</td>
+      </tr>
+
+Now our script calls the *index_html.pt* after doing all the computing and
+passes the resulting *options* dictionary to the template, which creates
+the HTML presentation of *options*.  The *Test* tab of the template no
+longer works because it now depends on the script.  Go to the *Test* tab of
+the script to see the result: The file library!
+
+If you add another file, Zope will dynamically adjust the file library
+page.  You may also want to try changing the titles of the files, uploading
+new files, or deleting some of the files.
+
+Step 16: Making the Library Sortable
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Find the table headers in *index_html.pt*::
+
+        <th width="300">File</th>
+        <th>Last Modified</th>
+
+2. Replace them with these dynamic table headers::
+
+        <th width="300"><a href="SORT_TITLE_URL"
+               tal:omit-tag="not: options/sort_title_url"
+               tal:attributes="href options/sort_title_url"
+               >File</a></th>
+        <th><a href="SORT_MODIFIED_URL"
+               tal:omit-tag="not: options/sort_modified_url"
+               tal:attributes="href options/sort_modified_url"
+               >Last Modified</a></th>
+
+3. Extend *index_html* to make it look like this::
+
+    ## Script (Python) "index_html"
+    ##parameters=sort='title'
+    ##
+    library_items = []
+    items = context.objectValues(['File'])
+    if sort == 'title':
+        sort_on = ( ('title_or_id', 'cmp', 'asc'), )
+        sort_title_url = ''
+        sort_modified_url = '%s?sort=modified' % context.absolute_url()
+    else:
+        sort_on = ( ('bobobase_modification_time', 'cmp', 'desc'), )
+        sort_title_url = '%s?sort=title' % context.absolute_url()
+        sort_modified_url = ''
+    items = sequence.sort(items, sort_on)
+    for item in items:
+        library_items.append(
+                { 'title': item.title_or_id(),
+                  'url': item.absolute_url(),
+                  'modified': item.bobobase_modification_time().aCommon()
+                  } )
+
+    options = { 'sort_title_url': sort_title_url,
+                'sort_modified_url': sort_modified_url,
+                'library_items': tuple(library_items) }
+
+    return getattr(context, 'index_html.pt')(**options)
+
+The changes in the template are quite simple.  If an url is provided, the
+column header becomes a link.  If not, the 'not:' expression of the
+'tal:omit-tag' statement is true and the 'a' tag is omitted.  The script
+will always provide an url for the column that isn't currently sorted.
+
+Basically we have to extend the logic, so most changes are in the script.
+First of all we define an optional parameter *sort*.  By default it is
+'title', so if no value is passed in we sort by title.  Sort criteria and
+urls depend on the sort parameter.  We use the sort function of the built
+in *sequence* module to apply the sort criteria to the *items* list.
+
+Now view the file library and click on the *File* and *Last Modified* links
+to sort the files.  If there is a *sort* variable and if it has a value of
+*modified* then the files are sorted by modification time.  Otherwise the
+files are sorted by *title*.
+
+Building a Guest Book
+---------------------
+
+A guest book is a common and useful web application that allows visitors to
+your site to leave messages.  Figure [5-6] shows what the guest book you're
+going to write looks like.
+
+.. figure:: ../Figures/5-6.png
+
+   Zoo guest book
+
+Start by creating a folder called *GuestBook* in the root folder.  Give
+this folder the title 'The Zope Zoo Guest Book'.  The *GuestBook* folder
+will hold the guest book entries and methods to view and add entries. The
+folder will hold everything the guest book needs. After the guest book is
+done you will be able to copy and paste it elsewhere in your site to create
+new guest books.
+
+You can use Zope to create a guest book several ways, but for this example,
+you'll use one of the simplest.  The *GuestBook* folder will hold a bunch
+of Files, one file for each guest book entry.  When a new entry is added to
+the guest book, a new file is created in the *GuestBook* folder.  To delete
+an unwanted entry, just go into the *GuestBook* folder and delete the
+unwanted file using the management interface.
+
+Let's create a method that displays all of the entries.  Call this method
+*index_html* so that it is the default view of the *GuestBook* folder::
+
+  <dtml-var standard_html_header>
+
+  <h2><dtml-var title_or_id></h2>
+
+  <!-- Provide a link to add a new entry, this link goes to the
+  addEntryForm method -->
+
+  <p>
+    <a href="addEntryForm">Sign the guest book</a>
+  </p>
+
+  <!-- Iterate over each File in the folder starting with
+  the newest documents first. -->
+
+  <dtml-in expr="objectValues('File')"
+           sort="bobobase_modification_time" reverse>
+
+  <!-- Display the date, author and contents of each file -->
+
+    <p>
+    <b>On <dtml-var bobobase_modification_time fmt="aCommon">, 
+       <dtml-var guest_name html_quote null="Anonymous"> said:</b><br>
+
+    <dtml-var sequence-item html_quote newline_to_br>
+
+    <!-- Make sure we use html_quote so the users can't sneak any
+    HTML onto our page -->
+
+  </p>
+
+  </dtml-in>
+
+  <dtml-var standard_html_footer>
+
+This method loops over all the files in the folder and displays each one.
+Notice that this method assumes that each file will have a *guest_name*
+property. If that property doesn't exist or is empty, then Zope will use
+*Anonymous* as the guest name. When you create a entry file you'll have to
+make sure to set this property.
+
+Next, let's create a form that your site visitors will use to add new guest
+book entries. In the *index_html* method above we already created a link to
+this form. In your *GuestBook* folder create a new DTML Method named
+*addEntryForm*::
+
+  <dtml-var standard_html_header>
+
+  <p>Type in your name and your comments and we'll add it to the
+  guest book.</p>
+
+  <form action="addEntryAction" method="POST">
+  <p> Your name: 
+    <input type="text" name="guest_name" value="Anonymous">
+  </p>
+  <p> Your comments: <br>
+    <textarea name="comments" rows="10" cols="60"></textarea>
+  </p>
+
+  <p>
+    <input type="submit" value="Send Comments">
+  </p>  
+  </form>
+
+  <dtml-var standard_html_footer>
+
+Now when you click on the *Sign Guest Book* link on the guest book page
+you'll see a form allowing you to type in your comments.  This form
+collects the user's name and comments and submits this information to a
+method named *addEntryAction*.
+
+Now create an *addEntryAction* DTML Method in the *GuestBook* folder to
+handle the form. This form will create a new entry document and return a
+confirmation message::
+
+  <dtml-var standard_html_header>
+
+  <dtml-call expr="addEntry(guest_name, comments)">
+
+  <h1>Thanks for signing our guest book!</h1>
+
+  <p><a href="<dtml-var URL1>">Return</a>
+  to the guest book.</p>
+
+  <dtml-var standard_html_footer>
+
+.. TODO:
+   
+   show how to send the form data straight to the form and then return
+   to the guestbook page with the validated entry
+
+This method creates a new entry by calling the *addEntry* method and
+returns a message letting the user know that their entry has been added.
+
+The last remaining piece of the puzzle is to write the script that will
+create a file and sets its contents and properties. We'll do this in Python
+since it is much clearer than doing it in DTML. Create a Python-based
+Script in the *GuestBook* folder called *addEntry* with parameters
+*guest_name* and *comments*::
+
+  ## Script (Python) "addEntry"
+  ##parameters=guest_name, comments
+  ##
+  """
+  Create a guest book entry.
+  """
+  # create a unique file id
+  id='entry_%d' % len(context.objectIds())
+
+  # create the file
+  context.manage_addProduct['OFSP'].manage_addFile(id,
+                                           title="", file=comments)
+
+  # add a guest_name string property
+  doc=getattr(context, id)
+  doc.manage_addProperty('guest_name', guest_name, 'string')
+
+This script uses Zope API calls to create a File and to create a property
+on it. This script performs the same sort of actions in a script that you
+could do manually; it creates a file, edits it and sets a property.
+
+.. TODO:
+   
+   also explain objectIds, OFSP
+
+The guest book is now almost finished. To use the simple guest book, just
+visit 'http://localhost:8080/ZopeZoo/GuestBook/'.
+
+One final thing is needed to make the guest book complete. More than likely
+your security policy will not allow anonymous site visitors to create
+files. However the guest book application should be able to be used by
+anonymous visitors. In Chapter 7, User and Security, we'll explore this
+scenario more fully. The solution is to grant special permission to the
+*addEntry* method to allow it to do its work of creating a file. You can do
+this by setting the *Proxy role* of the script to *Manager*. This means
+that when the script runs it will work as though it was run by a manager
+regardless of who is actually running the method. To change the proxy roles
+go to the *Proxy* view of the *addEntry* script, as shown in [5-7].
+
+.. figure:: ../Figures/5-7.png
+
+   Setting proxy roles for the *addEntry* script
+
+Now select *Manager* from the list of proxy roles and click *Change*.
+
+Congratulations, you've just completed a functional web application. The
+guest book is complete and can be copied to different sites if you want.
+
+Extending the Guest Book to Generate XML
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+All Zope objects can create XML. It's fairly easy to create XML with DTML.
+XML is just a way of describing information. The power of XML is that it
+lets you easily exchange information across the network. Here's a simple
+way that you could represent your guest book in XML::
+
+  <?xml version="1.0"?>
+  <guestbook>
+    <entry>
+      <author>Tom</author>
+      <comments>My comments</comments>
+    </entry>
+    <entry>
+      <author>Anonymous</author>
+      <comments>I like your web page</comments>
+    </entry>
+    <entry>
+      <author>Laura</author>
+      <comments>Please no blink tags</comments>
+    </entry>
+  </guestbook>
+
+This XML document may not be that complex but it's easy to generate. Create
+a DTML Method named "entries.xml" in your guest book folder with the
+following contents::
+
+  <?xml version="1.0"?>
+  <guestbook>
+    <dtml-in expr="objectValues('File')">
+    <entry>
+      <author><dtml-var guest_name null="Anonymous"></author>
+      <comments><dtml-var sequence-item html_quote></comments>
+    </entry>
+    </dtml-in>
+  </guestbook>
+
+As you can see, DTML is equally adept at creating XML as it is at creating
+HTML. Simply embed DTML tags among XML tags and you're set. The only tricky
+thing that you may wish to do is to set the content-type of the response to
+*text/xml*, which can be done with this DTML code::
+
+  <dtml-call expr="RESPONSE.setHeader('content-type', 'text/xml')">
+
+The whole point of generating XML is producing data in a format that can be
+understood by other systems. Therefore you will probably want to create XML
+in an existing format understood by the systems you want to communicate
+with.  In the case of the guest book a reasonable format may be the RSS
+(Rich Site Summary) XML format. RSS is a format developed by Netscape for
+its *my.netscape.com* site, which has since gained popularity among other
+web logs and news sites.  The Zope.org website uses DTML to build a dynamic
+RSS document.
+
+Congratulations! You've XML-enabled your guest book in just a couple
+minutes. Pat yourself on the back. If you want extra credit, research RSS
+enough to figure out how to change *entries.xml* to generate RSS.
+
+Building "Instance-Space" Applications
+--------------------------------------
+
+In Zope, there are a few ways to develop a web application.  The simplest
+and fastest way, and the one we've been concentrating on thus far in this
+book, is to build an application in *instance space*.  To understand the
+term "instance space", we need to once again put on our "object orientation
+hats".
+
+When you create Zope objects by selecting them from the Zope "Add" list,
+you are creating *instances* of a *class* defined by someone else (see the
+`Object Orientation <ObjectOrientation.html>`_ chapter if you need to brush
+up on these terms).  For example, when you add a Script (Python) object to
+your Zope database, you are creating an instance of the Script (Python)
+class.  The Script (Python) class was written by a Zope Corporation
+engineer.  When you select "Script (Python)" from the Add list, and you
+fill in the form to give an id and title and whatnot, and click the submit
+button on the form, Zope creates an *instance* of that class in the Folder
+of your choosing.  Instances such as these are inserted into your Zope
+database and they live there until you delete them.
+
+In the Zope application server, most object instances serve to perform
+presentation duties, logic duties, or content duties.  You can "glue" these
+instances together to create basic Zope applications.  Since these objects
+are really instances of a class, the term "instance space" is commonly used
+to describe the Zope root folder and all of its subfolders.  "Building an
+application in instance space" is defined as the act of creating Zope
+object instances in this space and modifying them to act a certain way when
+they are executed.
+
+Instance-space applications are typically created from common Zope objects.
+Script (Python) objects, Folders, DTML Methods, Page Templates, and other
+Zope services can be glued together to build simple applications.
+
+Instance-Space Applications vs. Products
+----------------------------------------
+
+In contrast to building applications in instance space, you may also build
+applications in Zope by building them as *Products*.  Building an
+application as a Product differs from creating applications in instance
+space inasmuch as the act of creating a Product typically allows you to
+*extend* Zope with new "addable" objects that appear in Zope's "Add" list.
+Building a Product also typically allows you to more easily distribute an
+application to other people, and allows you to build objects that may more
+closely resemble your "problem space".  We explore one way to create
+Products in the chapter entitled <Extending Zope
+<CustomZopeObjects.html>`_.
+
+Building a Product is typically more complicated than building an
+"instance-space" application, so we get started here by describing how to
+build instance-space applications.  When you find that it becomes difficult
+to maintain, extend, or distribute an instance-space application you've
+written, it's probably time to reconsider rewriting it as a Product.
+
+The Next Step
+-------------
+
+This chapter shows how simple web applications can be made.  Zope has many
+more features in addition to these, but these simple examples should get
+you started on create well managed, complex websites.
+
+In the next chapter, we'll see how the Zope security system lets Zope work
+with many different users at the same time and allows them to collaborate
+together on the same projects.

Modified: zope2book/trunk/source/index.rst
===================================================================
--- zope2book/trunk/source/index.rst	2009-02-10 21:14:24 UTC (rev 96421)
+++ zope2book/trunk/source/index.rst	2009-02-10 21:15:33 UTC (rev 96422)
@@ -21,6 +21,7 @@
    Acquisition.rst
    DTML.rst
    ZPT.rst
+   SimpleExamples.rst
    AppendixA.rst
    Contributions.rst
 



More information about the Checkins mailing list