5.9.05. Prototype.js and Mochikit

I've mentioned here before that I was impressed with the prototype.js library. It's a few months later and I now have a real Zope 3 project under my belt that has utilized the prototype.js library and the Scriptaculous that builds on top it. There were some great things that I was able to do with these two libraries - Drag and drop reordering? Just a couple of lines of Javascript and just a couple of lines of code in a browser view in Zope. Nicely, the data returned from the Scriptaculous reorderable functions is exactly what IOrderedContent.updateContent wanted in Zope. (Note - I did have to replace a Scriptaculous 'serialize' function, which encoded the list URI in a Rails friendly way to do so in a Zope friendly way).

So there have been some things to like about Prototype.js and friends so far:

  1. Visual effects for effective communication (or gross overuse) doable with just a couple of lines of code.
  2. Ajax Requests are pretty easy.
  3. Referring to elements with $('someobj') is much easier to type and remember than document.getElementById('someobj'), especially since $(this.form) is nice as well. Passing DOM elements around by their ID or by the DOM object itself is fine.

Finally, it seems that the religion of Prototype.js is that most of the heavy lifting logic is still expected to be done on the server, requiring very little Javascript code on the client to accomplish some really nice and useful (or annoying) effects and communications. I don't know if that was really the design goal, but that's the feeling. It's not a bad feeling, per se, and the way that prototype.js and scriptaculous have been merged into Ruby on Rails has probably helped blur the lines between server side display logic and client side display logic even further.

But Prototype.js also seems to do some monkeying with the core Javascript object system. At least, that's the complaint made by the developers of Mochikit. There are some things that they claim it breaks, such as for(var i in obj), and I believe I've now seen this breakage in action. Using Prototype.js and friends seems to be OK, as long as you stay in their universe. MochiKit takes another stance. It provides more functional programming techniques, whereas Prototype.js provides a more object-oriented experience. MochiKit is inspired by Python (and its main developers are seasoned Python and Objective C/Cocoa developers), and provides Python style namespaces. While many of the exported functions from MochiKit are available from their direct name, there's always a full name to access them, which helps avoid name conflicts.

There are some other differences in approach as well. Prototype.js's documentation lies basically in its code and whatever examples one might be able to dig up. Strangely enough, I do find most Prototype.js and Scriptaculous code readable enough for me to figure out what to use and the basics of how to use it. The number of concepts seem quite simple, really, and that which I haven't needed to use I've been able to ignore. Mochikit is rather well documented, includes plenty of doc strings, and is also backed by unit tests. MochiKit is a much larger system and covers a few different areas of coverage. It includes not only plenty of DOM manipulation, but also iteration support, including many of the functions seen now in Python's itertools module. MochiKit covers Asynchronous programming, inspired by the event driven network programming framework for Python, Twisted - specifically its Deffered objects (which I admit make my head explode). The MochiKit.Async package covers XMLHttpRequest communication, part of the core AJAX experience.

A quick comparison of a simple Ajax setup in each. This is from a function that I wrote that calls a URL, but before making the call it shows an 'updatemsg' element. When the call is successful, the message fades out. The first half is the MochiKit.Async way. The second half, commented out, is the Prototype.js way.

foo.bar.requestWithUpdateMessage = function(url, queryString) {
  var req = MochiKit.Async.getXMLHttpRequest();
  req.open("POST", url);
  
  Element.show('updatemsg');
  // d is a MochiKit.Async.Deferred object.
  var d = MochiKit.Async.sendXMLHttpRequest(req, queryString);
  d.addBoth(function(transport) {
    Effect.Fade('updatemsg', {duration: 1.2});
  });

  /*
  new Ajax.Request(url, {
    parameters: queryString,
    onLoading: function(transport) {
      Element.show('updatemsg');
      },
    onComplete: function(transport) {
      Effect.Fade('updatemsg', {duration: 1.2});
      }
    });
    */
}
They're both pretty good ways of doing things - this is a lot easier than manually grappling with finding the correct XMLHttpRequest object in the browser and setting up the callbacks yourself. But you can see the difference in programming style.

I've also done some work with MochiKit.Base, which boasts some wonderful tools familiar to Python programmers, as well as some nice partial and binding support. Using MochiKit.Base.bind, I was able to write some AJAX client functions and turn them into methods bound to an instance, effectively creating a client stub that mirrored server side functionality. Last week, I had this code boiled down to a collection of three-line methods that were all the same except for their parameters and the target URL endpoint. Today, I now have those replaced with single line declarations:

ContentsClient = function(baseUrl) {
  this.baseURL = baseUrl;

  this.editTitleFragment = bind(updateClientWithMessage, this, 'editTitleFragment', ['name']);
  this.cancelTitle = bind(updateClientWithMessage, this, 'cancelTitle', ['name']);
  this.updateTitle = bind(updateClientWithMessage, this, 'updateTitle', ['name','title']);
}
I'm envisioning a day when I can write a server side view that queries a Zope Interface object for method signatures that can generate a JSON description on the fly to build one of these Client objects... But I don't have need for that yet.

Finally, there's MochiKit.Logging, which amongst other things gives very nice logging support - "MochiKit.Logging - we're all tired of alert()." Using log('bla bla bla') plus a simple bookmarklet makes Javascript development much nicer, especially in an increasingly event driven browser client world.

Really finally - I was able to take the MochiKit Sortable Tables demo and apply it to my CMS interface with ease - even modifying it some so that not all columns instantly become sortable, and adding integer and float support to the sort functionality. Table sorting is not a core MochiKit piece of functionality, but is instead just shown in a demo to show how the MochiKit parts can work together.

Great work!