Chapter 1. Toolkit Overview

This chapter provides an overview of Dojo's architecture, takes you through installing Dojo, introduces some domain-specific jargon, runs through the bootstrapping process, and then provides some example code that should whet your appetite for the chapters that follow. Like any other introduction, much of this chapter paints in broad strokes and sets the tone for the rest of the book. Hopefully, you'll find it helpful as you begin your journey with the toolkit.

Overview of Dojo's Architecture

As you're about to see, describing Dojo as a toolkit is no mere coincidence. In addition to providing a JavaScript standard library of sorts, Dojo also packs a collection of feature-rich, turnkey widgets that require little to no JavaScript coding at all, build tools, a testing framework, and more. This section provides an overview of Dojo's architecture from a broad point of view, shown in Figure 1-1. As you'll see, the organization for the rest of this book is largely driven by the toolkit's architecture. Even though DojoX is displayed as an independent entity from Dijit, DojoX resources could also be built upon Dijit resources, just as your own custom widgets could leverage any combination of Dijit and DojoX resources.

One depiction of how the various Dojo components can be thought of as relating to one another
Figure 1-1. One depiction of how the various Dojo components can be thought of as relating to one another

Base

The kernel of Dojo is Base, an ultra-compact, highly optimized library that provides the foundation for everything else in the toolkit. Among other things, Base provides convenient language and AJAX utilities, a packaging system that allows you to pull in Dojo resources on-the-fly instead of requiring them to all be slurped in when the page loads. It also supplies you with tools for creating and manipulating inheritance hierarchies, a means of almost universally querying the DOM using CSS3 selectors, and a fabric that standardizes DOM events amongst various browsers. Everything that Base provides is available in the top level of the toolkit's namespace as a dojo.* function or attribute. Base comes packaged as a single file, dojo.js, which comes across the wire at under 30KB, and when you consider that most Flash-based advertisements that inundate the web are considerably larger than 30KB, such a small number seems quite amazing.

If you look at the actual size of dojo.js on disk, you'll see that it is around 80KB, but because web servers generally process content as it comes "across the wire" to the browser, it's the size of the compressed content that drives the amount of time it takes to download. If you manually apply gzip compression to dojo.js, you should see that it reduces in size by about one-third of the original size.

One other really interesting thing about Base is that it is designed to bootstrap the Dojo essentials automatically by simply including the dojo.js file into the page. To oversimplify things a bit, bootstrapping basically entails detecting the environment, smoothing out browser incompatibilities, and loading the dojo namespace. Various configuration options can also be specified to automatically parse any widgets in the page and perform other initialization tasks. (All coming up in future chapters.)

Base provides a tremendous wealth of utility for many standard operations you'll commonly need to achieve when doing just about anything in JavaScript. Even if you don't use anything else in the toolkit, Base will probably be a valuable resource that you won't want to live without once you've experienced the productivity boost it provides. There is no Dojo without Base; everything in the toolkit depends or builds on it one way or another.

With the contents of the Base being settled and fairly uniform, the terms "Base" is being used less and less within the project as time goes on, and you may even hear the term "Base" used interchangeably with "dojo.js."

Core

Core builds on Base by offering additional facilities for parsing widgets, advanced animation effects, drag-and-drop facilities, internationalization (i18n), back-button handling, managing cookies, and more. Resources available through Core are often used frequently and provide fundamental support for common operations, but were not deemed universal enough to include in Base. Although the distinction between what did and didn't make it into Core may not be a perfect boundary, Dojo's packaging system trivializes the amount of effort required to pull in additional modules and resources as needed with a simple mechanism that works like a #include from C or an import statement from Java.

In general, distinguishing between Base and Core is simple: any module or resource that you have to explicitly import into the page external to dojo.js is a part of Core if it is associated with the dojo namespace. Core facilities usually do not appear in the Base level namespace, and instead appear in a lower-level namespace such as dojo.fx or dojo.data.

Dijit

Describing Dojo as just a JavaScript standard library of sorts would only be telling you a small part of its story; Dojo also packs a fantastic library of widgets called Dijit (short for "Dojo widget") that is ready to use out of the box and often doesn't require you to write any JavaScript at all. Dijits conform to commonly accepted accessibility standards such as ARIA[7] and come with preconfigured internationalization that spans many common locales. Dijit is built directly upon Core (providing a strong testament to Core's integrity), so whenever you need a custom widget of your own devising, you'll be using the very same building blocks that were used to create everything else in Dijit. The widgets that you create with Dojo are ultra-portable and can easily be shared or deployed onto any web server or often even run locally without a web server at all via the file:// protocol.

Plugging a dijit into a page is as easy as specifying a special dojoType tag inside of an ordinary HTML tag—a dream come true for layout designers and users who aren't interested in doing a lot (or any) JavaScript programming. In fact, a key benefit of using Dijit for application developers is that it allows you to achieve incredibly rich functionality without having to dig into tedious implementation details. Even if you're more of a library-writing type or a custom widget developer, following Dijit's style and conventions ensures that your widgets will be portable and easy to use—essentials for any reusable software component.

The Dijit battery can be roughly divided into general-purpose application widgets like progress bars and modal dialogs, layout widgets like tab containers and accordion panes, and form widgets that provide super-enhanced versions of old hats like buttons and various input elements.

DojoX

DojoX is a collection of subprojects that officially stands for "Dojo Extensions," although it is often called "Extensions and Experimental." The "extensions" subprojects in DojoX accounts for stable widgets and resources that while extremely valuable just don't fit nicely into Core or Dijit; the "experimental" subprojects account for widgets that are highly volatile and in more of an incubation stage.

Each DojoX subproject is required to come with a README file that contains a synopsis of its status. Although DojoX subprojects strive to meet accessibility and internationalization initiatives consistent with Dijit, it is not generally the case that they're always quite that refined. Be that as it may, lots of heavy machinery for real world applications lives in DojoX, including the grid widget, data converters for common web services, etc. DojoX also provides a sandbox and incubator for fresh ideas, while simultaneously ensuring that the high standards and stable APIs for resources in Core and Dijit are not compromised. In that regard, DojoX strikes a sensitive balance for critical issues central to any community-supported OSS project.

Util

