Tuesday, 18 March 2008

Templating made nicer with Jaxer, dijit and dojo.query

Once upon a time dojo had markup ability using custom tags. This was pulled because as it turns out, some browsers just scrap tags they don't understand. One browser that did support tags of a non HTML nature though was Mozilla and in turn we get this freedom back via Jaxer.

So in this knowledge, I did a quick concept mock-up. And in essence the gain can be varying depending on the amount of work you want the back end to do.

In it's simplest form, we can change

<div dojoType="dijit.form.button" label="test"></div>

into
<dijit dojoType="dijit.form.button" label="test"></dijit>

and simply do a server-side rebadging of the nodes so our gain is mostly readability of tags.

But I wanted something a little more exciting. I've been working with JSF and JSTL on and off and am pretty familiar with the notion of a tag, render/component definition and tag definition in a config file. What this gives us is a splitting of code, presentation and config.

So following that blueprint I created a tag definition that looks something like this:

tags: {       
dijit:{
button: {
include: "dijit.form.Button",
dojoType: "dijit.form.Button",
passthrough:['label', 'iconClass', 'showLabel'],
passthroughContent: true
},
numberspinner: {
include: "dijit.form.NumberSpinner",
dojoType: "dijit.form.NumberSpinner",
passthrough:['constraints', 'value']
}
}
}


Here we have a reference to what include is needed, the dojoType and any passthrough tag attributes we might need. The passthrough is really an optional concept but I kind of like making safe the information that gets taken from the tag and pushed to the widget.

Next how to call it. Simply put:

<dijit type="button" label="test2"></dijit>


And lastly...the processor. Well usually we kick things off with a dojo.addOnLoad but that's not applicable in Jaxer land (at the moment) so instead we start things using a connect and the "onserverload" event.

The processor does the following:
  1. Loop over the the tag definition object grabbing the first level child nodes. These nodes are the actual tag names to search for so in our case we have "dijit".
  2. Use dojo.query to find every instance of custom tags like "dijit" and add them to a queue.
  3. Loop over the queue, first checking each node for content that has a dijit tag in it. If so add it to the back of the queue so that we process from inside content to outside parent tags.
  4. Continuing with the node, use its type to find the definition in the tag definition set and convert the node into a div tag with a dojoType attribute.
  5. Pull over a base set of attributes like id, name, style and then the pass through attributes.
  6. Add the specified require to an object for later.
  7. If necessary, pull content of the dijit tag over to the div tag.
  8. When all nodes are processed, loop over the require object building up a series of dojo.require statements.
  9. Add the require statements to a script block in the page and make sure it's set to runat='client'
With this process we convert all nodes to the expected divs and neatly contain all dojo.requires in one place. This means we can now create a simple reference in a custom tag to a more elaborate template configuration and backend generation. It really feels like an evolution of JSTL in some ways.

Does it work? My proof of concept code says yes and I've taken it further so that instead of replacing dijit tags with divs we replace it with programmatic instantiation. This idea is even better in some ways as it takes some of the heavy lifting away from the parser. The client-side only has to worry about code execution and not only that we can use the backend to accumulate code and keep it tidy just as we did with accumulating the dojo.requires and then outputting them in one place. Having said that I've been really impressed at recent optimizations with the parser.

It's worth noting that this as always is a "what if" experiment and should not be taken as perfect or an enterprise solution

From my quick trials one of the key advantages with Jaxer has been the ability for the server to keep track of various page level pieces of information and then arrange them neatly for the client-side. The fact that it's Mozilla-like at the back end effortlessly supporting the required features is really refreshing.

3 comments:

Kevin said...

Tony--

This sounds like great stuff. Do you plan to share the source for this and evolve it? Is this something you'd like to contribute to the Aptana community?

-khakman (at) aptana.com

Tony Issakov said...

At this point I'm still tinkering with ideas more than solutions. As I get time to play around I'll put some working examples up.

dante hicks said...

Tony --
Great blog. For my own ease (and others). I'd love to roll this feed
into Planet Dojo, but Drupal hates Atom ...

Keep it up --

dante (at) dojotoolkit.org