Do you dojo? Dojo is the JavaScript toolkit that I'm going to use from now on. Why? Well I did a quick eval of most of the toolkits out there, and it made the best impression. I wasn't looking for database-oriented features. I was looking more for something to help me put together DHTML interfaces.
The thing is, when you enter a new programming space you are faced with a real challenge to your time. You can't properly evaluate each option, because that means learning each system completely. And for programmers, since most learning is done by doing, that would just take too much time. If you can find some neutral reviews of the options in your chosen area, great. But what you find most often are opposing position statements – heartfelt defences of chosen frameworks and thinly disguised contempt for the other options.
My approach in this case is to check out each site, check the level of activity, the state of the docs, the overall approach, the background of the main committers, all that stuff. But not exhaustively. You want to trust your intuition. After all, the right framework for you might not be the “best” framework, the one to rule them all. So, Blink.
I opened my eyes, and I saw dojo. Whojo? It's the JavaScript stuff behind JotSpot, apparently. Technically it's a merger of several extant frameworks into a sort of JavaScript Gestalt. In other words, a great big grab-bag of JavaScript goodies! And they have a pretty website!
The real biggie for any JavaScript toolkit is HTTP request handling. Hiding all that dodgy XMLHttpRequest crap. Such a humane interface (NOT). And dojo sure does it nicely. I decided to use dojo for the online demo of my new product: XML Manager Demo. This demo submits an XML document for server-side parsing, and includes a set of XPath expressions defining what to parse out of the document. If you use dojo together with the JSON data format, the whole thing is a cinch. Here's the request code:
dojo.io.bind({ url: 'demo-handler.htm', method: 'post', postContent: jsonquerystr, handle: function(type, data, evt){ if( type == 'load' ){ jso = JSON.parse(data); if( jso.data ) { setTableData( jso.data ); } else if( jso.xml ) { setXmlData( jso.xml ); } setMessage( jso.stats+ (jso.msg?jso.msg:'') ); } else { setMessage( "Sorry, "+ "there's been a server error." ); } }, mimetype: 'text/plain' });
Pretty nifty huh? If you want to see the whole thing, here's the code: <a href="http://www.ricebridge.com/products/xmlman/demo.js">demo.js</a>
(Yeah, I know, that code needs some cleanup – hey, it's on the to-do list…).
The only little problem is that there is no user feedback when the demo is on the server-side doing the XML parsing. The user just has to wait. Not so good.
Ages ago I had a similar problem with the back office admin site of a client. Now I was using a hacked together pre-AJAX solution – an invisible iframe
with a hard-coded form
. But it worked pretty like the modern AJAX model. Anyway, I had the same problem: how to provide feedback to the user when a request has been submitted behind the scenes.
What I wanted was a progress bar. It would start with a set of grey boxes and change them blue one by one until the request was done. Of course, we have the little issue of not knowing how long the server is going to take. So the idea I came up with was to make it an exponential progress bar. Each little box takes longer than the last one, rather than all boxes dividing the time equally. So you never actually get to the final box. Instead, when the server returns, you mark the boxes that have turned blue a darker gray. What you are left with is an indication of how long the request will take the next time (based on the principla that, as a general rule of thumb, tomorrow's weather has a 70% probability of being the same as today's). This turns out to work rather well, and users pick it up right away without explanation. The whole thing is completely visual.
So this what I want for my demo, a web progress bar, not a desktop progress bar. So at first I was just going to cut-and-paste (ah the joys of being a professional!) the old code over to my site. But then I thought: hold on, what if I write a dojo widget to do this? Coolaboola says I, we'll do this properly!
Well, it turns out that dojo is, um, challenged, in the documentation domain. But they do have starter article on widget writing. It does tell you pretty much all you need to know to write a dojo widget. And that's the problem. I don't want to write a dojo widget, I want to write my own widget. Hey, I might submit it to the project later, but for the moment, as a good engineer, I want to keep my custom stuff from polluting the dojo framework. Hmm.
So here then is my first utterly simple and completely pointless widget, to be morphed into a progress bar live on this blog! All it does is display the word “Foo” with a border. But it is a proper dojo widget, and it is as separate as possible from the main dojo code. I say, “as possible”, because complete separation turns out to be, well, difficult. I am just hacking about here, so bear with me.
Dojo widgets have their own HTML and CSS files. I placed the files for my Foo
widget in the same folder as the test HTML page. Here they are:
foo.html
<div class="foo"><b>Foo</b></div>
foo.css
div.foo { border: 1px solid black; }
Whoopy-doo, says you. Indeed. But hey, it's a start.
So the main page, the page with the user interface, looks like this:
usefoo.htm
<html> <head> <script type="text/javascript"> var djConfig = {isDebug: true}; </script> <script src="dojo.js"></script> <script> dojo.require("dojo.widget.*"); dojo.require("dojo.widget.Foo"); </script> </head> <body> <div dojoType="foo"> </div> </body> </html>
Notice the isDebug
declaration. That's real handy. Use it.
The dojo require
statements are a dojoism that tells the dojo system about the widget support code that we need. It's standard dojo stuff and covered in their docs. The div
with the dojoType
attribute is where the magic happens. This makes our Foo
widget appear.
Now for the widget code itself. This pretty much a direct copy from their example.
src/widget/Foo.js
dojo.provide("dojo.widget.HtmlFoo"); dojo.provide("dojo.widget.Foo"); dojo.require("dojo.widget.*"); dojo.widget.HtmlFoo = function(){ dojo.widget.HtmlWidget.call(this); this.templatePath = dojo.uri.dojoUri("foo.html"); this.templateCssPath = dojo.uri.dojoUri("foo.css"); this.widgetType = "Foo"; } dj_inherits(dojo.widget.HtmlFoo, dojo.widget.HtmlWidget); dojo.widget.tags.addParseTreeHandler("dojo:Foo");
This is just the object-oriented JavaScript that defines the Foo
widget. I still have a pretty weak grasp of all this, so let's just leave it as an artefact and move on. Suffice to say that you need the Html
prefix on your widget name, otherwise the voodoo won't work.
The tricky bit is where you put this file. You have to put it in a folder structure where dojo can find it. It needs to be under src/widget
, relative to your main HTML user interface file. Why? Dunno, just does.
And amazingly, the whole thing works. Next time I'll be blogging about my attempts to get this toy code to actually do something. I still want that web progress bar. Hopefully this blog entry will save you the half hour of trial-and-error I spent on this.
One final word, to the dojo guys. Love your stuff, but please just stop coding and write some docs. Pretty please? Cherry etc?