Infrequently Noted

Alex Russell on browsers, standards, and the process of progress.

Dojo 1.1: Some Awesome For You App

I could go on for a long, long time about what's great in Dojo 1.1...but I'll spare you most of that. James, Pete, Dylan, and the release notes can give you a strong sense of why Dojo 1.1 is the most polished, fastest, and easiest-to-use release of Dojo we've ever done. For the impatient, you can already start using it from the CDN without downloading anything.

I should mention a couple of Core features from 1.1 that might otherwise go overlooked, though. The first is a lack of visible change. Dojo Core and Dijit from 1.1 are fully backwards compatible with 1.0. We promised that the fundamental incompatibility between 0.4.x and 0.9.x+ was a one-time change, and Dojo 1.1 keeps that promise. We've already had reports during the RC cycle of people swapping out Dojo 1.1 for 1.0 without any changes to their apps. It takes dedication and discipline across the entire team to achieve that kind of API stability while still taking risks to deliver better features, reliability, and performance.

Next up, we updated the animation APIs significantly. In Dojo 1.0, we moved to a unified timing loop for animations which helped to significantly improve the performance of Dojo animations. In 1.1, we've again improved the performance of the animation system but have also added some great syntactic sugar to the already powerful APIs which we expose. As always, start and end coordinates for an animation can be values or functions which return calculated starting and ending positions. Now, though, you can elide away the { end: 30 } structure and just provide a value. This lets us go from:

dojo.animateProperty({
    node: "thinger",
    duration: 500,
    properties: {
        width: { end: 500 },
        height: { end: 500 }
    }
}).play();

To just:

dojo.animateProperty({
    node: "thinger",
    duration: 500,
    properties: { width: 500 , height: 500 }
}).play();

But to get even more terse, we'll need a different API structure that doesn't require so much explicit argument packing. Dojo 1.1 adds just such an API:

dojo.anim("thinger", { width: 500, height: 500 }, 500);

Note that in addition to being able to drop a lot of stuff out of the function call, dojo.anim also doesn't require that we call .play() on its returned animation object since in the common case you'll just want to play right away.

Next up, Dojo now has a unified dojo.xhr() function that covers a lot of bases and gives you a single entry point into the various bits of XHR goodness contained in dojo.js.

As I've noted elsewhere, Dojo is also now supporting querySelectorAll on the browsers that support it sanely. Dojo's CSS engine has always been fast, and by keeping our query syntax to just what CSS provides, we've avoided getting ourselves into a situation where we'll always need to be shipping such a query engine down the wire. Sooner or later, dojo.query() will become nothing more than a call into querySelectorAll plus some syntactic sugar on the returned array. Best yet, API won't change and you can get the speedup on the browsers that support it now, knowing full-well that things will only get faster and smaller in the future. An investment in a toolkit that is pays attention to the evolution of the web is already paying dividends for Dojo users.

Lastly (for now), there have been some fun additions to the API of dojo.NodeList, the thing that's returned out of every call to dojo.query(). dojo.attr() and dojo.anim() are now available on groups of nodes. For instance, we can make a group of elements tab-focusable on browsers that support it and then draw some attention to them:

dojo.require("dojo.NodeList-fx");

dojo.query("#nav > .focusable"). attr("tabIndex", 0). style("border", "1px solid transparent"). anim({ "borderColor": { start: "yellow", end: "white" } });

There's also a new empty() method on node lists which makes removing children simpler, and the instantiate() method which helps you create instances of a class for every item in the list. Lets say you want to encapsulate some behavior in a class. You could use the hotness that is dojo.behavior or you could use the traditional combination of the Dijit base classes plus the Core parser system. Or you could strike out on your own, particularly for implementing something like a microformat handling library:

// define a Card class which we can create instances of
dojo.declare("mf.Card", null, {
    constructor: function(props, node){
        this.setAddrs(dojo.query("> .adr", node));
        this.setName(dojo.query(".fn, .n", node));
        // ...
    },
    name: null,
    addrs: [],
    tels: [],
    emails: [],
    // ...
});

dojo.query(".vcard").instantiate(mf.Card);

Taken together, these extensions make dojo.query significantly more powerful. There's also a growing set of extensions to node lists, such as those for easy templating of generated content via dojox.dtl. We've also taken care to ensure that anywhere that Dojo returns you an array of nodes, it'll probably be handing you a dojo.NodeList. That means you can treat these arrays as regular, intrinsic Array instances, or you can use these chainable methods for added node-manipulating power.

An Aside

The team that put together Dojo 1.1 is really, truly, amazing and it shows in the end product.

When it became clear that we had a responsibility to the a11y of Dojo application, they built it and shipped solutions. While others still aren't thinking about localization, they built it and shipped solutions to right-to-left as well as string handling (including optimizing those processes for deployment). When it became clear that the CSS file structure for building themes was too hard, they fixed it...in a 100% backwards compatible way. When Dojo was "dinged" for poor documentation, they did what they knew was the right thing and kept working on what is now the world's best JavaScript documentation tool.

What's most impressive to me about the Dojo team, though, is that this isn't a centrally planned, in-house operation by a giant company. There isn't a product road-map other than what's decided at the Developer Day events and in the weekly IRC meetings. Dojo is the collective work of volunteers, committers, and companies that understand that building things together in a truly open project is better for everyone. Having the source of a product be available under an OSS license gives you certain rights in an instantaneous sense, but for those advantages are usually just advantages for people already "inside" of a project. To really convert on the benefits of openness, the process of developing the product needs to be just as open as the license. Open Source business models all tacitly acknowledge that most pithy of truisms: the people on a project are its greatest asset. If new people can't join or "get in", then the project is effectively closed, and the benefits of openness can't be fully realized. Users win when advocates for their needs can emerge from more places, developers win when they can get involved and make a real difference, and a project benefits its community is really that: a group of people who show up because they want to make things better. I'm proud to be working with just such a dedicated group on Dojo.

During the 1.1 release cycle, Wolfram Kriesing and Nikolai Onken earned their committer stripes. They didn't start making Dojo better because they happened to work somewhere or because their company sells Dojo...they joined the project the way most of us did: they saw a place where they could contribute and because Dojo is run as an open project, they were able to have a huge impact. Nikolai's artwork and theme wrangling are largely responsible for Dojo 1.1 being the most attractive Dojo ever and Wolfram's code contributions have made interfacing services with dojo.data stores easier than ever before.

We've got an ambitious set of improvements slated for 1.2, and I'm confident that while it always looks slightly chaotic, the advantages of working in the open with whoever shows up will continue to pay off for everyone. If you've been a Dojo user and have thought about contributing, there's never been a better time to come find us on IRC or the forums and help to shape the future of the toolkit. You can be part of this amazing team too. It's as simple as that, really.

I can't wait to work with you to make our corner of the Open Web better.