Util is a collection of Dojo utilities that includes a JavaScript unit-testing framework and build tools for creating custom versions of Dojo for production settings. The unit-testing framework, DOH,[8] does not have a specific coupling to Dojo and provides a simple set of constructs that can be used to automate quality assurance on any JavaScript code. After all, you do want to implement well-defined, systematic tests for your JavaScript code, don't you?

The essence of the build tools is that they shrink the size of your code and can aggregate into a set of layers, where each layer is nothing more than a collection of other JavaScript files. The compression is accomplished via ShrinkSafe, a patched version of Mozilla's powerful Rhino JavaScript engine that compresses JavaScript code without mangling public APIs, and the aggregation is accomplished with a collection of custom scripts that are also run by Rhino. Other auxiliary components in Util do things like inline HTML template strings (more on this when Dijit is formally introduced in Chapter 11) into JavaScript files—another trick for reducing latency.

While reading this section, you may understand what build tools do for you, but it may not be clear why you'd want them. In short, build tools that consolidate and minify your JavaScript code significantly reduce the HTTP latency, which yields a serious performance advantage when it comes time for production.

Like DOH, ShrinkSafe may be used independently of Dojo, and for production settings there is almost never a good reason not to use it, given that it is not uncommon for it to reduce the JavaScript footprint by 50% or more. The performance difference between loading many large JavaScript files via a series of synchronous requests and retrieving one or two compressed JavaScript files can be quite staggering.

Prepping for Development

You don't need any fancy tools nor do you have to be able to configure a beast of a web server like Apache to learn how to develop with Dojo. In fact, very few examples in this entire book require you to interact with a web server at all. Most resources will be resolved via relative paths on your local machine or they will be cross-domain loaded, so for the most part, it's just you, your favorite text editor, and your web browser.

There are three primary ways you can download Dojo and prep for development: downloading an official release, checking out the latest and greatest from Subversion, and using a cross-domain (XDomain) build that's available from AOL's Content Developer Network (CDN). Let's walk through each of these options. Although downloading an official release to your local machine may be the most typical approach, there can be specific value in the other approaches as well.

Getting Dojo

There are three primary ways you can use Dojo: downloading an official release to your local environment, checking out a copy from Subversion to your local environment, and using an XDomain build from AOL's CDN. This section walks you through each of these options.

Downloading an official release

Downloading the latest official Dojo release is by far the most traditional way to prep for development. An "official" release is really nothing more than a tagged, blessed snapshot from the Subversion repository that has been well-tested and that comes with some helpful release notes. You can find official releases of the toolkit at http://dojotoolkit.org/downloads; the only notable caveat when downloading an official release is that it does not come packaged with the build tools. To retrieve the build tools, you either need to use Subversion or download a source release, which you can find at http://download.dojotoolkit.org/.

When you uncompress the downloaded archive, you'll find it expands into a folder that has the general form dojo-release-x.y.z, where, "x," "y," and "z" correspond to the major, minor, and patch numbers for a particular release. To keep your setup and URLs as generic as possible, you may want to rename the folder in place so that it is simply called js (short for JavaScript). Other options include using server directives to alias dojo-release-x.y.z to js, or using symbolic links on Linux and Unix environments. In any case, this extra effort has the advantage of allowing you to use a relative path such as www/js to point to Dojo instead of a more brittle path such as www/dojo-release-x.y.z.

Creating a symbolic link is easy. On Linux, Mac OS X, or Unix platforms, simply execute a command of the following form from a terminal: ln -s dojo-release-x.y.z js. You can read more about symbolic links by reading the man page via the man ls command.

Once you have downloaded Dojo, you might initially be surprised that it's all not in one JavaScript file, but don't worry. A quick look at what unpacks reveals that the code base is broken into the same architectural components that we just talked about in the previous section—Base (dojo/dojo.js ), Core (dojo ), Dijit (dijit ), DojoX (dojox), and Util (util). While we'll systematically work through all of this, the only action that's required to get Base into your page is to provide the relative path to the dojo.js file (located at dojo/dojo.js via a SCRIPT tag in your page just like any other JavaScript file). Easy as pie.

Downloading from Subversion

The latest official build is probably what you want to use for development. Still, if you're interested in maintaining a copy of the Subversion repository to stay up to date with the bleeding edge, then read this section closely; it walks you through the steps involved in checking out Dojo from Subversion and getting a convenient development environment set up. Developing against the Subversion trunk might be helpful if you want to keep a close eye on a bug that's being fixed, if you want to try out a new feature that's in the works, or if you're a first-class hacker who just can't rest easy unless you're always in the know with the latest.

For the authoritative reference on Subversion, take a look at Version Control with Subversion, which is available at http://svnbook.red-bean.com/.

Dojo's Subversion repository is located at http://svn.dojotoolkit.org/src/, so start there if you're interested in skimming some code in your web browser. You'll want to check out the code from the externals view that can be accessed at http://svn.dojotoolkit.org/src/view/anon/all/trunk, however, which keeps things simple by grabbing the entire toolkit in one fell swoop.

The Subversion externals property provides a way of constructing a working copy that would normally require multiple separate checkouts. You can read more about it at http://svnbook.red-bean.com/en/1.0/ch07s03.html.

