Edgewall Software

Changes between Version 61 and Version 62 of GenshiTutorial


Ignore:
Timestamp:
Sep 1, 2007, 12:45:03 AM (12 years ago)
Author:
cmlenz
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • GenshiTutorial

    v61 v62  
    384384
    385385    <form action="" method="post">
    386       <table summary=""><tr>
     386      <table summary=""><tbody><tr>
    387387        <th><label for="username">Your name:</label></th>
    388388        <td><input type="text" id="username" name="username" /></td>
     
    390390        <th><label for="url">Link URL:</label></th>
    391391        <td><input type="text" id="url" name="url" /></td>
    392       </tr>
    393       <tr>
     392      </tr><tr>
    394393        <th><label for="title">Title:</label></th>
    395394        <td><input type="text" name="title" /></td>
    396       </tr></table>
    397       <div>
    398         <input type="submit" value="Submit" />
    399         <input type="submit" name="cancel" value="Cancel" />
    400       </div>
     395      </tr><tr>
     396        <td></td>
     397        <td>
     398          <input type="submit" value="Submit" />
     399          <input type="submit" name="cancel" value="Cancel" />
     400        </td>
     401      </tr></tbody></table>
    401402    </form>
    402403
     
    427428    url = validators.URL(not_empty=True, add_http=True, check_exists=False)
    428429    title = validators.UnicodeString(not_empty=True)
    429 }}}
    430 
    431 Now let's use that class in the `Root.submit()` method. First add the following to the top of `geddit/controller.py`:
     430
     431
     432class CommentForm(Schema):
     433    username = validators.UnicodeString(not_empty=True)
     434    content = validators.UnicodeString(not_empty=True)
     435}}}
     436
     437Now let's use those in the `Root.submit()` method. First add the form classes, as well as the `Invalid` exception type used by !FormEncode, to the imports at the top of `geddit/controller.py`, which should then look something like this:
    432438
    433439{{{
    434440#!python
     441import cherrypy
    435442from formencode import Invalid
    436 from geddit.form import LinkForm
     443from genshi.template import TemplateLoader
     444
     445from geddit.form import LinkForm, CommentForm
     446from geddit.model import Link, Comment
    437447}}}
    438448
     
    473483  <body>
    474484    <div id="header">
    475       <h1>Geddit</h1>
     485      <h1>Submit new link</h1>
    476486    </div>
    477487
    478     <h2>Submit new link</h2>
    479488    <form action="" method="post">
    480       <table summary=""><tr>
     489      <table summary=""><tbody><tr>
    481490        <th><label for="username">Your name:</label></th>
    482491        <td>
     
    490499          <span py:if="'url' in errors" class="error">${errors.url}</span>
    491500        </td>
    492       </tr>
    493       <tr>
     501      </tr><tr>
    494502        <th><label for="title">Title:</label></th>
    495503        <td>
     
    497505          <span py:if="'title' in errors" class="error">${errors.title}</span>
    498506        </td>
    499       </tr></table>
    500       <div>
    501         <input type="submit" value="Submit" />
    502         <input type="submit" name="cancel" value="Cancel" />
    503       </div>
     507      </tr><tr>
     508        <td></td>
     509        <td>
     510          <input type="submit" value="Submit" />
     511          <input type="submit" name="cancel" value="Cancel" />
     512        </td>
     513      </tr></tbody></table>
    504514    </form>
    505515
     
    518528But there's a problem here: Note how the input values have vanished from the form! We'd have to repopulate the form manually from the data submitted so far. We could do that by adding the required `value=""` attributes to th text fields in the template, but Genshi provides a more elegant way: the [wiki:Documentation/filters.html#html-form-filler HTMLFormFiller] steam filter. Given a dictionary of values, it can automatically populate HTML forms in the template output stream.
    519529
    520 To enable this functionality, first you'll need to add the import `from genshi.filters import HTMLFormFiller` to the `genshi/controller.py` file. Next, update the bottom lines of the `Root.submit()` method implementation so that they look as follows:
     530To enable this functionality, first you'll need to add the following import to the `genshi/controller.py` file:
     531
     532{{{
     533#!python
     534from genshi.filters import HTMLFormFiller
     535}}}
     536
     537Next, update the bottom lines of the `Root.submit()` method implementation so that they look as follows:
    521538
    522539{{{
     
    633650}}}
    634651
    635 As you can see here, the code is now less repetitive: there's a simple decorator to define which template should be used, and the `render()` produces the template out stream which can then be further processed if necessary.
     652As you can see here, the code is now less repetitive: there's a simple decorator to define which template should be used, and the `render()` function produces the template output stream which can then be further processed if necessary.
    636653
    637654
     
    644661Match templates in Genshi turn this up side down. They are conceptually similar to running an XSLT transformation over your template output: you create rules that match elements in the template output stream based on XPath patterns. Whenever there is a match, the matched content is replaced by what the match template produces. This sounds complicated in theory, but is fairly intuitive in practice, so let's look at a concrete example.
    645662
    646 Let's create a layout template first: in the `geddit/templates/` directory, add a file named `layout.html`, with the following content:
     663In the `geddit/templates/` directory, add a file named `layout.html`, with the following content:
    647664
    648665{{{
     
    655672    <head py:attrs="select('@*')">
    656673      <title py:with="title = list(select('title/text()'))">
    657         geddit<py:if test="title">: ${title}</py:if>
     674        Geddit<py:if test="title">: ${title}</py:if>
    658675      </title>
    659676      <link rel="stylesheet" href="${url('/media/layout.css')}" type="text/css" />
     
    743760  </head>
    744761  <body>
    745     <p><a class="action" href="/submit/">Submit new link</a></p>
     762    <h1>News</h1>
    746763
    747764    <ol py:if="links">
     
    751768      </li>
    752769    </ol>
     770
     771    <p><a class="action" href="/submit/">Submit new link</a></p>
    753772  </body>
    754773</html>
    755774}}}
    756775
    757 Also change the `submit.html` template analogously, by adding the namespace prefix, the `<xi:include>` element, and by removing the header and footer `<div>`s.
    758 
    759 Speaking of “layout”, you can see that we've added references to some static resources in the layout template: there's an embedded image as well as a linked stylesheet and javascript file. [http://svn.edgewall.org/repos/genshi/trunk/examples/tutorial/geddit/static Download] those files and put them in your `geddit/static/` directory.
     776Also change the `submit.html` template analogously, by adding the namespace prefix, the `<xi:include>` element, and by removing the header and footer `<div>`s:
     777
     778{{{
     779#!genshi
     780<html xmlns="http://www.w3.org/1999/xhtml"
     781      xmlns:xi="http://www.w3.org/2001/XInclude"
     782      xmlns:py="http://genshi.edgewall.org/">
     783  <xi:include href="layout.html" />
     784  <head>
     785    <title>Submit new link</title>
     786  </head>
     787  <body>
     788    <h1>Submit new link</h1>
     789
     790    <form action="" method="post">
     791      <table summary=""><tbody><tr>
     792        <th><label for="username">Your name:</label></th>
     793        <td>
     794          <input type="text" id="username" name="username" />
     795          <span py:if="'username' in errors" class="error">${errors.username}</span>
     796        </td>
     797      </tr><tr>
     798        <th><label for="url">Link URL:</label></th>
     799        <td>
     800          <input type="text" id="url" name="url" />
     801          <span py:if="'url' in errors" class="error">${errors.url}</span>
     802        </td>
     803      </tr>
     804      <tr>
     805        <th><label for="title">Title:</label></th>
     806        <td>
     807          <input type="text" name="title" />
     808          <span py:if="'title' in errors" class="error">${errors.title}</span>
     809        </td>
     810      </tr><tr>
     811        <td></td>
     812        <td>
     813          <input type="submit" value="Submit" />
     814          <input type="submit" name="cancel" value="Cancel" />
     815        </td>
     816      </tr></tbody></table>
     817    </form>
     818
     819  </body>
     820</html>
     821}}}
     822
     823And speaking of “layout”, you can see that we've added references to some static resources in the layout template: there's an embedded image as well as a linked stylesheet and javascript file. [http://svn.edgewall.org/repos/genshi/trunk/examples/tutorial/geddit/static Download] those files and put them in your `geddit/static/` directory.
    760824
    761825When you reload the front page in your browser, you should now see something similar to the following:
     
    853917At this point you should be able to see the number of comments on the start page, click on that link to get to the details page, where you should see all comments listed for the corresponding link submission. That page also contains a link for submitting additional comments, and that's what we'll need to set up next.
    854918
    855 First, we need to add a form for submitting comments to `geddit/form.py`. At the bottom of that file, add the following class:
    856 
    857 {{{
    858 #!python
    859 class CommentForm(Schema):
    860     username = validators.UnicodeString(not_empty=True)
    861     content = validators.UnicodeString(not_empty=True)
    862 }}}
    863 
    864 And add a corresponding import to `geddit/controller.py`, which should then have a line like this somewhere at the top:
    865 
    866 {{{
    867 #!python
    868 from geddit.form import LinkForm, CommentForm
    869 }}}
    870 
    871 Now we need to add the method for handling comment submissions to our `Root` object. It should look like this:
     919We need to add the method for handling comment submissions to our `Root` object. It should look like this:
    872920
    873921{{{