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, “One depiction of how the various Dojo components can be thought of as relating to one another”. 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.
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.
Tip
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.
Tip
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, Dijit Overview) into JavaScript files—another trick for reducing latency.
Tip
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.
Tip
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.
Tip
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.
Tip
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.
Tip
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, A Firebug Primer 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:
In the address bar, type
about:configand press the Enter key.Change the value of
security.fileuri.origin_policyto3or 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.
Tip
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, “A very simple CherryPy application” 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, “A very simple CherryPy application”, 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
dojonamespace.- 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
newoperator, which creates a new JavaScript Function object and performs initialization on it. Note that all JavaScript objects inherit from JavaScript's built-inObjecttype and have aprototypeproperty 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 theconstructorkey indojo.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 thedojo.declarefunction, 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.declarestatement are said to be methods becausedojo.declareprovides 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.declarefunction (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.declarestatement that includesdijit._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
Tip
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.
Tip
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, “A minimalist application harness example” 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>Tip
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, Language and Browser Utilities, 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.
Warning
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.
Tip
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 theSCRIPTtag that loads Dojo is executed or as an attribute of theSCRIPTtag that loads Dojo. More specifics ondjConfigare 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.isIEanddojo.isFFto 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
dojonamespace so that all of the utility provided by the toolkit does not clobber any existing symbols in the page.Loads the
dojonamespace with the various functions and symbols that constitute Base.Tip
Although less frequently used than
dojo.addOnLoad,dojo.addOnUnloadis the preferred vehicle for performing logic that should take place when the page unloads.
Configuration with djConfig
Tip
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, “djConfig configuration switches” 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.)
Warning
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] | ||
|
| 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. |
|
| 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. |
|
| String|Date (undefined) | In the case of a
During the development cycle, you
might provide a |
|
| 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. |
|
| String ("") |
Used to provide the
location for a blank HTML document, which is necessary for
using the IFRAME transport via |
|
| String ("") |
Used to provide the
location for a special file that is used in combination with
|
|
| Boolean (false) |
Gecko-based browsers
like Firefox may optionally use the |
|
| 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 |
|
| Boolean (false) |
Loads Firebug or
Firebug Lite machinery for debugging. Note that stubs for
debugging functions such as the various |
|
| 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. |
|
| String (browser provided) |
Used to override
|
|
| 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 |
|
| Boolean (false) |
Specifies whether to
automatically parse the page for widgets on page load
(essentially just a |
|
| Array ([]) |
Provides a convenient
way of providing modules that should be automatically
required once Base loads. When used in conjunction with
|
|
| 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.) |
|
| Number (15) |
Specifies the number of seconds to wait before timing out a request for resources that are cross-domain loaded. |
Warning
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, “A really simple HTML page for illustrating a few features
from Base” 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, “Firebug reveals valuable information that you can use to sanity check what is happening with network requests, and more”. (If you haven't read the primer on Firebug in Appendix A, A Firebug Primer, 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.
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
Tip
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, “Dojo makes your code more portable by insulating you from
browser quirks”
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.
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").innerHTMLMore 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.
Warning
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 handleTo 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.
Tip
Chapter 5, Node Manipulation 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 DOMIf 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=d2And 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 SPANAfter 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 appliedGetting 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, “A very primitive form example”.
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, “A functional but very ugly form” shows what that page looks like, although it's not very difficult to imagine.
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, “A form that's not so primitive anymore (thanks to some Dojoification)”. 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, “A much better looking form, using out-of-the-box dijits” shows what it looks like, complete simple validation functionality.
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.











Add a comment



Add a comment