In order to check out the code, execute the following command from a terminal. (The remainder of this section assumes you've performed the checkout from inside of a folder named www.)

svn co http://svn.dojotoolkit.org/src/view/anon/all/trunk ./svn

Just as if you had downloaded an official release, you'll have an svn folder that contains subfolders corresponding to each major component of the toolkit (dojo, dijit, dojox, and util ) when your Subversion checkout completes. However, your util folder will contain the build scripts (and possibly a few other things auxiliary tools used to support the toolkit). We'll delay elaboration on Subversion details, but do note that it is not difficult to have multiple versions of Dojo around—say, the latest official release, a nightly build, and an actual checkout of the repository—and use a server directive or other means of toggling between them all, depending on which version you'd like to use at any given time.

AOL's CDN

AOL hosts a cross-domain version of Dojo on their Content Delivery Network (AOL CDN) and makes it available for you to use by simply providing a few configuration parameters and including a SCRIPT tag that points to the XDomain build of Dojo on AOL's CDN server. Because it's just that easy, all of the examples in this book use the XDomain build so there is minimal fuss when you are trying things out.

As alluded to in the previous two sections, you normally load Dojo by pointing to your own dojo.js file; specify a relative path like this one:

<script
    type="text/javascript"
    src="www/js/dojo/dojo.js">
</script>

Using AOL's XDomain build is just as easy: simply change the src reference and let Dojo (and AOL) take care of the rest. The following SCRIPT tag illustrates this process for Dojo 1.1:

<script
    type="text/javascript"
    src="http://o.aolcdn.com/dojo/1.1/dojo/dojo.xd.js">
</script>

The dojo.xd.js was emphasized in the code because if you accidentally specify dojo.js, you'll probably get an error instead of the Dojo goodness you were looking for. It is also noteworthy that the 1.1 in the src path references the latest bug release for the said version. You could request a specific bug fix release by asking for, say, 1.1.0 or 1.1.1. You may want to bookmark http://dev.aol.com/dojo because it's the ultimate authority on what versions of Dojo are available via the CDN.

Debugging with Firebug

If you've done even a trivial amount of web development, you already know that debugging can sometimes be quite painful, especially when it involves obscure differences between browsers or deviations from the W3C standards. Unfortunately, throwing in a toolkit that wields a lot of power and complexity of its own can sometimes make debugging even tougher, and this might especially be the case for the JavaScript realm that involves the dynamism of closures, dynamic typing, and inconvenient ways of producing debug messages with alert boxes. And then there was Firebug, an amazing Firefox extension that made debugging and web development a lot easier.

As a rule of thumb, you should strongly consider developing in Firefox, because Firebug in and of itself is nothing short of incredible in terms of speeding up the development cycle. You can inspect/manipulate anything in the DOM (including style) in real time, log events to the Firebug console, and get error information that's often specific enough to identify your actual problem. (Compare that to a brilliant alert box that asks, "Would you like to debug?")

Of course, do remember to verify that your design is truly cross-platform by frequently sanity testing in IE and other browsers. Although Dojo itself goes to great lengths to work around browser quirks, it is still possible that anomalies can occur—and the sooner you discover these, the better.

Firebug is an amazing tool that's hard to live without once you've experienced it. You can save yourself a lot of time if you develop in Firefox and use Firebug for all that it's worth. However, it's best to frequently test in IE (say, at least every 30 minutes) to catch any hard-to-find anomalies that might creep into your application. For example, if you leave a trailing comma after the last key/value pair in a JavaScript associative array, Firefox forgives you, but IE does not . . . and the error message you get back from IE isn't very helpful either.

By far the most common function you'll probably use from Firebug is console.log, which allows you to print information to the Firebug console from inside of your JavaScript. (We're all tired of alert boxes by now, right?)

Be advised that Dojo aims to integrate as tightly with Firebug as possible, so it comes packaged with Firebug Lite. Thus, even if you must develop in another browser, functions such as console.log are always available to you if you want them.

You can download Firefox and Firebug from http://www.getfirefox.com and http://www.getfirebug.com, respectively. Appendix A contains a Firebug tutorial that you may find helpful for development.

Browser Security Settings for Running Dojo Locally

Most of the examples in this book are designed to loaded from a locale file:// protocol, which generally works fine. However, it appears that users of Firefox 3 may need to make one small adjustment to load Dojo locally:

  1. In the address bar, type about:config and press the Enter key.

  2. Change the value of security.fileuri.origin_policy to 3 or greater.

You can read more about this issue at http://kb.mozillazine.org/Security.fileuri.origin_policy.

Lightweight Server Responses

Almost all of the content in this book can be demonstrated without a web server. To adequately demonstrate a select few pieces of the toolkit, however, it is helpful to serve up some dynamic content coming from a server. When these times arise, we'll use CherryPy (version 3.1+), an extremely easy-to-use web server that's written in Python. You can download and read all about CherryPy at http://cherrypy.org, but don't fret, you won't be derailed on your Dojo learning efforts by getting all bogged down with the details of having to learn about a new web server.

Installing CherryPy is as simple as downloading it and following a few short instructions in the README file. CherryPy installs just like any other Python module, so there isn't an exposed installation directory, per se. Unlike other, heftier server-side technologies, CherryPy just becomes readily available for you to use whenever you include it via an import statement like other Python modules. In fact, a CherryPy application is nothing more than a standalone Python application that is running its own multithreaded web server; thus, actually executing a "server-side script" is as simple as running a single command in a terminal.

All of the (very few) examples involving the need to serve up some dynamic content or explicitly get a response for the server require nothing more than a single command in a terminal, so don't be scared away—these server-side examples are for the faint of heart! Of course, you are more than welcome to skip any examples involving server-side technologies completely; a thorough discussion of what is happening will always accompany them.

For example, if you were asked to invoke the following simple application stored in a file called hello.py, you'd do nothing more than type python hello.py on the command line. That's all that it takes to have CherryPy start up and listen on port 8080 for incoming requests. Having already installed CherryPy, the import cherrypy statement shown in Example 1-1 locates it and makes it available for use.

Example 1-1. A very simple CherryPy application
1 import cherrypy
2
3 class Content:
4
5     @cherrypy.expose
6     def index(self):
7         return "Hello"
8
9     @cherrypy.expose
10     def greet(self, name=None):
11         return "Hello "+name
12
13  cherrypy.quickstart(Content(  ))

For Example 1-1, if you navigate to http://localhost:8080/ in your web browser, you would access the index method (lines 6–7) and get back the response "Hello", whereas if you navigate to http://localhost:8080/greet?name=Dojo, you'd access the greet method (lines 10–11), which processes the name query string parameter and gives back the response "Hello Dojo". That's the general pattern, and given how inherently readable Python code is, it can't get much easier than that.

While you'll never need to write or understand Python code to this book, the previous walk-through was included just to show you how quick and easy it is to do with CherryPy and Python in case you ever need or want create dynamic content of your own. Learning Python by Mark Lutz (O'Reilly) is a great reference on Python if you find yourself ever needing to work up more complex Python code. Python's official web presence at http://www.python.org and CherryPy's web site at http://www.cherrypy.org have great documentation as well.

Terminology

It will be helpful for us to take just a moment and clarify some of the terms that we'll use in discussions throughout the book. A precise explanation of JavaScript's mechanics packs a lot of lingo that requires precise terminology, and the lines only get blurrier when you start building a powerful toolkit on top of it—not to mention a toolkit that does things like simulate classes for a language in which proper classes from an object-oriented context does not exist.

