The Book of Dojo

Welcome to the Book of Dojo. This book covers versions 0.9, 1.0, and all follow-on 1.x releases; additions from minor releases are clearly marked for your enjoyment. Please use the forums for support questions, but if you see something missing, incomplete, or just plain wrong in this book, please leave a comment.

For an offline version, click on the Printer-Friendly Page link at the bottom. This assembles the entire book into one long HTML page, which you can then save offline. Caveats: it takes a long time to load, you will get approximately 150 JavaScript errors (which you can ignore), and images won't appear. However, all the text and code will be intact.

Table of Contents


The Book of Dojo
Quick Installation
Hello World - Dojo for the Attention-Impaired
Debugging Tutorial
Introduction
Licensing
History
Why Dojo?
Part 1: Life With Dojo - Dojo and Dijit Application Examples
Example 1: Why Doesn't Anyone Fill Out Their Tax Forms?
Example 2: The Postman Always Clicks Twice
Example 3: Chatting With Tech Support
Part 2: Dijit - The Dojo Widget Library
Dijit at a Glance
Common Features
Form, Validation, Specialized Input
Form Widget
CheckBox, RadioButton, ToggleButton
ComboBox
FilteringSelect
InlineEditBox (0.9)
NumberSpinner
Slider
Textarea
TextBox family: Validation, Currency, Number, Date, Time
Layout
AccordionContainer
BorderContainer (1.1)
ContentPane
LayoutContainer
SplitContainer
StackContainer
TabContainer
Command Control
Button, ComboButton, DropDownButton
Menu
Toolbar
User Assistance and Feedback
ProgressBar
Tooltip
Dialog and TooltipDialog
TitlePane
Advanced Editing and Display
ColorPalette
InlineEditBox (1.0)
Editor
Tree
Themes and Design
Common Elements
Overriding and Combining Themes
Writing Your Own Theme
Accessibility
Web Accessibility Issues
Dojo Accessibility Strategy
Dojo Accessibility Resources
Part 3: JavaScript Programming With Dojo and Dijit
Functions Used Everywhere
Object Orientation
Modules
Creating and Scripting Widgets
Writing Your Own Widget Class
The Event System
XMLHttpRequest (XHR)
Drag and Drop
Using dojo.data
Selecting DOM Nodes with dojo.query
Internationalization (i18n)
Back Button
Other Functions
Multiple Versions of Dojo in a Page
Part 4: Testing, Tuning and Debugging
Getting the Code from Source Control
Development Tools
Debugging Facilities
D.O.H. Unit Testing
Performance Optimization
The Package System and Custom Builds
Part 5: DojoX - Experimental and Specialized Extensions
Cometd (client)
DojoX Charting
DojoX Collections
DojoX Cryptography
DojoX Data
DojoX DTL (Django Template Language)
DojoX FX
DojoX GFX
DojoX Grid
DojoX I/O
DojoX Image
DojoX Layout
DojoX Offline
DojoX Presentation
DojoX String Utilities
DojoX Timing
DojoX UUID
DojoX Validate
DojoX Widgets
DojoX Wire
DojoX XML Utilities

Contributors

Simon Bates David Bolter Matt Bowen Pete Brunet Dipen Chaudhary
Jeff Chimene Lance Duivenbode Sam Foster Becky Gibson Peter Higgins
Martin Humphreys Bill Keese Carla Mott Brad Neuberg Shane O'Sullivan
Shelita Overton Ashish Patil Adam Peller Leesa Payne Craig Riecke, editor
Alex Russell Gerwood Stewart Peter Waegener

Quick Installation

There are three main ways to install Dojo:

  1. Install nothing! Use Dojo from AOL's Content Distribution Network (CDN).
  2. Install the latest release on your server
  3. Install directly from source control

Use Dojo from CDN

This method is quick and painless! You simply load Dojo through <script> tags pointing to the AOL CDN. You don't need to invest any of your own server disk space or resources nor will you need to install Dojo locally in many cases. Instructions are available on using Dojo from the CDN.

All of the Dijit examples in this book load Dojo through this method. You can literally copy and paste any example in Parts 1 and 2 onto your own web server and it will work as-is! In Part 3, where examples are most often code fragments, we'll tell you any modifications needed to run the example on CDN.

Use Dojo from your Own Server

For you traditionalists out there, you can download, install and use Dojo the old fashioned way.

  1. Download the latest build from http://dojotoolkit.org/downloads.
  2. Uncompress the file onto your web server. Assuming you install it under the directory /js, when you're done, the file system should look something like this:
    [inline:dir_list.png]
  3. With your browser, open http://yoursite.com/js/dojo-0.9.0/dijit/themes/themeTester.html You should see a page like this:
    [inline:themeTester.png]

You've got a working Dojo!

Getting the Nightly Build

Finally, for those of you who live on the edge ... you can get the latest, greatest code directly from the Subversion code repository.

Hello World - Dojo for the Attention-Impaired

The purpose of this tutorial is to provide a starting point for users who are new to Dojo. Whilst every effort is made to introduce as much as possible about Dojo, it is impossible to include more of the detailed information since to do so would be counterproductive and confusing to new users. For more information on the concepts introduced here, please see the links to other resources at the end of this document (Finding More Resources).

Requirements

Obviously, you need Dojo first! You can get the latest stable build from http://download.dojotoolkit.org. Next you need a web server. Whether it's hosted offsite or onsite, on Linux or Windows or Mac ... matters naught. The Dojo JavaScript library is simply pulled from your web server to the browser as needed. However, the AJAX examples in this document require a server-side scripting language like PHP or ASP.

The Dojo and Dijit code, which runs on the client browser, is certified to run on IE 6 and 7, Firefox 2, and Safari.

Setting Up Dojo

First, you should create a directory on the web server. We'll call ours HelloWorldTutorial. Then create a directory called dojoroot underneath it. Finally, use your favorite unzipping tool to unzip Dojo into /HelloWorldTutorial/dojoroot. It'll look like this when you're done:

[inline:debugging9.png]

Getting Started

