farmdev

Degradable Ajax by Sharing Mako Templates With Dojo

For a Pylons site I have been working on I wanted to provide Ajax functionality for the users but also allow the content to be crawled by search engines. Let me point out that not all of the Ajax content needs to degrade to static HTML, only the content that a user might search for on a search engine. Some people might decide that none of their site needs to be crawled by search engines, say, if it was Gmail or something similar.

Since the site is using Pylons it also uses Mako for templating and on the JavaScript side it uses the Dojo toolkit. The easiest way to render content dynamically (via altering the DOM in JavaScript) and render static HTML seemed to be by sharing my templates between Pylons and Dojo. While probably not the most elegant solution, here's how I did it.

Mako allows you to make small template snippets that have a variable signature defined by a page tag. For example, here is img_box.mako

<%page args="href, src, alt, height, width" />
<div class="img_box"
    ><a href="${href}"
        ><img src="${src}" alt="${alt}"
              height="${height}" width="${width}"
/></a></div>

As luck would have it, this curly brace interpolation format is already compatible with Dojo templates so with some regular expressions to strip out the page tag it can be used by Dojo. I should mention that although the whitespace between tags in the above example looks funny it helps Dojo to parse the template faster.

In the Mako template for HTML rendering, img_box.mako can be displayed like this:

% for img in images:
    <%include file="img_box.mak"
                    args="href=img.href,
                          src=img.src,
                          alt=img.alt,
                          height=img.height,
                          width=img.width" />
% endfor

To expose the templates to Dojo, I just added each one as a JavaScript variable in the head of the HTML page, with code like this

<script type="text/javascript">
    myapp.templates.img_box = ${h.share_tpl_with_dojo('img_box.mako')};
    // etc ...
</script>

h is a reference to my custom Pylons helper module and share_tpl_with_dojo() just strips out the page tag using the regex <%page.*/>\s* then quotes the template string for use as a JavaScript variable.

Finally, the template string is applied to my custom Dojo Dijit with code similar to this

dojo.declare("myapp.ImageBox", [dijit._Widget,
                                dijit._Templated], {
    // these vars get set when the dijit is
    // instantiated (i.e. XHR request) ...
    src: null,
    alt: null,
    href: null,
    width: 0,
    height: 0,

    render: function() {
        var node = this.domNode;
        // renders the template using this as the context :
        node.innerHTML = this._stringRepl(this.templateString);
    },

    templateString: myapp.templates.img_box
});

There you have it. I mainly posted this as a nudge for Daniel Greenfield ;) to share some ideas for how he's been doing this in Django + jQuery. I'm currently working on a Pinax-based site with some Ajax goodness but I haven't yet had time to think about making the Ajax degradable in a DRY kinda way.