Hopefully, you'll find the following list of terms helpful as we progress through some of these murky waters:

Toolkit

A toolkit is simply a collection of tools. It just so happens that toolkits in the computer programming realm are frequently used within the context of user interface design. Dojo is most accurately defined as a toolkit because it's more than just a library of supporting code that provides a set of related functions and abstractions; it also provides items such as deployment utilities, testing tools, and a packaging system. It's easy to get wrapped around the axle on library versus framework versus toolkit, and so forth, but Dojo has been dubbed a toolkit, so let's go with it.

Module

Physically, a Dojo module is nothing more than a JavaScript file or a directory containing a cohesive collection of JavaScript files. As it turns out, this top-level directory also designates a namespace for the code it contains. In a logical sense, modules in Dojo are similar to the concept of packages in other programming languages in that they are used to compartmentalize related software components. Do note, however, that while Dojo's packaging system refers to the actual mechanism that performs tasks such as determining and fetching dependencies, Dojo modules themselves are not called "packages."

Resource

When it becomes necessary to split a Dojo module into multiple files, or when a module consists of only a single JavaScript file, each JavaScript file is referred to a resource. Although a resource could strictly be used to logically organize the various abstractions that are associated with a module, there is also the consideration of minimizing the size of a JavaScript file. The trade-off essentially amounts to minimizing file size so that you don't download superfluous code that isn't needed, while also not downloading too many small files—all of which are synchronous requests and incur the overhead of communicating back to the web server (although using the build tools to create layers can make this overhead somewhat of a moot point).

Namespace

Physically, Dojo namespaces map to the same filesystem hierarchy that specifies modules and resources; logically, the concept of a namespace prevents identically named modules and resources from clashing. Note that while namespaces themselves are neither modules nor resources, the semantic idea behind what they represent does directly map to modules and resources. It is also worthwhile to note that Dojo preserves the global namespace of a page, and any modules you create with Dojo do not pollute the global namespace if implemented properly. Recall that everything in Base fits into the top-level dojo namespace.

First-class

In computer programming, something is first-class when it can be passed around without restrictions compared to other entities in the same language. For example, in many programming languages, you cannot pass around functions in the same way that you can pass around other data types such as number or string values. In this particular context, functions would not be considered first-class objects. In our discussions, the most common way this term will be used is to highlight the fact that functions are first-class objects in JavaScript. As we'll see, operations such as assigning functions directly to variables and/or placing them in associative arrays are fundamental to many Dojo design patterns.

Function

A function is a code snippet that is defined once, but can be executed multiple times. In JavaScript, functions are first-class objects that can be passed around just like any other variable. A constructor function is a function that is used specially via the new operator, which creates a new JavaScript Function object and performs initialization on it. Note that all JavaScript objects inherit from JavaScript's built-in Object type and have a prototype property that conveys the basis for JavaScript's powerful inheritance mechanism that is based on prototype-chaining. In Dojo parlance, the term constructor may also refer to the anonymous function that maps to the constructor key in dojo.declare 's associative array and that is used primarily for initializing properties of a Dojo class.

Object

The most generic concept of an object in JavaScript refers to a compound data type that can contain any number of named properties. For example, the simple statement var o = {} uses object literal syntax to create a JavaScript object. Because the term "object" gets thrown around so much in this document, the term "associative array" is sometimes used to describe contexts of key-value pairs such as {a : 1, b : 2} instead of calling them objects. Technically speaking, JavaScript only has objects and no classes—even though Dojo simulates the notion of a class via the dojo.declare function, a special function that is used for this express purpose.

Property

In OOP, any piece of data stored in a class is commonly called a property. In our Dojo-specific discussions, this term may refer to data contained in Function objects or to data contained in Dojo classes that are defined by dojo.declare.

Method

A function that is a member of a class is commonly referred to as a method in broad OOP contexts, JavaScript, and Dojo. Furthermore, in Dojo parlance, the anonymous functions that appear in the dojo.declare statement are said to be methods because dojo.declare provides the basis for a class-based inheritance mechanism. In general, you might just do well to think of a method as a function defined on a class that is subsequently used through an object context.

Class

In Dojo, a declaration that represents a logical entity as defined via the dojo.declare function (a special function specifically used to simulate classes and inheritance hierarchies) is referred to as a class. Again, this term is being used loosely, because JavaScript does not support classes in the same sense that they exist in languages like Java and C++.

Widget

A Dojo widget is a Function object that is created via a dojo.declare statement that includes dijit._Widget (a base class for all widgets) as an ancestor. Usually, a widget has a visible appearance on the screen and logically bundles HTML, CSS, JavaScript, and static resources into a unified entity that can easily be manipulated, maintained, and ported around just like a file.

Bootstrapping

This section discusses some material that you may want to initially skim over and come back to review once you feel well acquainted with Dojo.

Before you can use Dojo at all, you have to somehow get it into the page. Regardless of whether you install Dojo locally or load it via AOL's CDN, you simply provide a SCRIPT tag that points to the file that loads some JavaScript code, and then magic elves inside of your web browser miraculously causes everything to "just work," right? Well, not quite. Like most other things in computing, it all comes back to pure and simple automation, and Dojo's bootstrap process is not different.

The term "bootstrap" refers to the idea of "pulling yourself up by your own bootstraps." In other words, it's the idea of getting up and running without help from anywhere else. The notional idea of Dojo bootstrapping itself is the same concept as your computer "booting up" when you turn it on.

For the record, Example 1-2 is the absolute minimum effort that is generally required to get some XDomain Dojo goodness into your HTML page. What's especially notable about loading Dojo from the CDN is that less than 30KB of data comes across the wire. Chances are good that you'll use the previous code block, or some variation of it, quite often. Save yourself some typing by copying it into a template that you can reuse.

