Section 9.3. A First Look at project.kid


9.3. A First Look at project.kid

Let's take a look at project.kid. This is certainly the longest bit of code we've seen so far, and there's lots of new stuff in here.

We'll take a multipass approach where we run through the whole template at rather high speed to get a lay of the land, and then we'll take a slightly deeper look at scripting the DOM, using lots of examples from this template and master.js and project.js, and then we'll circle back around a third time to look at how you can meld server calls with simple DOM manipulation to achieve that "dynamic Ajax-driven" website effect that everybody seems to want these days.

9.3.1. Laying the Groundwork for Our Project Page

The first thing you should see in the project.kid file is a <?python> tag:

<?python          from whatwhat.model import STATUS_BEHIND_SCHEDULE          from whatwhat.utils import textilize          def get_display_notes(project, show_all_notes):                  if show_all_notes:                          return project.notes                  return project.recent_notes ?>


This should look familiar to you. The project.kid template starts out with a quick bit of Python that imports the textilize function (which we explored in Chapter 8, "RSS, Cookies, and Dynamic Views in WhatWhat Status"), and the behind-schedule status identifier. The get_display_notes function is new, but it should be pretty easy to see what it does. If the show_all_notes value is true, it returns a list of all the notes; otherwise, it returns just a list of recent notes.

Next we see the header, which shows a bunch of JavaScript imports. In addition to what we see here, there is a "hidden" import at work. TurboGears includes an option to import MochiKit on every page of your application. That way you don't have to bother to manually import it in your template, and WhatWhat Status makes use of that option to get MochiKit on every page.

In addition to the basic JavaScript improvements and Ajax helpers that MochiKit provides, WhatWhat Status uses some third-party visual effects to provide users with feedback as Ajax things happen. So, they import prototype, and scriptaculous, along with several scriptaculous libraries.

As I write this there is a functional port of the scriptaculous visual effects libraries sitting in the trunk of MochiKit's subversion repository, so there is an extremely high probability that you won't have to import all of this into your projects. You can just use MochiKit's visual effects library.

Here's the section of project.kid that does all the JavaScript library imports:

<head>   <meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>   <title>WhatWhat Status - Project Details for ${project.name}</title>   <script src="/books/4/370/1/html/2//static/javascript/master.js"    type="text/javascript"></script>   <script src="/books/4/370/1/html/2//static/javascript/project.js"    type="text/javascript"></script>   <script src="/books/4/370/1/html/2//static/javascript/thirdparty/prototype.js"    type="text/javascript"></script>   <script src="/books/4/370/1/html/2//static/javascript/thirdparty/scriptaculous.js"    type="text/javascript"></script>   <script src="/books/4/370/1/html/2//static/javascript/thirdparty/effects.js"    type="text/javascript"></script>   <script src="/books/4/370/1/html/2//static/javascript/thirdparty/slider.js"    type="text/javascript"></script>   <script src="/books/4/370/1/html/2//static/javascript/thirdparty/builder.js"    type="text/javascript"></script>   <script src="/books/4/370/1/html/2//static/javascript/thirdparty/controls.js"    type="text/javascript"></script>


In addition to importing JavaScript libraries, you can always define page-specific functions right there in your page header. If for some reason you need to use dynamically generated JavaScript, this is probably the easiest place to do it. Fortunately, WhatWhat Status just needs to prevent huge notes from being added to the database, so they created a check_note_length function to ensure that notes are always fewer than 1500 characters.

  <script type="text/javascript">   //<![CDATA[         function check_note_length(note){               var note = document.getElementById(note);               if (note.value.length >= 1500) {                       alert('Please use separate notes for lengthy posts');                       note.focus();                            return false;                       }               return true;         }   //]]>   </script>   <link href="/static/css/master.css" media="screen" rel="Stylesheet"   type="text/css" />   <link href="/static/css/project.css" media="screen" rel="Stylesheet"   type="text/css" /> </head>


And the head portion of our template is rounded out by a couple of links to the stylesheets that make things look nice on our page.

9.3.2. Using Ajax to Update Project Status and Descriptions

Right at the top of our template body, we see the project name, description, and project status edit box.

These are created with the following code from the template:

As you can see, the update_project function is called whenever the status is changed. This same function is called whenever the description or project contact is updated, so let's take a closer look at it now:

This little JavaScript function uses several MochiKit helpers to make the Ajax stuff easier. The most central is the sendXMLHttpRequest object, which abstracts away the various different HTTPRequest objects for IE-5, IE-6, and the more standards compliant browsers such as Firefox and Safari. Not only that, it handles the asyncronous part of Ajax for you, too. You just use the addCallback method on the sendXMLHttpRequest object to set up a function to handle the server response. This tells the browser which function to call when it receives a response from the server. If you didn't do this all asyncronously, the browser would just lock up until the server responded to the request.

In this case, the callback function is update_project_callback, which takes the JSON that is returned by the server, evaluates it, and updates the description and contact content using the innerHTML method discussed in Chapter 8. This is kind of an interesting hybrid approach. We mentioned earlier in this chapter that you can return plain XHTML or JSON, but in this case the server is returning two XHTML fragments wrapped in a JSON object. This allows WhatWhat Status to update the contact and description elements in a single request.

If you are particularly quick, you'll notice that the project status is updated on the server, but the status is not changed in the browser after that update is done. And if you're really quick, you've already figured out why: The status box is updated by the user, before this function is called, and will already match what was sent to the server.

Before we move on, let's take a quick look at the code on the server that is called by this little update_project JavaScript function.

[View full width]

@tg.expose(allow_json=True) @tg.validate(validators=dict(contact_id=validators.Int(), status=validators. Int(), description=validators.String())) def update_project(self, contact_id, status, description): contact = Person.get(contact_id) project = Project.get(self._active_project_id()) project.set(status=int(status), contact=contact, description=description) contact_content = '<a href="mailto:%s">%s</a>' % (contact.emailAddress, contact. displayName) desc = textile(description.encode('utf-8'), encoding='utf-8', output='ascii') return dict(success=True, description=desc, contact=contact_content)


On the controller, the update_project method has two responsibilities. First, it has to take the updates sent in by our JavaScript and modify our model objects (and therefore our database) accordingly. And second, it has to return a JSON object containing three elements: a Boolean that tells the browser that the server update was successful, and two XHTML fragments that contain contact info, and the project description. Just like any HTTP Post, the values contact_id, status, and description are parsed out of the HTTP request by CherryPy and passed into the update_project method as parameters. The relevant project and contact objects are retrieved from their SQLObject classes, and the project is updated with the values sent in over the Ajax request.

When that's all done, the contact and desc XHTML fragments are set up, and the whole dictionary is returned as a JSON object. The tg.expose(allow_json=True) declares that it is okay for this function to return JSON, if that's what you ask for. And the way you ask is to send in a parameter tg_format='json'. This alerts the controller that what you want back is a JSON object, and it uses Bob Ippolito's simple_json package to turn the resulting dictionary into a JSON object. On its own, simple_json can handle native Python types; but if you include other objects in your dictionary, this might not work automatically for you. TurboGears makes extending simple_json easy, and even includes a file for your custom serialize in its standard quickstart. In this case, however, everything is standard, and it is automatically serialized.

There's a lot more code in the WhatWhat Status project template, but you should be able to work your way through all of it on your own.




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