Section 8.3. WhatWhat Status Widgets


8.3. WhatWhat Status Widgets

In the widgets directory, you'll find widgets.py, which defines each of the widgets that WhatWhat Status uses in the Recent Changes page.

Each of these widgets inherits from the turbogears.widgets.widget base class, which provides methods such as the display method used to display each widget in the recent changes template:

from turbogears.widgets import Widget class NoteWidget(Widget):     template        = 'whatwhat.widgets.templates.note'     template_vars   = ['note', 'read_only']     read_only       = False note_widget = NoteWidget() class NotesWidget(Widget):     template        = 'whatwhat.widgets.templates.notes'     template_vars   = ['notes', 'read_only', 'note_widget']     note_widget     = note_widget     read_only       = False notes_widget = NotesWidget()


There are widgets for Questions, Risks, Projects, etc. But when you understand the NotesWidget, the others will all be trivial to figure out. To render properly to the browser, every widget needs a template. This can either be a .kid file, or it can be placed right inside the widget. For anything more complex than a simple text area, you are better off creating a .kid file for the template and referencing itthe way the WhatWhat Status authors do here.

Widgets also have special variables that can only be set at widget instantiation or at render time, called params. The NotesWidget has two params: note and read_only, which are assigned at render time. The note param will be the actual text of the note that is passed into the widget at render time in the recent changes template. The other thing that happens at render time is that read_only is being set to true.

Let's take a look at the note widget template:

<?python   from whatwhat.utils import textilize, getGroups   from turbogears.i18n.format import format_date   from turbogears import identity   groupids = getGroups() ?> <li xmlns:py="http://purl.org/kid/ns#"     onmouseover="show_inline('remove_note_link_$note.id');show_inline('edit_note_ link_$note.id')"   onmouseout="hide('remove_note_link_$note.id'); hide('edit_note_link_$note. id');">     <div  >       <div>${XML(textilize(note.note))}</div>         <div py:if="note.last_edit_date != None">           <i>Last edited:              ${format_date(note.last_edit_date, time_format=' %I:%M %p')}           </i>         </div>       <br/>       <div >         <span> Posted by            <a                href="mailto:$note.creator.emailAddress">            ${note.creator.displayName}</a>           on ${format_date(note.creation_date, time_format=' %I:%M %p')}         </span>         <a py:if="(identity.current.user == note.creator or 'admin' in groupids) and not read_only"            style="display: none"  href="#"             onclick="request_note_content($note.id); return false;">edit         </a>         <a py:if="(identity.current.user == note.creator or 'admin' in groupids) and not read_only"            style="display: none"  href="#"             onclick="remove_note($note.id); return false;">remove    </a>       </div>     </div>   <div py:if="not read_only"   style="display: none;">     <textarea style="display: block; width: 540px; height: 275px;"                   name="content" rows="16" cols="74">     </textarea><br/>     <a href="#" onclick="edit_note($note.id); return false;">save</a>     <a href="#" onclick="cancel_edit($note.id); return false;">cancel</a>     <br/>   </div> </li>


By moving all this code out of the RecentChanges template and the projects page, the authors of WhatWhat Status are reducing code duplication. There's a lot of JavaScript in this widget (which we look at in more depth in Chapter 9, "Ajax and WhatWhat Status Projects"): but in this case, the template passed in read_only=true, so most of the dynamic sections of this widget are not executed. Either way, the most important piece of this widget is this little bit of code: <div>${XML(textilize(note.note))}</div>. It takes a note instance from the database, processes it, and then renders the resulting XHTML out to the page.

The authors of WhatWhat Status wanted to enable users to use italics, bold, and other markup in their text. So, they are providing access to the textual markup language to their users. Lucky for us, there is an easy-to-use Python language interpreter for textile already built, so theoretically all that is needed is to import the proper module and pass our note text through the textile function. Because there's a little bit of added complexity to make sure that the results of textilize are encoded in UTF-8 (to match the default encoding of our Kid template), the authors of WhatWhat Status wrapped textile up in a helper function, which they keep in the whatwhat.utils module:

def textilize(unicodeStr):     return textile(escape(unicodeStr).encode('utf-8'), encoding='utf-8', output='utf-8')


Note that if you just pass the result of textalize into Kid using ${textilize (someString)}, you probably won't like the results you get.

Normally, Kid takes whatever strings you pass it and escapes them into proper HTML, so special charaters such as < and & become &lt; and &amp; which are then recognized by the browser and turned back into the < and & characters for display to your user.

If Kid didn't escape these characters from the strings you pass in, it would create invalid XML, and broken HTML, and things would start to look pretty darned funny in the browser. But sometimes you already have the XHTML and you just want it displayed, and that's where Kid's XML function comes in. XML(value) bypasses Kid's escaping mechanism, and slides your XHTML right into Kid. By default, Kid then turns it into HTML from XML the same way that it processes any other XHTML to produce the final page output.

Beyond inserting the text for the note, the note (when in read-only mode) will just display the author's name with a link to her e-mail address, along with that note's creation date:

  <span>  Posted by      <a          href="mailto:$note.creator.emailAddress">       ${note.creator.displayName}</a>      on ${format_date(note.creation_date, time_format=' %I:%M %p')}   </span>


Everything else is inside a py:if block, which will not be executed if read_only = true. But don't worry, we aren't going to skip over this stuff for long; it features prominently in Chapter 9, where we discuss the details of how WhatWhat Status's project page works and peer a little bit more deeply into WhatWhat Status's use of JavaScript and Ajax.




Rapid Web Applications with TurboGears(c) Using Python to Create Ajax-Powered Sites
Rapid Web Applications with TurboGears: Using Python to Create Ajax-Powered Sites
ISBN: 0132433885
EAN: 2147483647
Year: 2006
Pages: 202

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net