Example 1-2. A minimalist application harness example
<html>
  <head>
    <title>Title Goes Here</title>
    <!-- A lightweight style sheet that smoothes out look and feel across browsers -->
   <link rel="stylesheet"  type="text/css"
       href="http://o.aolcdn.com/dojo/1.1/dojo/resources/dojo.css" />

    <script
      type="text/javascript"
      src="http://o.aolcdn.com/dojo/1.1/dojo/dojo.xd.js">
    </script>

    <script type="text/javascript">
        /* If needed, Dojo modules may be asynchronously requested into the page
here via dojo.require statements... */

        dojo.addOnLoad(function(  ) {

            /* Any content that depends upon dojo.require statements goes here... */

        });
    </script>

  </head>
  <body>
    <!-- ... -->
  </body>
</html>

The dojo.addOnLoad function accepts another function as its parameter. The examples in this book generally supply this parameter with an anonymous function, although you could opt to define a function like var init = function( ) { /*...*/} and pass it in. Anonymous functions and some of the reasons they are important were briefly discussed in the Preface.

Two new constructs in the previous listing include the dojo.require statement and the dojo.addOnLoad block. The dojo.require statement is discussed at length in the section "Managing Source Code with Modules" in Chapter 2, but in a nutshell, it pulls a named resource into the page for you to use the same way that import works in Java or #include works in C programming. One incredibly important aspect of dojo.require is that it performs synchronous loading for local installations of the toolkit but acts asynchronously if you are doing XDomain loading. That distinction is especially important as it relates to dojo.addOnLoad.

dojo.addOnLoad

Because dojo.require statements act asynchronously over XDomain loads, it is not necessarily safe to immediately use resources you have requested via dojo.require when the page loads[9] because latency and other factors may (and usually will) cause some delay. Then, when you try to reference a module requested via dojo.require that is not yet loaded, you get a nice error thrown at you and the entire bootstrapping process most likely screeches to a halt. The technical term for the situation in which the outcome is undefined because of unpredictable timing constraints that compete with one another is called a race condition.

For the reasons just mentioned, using dojo.addOnLoad is a very good habit to get into because it makes your page as portable as possible—whether or not it is XDomain-loaded.

A common mistake is not using dojo.addOnLoad to safely and portably perform logic that should occur after the page loads and all dojo.require statements have been satisfied. The issue usually comes up when you have developed locally and then start switching SCRIPT tags to do XDomain loading.

Given that the previous code snippet uses XDomain loading, there aren't any extra steps involving local installation, so it really is a one-step process to bootstrap the entire toolkit from an existing page.

Although widgets are not introduced for many more chapters, another nuance of addOnLoad that bears mentioning—because we're on the topic—is that addOnLoad does not fire until after widgets have been parsed in the page (assuming Dojo has been configured to parse widgets on page load).

While bootstrapping is synonymous with "loading a script" at a high level, there's a lot more happening with that loading process than meets the eye. From a bird's eye view, at least two basic actions occur, though not necessarily in this exact order:

Platform configuration

Takes into account any custom configuration options that may have been specified through djConfig, an associative array that must be defined before the SCRIPT tag that loads Dojo is executed or as an attribute of the SCRIPT tag that loads Dojo. More specifics on djConfig are coming up later in this chapter.

Determines Dojo should be cross-domain loaded or loaded locally. XDomain loading details happen transparently so long as an Internet connection is available and the inclusion of the XDomain loader was configured at build time. By default, configuring for XDomain loading produces a dojo.xd.js (and other *.xd.js build artifacts), which provides a replacement for standard dojo.js.

Based on the environment specified for the particular build of Dojo (usually the browser but it could also be another option such as Rhino or a mobile device), sets up any environment-specific features. Even though you won't generally need to perform browser-specific configuration when using the default build of Dojo for the browser, Base still provides data members like dojo.isIE and dojo.isFF to expose the underlying browser for those few times when you do need them.

Performs browser-specific augmentation such as establishing an XMLHttpRequest (XHR) object for asynchronous calls using Dojo's various AJAX utilities. Workarounds for browser incompatibilities such as normalizing DOM events, standardizing a map of key codes, and extra measures to minimize and prevent memory leaks are also handled.

Namespace establishment and loading

Establishes the dojo namespace so that all of the utility provided by the toolkit does not clobber any existing symbols in the page.

Loads the dojo namespace with the various functions and symbols that constitute Base.

Although less frequently used than dojo.addOnLoad, dojo.addOnUnload is the preferred vehicle for performing logic that should take place when the page unloads.

Configuration with djConfig

Much of the content in this section will make a lot more sense once you've spent some time writing code, so don't feel the need to dwell on it. It's here as a reference more than anything.

Upcoming sections introduce djConfig, a configuration switch that you can place in the SCRIPT tag that bootstraps the toolkit (or define anytime before Dojo bootstraps) to customize where it looks for resources, whether debugging tools should be wired in, and so on.

Table 1-1 provides a synopsis of the key/value pairs you can pass into it to configure the bootstrapping process. (Some of the commentary may introduce constructs that have not yet been introduced. For now, just skim over those and come back to them whenever the occasion calls for it.)

Defining djConfig anytime after the SCRIPT tag that loads the toolkit executes has no effect.

Table 1-1. djConfig configuration switches

Key

Value type (default value)

Comment

[a]

afterOnLoad

Boolean

(false)

Used to facilitate injecting Dojo into a page after it has already been loaded. Useful for hacking on a page or developing widgets that are necessarily lazy-loaded, i.e., for social networking apps, etc.

baseUrl

String

(undefined)

Technically, this parameter allows you to redefine the root level path of the toolkit for a local or an XDomain load, usually for the purpose of resolving dependencies such as custom modules. In practice, however, it is almost exclusively used to resolve local modules when bootstrapping over XDomain.

cacheBust

String|Date

(undefined)

In the case of a String value, appends the value provided to requests for modules so that previous version of the page that is cached locally will be overridden. Typically, this value will be a random string of characters that you generate yourself or a unique identifier for your application version that would prevent nasty bugs from surfacing that may be caused by older versions of modules.

During the development cycle, you might provide a Date value such as (new Date( )).getTime( ), which guarantees a new value each time the page loads and prevents annoying caching problems.

debugAtAllCosts

Boolean

(false)

Usually provides more specific debugging information at the cost of performance. You might specify this value to better track down the line number where an error occurred if you are told that an error originated in a build file like bootstrap.js, dojo.js, or dojo.xd.js.

dojoBlankHtmlUrl

String

("")

Used to provide the location for a blank HTML document, which is necessary for using the IFRAME transport via dojo.io.iframe.create (discussed in Chapter 4). A default is located at dojo/resources/blank.html.