Once we have setup the directory and file structure for the tutorial, we will need to setup the JavaScript component of our HTML page. Have a look at the code below:

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */
.geshifilter {font-family: monospace;}
.geshifilter .imp {font-weight: bold; color: red;}
.geshifilter .kw1 {color: #b1b100;}
.geshifilter .kw2 {color: #000000; font-weight: bold;}
.geshifilter .kw3 {color: #000066;}
.geshifilter .coMULTI {color: #808080; font-style: italic;}
.geshifilter .es0 {color: #000099; font-weight: bold;}
.geshifilter .br0 {color: #66cc66;}
.geshifilter .st0 {color: #ff0000;}
.geshifilter .nu0 {color: #cc66cc;}
.geshifilter .sc0 {color: #00bbdd;}
.geshifilter .sc1 {color: #ddbb00;}
.geshifilter .sc2 {color: #009900;}

<html>
  <head>
    <title>Dojo: Hello World!</title>

    <!-- SECTION 1 -->
    <style type="text/css">
        @import "dojoroot/dijit/themes/tundra/tundra.css";
        @import "dojoroot/dojo/resources/dojo.css"
    </style>
    <script type="text/javascript" src="dojoroot/dojo/dojo.js"
      djConfig="parseOnLoad: true">
</script>
  </head>

  <body class="tundra">
  </body>
</html>

As it can be seen above, the page is a just a standard HTML skeleton with three things:

Creating a Button Widget

Ok, now for the exciting part! In this example we're going to create a Button widget with the text 'Hello World!'. In the case of the Button widget, three visual states (mouseOut, mouseOver, and mouseDown) are available which means that we are able to enhance the user's experience somewhat.

The first step in creating the widget is telling Dojo to load the appropriate modules. In the header, add another section (hereafter referred to as section 2) below section 1 as follows:

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */
.geshifilter {font-family: monospace;}
.geshifilter .imp {font-weight: bold; color: red;}
.geshifilter .kw1 {color: #b1b100;}
.geshifilter .kw2 {color: #000000; font-weight: bold;}
.geshifilter .kw3 {color: #000066;}
.geshifilter .coMULTI {color: #808080; font-style: italic;}
.geshifilter .es0 {color: #000099; font-weight: bold;}
.geshifilter .br0 {color: #66cc66;}
.geshifilter .st0 {color: #ff0000;}
.geshifilter .nu0 {color: #cc66cc;}
.geshifilter .sc0 {color: #00bbdd;}
.geshifilter .sc1 {color: #ddbb00;}
.geshifilter .sc2 {color: #009900;}

<!-- SECTION 2 -->
    <script type="text/javascript">
       // Load Dojo's code relating to the Button widget
       dojo.require("dijit.form.Button");
    </script>

The dojo.require line instructs Dojo to load the Button widget. If you were to omit this line, the markup code for the button would not be evaluated by Dojo upon loading, resulting in a plain HTML button instead of what you expect.

After making the changes, insert the following code into the body section of the HTML:

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */
.geshifilter {font-family: monospace;}
.geshifilter .imp {font-weight: bold; color: red;}
.geshifilter .kw1 {color: #b1b100;}
.geshifilter .kw2 {color: #000000; font-weight: bold;}
.geshifilter .kw3 {color: #000066;}
.geshifilter .coMULTI {color: #808080; font-style: italic;}
.geshifilter .es0 {color: #000099; font-weight: bold;}
.geshifilter .br0 {color: #66cc66;}
.geshifilter .st0 {color: #ff0000;}
.geshifilter .nu0 {color: #cc66cc;}
.geshifilter .sc0 {color: #00bbdd;}
.geshifilter .sc1 {color: #ddbb00;}
.geshifilter .sc2 {color: #009900;}

<button dojoType="dijit.form.Button" id="helloButton">Hello World!</button>

The key attribute of this HTML element to notice is the dojoType attribute. The dojoType attribute is responsible for instructing Dojo on how to process the element when the page is loading. In this case we've used a button element for the button though we could have used an input element - Dojo will work with either as long as the dojoType attribute is present. It is worth noting that if we did use an input element, we would have to specify the button's text by using adding a caption attribute that contained the desired text.

Connecting an Event to the Widget

A button is all well and good, but what about getting it to do something when it's clicked? We could just specify an onClick event handler for the button, but there's another, more efficient way - the Dojo event system!

The easiest way to attach an event to a button is through a script tag. But not just any script tag ... this one has a type of dojo/method, like this:

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */
.geshifilter {font-family: monospace;}
.geshifilter .imp {font-weight: bold; color: red;}
.geshifilter .kw1 {color: #b1b100;}
.geshifilter .kw2 {color: #000000; font-weight: bold;}
.geshifilter .kw3 {color: #000066;}
.geshifilter .coMULTI {color: #808080; font-style: italic;}
.geshifilter .es0 {color: #000099; font-weight: bold;}
.geshifilter .br0 {color: #66cc66;}
.geshifilter .st0 {color: #ff0000;}
.geshifilter .nu0 {color: #cc66cc;}
.geshifilter .sc0 {color: #00bbdd;}
.geshifilter .sc1 {color: #ddbb00;}
.geshifilter .sc2 {color: #009900;}

<button dojoType="dijit.form.Button" id="helloButton">
        Hello World!
        <script type="dojo/method" event="onClick">
           alert('You pressed the button');
        </script>
    </button>
    }

Pretty simple, eh? Putting the script inside the tag body makes a good deal of sense. And you can harness the full power of DOM Level 2 events inside the script. That means you can detect SHIFT and CTRL keys, get all sorts of event properties, and bubble events up through the HTML tree. If you've ever used Level 2 events, you know how IE and Firefox use different syntax. In Dojo, the same functions work in any supported browser. That's powerful stuff!

Reading Data from the Server

Having an alert pop up when we press the button is great, but what if we want to retrieve some data from the server? Again, Dojo comes to the rescue with an easy method of accomplishing this - dojo.xhrGet. For easy reference, the code for this section is available as HelloWorld-Section5.html and response.txt in the attachments section.

To get started, we first need a callback function to handle the data to be returned from the server. Insert the following code into the header:

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */
.geshifilter {font-family: monospace;}
.geshifilter .imp {font-weight: bold; color: red;}
.geshifilter .kw1 {color: #b1b100;}
.geshifilter .kw2 {color: #000000; font-weight: bold;}
.geshifilter .kw3 {color: #000066;}
.geshifilter .coMULTI {color: #808080; font-style: italic;}
.geshifilter .es0 {color: #000099; font-weight: bold;}
.geshifilter .br0 {color: #66cc66;}
.geshifilter .st0 {color: #ff0000;}
.geshifilter .nu0 {color: #cc66cc;}
.geshifilter .sc0 {color: #00bbdd;}
.geshifilter .sc1 {color: #ddbb00;}
.geshifilter .sc2 {color: #009900;}

<script>
       function helloCallback(data,ioArgs) {
          alert(data);
       }       
       function helloError(data, ioArgs) {
          alert('Error when retrieving data from the server!');
       }
</script>

The two arguments to the functions (data, and ioArgs) are important - don't leave any of them out! The first argument (data) contains the data sent back from the server, whilst the second argument contains a Dojo I/O Bind object. Only the first concerns us right now.

The next step is to link the click of the button to the server request. To do this, modify the following code:

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */
.geshifilter {font-family: monospace;}
.geshifilter .imp {font-weight: bold; color: red;}
.geshifilter .kw1 {color: #b1b100;}
.geshifilter .kw2 {color: #000000; font-weight: bold;}
.geshifilter .kw3 {color: #000066;}
.geshifilter .coMULTI {color: #808080; font-style: italic;}
.geshifilter .es0 {color: #000099; font-weight: bold;}
.geshifilter .br0 {color: #66cc66;}
.geshifilter .st0 {color: #ff0000;}
.geshifilter .nu0 {color: #cc66cc;}
.geshifilter .sc0 {color: #00bbdd;}
.geshifilter .sc1 {color: #ddbb00;}
.geshifilter .sc2 {color: #009900;}

<script type="dojo/method" event="onClick">
    alert('You pressed the button');
</script>

To this:

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */
.geshifilter {font-family: monospace;}
.geshifilter .imp {font-weight: bold; color: red;}
.geshifilter .kw1 {color: #b1b100;}
.geshifilter .kw2 {color: #000000; font-weight: bold;}
.geshifilter .kw3 {color: #000066;}
.geshifilter .coMULTI {color: #808080; font-style: italic;}
.geshifilter .es0 {color: #000099; font-weight: bold;}
.geshifilter .br0 {color: #66cc66;}
.geshifilter .st0 {color: #ff0000;}
.geshifilter .nu0 {color: #cc66cc;}
.geshifilter .sc0 {color: #00bbdd;}
.geshifilter .sc1 {color: #ddbb00;}
.geshifilter .sc2 {color: #009900;}

<script type="dojo/method" event="onClick">
   dojo.xhrGet({
        url: 'response.txt',
        load: helloCallback,
        error: helloError
   });
</script>

The above code basically tells Dojo to query the URL specified by url and to use the function specified by handler to process the response from the server.

Finally, we need to create another file in the same directory as HelloWorld.html called response.txt. In this file, place the text 'Welcome to the Dojo Hello World Tutorial'.

Now, when the button is clicked, a JavaScript alert should display the text from the response.txt file. Dojo-Easy!

Next, we'll look at doing something meaningful with that server request.

Sending Data to the Server Using GET

It's all well and good retrieving static data from the server, but it is hardly a widely used situation in real life. So, instead of simply requesting data from the server we also will send it some information for it to process. In this section, we'll use the GET method whilst in the next section we'll use the POST method. For easy reference, the code for this section is available as HelloWorld-Section6.html in the attachments section. Server side code is also available as HelloWorldResponseGET. where type is ASP ('.asp'), PHP ('.php'), ColdFusion ('.cfm'), or Java ('.jsp').

Firstly, in the markup section of the HelloWorld.html file (i.e. the body section), we need to add another element - an input element. So, change the code in this section from:

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */
.geshifilter {font-family: monospace;}
.geshifilter .imp {font-weight: bold; color: red;}
.geshifilter .kw1 {color: #b1b100;}
.geshifilter .kw2 {color: #000000; font-weight: bold;}
.geshifilter .kw3 {color: #000066;}
.geshifilter .coMULTI {color: #808080; font-style: italic;}
.geshifilter .es0 {color: #000099; font-weight: bold;}
.geshifilter .br0 {color: #66cc66;}
.geshifilter .st0 {color: #ff0000;}
.geshifilter .nu0 {color: #cc66cc;}
.geshifilter .sc0 {color: #00bbdd;}
.geshifilter .sc1 {color: #ddbb00;}
.geshifilter .sc2 {color: #009900;}

<button dojoType="Button" widgetId="helloButton">
    <script type="dojo/method" event="onClick">
    dojo.xhrGet({
        url: 'response.txt',
        load: helloCallback,
        error: helloError
    });
    </script>
</button>

to:

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */
.geshifilter {font-family: monospace;}
.geshifilter .imp {font-weight: bold; color: red;}
.geshifilter .kw1 {color: #b1b100;}
.geshifilter .kw2 {color: #000000; font-weight: bold;}
.geshifilter .kw3 {color: #000066;}
.geshifilter .coMULTI {color: #808080; font-style: italic;}
.geshifilter .es0 {color: #000099; font-weight: bold;}
.geshifilter .br0 {color: #66cc66;}
.geshifilter .st0 {color: #ff0000;}
.geshifilter .nu0 {color: #cc66cc;}
.geshifilter .sc0 {color: #00bbdd;}
.geshifilter .sc1 {color: #ddbb00;}
.geshifilter .sc2 {color: #009900;}

<button dojoType="dijit.form.Button" id="helloButton">
        Hello World!
        <script type="dojo/method" event="onClick">
        dojo.xhrGet({
           url: 'HelloWorldResponseGET.php',
           load: helloCallback,
           error: helloError,
           content: {name: dojo.byId('name').value }
        });
        </script>
     </button>
     Please enter your name: <input type="text" id="name">

Before we go any further - it is important to mention that the url property in the dojo.xhrGet function call must be set to the file that is appropriate to your environment. If you are using an ASP server then the value must read 'HelloWorldResponseGET.asp' instead of 'HelloWorldResponseGET.php' Likewise, if you are using a ColdFusion server then the value must read 'HelloWorldResponseGET.cfm' instead of 'HelloWorldResponseGET.php'. Finally, if you are using a Java server (JSP) then the value must read 'HelloWorldResponseGET.jsp' instead of 'HelloWorldResponseGET.php', or if you are using a Perl server then the value must read 'HelloWorldResponseGET.pl' instead of 'HelloWorldResponseGET.pl'. The code for these files is in the sections below, and is also available as attachments to this tutorial.

In the code above, you will notice that there is a new property that has been passed to the dojo.xhrGet function. This property - content - allows the programmer to send arbitary values to the server as parameters. In this case, since we are using the default method of dojo.io.bind which is GET, the server side script will have the value of the textbox available to it as a the GET parameter 'name'. It is worth mentioning that if the script expected the parameter under a different name (such as 'myName'), we would simply change the content property to be (note the change of 'name' to 'myName' on the left of the assignment operator ':'):

content: {myName: dojo.byId('name').value }

Since we've not used it before, it is also worth noting the call dojo.byId('name').value. Quite simply, this call is a shortcut for the standard document.getElementById(..) function.

Finally, if you enter your name into the text box and you click the 'Hello World' button, an alert box should appear with the message 'Hello , welcome to the world of Dojo!' where is the name you entered into the text box.

Here are the server side scripts. A few of them are downloadable at the bottom of this page (the website content management system doesn't allow .jsp or .cfm files).

Using a PHP Server

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */
.geshifilter {font-family: monospace;}
.geshifilter .imp {font-weight: bold; color: red;}
.geshifilter .kw1 {color: #b1b100;}
.geshifilter .kw2 {color: #000000; font-weight: bold;}
.geshifilter .kw3 {color: #000066;}
.geshifilter .co1 {color: #808080; font-style: italic;}
.geshifilter .co2 {color: #808080; font-style: italic;}
.geshifilter .coMULTI {color: #808080; font-style: italic;}
.geshifilter .es0 {color: #000099; font-weight: bold;}
.geshifilter .br0 {color: #66cc66;}
.geshifilter .st0 {color: #ff0000;}
.geshifilter .nu0 {color: #cc66cc;}
.geshifilter .me1 {color: #006600;}
.geshifilter .me2 {color: #006600;}
.geshifilter .re0 {color: #0000ff;}
.geshifilter .re1 {color: #ff0000}

<?php
  /*
  * HelloWorldResponseGET.php
  * --------
  *
  * Print the name that is passed in the
  * 'name' $_GET parameter in a sentence
  */


  header('Content-type: text/plain');
  print "Hello {$_GET['name']}, welcome to the world of Dojo!\n";
?>

Using an ASP Server

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */
.geshifilter {font-family: monospace;}
.geshifilter .imp {font-weight: bold; color: red;}
.geshifilter .kw1 {color: #990099; font-weight: bold;}
.geshifilter .kw2 {color: #0000ff; font-weight: bold;}
.geshifilter .kw3 {color: #330066;}
.geshifilter .co1 {color: #008000;}
.geshifilter .co2 {color: #ff6600;}
.geshifilter .coMULTI {color: #008000;}
.geshifilter .es0 {color: #000099; font-weight: bold;}
.geshifilter .br0 {color: #006600; font-weight: bold}
.geshifilter .st0 {color: #cc0000;}
.geshifilter .nu0 {color: #800000;}
.geshifilter .me1 {color: #9900cc;}

<%
  '
  ' HelloWorldResponseGET.asp
  ' --------
  '
  ' Print the name that is passed in the
  ' 'name' GET parameter in a sentence
  '

  response.ContentType="text/plain"
  response.write("Hello " & request.querystring("name") & ", welcome to the world of Dojo!\n")
%>

Using a ColdFusion Server


Hello, #url.name#, welcome to the world of Dojo!

Using a Java Server (JSP)

<%
  /*
  ' HelloWorldResponseGET.jsp
  ' --------
  '
  ' Print the name that is passed in the
  ' 'name' GET parameter in a sentence
  */

  response.setContentType("text/plain");
%>
Hello <%= request.getParameter("name") %> , welcome to the world of Dojo!

Using a Perl Server

#!/usr/bin/perl
#
#  ' HelloWorldResponseGET.pl
#  ' --------
#  '
#  ' Print the name that is passed in the
#  ' 'name' GET parameter in a sentence
#
use strict;
use CGI;
my $cgi = CGI::new();
print $cgi->header(-type => "text/html; charset=utf-8");
print "Hello " . $cgi->param('name') . ", welcome to the world of Dojo!\n";

Sending Data to the Server Using POST

Using GET data is all well and good, but sometimes you want to use Dojo to improve the user's experience when using a traditional HTML form. As usual, Dojo has a very nice way of making this easier. Again, the code for these files is in the sections below, and are also available as attachments to this tutorial. Additionally, as with the last section, you will need to change the 'url' property to point to the file that is appropriate to your environment.

First, we need to change the markup in the body of HelloWorld.html from:

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */
.geshifilter {font-family: monospace;}
.geshifilter .imp {font-weight: bold; color: red;}
.geshifilter .kw1 {color: #b1b100;}
.geshifilter .kw2 {color: #000000; font-weight: bold;}
.geshifilter .kw3 {color: #000066;}
.geshifilter .coMULTI {color: #808080; font-style: italic;}
.geshifilter .es0 {color: #000099; font-weight: bold;}
.geshifilter .br0 {color: #66cc66;}
.geshifilter .st0 {color: #ff0000;}
.geshifilter .nu0 {color: #cc66cc;}
.geshifilter .sc0 {color: #00bbdd;}
.geshifilter .sc1 {color: #ddbb00;}
.geshifilter .sc2 {color: #009900;}

<br>
    Please enter your name: <input type="text" id="name">

to:

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */
.geshifilter {font-family: monospace;}
.geshifilter .imp {font-weight: bold; color: red;}
.geshifilter .kw1 {color: #b1b100;}
.geshifilter .kw2 {color: #000000; font-weight: bold;}
.geshifilter .kw3 {color: #000066;}
.geshifilter .coMULTI {color: #808080; font-style: italic;}
.geshifilter .es0 {color: #000099; font-weight: bold;}
.geshifilter .br0 {color: #66cc66;}
.geshifilter .st0 {color: #ff0000;}
.geshifilter .nu0 {color: #cc66cc;}
.geshifilter .sc0 {color: #00bbdd;}
.geshifilter .sc1 {color: #ddbb00;}
.geshifilter .sc2 {color: #009900;}

<br>
    <form id="myForm" method="POST">
      Please enter your name: <input type="text" name="name">
    </form>

Next we need to change the dojo/method:

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */
.geshifilter {font-family: monospace;}
.geshifilter .imp {font-weight: bold; color: red;}
.geshifilter .kw1 {color: #b1b100;}
.geshifilter .kw2 {color: #000000; font-weight: bold;}
.geshifilter .kw3 {color: #000066;}
.geshifilter .coMULTI {color: #808080; font-style: italic;}
.geshifilter .es0 {color: #000099; font-weight: bold;}
.geshifilter .br0 {color: #66cc66;}
.geshifilter .st0 {color: #ff0000;}
.geshifilter .nu0 {color: #cc66cc;}
.geshifilter .sc0 {color: #00bbdd;}
.geshifilter .sc1 {color: #ddbb00;}
.geshifilter .sc2 {color: #009900;}

<script type="dojo/method" event="onClick">
        dojo.xhrGet({
           url: 'HelloWorldResponseGET.php',
           load: helloCallback,
           error: helloError,
           content: {name: dojo.byId('name').value }
        });
</script>

to:

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */
.geshifilter {font-family: monospace;}
.geshifilter .imp {font-weight: bold; color: red;}
.geshifilter .kw1 {color: #b1b100;}
.geshifilter .kw2 {color: #000000; font-weight: bold;}
.geshifilter .kw3 {color: #000066;}
.geshifilter .coMULTI {color: #808080; font-style: italic;}
.geshifilter .es0 {color: #000099; font-weight: bold;}
.geshifilter .br0 {color: #66cc66;}
.geshifilter .st0 {color: #ff0000;}
.geshifilter .nu0 {color: #cc66cc;}
.geshifilter .sc0 {color: #00bbdd;}
.geshifilter .sc1 {color: #ddbb00;}
.geshifilter .sc2 {color: #009900;}

<script type="dojo/method" event="onClick">
   // Don't forget to replace the value for 'url' with
   // the value of appropriate file for your server
  // (i.e. 'HelloWorldResponsePOST.asp') for an ASP server
    dojo.xhrPost({
        url: 'HelloWorldResponsePOST.php',
        load: helloCallback,
        error: helloError,
        form: 'myForm'
   });
</script>

As can be seen from the code above, we've changed dojo.xhrGet to dojo.xhrPost. We removed the 'content' property and replaced it with a new property 'form'. This basically informs the dojo.xhrPost function that it needs to use the form 'myForm' as the source for the data in the call.

As with the last section, entering your name and clicking 'Hello World!' should yield a message such as 'Hello , welcome to the world of Dojo!' where is the name you entered into the text box.

Using a PHP Server

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */
.geshifilter {font-family: monospace;}
.geshifilter .imp {font-weight: bold; color: red;}
.geshifilter .kw1 {color: #b1b100;}
.geshifilter .kw2 {color: #000000; font-weight: bold;}
.geshifilter .kw3 {color: #000066;}
.geshifilter .co1 {color: #808080; font-style: italic;}
.geshifilter .co2 {color: #808080; font-style: italic;}
.geshifilter .coMULTI {color: #808080; font-style: italic;}
.geshifilter .es0 {color: #000099; font-weight: bold;}
.geshifilter .br0 {color: #66cc66;}
.geshifilter .st0 {color: #ff0000;}
.geshifilter .nu0 {color: #cc66cc;}
.geshifilter .me1 {color: #006600;}
.geshifilter .me2 {color: #006600;}
.geshifilter .re0 {color: #0000ff;}
.geshifilter .re1 {color: #ff0000}

<?php
  /*
  * HelloWorldResponsePOST.php
  * --------
  *
  * Print the name that is passed in the
  * 'name' $_POST parameter in a sentence
  */


  header('Content-type: text/plain');
  print "Hello {$_POST['name']}, welcome to the world of Dojo!\n";
?>

Using an ASP Server

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */
.geshifilter {font-family: monospace;}
.geshifilter .imp {font-weight: bold; color: red;}
.geshifilter .kw1 {color: #990099; font-weight: bold;}
.geshifilter .kw2 {color: #0000ff; font-weight: bold;}
.geshifilter .kw3 {color: #330066;}
.geshifilter .co1 {color: #008000;}
.geshifilter .co2 {color: #ff6600;}
.geshifilter .coMULTI {color: #008000;}
.geshifilter .es0 {color: #000099; font-weight: bold;}
.geshifilter .br0 {color: #006600; font-weight: bold}
.geshifilter .st0 {color: #cc0000;}
.geshifilter .nu0 {color: #800000;}
.geshifilter .me1 {color: #9900cc;}

<%
  '
  ' HelloWorldResponsePOST.asp
  ' --------
  '
  ' Print the name that is passed in the
  ' 'name' $_POST parameter in a sentence
  '

  response.ContentType="text/plain"
  response.write("Hello " & request.form("name") & ", welcome to the world of Dojo!\n")
%>

Using a ColdFusion Server


Hello, #form.name#, welcome to the world of Dojo!

Using a Java Server (JSP)

<%
  /*
  ' HelloWorldResponsePOST.jsp
  ' --------
  '
  ' Print the name that is passed in the
  ' 'name' POST parameter in a sentence
  */

  response.setContentType("text/plain");
%>
Hello <%= request.getParameter("name") %> , welcome to the world of Dojo!

Using a Perl Server

#!/usr/bin/perl
#
#  ' HelloWorldResponsePOST.pl
#  ' --------
#  '
#  ' Print the name that is passed in the
#  ' 'name' POST parameter in a sentence
#
use strict;
use CGI;
my $cgi = CGI::new();
print $cgi->header(-type => "text/html; charset=utf-8");
print "Hello " . $cgi->param('name') . ", welcome to the world of Dojo!\n";

Finding more resources

I hope you've enjoyed this tutorial and found it informative. No doubt though, you will need more information on Dojo and how it and it's widgets work. Below is a list of links that will point you in the right direction.

Contacting the Author

Thinking of making modifications to this document? Want to make suggestions / constructive criticism?

If so, please contact me (Lance Duivenbode) at dojo AT duivenbode DOT id DOT au. Feedback is always welcome since it helps me improve my documentation - both now and in the future. Thanks!

Changelog

Debugging Tutorial

Dojo is very lean and speedy, and uses some very clever tricks to save memory and time. The downside: Dojo does not contain much error trapping, which would bloat and slow down the code. If your code is not behaving, some of the resulting errors can look mighty puzzling at first.

No worries! Here are a few tips to make you a confident, successful bug finder. Knowing these ahead of time will make your Dojo learning curve less steep.

Use Firebug or Firebug Lite

We can't stress this enough. Firebug, an open source debugging extension for Firefox, is essential for JavaScript, HTML and CSS debugging. You can download it from the Firebug web site.

Not a Firefox user? You may want to consider switching, at least for development work. One of Dojo's virtues is its hiding of cross-platform differences. So the more you rely on it, the more your code will be portable, and the less difference your development browser choice matters.

Still not convinced? That's OK too. If you use Internet Explorer or Safari, you can use the Firebug Lite library, bundled with Dojo. This gives you some of the logging and command line features of Firebug. It's not a full emulation, but it's a fairly good alternative and is fully API-compatible.

To use Firebug Lite, you must include the isDebug config parameter like so:

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #b1b100;} .geshifilter .kw2 {color: #000000; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .coMULTI {color: #808080; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #ff0000;} .geshifilter .nu0 {color: #cc66cc;} .geshifilter .sc0 {color: #00bbdd;} .geshifilter .sc1 {color: #ddbb00;} .geshifilter .sc2 {color: #009900;}
<script type="text/javascript" src="http://o.aolcdn.com/dojo/1.0.0//dojo/dojo.js"
        djConfig="parseOnLoad: true, isDebug: true">
</script>

This parameter has no effect on Firefox browsers with Firebug already present. So including this parameter makes your debugging code usable in IE, Safari, and Firefox with no changes.

Faulty dojo.require's and the Firebug Console

The following code has a subtle bug:

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #b1b100;} .geshifilter .kw2 {color: #000000; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .coMULTI {color: #808080; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #ff0000;} .geshifilter .nu0 {color: #cc66cc;} .geshifilter .sc0 {color: #00bbdd;} .geshifilter .sc1 {color: #ddbb00;} .geshifilter .sc2 {color: #009900;}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
            "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Fix me!</title>
    <style type="text/css">
        @import "http://o.aolcdn.com/dojo/1.0.0/dijit/themes/tundra/tundra.css";
        @import "http://o.aolcdn.com/dojo/1.0.0/dojo/resources/dojo.css"
    </style>
        <script type="text/javascript" src="http://o.aolcdn.com/dojo/1.0.0/dojo/dojo.js"
                djConfig="parseOnLoad: true, isDebug: true">
</script>
        <script type="text/javascript">
                dojo.require("dojo.parser");
                dojo.require("dijit.form.Textbox");
    </script>
</head>
<body class="tundra">
<form>
What's the 411? <input type="text" size="20" name="info"  dojoType="dijit.form.TextBox"
           trim="true" propercase="true" />
<br>
</body>
</html>

Without Firebug, this code may pop up an unhelpful dialog box (IE) or display nothing (Firefox). In either case the textbox doesn't look right. You check this by entering a lowercase name and tabbing out of the box ... the propercase attribute should capitalize the first letter. It doesn't.

With Firebug the error is easier to spot. First, there's an indicator at the bottom right hand corner.

[inline:debugging1.png]

You click on the "1 Error" message and the Firebug console pops up:

[inline:debugging2.png]

Looking back at your code, you notice the capitalization on "Textbox" in the dojo.require is wrong. That's a common mistake, but easily fixed. It's also common to forget the dojo.require, or to misspell the class in the dojoType attribute. In each case, Firebug will set you straight.

Firebug Lite will give you a similar console, but it will appear naturally at the bottom of your browser window. To turn it off, you must set the isDebug flag to false and run the page again.

Errors In Dojo/Method and Dojo/Event Code

The following code has an error:




Fix me!
    
    
    


Click to break!

But when you look at the console, there's no apparent error. If you were programming in other languages, you might use a debugger and set a breakpoint on the "this.domNode" line. Firebug's debugger let's you do that, but not on this particular code. Scripts of type "dojo/event" and "dojo/method" are compiled and interpreted differently than "text/javascript" ones. But there are a couple of alternate debugging methods.

Method 1: Logging

The first method is logging, and if you've used modern logging tools like log4j you'll find it familiar. The idea is to write trace messages to a log which you can then use to find variable values or the last executed bit of code.

Why not just use alert() ? The trusty JavaScript alert() is a favorite debugging tool, but it suffers from the following problems:

Clearly alert's just not powerful enough. In Dojo logging, you can associate messages with severity, just like in log4j. The following code illustrates the five severity levels:

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #000066; font-weight: bold;} .geshifilter .kw2 {color: #003366; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .co1 {color: #009900; font-style: italic;} .geshifilter .coMULTI {color: #009900; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #3366CC;} .geshifilter .nu0 {color: #CC0000;} .geshifilter .me1 {color: #006600;} .geshifilter .re0 {color: #0066FF;}
console.log("Nothing happening");
console.debug("Checking to make sure nothing happened");
console.info("Something might happen.");
console.warn("Something happened, but it's no big deal.");
console.error("Cough cough!");

In the Firebug console, the messages will appear like this:

[inline:firebug_logging.png]

In IE, they will appear like this:

[inline:firebug_ie_capture.png]

Another useful method, console.dir() dumps variable contents to the screen. While console.log works fine for strings and integers, console.dir prints more complex variables - objects, arrays, arrays of objects, or whatever. For example:

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #000066; font-weight: bold;} .geshifilter .kw2 {color: #003366; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .co1 {color: #009900; font-style: italic;} .geshifilter .coMULTI {color: #009900; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #3366CC;} .geshifilter .nu0 {color: #CC0000;} .geshifilter .me1 {color: #006600;} .geshifilter .re0 {color: #0066FF;}
console.dir([
   {attribute: "last_name", sortDescending: true},
   {attribute: "last_name", sortDescending: true}
]);

produces:

[inline:firebug_logging2.png]

So in our example above, we write:

console.debug("dojo.newWidth is" + dojo.newWidth);
this.domNode.style.width = dojo.newWidth;

Running this, we quickly find that dojo.newWidth is undefined. Maybe we spelled it wrong? To quickly find out, we change the debugging statement to:

console.dir("dojo is" + dojo);
this.domNode.style.width = dojo.newWidth;

Nope, there's no property in dojo that looks like newWidth. Finally, we spot our error and change the right hand side to "newWidth." Case closed.

Method 2: The "debugger" Statement

Alternatively you can set a "poor person's breakpoint" in the code. Just insert the debugger; statement, which is a legal JavaScript reserved word.

debugger;
this.domNode.style.width = dojo.newWidth;

This statement stops the code and brings you to a Firebug command prompt. It appears the code has stopped at ... huh?

[inline:debugging4.png]

That's a side effect of running dojo/event code. The breakpoints don't seem correct at all.

But just click the Console tab and now you can examine variables or execute just about any JavaScript you want. In this case, we look at the dojo.newWidth property, which has nothing in it. But "dojo" does and we examine it by console.dir(dojo). Basically all the logging features of method 1 are available to type here.

[inline:debugging3.png]

To Follow The dojo.require Trail, Use Dojo Locally

Since that code is now running, we try a minor variant which sets the button to blue:

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #b1b100;} .geshifilter .kw2 {color: #000000; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .coMULTI {color: #808080; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #ff0000;} .geshifilter .nu0 {color: #cc66cc;} .geshifilter .sc0 {color: #00bbdd;} .geshifilter .sc1 {color: #ddbb00;} .geshifilter .sc2 {color: #009900;}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
            "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Fix me!</title>
    <style type="text/css">
        @import "http://o.aolcdn.com/dojo/1.0.0/dijit/themes/tundra/tundra.css";
        @import "http://o.aolcdn.com/dojo/1.0.0/dojo/resources/dojo.css"
    </style>
    <script type="text/javascript" src="http://o.aolcdn.com/dojo/1.0.0/dojo/dojo.xd.js"
            djConfig="parseOnLoad: true">
</script>
    <script type="text/javascript">
        dojo.require("dojo.parser");
        dojo.require("dijit.form.Button");
    </script>
</head>
<body class="tundra">
<div dojoType="dijit.form.Button">
   Click to break!
   <script type="dojo/event" event="onClick">
      this.domNode.style.backgroundColor = dojo.Color.named.aliceblue;
   </script>
</div>
</html>

You check the console ... no errors there. But that dojo.Color.named.aliceblue is a little questionable. You know that dojo.colors needs to be included, but you thought dijit.form.Button already did that.

You can find out for sure by using a local copy of Dojo. CDN Dojo is very quiet about the modules it loads. Local Dojo is very noisy. So, assuming our local copy of Dojo is installed on the web server underneath /dojoroot, the following change:

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #b1b100;} .geshifilter .kw2 {color: #000000; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .coMULTI {color: #808080; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #ff0000;} .geshifilter .nu0 {color: #cc66cc;} .geshifilter .sc0 {color: #00bbdd;} .geshifilter .sc1 {color: #ddbb00;} .geshifilter .sc2 {color: #009900;}
<style type="text/css">
        @import "http://o.aolcdn.com/dojo/1.0.0/dijit/themes/tundra/tundra.css";
        @import "http://o.aolcdn.com/dojo/1.0.0/dojo/resources/dojo.css"
    </style>
    <script type="text/javascript" src="http://o.aolcdn.com/dojo/1.0.0/dojo/dojo.xd.js"
            djConfig="parseOnLoad: true">
</script>

Yields the following on the console

[inline:debugging5.png]

You see every Dojo Core and Dijit Component loaded. Sure enough, dojo.colors is not in the list, so we add a dojo.require statement

That Doesn't Look Right ... DOM Inspection

Unfortunately, that doesn't fix the problem either. When styling errors occur, it's a good time to use Firebug's DOM Inspector. You can think of it as View Source on steroids.

So we click Inspect and point at the screen button

[inline:debugging6.png]

The right-hand side of the console tells what styles and style rules are applied to this class. Crossed-off lines are styles that have been overriden. Very nice!

Debugging External Classes With debugAtAllCosts

dojo/method and dojo/event scripts are good for short, non-reusable snippets of code. But when you start building reusable components, you'll be storing your code into Dojo-declared classes instead. The good news is the more you make this switch, the easier your debugging task will be.

So here's a piece of HTML code and a reusable Dojo-based widget:

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #b1b100;} .geshifilter .kw2 {color: #000000; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .coMULTI {color: #808080; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #ff0000;} .geshifilter .nu0 {color: #cc66cc;} .geshifilter .sc0 {color: #00bbdd;} .geshifilter .sc1 {color: #ddbb00;} .geshifilter .sc2 {color: #009900;}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
            "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Goolica Tax Form</title>
    <style type="text/css">
        @import "/dojoroot/dijit/themes/tundra/tundra.css";
        @import "/dojoroot/dojo/resources/dojo.css"
    </style>
    <script type="text/javascript" src="/dojoroot/dojo/dojo.js"
            djConfig="parseOnLoad: true">
</script>
    <script type="text/javascript">
        dojo.require("dojo.parser");
        dojo.require("dojobook.online-book.debugging.BuggyWidget");
    </script>
</head>
<body class="tundra">
    <div dojoType="dojobook.online-book.debugging.BuggyWidget"></div>
</body>
</html>
dojo.provide("dojobook.online-book.debugging.BuggyWidget");

dojo.require("dijit._Widget");

dojo.declare(
"dojobook.online-book.debugging.BuggyWidget",
[dijit._Widget],
{ 
   postCreate: function() {
      dojo.nonExistentMethod();
   }
});

Running this code, you will see an error appear, but it's nowhere near the right location:

[inline:debugging8.png]

But by simply setting the debugAtAllCosts flag to true:

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #b1b100;} .geshifilter .kw2 {color: #000000; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .coMULTI {color: #808080; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #ff0000;} .geshifilter .nu0 {color: #cc66cc;} .geshifilter .sc0 {color: #00bbdd;} .geshifilter .sc1 {color: #ddbb00;} .geshifilter .sc2 {color: #009900;}
<script type="text/javascript" src="/dojoroot/dojo/dojo.js"
            djConfig="parseOnLoad: true, debugAtAllCosts: true">
</script>

the displayed error location will now be correct:

[inline:debugging7.png]

Important! you should always remove debugAtAllCosts from production code. It slows down the client unnecessarily. Rather than manually inserting and removing them, I like to delegate that job to a server side language like PHP:

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #b1b100;} .geshifilter .kw2 {color: #000000; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .co1 {color: #808080; font-style: italic;} .geshifilter .co2 {color: #808080; font-style: italic;} .geshifilter .coMULTI {color: #808080; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #ff0000;} .geshifilter .nu0 {color: #cc66cc;} .geshifilter .me1 {color: #006600;} .geshifilter .me2 {color: #006600;} .geshifilter .re0 {color: #0000ff;} .geshifilter .re1 {color: #ff0000}
<?php
$djConfig     = $inProduction ? "parseOnLoad: true" : "parseOnLoad: true, debugAtAllCosts: true";
$loadLocation = $inProduction ? "http://o.aolcdn.com/dojo/1.0.0" : "/dojoroot";
$useXd        = $inProduction ? ".xd" : "";
?>
    <style type="text/css">
        @import "<?= $loadLocation ?>/dijit/themes/tundra/tundra.css";
        @import "<?= $loadLocation ?>/dojo/resources/dojo.css"
    </style>
    <script type="text/javascript" src="<?= $loadLocation ?>/dojo/dojo<?= $useXd ?>.js"
            djConfig="<?= $djConfig ?>"></script>

Introduction

Dojo provides a lot of power and attempts to make it digestable in three major layers: Dojo Core, Dijit, and DojoX. This book serves as a guide to these layers, introducing concepts as you need them and working downward from high-level usage to getting your hands dirty in building your own widgets, custom namespaces, and unit tests.

As you'll see, Dijit and DojoX build on the solid foundation that Dojo Core provides for all Dojo applications. With Core and Dijit locked into stable APIs and a heavy QA, i18n, and accessibility process many edge-of-the-web features for which Dojo is known are developed in the looser, more organic DojoX project. Throughout the book we will show you how these parts build on each other and use the infrastructure each provides to elegantly solve user experience problems which until now have been difficult for browser-based UIs to address.

Thanks for checking out Dojo and the Dojo Book. If things aren't clear in the book, just comment on the book page in question and we'll try to improve it. It's your applications that have inspired us to build Dojo and the stories of people improving user experiences with the toolkit keep us going, and it's with your help that we are evolving this book.

Licensing

You may use Dojo in commercial software without obtaining a separate license or incurring other obligations.

The Dojo Toolkit is dual-licensed. The preferred license is the Academic Free License v2.1. It is extremely liberal, allows for commercial use, and provides for sub-licensing. All Dojo Foundation projects release their code under the terms of this license. It is almost never necessary to exercise the "dual" portion of the dual-licensing terms since the AFL is extremely permissive.

For users who face the problem of artificial ambiguity the FSF has created regarding the compatibility of the AFL and the (L)GPL, The Dojo Toolkit may alternately be used under the terms of the BSD License. Both the AFL and the BSD licenses meet the licensing goals of the Dojo Foundation.

Dojo's "dual licensing" is different than that of many Open Source projects in that the terms of both licenses are Open Source and extremely permissive. There are no royalties or commercial use clauses to complicate the matter. In almost every case, you will not need to choose anything other than the AFL and in the common case you need not do anything to denote this choice of license. If you have questions regarding Dojo licensing, please do not hesitate to contact Alex Russell, current President of the Dojo Foundation.

The Role of the Dojo Foundation

Dojo is Open Source software, distributed by a non-profit foundation which has been set up for the purpose of providing a vendor-neutral owner of Dojo intellectual property. In order to ensure to users of Foundation projects that there is no ambiguity or hidden liability regarding the use of Foundation code, all contributors are required to provide signed Contributor License Agreements.

All committers on Dojo Foundation projects have a vote in Foundation matters. The Foundation is run by contributors, operates in a transparent way, and is funded exclusively by donations. The licensing goals of the Foundations are briefly covered on the Foundation page.

Third-Party Licenses

Dojo uses code from other open source projects, subject to the terms of their licenses. Those licenses and software copyright notices are listed below:

History

In early 2004 Alex Russell (original creator of netWindows) began looking to hire a collaborator on DHTML projects at Informatica. In the process many members of the DHTML community were contacted, culminating in the April 25, 2004 email titled "Selling the future of DHTML". David Schontzler (Stilleye) spent a summer working at Informatica, and Dylan Schiemann also joined Informatica at that time. The first lines of code contributed to Dojo were done by Alex and Dylan with the support of Informatica. There were many other community members that were active participants in shaping the direction of Dojo, including Joyce Park, Tom Trenka, Mark Anderson, Leonard Lin (who suggested the name Dojo), Aaron Boodman, Simon Willison, Cal Henderson, and Dan Pupius.

After several months of discussions on the ng-dhtml (now dojo-developer) mailing list about licensing, choosing a name, coding conventions, build tools, server configuration, and requirements, work began and the Dojo Foundation was formed. The foundation is a 501(c)6 entity designed to house the code and IP rights and today hosts several other projects as well. By March 2005 contributions from the community began to outweigh those of the core development team and today 8 major releases have been made with over 1 million downloads of Dojo to date. Contributions and code have come from more than 60 developers and companies and major users such as IBM, AOL, Sun, SitePen, Bloglines, Google, Nexaweb and others continue to keep Dojo's quality high and the community vibrant.

Why Dojo?

Today there are several high-quality JavaScript toolkits available and several hundred other toolkits of varying quality and completeness. Why, out of that sea of possible options, should you chose Dojo?

  • Breadth and Depth: Dojo is the "full stack". Instead of cobbling together components from several different sources, Dojo allows each component to build on a trusted set of high-quality building blocks by providing integrated infrastructure and a wide variety of optional modules. These components provide good solutions to common user experience problems and can be easily tweaked to meet your needs. From pane-based layouts to client-side charting and graphing to data binding to a time-tested module system, Dojo is solid infrastructure for delivering great experiences.
  • Quality: Infrastructure for internationalization and accessibility is woven through the entire fabric of Dojo. Keystrokes are hinted correctly. The components all fit together as a cohesive whole. Everything is customizable easily with CSS, but very little needs to be tweaked to get a great looking UI nearly everywhere. These are the hallmarks of a system which has been designed and tested to deliver great experiences, not only to users, but also to designers and developers.
  • Performance: Dojo is used on high-profile, high-traffic sites every day and Dojo's build tools are a key reason why. Dojo's package system makes it easy to manage large-scale UI development projects and the build system layers on top to make your applications scream; all without code changes. Dojo also packs high-performance implementations of common utilties into its core, and the rebuild of Dojo for 0.9 focuses heavily on performance and reduced code footprint. The result is a small, tight toolkit that is blazing fast. Dojo's performance alone makes it an ideal platform to extend and build on.
  • Community: Dojo is an open community. As a result many individuals and companies have been able to come together on a level playing field to build tools that benefit everyone. The licensing of the toolkit is designed to be as apolitical as possible and we work hard to ensure that getting your itches scratched is easy if you are willing to get involved. All development happens in the open and the barriers to entry are intentionally very low. We don't care where you work or how "qualified" you are, all we care is that you want to build products that makes user experiences better. Designer or developer or doc writer, the community Dojo values contributions of every kind and position in the community is commensurate with the quality of the work you do, not political wrangling. We're working to change the notions of who can be contributors in Open Source and we invite you to join us in charting a new path. If you want to build a great product and think you can help us, we want to hear from you.

Dojo vs. Other Toolkits

Several other toolkits are often compared to Dojo. What follows is not a comprehensive comparison, but rather a high-level comparison of the features and design goals of these alternatives and how they compare to Dojo's features, development process, and philosophy.

  • MochiKit: MochiKit is a high-quality JavaScript toolkit which makes writing JavaScript as pythonic as is reasonably possible while still achieving good performance. It follows many of the same conservative principles about packaging, naming, and global namespace usage as Dojo. Authored primarily by Bob Ippolito, it has great docs and tests but unlike Dojo does not ship with a widget system or extensive component set. Some code is shared between Mochi and Dojo (under CLA, of course). Mochi is not backed by a foundation and code lineage is not verified but it is very liberally licensed.
  • Prototype+Scriptaculous: These pervasive libraries provide much of the same functionality as Dojo Core but do not share the same conservative philosophy regarding global namespace contention, favoring shorter naming of commonly used functions over other concerns. They feature good documentation and broad community support as well as tight integration with Ruby On Rails (among other frameworks). Scriptaculous provides some controls (auto-complete, sliders, etc.) but is not a widget toolkit and does not have support for building widgets easily. Many add-on libraries are available for Prototype+Scriptaculous but they are not distributed with the library as such. They do not feature a package or build system (aside from their own distributables).  Prototype and Scriptaculous are not backed by a foundation and code lineage is not verified but they are very liberally licensed.
  • YUI: YUI is developed in-house at Yahoo and features extensive, high-quality documentation and examples. Designed for speed and targeted at a population of professional PHP developers, YUI is designed with the needs of Yahoo-scale applications in mind. A growing list of controls is available with the toolkit as are useful CSS normalizing and layout style sheets. No package system is available, but "roll up" files of common functionality are distributed and documentation makes clear what order to load files in. No CSS query or markup-driven widget construction system is available in YUI. YUI has an active community and liberal licensing but external committers are not allowed on the project and Yahoo has not clarified the code lineage and other IP rights around the toolkit. No source control access of any sort is available. YUI is edge-cached on Yahoo's CDN for use by all.
  • JQuery: A minimalist system focused primarily on operating on existing DOM structures, JQuery features a hybrid XPath/CSS query language (Dojo uses standard CSS 3 queries) and provides a rich set of options and operations on the results of these queries. JQuery packs Ajax, effects, and other utilities into a small core (beating all but MooTools). While there is no widget or package system in JQuery per sae, 3rd party component libraries are available which build on top of JQuery. The JQuery community is highly active, usually helpful, and external contributions and patches are accepted. Good docs for the system are readily available. JQuery is dual-licensed MIT and GPL with all copyrights resting with John Resig. It is not clear how IP rights are assigned to John by other contributors and under what terms. Several frameworks (notably Drupal) integrate JQuery.
  • EXT: Like Dojo's Dijit system, EXT is a component library. It features a large number of consistent, good looking widgets with an emphasis on pixel-perfect layout and desktop-like UIs across browsers. Originally developed to run on top of YUI and later JQuery, EXT now has it's own low-level library, removing the need for 3rd party dependencies. The EXT community is very active and good documentation is available for the library. It is licensed under the terms of the LGPL and commercial licenses of various forms are available. It is not clear whether or not external contributions are accepted (and under what terms) and anonymous subversion access is limited to those who financially support the project in some way.
  • GWT: Directly integrating server-side development and client-side development, GWT takes the perspective that JavaScript is a bug to be solved and uses advanced compiler technology to allow developers to write in Java and generate dynamic, JavaScript based UIs in the Google style. The default widget set is a strict subset of those provided by Dijit, but GWT takes great pains to optimize all generated code. A growing trove of add-on libraries are available to enhance the default components. Unlike YUI and EXT, GWT is being run as a real Open Source project, allowing external committers, and doing development in the open while managing IP issues in a very sophisticated manner (CLAs, code review, etc. Much like Apache or Dojo).  GWT applications can only be written in Java and are most often deployed on Java containers. Good documentation is available and a thriving community is helpful.

For the sake of comparison, Dojo:

  • Allows external committers and uses CLAs (like GWT or Apache) to ensure that there are no IP issues
  • Is very liberally licensed and provides anonymous SVN access to everyone. Committer privs are earned
  • Provides a relatively rich client-side component set but does not require tight binding to any server-side language ("protocols, not APIs")
  • Attempts to provide a balance between on-the-wire size and common-case functionality. Dojo Base is similar in size to Prototype.
  • Is very conservative about not stepping on the toes of other code in your pages and preserving the global namespace
  • Is edge-cached on AOLs CDN for use by all
  • Provides a package system which makes knowing which order to load things in a moot problem
  • Allows for incremental enhancement via markup and provides a very easy-to-use widget system for building your own reusable components which can then be easily instantiated via markup.

Part 1: Life With Dojo - Dojo and Dijit Application Examples

Dojo applications look good, but their primary benefit is in helping real people solve real interaction problems in real web application. Dojo makes it easy to design a more usable web experience for the intended audience.

The following personas illustrate how people with different goals and skill sets can make Dojo work for them. We will follow them working through an example. The personas and examples are made-up, but broadly represent who the toolkit is built for and each section of the book is designed to help solve problems for each of them, sometimes more for one than the others, but always for their users:

John Walsh is a Web Developer. He’s been out of college for 3 years and he works for a small company that creates web sites for clients. He lives and breathes HTML and CSS. He has some basic JavaScript experience, for example with click handlers.  He knows a lot about Photoshop, but if you ask him most days, he doesn’t really consider himself to be a Designer. Several of his older co-workers would call themselves Designers and only incidentally Web Developers. John and his co-workers care greatly about how an interface looks, they are completely sold on CSS, and they want their tools to work the way they think they should.

Andy Tso has been doing the "startup thing" for nearly a decade. He's seen it all and is a very discerning consumer of technology. He couldn't get enough of his CS and math courses when he was at Stanford. After graduation Andy didn't really know where he wanted to go, so he started on an advanced CS degree at MIT but dropped when some of his other friends left to found an e-commerce thing in '98. It imploded quickly but by that time he'd caught the startup bug. His current startup is pushing the edges of what you can (or should) do in a browser and when they started investigating Dojo, they saw it wasn't everything they needed, but certainly a good starting point. Andy is the kind of guy who could have written Dojo but is wise enough not to. He might contribute patches, though. Andy's main problem is getting through the gunk to the hard tech docs and giving his junior Developers something to work from.

Laura Allen is an Enterprise IT Developer. She has worked for the same (medium sized) company over the past 15 years as it has been bought out twice and renamed three times. She supports internal development sites and relies on tools and frameworks all day long. For her, Web2.0 is tremendously exciting. She didn't know you could do much of anything in a browser, but things that aren't Java/PHP scare her a bit. She’s heard that Microsoft mentioned a toolkit too but her manager saw a Dojo demo at a conference and now he’s pushing his teams to investigate Dojo.

Example 1: Why Doesn't Anyone Fill Out Their Tax Forms?

John Walsh lives in the country of Googolica. This country is the first in the world to require its citizens to file their taxes online. Here's the form they use:

2007 Tax Form

The Sovreign Nation of Googolica, In Search We Trust

First Name:
Last Name:
Email Address:

  1. Please Enter Your 2007 Gross Income
  2. Please enter the value from line 1. This is your 2007 tax
  3. Would you like to contribute an extra $3 to the Presidential Campaign Fund?


To the astonishment of the Googolican government, people have not been using the form. The Parliament investigated. The problem, they first thought, might be the brutal tax percentage - 100%. This theory was quickly dismissed.

The final report concluded the web page is faulty, thus discouraging it use. Among its problems:

  • It's ugly. Really ugly.
  • The form does nothing to help the user. It does not clean up mistakes. And it reports errors after the form has been submitted, leaving the user to stare at a blank form again.
  • Googolica has two official languages, English and Snobol. Snobol-speakers are out of luck. And bifurcating the page into an English and a Snobol version makes development twice as difficult.
  • People with special needs - low vision, motor problems that discourage mouse use - are out of luck.
  • MORE...

Fortunately, the Googolican IT department employs John Walsh. And John has just downloaded Dojo and Dijit. Things are looking up!

Adding Dijit

Let's look at the HTML code for that form:

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #b1b100;} .geshifilter .kw2 {color: #000000; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .coMULTI {color: #808080; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #ff0000;} .geshifilter .nu0 {color: #cc66cc;} .geshifilter .sc0 {color: #00bbdd;} .geshifilter .sc1 {color: #ddbb00;} .geshifilter .sc2 {color: #009900;}
<head>
    <title>Taxes, The Surest Thing Next to Death!</title>
</head>
<body>
<h1>2007 Tax Form</h1>
    The Sovereign Nation of Googolica,  In Search We Trust
<form>
    First Name: <input type="text" length="20" name="first"><br>
    Last Name: <input type="text" length="20" name="last"><br>
    Email Address: <input type="text" length="20" name="email"><br>
<hr>
<ol>
    <li>
        Please Enter Your 2007 Gross Income
        <input type="text" length="10" name="grossIncome">
    </li>
    <li>
        Please enter the value from line 1.  This is your <em>2007 tax</em>
        <input type="text" length="10" name="tax">
   </li>
    <li>
        Would you like to contribute an extra $3 to the Presidential Campaign Fund?
        <input type="checkbox" name="campaign" value="Y">
    </li>
    <li>
        Filing Date:
        <input type="text" length="10" name="filingDate">
    </li>
</ol>
<input type="submit" value="Submit">
</form>
</body>

Pretty standard stuff. Using Dojo we can improve the UI just a few lines of Javascript and some extra attributes on our existing markup.

The magic is in Dijit - shorthand for "dojo widgets". Dijit widgets perform all sorts of tasks, from embelllishing a form control, to controlling the layout of sections and beyond.

Preliminaries for Dijit

You must add two snippets of code for every page using dijits:

  • A HEAD snippet which loads the style sheet and Dojo libraries, then calls functions to load individual dijit types.
  • A class to the BODY tag specifying the name of your theme. In our examples, we'll use the "Tundra" theme.

Our examples will use the America Online hosted version of Dojo, so you don't have to install one bit of Dojo code! Just copy and paste them to a file on your server, and they will work. So here's the HEAD snippet:

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #b1b100;} .geshifilter .kw2 {color: #000000; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .coMULTI {color: #808080; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #ff0000;} .geshifilter .nu0 {color: #cc66cc;} .geshifilter .sc0 {color: #00bbdd;} .geshifilter .sc1 {color: #ddbb00;} .geshifilter .sc2 {color: #009900;}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
            "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Taxes, The Surest Thing Next to Death!</title>
    <style type="text/css">
        @import "http://o.aolcdn.com/dojo/1.0.0/dijit/themes/tundra/tundra.css";
        @import "http://o.aolcdn.com/dojo/1.0.0/dojo/resources/dojo.css"
    </style>
    <script type="text/javascript" src="http://o.aolcdn.com/dojo/1.0.0/dojo/dojo.xd.js"
        djConfig="parseOnLoad: true">
</script>
    <script type="text/javascript">
       dojo.require("dojo.parser");
    </script>
</head>

Alternatively, if you're a do-it-yourselfer running Dojo from your local site, you just make a few changes to the header:

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #b1b100;} .geshifilter .kw2 {color: #000000; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .coMULTI {color: #808080; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #ff0000;} .geshifilter .nu0 {color: #cc66cc;} .geshifilter .sc0 {color: #00bbdd;} .geshifilter .sc1 {color: #ddbb00;} .geshifilter .sc2 {color: #009900;}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
            "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Taxes, The Surest Thing Next to Death!</title>
    <style type="text/css">
        @import "/dojoroot/dijit/themes/tundra/tundra.css";
        @import "/dojoroot/dojo/resources/dojo.css"
    </style>
    <script type="text/javascript" src="/dojoroot/dojo/dojo.js"
        djConfig="parseOnLoad: true">
</script>
    <script type="text/javascript">
       dojo.require("dojo.parser");
    </script>
</head>

All of the remaining examples will use the AOL version of the header. The important thing is: none of the rest of the code changes. You can use AOL CDN while you're trying out Dojo, then just change the first lines when/if you install you're own.

This is a fairly standard block. If you have access to a server-side language like PHP or ASP, it's handy to place the header in a separate file and include it.

Tundra is the default