dojoIframeHistoryUrl

String

("")

Used to provide the location for a special file that is used in combination with dojo.back, a module for managing the back button (discussed in Chapter 2). A default is located at dojo/resources/iframe_history.html.

enableMozDomContentLoaded

Boolean

(false)

Gecko-based browsers like Firefox may optionally use the DOMContentLoaded event as the trigger to signal that the page has loaded because of a technical nuance related to synchronous XHR request involving a document greater than 65536 bytes[a]

extraLocale

String or Array

("")

Used to specify additional locales so that Dojo can transparently handle the details associated with providing a localized module. Values may be provided as a String value or as an Array of String values.

isDebug

Boolean

(false)

Loads Firebug or Firebug Lite machinery for debugging. Note that stubs for debugging functions such as the various console methods are in place by default so that code doesn't bust if you choose to remove diagnostic information from your application.

libraryScriptUri

String

("")

Used to configure nonbrowser environments such as Rhino and SpiderMonkey (JavaScript engines) in a manner similar to the way that baseUrl works for browser environments.

locale

String

(browser provided)

Used to override dojo.locale with a local other than the one that is retrieved from the browser.

modulePaths

Object

(undefined)

Specifies a collection of key/value pairs that associates modules with their relative paths on disk. While you'll generally place your modules in the toolkit's root directory, this parameter allows for variations if they are needed. When loading Dojo from the CDN or other XDomain, a baseUrl parameter is also required.

parseOnLoad

Boolean

(false)

Specifies whether to automatically parse the page for widgets on page load (essentially just a dojo.parser.parse( ) function call at the appropriate time during the bootstrap process).

require

Array

([])

Provides a convenient way of providing modules that should be automatically required once Base loads. When used in conjunction with afterOnLoad, it designates resources that should be loaded when injecting Dojo into a page after the page has already loaded.

useXDomain

Boolean

(false)

Used to force XDomain loading. This action is taken by default with XDomain builds. (See "Benefits of Using XDomain Builds" for benefits of using XDomain loading locally.)

xdWaitSeconds

Number

(15)

Specifies the number of seconds to wait before timing out a request for resources that are cross-domain loaded.

The djConfig parameter is modulePaths, while the Base function for setting up individual module paths is dojo.registerModulePath (no "s" on the end).

Most of the time, you will define djConfig in the same SCRIPT tag that bootstraps the toolkit using Object -like syntax. The following example illustrates:

<script
    type="text/javascript"
    src="http://o.aolcdn.com/dojo/1.1/dojo/dojo.xd.js"
    djConfig="parseOnLoad:true,isDebug:true">
</script>

However, you might opt to define it prior to the SCRIPT tag that loads the toolkit if you have a lot of configuration switches, or if it's just more convenient to do it that way for your particular situation. Here's a translation of the previous example that produces the very same effect:

<script type="text/javascript">
    djConfig = {
        parseOnLoad : true,
        isDebug : true
    };
</script>

<script
  type="text/javascript"
  src="http://o.aolcdn.com/dojo/1.1/dojo/dojo.xd.js ">
</script>

Exploring Dojo with Firebug

Although the rest of this book systematically works through the entire toolkit, let's take a moment to tinker around with Dojo from the Firebug console. During development, there may be times when it is helpful to try out a few ideas in isolation, and the Firebug console provides an environment that behaves much like an interpreter.

Exploring Base

To illustrate, transcribe the minimalist HTML page in Example 1-3 into a local file to get started. The only Dojo-specific nuance is the script tag that performs the XDomain loading. Although we haven't covered the djConfig parameter that you'll see is included in the SCRIPT tag, it's just a way of passing in configuration information to Dojo as it bootstraps. In this case, we're specifying that debugging facilities such as the Firebug console should be explicitly available to us. Even if you're using another browser such as IE, the djConfig="isDebug:true" option ensures that Firebug Lite is loaded.

Example 1-3. A really simple HTML page for illustrating a few features from Base
<html>
     <head>
         <title>Fun with Dojo!</title>

            <link rel="stylesheet"  type="text/css"
              href="http://o.aolcdn.com/dojo/1.1/dojo/resources/dojo.css" />

         <script
              type="text/javascript"
              src="http://o.aolcdn.com/dojo/1.1/dojo/dojo.xd.js"
             djConfig="isDebug:true">
        </script>

        <style type="text/css">
              .blue {color: blue;}
        </style>
    </head>
     <body>
        <div id="d1" class="blue">A div with id=d1 and class=blue</div>
        <div id="d2">A div with id=d2</div>
        <div id="d2">Another div with id=d2</div>
        <div id="d4">A div with id=d3.
            <span id="s1">
                This sentence is in a span that's contained in d1.
                The span's id is s1.
            </span>
        </div>
         <form name="foo" action="">
             A form with name="foo"
         </form>
          <div id="foo">
             A div with id=foo
          </div>
      </body>
</html>

Once you've saved out the file, open the page in Firefox, and click on the little green circle with the checkmark in it to expand the Firebug console. Then, click on the caret icon just beside Firebug's search box to open up Firebug in a new window, as shown in Figure 1-2. (If you haven't read the primer on Firebug in Appendix A, this would be a good time to divert and do so.) Clicking on the "Net" tab reveals that the XDomain dojo.xd.js file consisting of Base has indeed been downloaded from the CDN.

Firebug reveals valuable information that you can use to sanity check what is happening with network requests, and more
Figure 1-2. Firebug reveals valuable information that you can use to sanity check what is happening with network requests, and more

If you click back on the "Console" tab and type dojo on the >>> prompt followed by the enter key, you should see a Firebug console message that says something along the lines of Object global=window isBrowser=true isRhino=false, which shows you that the global JavaScript object dojo is indeed alive and well. Typing in console.dir(dojo) would provide an exhaustive tree-view of everything that's contained in Dojo. Although you'll also see a lot of private members that are prefixed with a leading underscore, go ahead try it out for yourself. Skimming the contents of the output will give you a small taste of what's packed up inside of Base.

dojo.byId

Dojo provides dojo.byId as a drop-in replacement for document.getElementById. Thus, passing in a string value like dojo.byId("s1"), for example, shows that it returns a reference that you could store in a variable just like you could with a call to document.getElementById. However, in addition to looking up an id value, dojo.byId also acts like a no-op if you pass it a DOM node. Internally, the function introspects its argument, so on the application level, you don't have to even think twice. Its complete function signature looks like this:

dojo.byId(/*String*/ id | /*DomNode*/ node)  // Returns a DOM Node

Throughout the book, the pipe, |, is used to denote the logical "or" operation in function signatures whenever there is more than one possibility.

Because it appears that dojo.byId does almost the very same thing as document.getElementById, you may be tempted to just forget about dojo.byId all together—but don't! As it turns out, it smooths out some subtle inconsistencies that might just burn you when you least expect it. One well-known bug for document.getElementById surfaces IE6 and IE7. To illustrate, type the following into the Firebug Lite console for the sample document we're working on, and you'll see Figure 1-3:

The resulting behavior of document.getElementById versus dojo.byId for the previous document
Figure 1-3. The resulting behavior of document.getElementById versus dojo.byId for the previous document
document.getElementById("foo") //Isn't the answer *so* obvious?!?

Hmm. You probably didn't expect to have the FORM element returned, did you? As it turns out, if it had not appeared first in the document, you should have gotten the div element returned. This particular bug arises because the name and id attribute namespaces are merged for IE. So much for cross-browser compatibility on the obvious things in life! Figure 1-4 shows how Dojo protects you from the cold hard metal of the browser, saving you from working around the multitude of inconsistencies that would otherwise prevent your application from being portable.

Dojo makes your code more portable by insulating you from browser quirks
Figure 1-4. Dojo makes your code more portable by insulating you from browser quirks

But in addition to dojo.byId working around that particular quirk, dojo.byId also returns the first element if more than one element has an id set to the same value, thereby normalizing corner case behavior. For our example document, you can verify that dojo.byId always returns the first element by trying out the following statement:

dojo.byId("d2").innerHTML

More than anything else, the takeaway from this short lesson is that if you're developing with a JavaScript toolkit, use its API to get work done instead of ways you may have learned with raw JavaScript. Occasionally, you may see an API call that doesn't seem to add any additional value, and the temptation may be to fall back to your own tried-and-true method of getting something accomplished—but resist the temptation! Well-designed APIs do not provide useless functionality.

Viewing an API call as "worthless" may be an indication that you may be confused about the exact utility that the call provides. Whenever this happens, review the documentation to find out what it is you're missing. If the documentation still doesn't convince you, hop on a mailing list or IRC channel and ask someone about it.

dojo.connect

Grabbing a DOM node is admittedly boring, so let's look at something slightly more interesting—like attaching a UI event such as a mouse movement to a node via dojo.connect, the toolkit's machinery for dynamically adding and removing these types of events. Its signature might look complex at first glance, but it's actually quite simple in routine use. Take a look:

connect(/*Object|null*/ obj,
        /*String*/ event,
        /*Object|null*/ context,
        /*String|Function*/ method) // Returns a connection handle

To try out connect, execute the following code into the Firebug console, and then move your mouse over the content of the sentence contained in the SPAN to see that the mouseover event was set up properly. (You'll probably want to click on the caret icon in the lower-right corner to expand the command prompt to multiline mode.)

var handle = dojo.connect(
  dojo.byId("s1"), //context
  "onmouseover", //event
  null, //context
  function(evt) {console.log("mouseover event", evt);} //event
);

You should notice that in addition to seeing confirmation in the Firebug console that an event has occurred, you get an actual reference to the event that you can click on and inspect—usually getting vital information relating to where the click occurred on the screen and more.

As it turns out, dojo.connect, like dojo.byId, does a lot of inspecting so that you don't have to think nearly as much about it as you might initially imagine. In fact, any arguments that may be null can be omitted completely. Thus, the previous function call could be reduced to the slightly more readable:

var handle = dojo.connect(
  dojo.byId("s1"), //context
  "onmouseover", //event
  function(evt) {console.log("mouseover event",evt);} //event
);

Tearing down the connection so that the function that is executed is based on a DOM event is even easier, and is important for preventing memory leaks if you are doing a lot of connecting and disconnecting. Just call dojo.disconnect on the handle you saved, and Dojo takes care of the rest for you:

dojo.disconnect(handle);

Although it is a simple example, dojo.connect demonstrates a key principle behind Dojo's philosophy: make getting from A to B as simple as it should have been all along. Sure—if you're well-versed in your JavaScript, you could go through the motions of setting up, maintaining, and tearing down connections all on your own. However, you'd still incur the cost of boilerplate that would clutter up your design, and let's not forget: every line of code you write is a line you have to maintain. For the aspiring web developers out there and those among us who prefer to keep things simple, calling dojo.connect and dojo.disconnect is a fine option.

Dojo doesn't do anything that JavaScript can't already do, and for that matter, neither does any other JavaScript toolkit. The tremendous value that Dojo introduces is in smoothing out inconsistencies amongst multiple browsers and making common operations as simple as they should have been all along—protecting you from writing and maintaining all of that boilerplate, which allows you to be as productive as possible.

Another neat feature that demonstrates tremendous power in a tiny package is dojo.query, the toolkit's mechanism for quickly querying the page with CSS3 style syntax.

Chapter 5 covers dojo.query in detail and provides a lot more context about CSS3 selectors, if you want to jump ahead and skim over them.

For example, finding all of the DIV elements on the page is as simple as calling:

dojo.query("div") //find all of the div elements in the DOM

If you try that statement out in the Firebug console, you'll see that you indeed get back a list of DIV elements. Querying the page for the existence of a particular named DIV element is just as easy as it should be as well:

dojo.query("div#d2") //check for the existence of a div with id=d2

And then there's querying by class:

dojo.query(".blue") //returns a list of elements that have the blue class applied.

Speaking of classes, you could also filter on particular element types, but because there's only one DIV that has a class applied to it, we'll need to apply the blue class to another element as well. But before you go and start editing the page itself, why not just use another built-in function from Base, dojo.addClass, to apply the class like so:

dojo.addClass("s1", "blue");  //add the blue class to the SPAN

After we apply the blue class to s1, we can illustrate another query with dojo.query like so:

dojo.query("span.blue") //returns only span elements with the blue class applied

Getting the hang of it? Sure, we could do all of these things in our own roundabout ways, but isn't it nice to know that the toolkit insulates you from all of that mayhem and provides a single, easy-to-use function instead?

Exploring Dijit

While we could go on and on showcasing Base's easy-to-use API, let's save that for subsequent chapters and instead divert to a quick example of how easy it is to snap some dijits into your page without any additional programming.

Suppose you have the page shown in Example 1-4.

Example 1-4. A very primitive form example
<html>
    <head>
        <title>Fun with Dijit!</title>
    </head>
        <body>
        Just Use the form below to sign-up for our great offers:<br /><br />
        <form id="registration_form">
            First Name: <input type="text" maxlength=25 name="first"/><br />
            Last Name: <input type="text" maxlength=25 name="last"/><br />
            Your Email: <input type="text" maxlength=25 name="email"/><br /><br />
            <button onclick="alert('Boo!')">Sign Up!</button>
        </form>
    </body>
</html>

Figure 1-5 shows what that page looks like, although it's not very difficult to imagine.

A functional but very ugly form
Figure 1-5. A functional but very ugly form

That might have cut it back in '92, but it's wholly unacceptable for this day and age. Take a moment to consider what your normal routine would be at this point: define some classes, apply the classes, write some JavaScript to provide validation routines, etc.

To give you a taste of how the page would look after some Dojoification, take a look at Example 1-5. Don't worry about what every little detail is doing; lots of pages follow on that get into the nooks and crannies of the finer details. For now, just familiarize yourself with the general structure of a page with some dijits snapped into it.

Example 1-5. A form that's not so primitive anymore (thanks to some Dojoification)
<html>
    <head>
        <title>Fun with Dijit!</title>

        <!-- Grab some style sheets for the built-in tundra theme that Dojo offers for
         styling the page, equipping you with a professional style without
any additional
         effort required. -->
        <link rel="stylesheet" type="text/css"
          href="http://o.aolcdn.com/dojo/1.1/dijit/themes/tundra/tundra.css" />
        <link rel="stylesheet" type="text/css"
          href="http://o.aolcdn.com/dojo/1.1/dojo/resources/dojo.css" />
        <!-- Add in some plain old CSS to line up the form elements more nicely -->

        <style type="text/css">
            h3 {
                margin : 10px;
            }
            label,input {
                display: block;
                float: left;
                margin-bottom: 5px;
             }
             label {
                text-align: right;
                width: 70px;
                padding-right: 20px;
             }
             br {
                clear: left;
             }
             .grouping {
                width:300px;
                border:solid 1px rgb(230,230,230);
                padding:5px;
                margin:10px;
             }
        </style>

        <!-- Load Base and specify that the page should be parsed for dijits after it
          loads -->
        <script
            type="text/javascript"
            src="http://o.aolcdn.com/dojo/1.1/dojo/dojo.xd.js"
            djConfig="parseOnLoad: true" >
        </script>

        <!-- Load some dijits via dojo.require in the same manner that you
would #include
          some files in C programming or perform an import in Java -->
        <script type="text/javascript">
            dojo.require("dojo.parser");
            dojo.require("dijit.form.TextBox");
            dojo.require("dijit.form.ValidationTextBox");
            dojo.require("dijit.form.Button");
        </script>
    </head>

        <!-- Specify that the built-in tundra theme should be applied to
everything in the
          body of the page. (Dijit relies heavily on CSS so including the appropriate
          theme is crucial.)-->
        <body class="tundra">

            <h3>Sign-up for our great offers:</h3>

            <form id="registration_form">

                <!-- Weave some widgets into the page by supplying the tags and
including
                  a dojoType attribute so the parser can find them and swap
them out -->

                <div class="grouping">
                    <label>First Name:</label>
                    <input type="text"
                     maxlength=25
                     name="first"
                     dojoType="dijit.form.TextBox"
                     trim="true"
                     propercase="true"/><br>

                    <label>Last Name:</label>
                    <input type="text"
                     maxlength=25
                     name="last"
                     dojoType="dijit.form.TextBox"
                     trim="true"
                     propercase="true"/><br>

                    <label>Your Email:</label>
                    <input type="text"
                     maxlength=25
                     name="email"
                     dojoType="dijit.form.ValidationTextBox"
                     trim="true"
                     lowercase="true"
                     regExp="[a-z0-9._%+-]+@[a-z0-9-]+\.[a-z]{2,4}"
                     required="true"
                     invalidMessage="Please enter a valid e-mail address"/><br>

                    <button dojoType="dijit.form.Button"
                     onClick="alert('Boo!')">Sign Up!</button>
                </div>

            </form>
    </body>
</html>

And voilà, Figure 1-6 shows what it looks like, complete simple validation functionality.

A much better looking form, using out-of-the-box dijits
Figure 1-6. A much better looking form, using out-of-the-box dijits

If you're intrigued by the examples in this chapter, and are ready to learn more about Dojo, then you've come to the right place. The following chapters systematically work through the specifics of the toolkit. But first, let's take a quick moment to reflect on what this chapter was all about (as we'll do in every chapter).

Summary

This chapter barely scratched the surface of your journey with Dojo, but it nonetheless covered a lot of ground. After reading this chapter, you should:

  • Know where to go to download the toolkit and set up a development environment

  • Understand the toolkit's architecture and the key differences between each component

  • Understand some of the common parlance used in Dojo development

  • Realize some of the benefits of using Firebug during the development cycle

  • Understand the basic ideas behind how the toolkit bootstraps itself

  • Have an appreciation for how easy it is to use Base and plug out-of-the-box dijits into a page

  • Be familiar with the look and feel of Dojo code

  • Be excited to read the subsequent chapters and learn more about Dojo

The next chapter will discuss language and browser utilities.



[7] A standard for accomplishing Accessible Rich Internet Applications: http://www.w3.org/WAI/intro/aria.

[8] As you might already have been thinking, DOH is also a pun on Homer Simpson's famous expletive; the test runner can optionally play a "D'oh!" sound effect when a test fails.

[9] Generally speaking, the page load occurring consists of either the window's onload event or possibly the DOMContentLoaded for Mozilla variations completing.

[10] Bookmarklets are nothing more than snippets of JavaScript code that can be stored as a bookmark. Generally, bookmarklets are designed to augment the behavior in a page.