The Dojo Book, 0.4

The Dojo Book has two versions because the Dojo project itself has two versions. This book addresses version 0.4. And like the code itself, resources are currently concentrated on writing and editing the 0.9 book.

Part 1: "Introduction"

Dojo provides a lot of power and attempts to make it digestable in layers. For server-side developers, there's "widgets without coding", for HTML+CSS devs Dojo provides wonderful facilities for quickly building template-driven widgets, and for serious JavaScript and DHTML hackers Dojo is the standard library you will wish JavaScript always had.

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.

In the Introduction, you'll get an overview of how Dojo can help you, what problems it solves, and where in the book you might be able to best find the information you're looking for. Also, remember that because this book is maintained by the community and is online, you can search it (and the rest of the Dojo site) at any time.

Lastly, thanks for checking out Dojo and the Dojo Book. It's your applications that have inspired us to build Dojo and the stories of how people are improving experiences with the toolkit that keep us going.

Dojo Architecture

Dojo is a set of layered libraries. The bottom most layer is the packaging system that enables you to customize the distribution of Dojo for your application. On top of Dojo's package system reside language libraries such as the Dojo event system and the language utilities that greatly improve and simplify the lives of JavaScript developers. Environment-specific libraries are provided in some cases, but in most uses, you'll only need to know that all of Dojo works without incident across every major browser.

The bulk of the Dojo code lives in the application support libraries, which are too numerous to display completely in the diagram. dojo.gfx provides native vector graphics support across the major browser implementations of SVG and VML. dojo.lfx is a lightweight effects library, while dojo.io is "where the ajax lives."

Most of the "action" in Dojo is in the widget toolkit, that contains a template-driven system for constructing widgets, a declarative parser for putting widgets in pages without writing JavaScript, and a set of base components that implement common-case solutions to web interaction problems that HTML+CSS alone cannot solve.

Dojo: What Is It?

Dojo is an Open Source DHTML toolkit written in JavaScript. It builds on several contributed code bases (nWidgets, f(m) and Burstlib), which is why we refer to it sometimes as a "unified" toolkit. Dojo aims to solve some long-standing historical problems with DHTML which prevented mass adoption of dynamic web application development.

Dojo allows you to easily build dynamic capabilities into web pages and any other environment that supports JavaScript sanely. You can use the components that Dojo provides to make your web sites more useable, responsive, and functional. With Dojo you can build degradeable user interfaces more easily, prototype interactive widgets quickly, and animate transitions. You can use the lower-level APIs and compatibility layers from Dojo to write portable JavaScript and simplify complex scripts. Dojo's event system, I/O APIs, and generic language enhancement form the basis of a powerful programming environment. You can use the Dojo build tools to write command-line unit-tests for your JavaScript code. The Dojo build process helps you optimize your JavaScript for deployment by grouping sets of files together and reuse those groups through "profiles."

Dojo does all of these things by layering capabilities onto a very small core that provides the package system and little else. When you write scripts with Dojo, you can include as little or as much of the available APIs as you need to suit your needs. Dojo provides:

  • Multiple Points of Entry - You can start using Dojo at the level you are most comfortable with. For example, expert JavaScript programmers can use the foundation capabilities to be more productive quickly, while Web designers and developers can use the set of easy to use, modify, and extend components that make their applications more responsive without requiring them to learn a large JavaScript API. This fundamental design decision drives the layered implementation of most of the major capabilities of Dojo.
  • Interpreter Independence - Dojo is squarely a JavaScript toolkit but, within the realm of JavaScript interpreters and environments, not everything was created equally. Dojo supports at least the very core of the system on as many JavaScript enabled platforms as possible. This allows Dojo to serve as a "standard library" for JavaScript programmers as they move between client-side, server-side, and desktop programming environments.
  • Forward Looking APIs - No one has a crystal ball when it comes to what technologies will be broadly available or used in 5 years, but Dojo attempts to provide APIs that are generic enough to be (directly) useful with todays capabilities while still building in room for future improvement. The dojo.io.bind() interface is a great example of this principle: when first written it wrapped only a single Transport class, but now provides a normalized interface to many ways of receiving and sending data from JavaScript enabled environments.
  • ReducingBarriersToAdoption - This core philosophy behind Dojo's design acknowledges the fact that tools which are hard to use just won't get used, no matter how good they are. Dojo should be built in every way (licensing to deployment) to not give users any reason to not trust or use Dojo for the tasks it's good at. Many of the project's overall decisions get made on the basis of this principle.

Dojo is being built around a single markup language that provides application authors a (more) simple way of declaring and using responsive DHTML interface components. Renderings can be made available in several rendering contexts (such as SVG, or perhaps even the desktop or Flash), but the markup language (DojoML) and scripting language (JavaScript) will not change. Better yet, the DojoML parser accepts extended HTML and SVG as valid input, and can be used to easily create Degradeable Responsive Applications.

Dojo's homepage is: http://dojotoolkit.org.

How this Book is Written

Imagine for a second that you've just come from looking through the API of Dojo. You've memorized every function, every parameter, every example. All of the API has been studied and digested, but you're still not sure how to proceed. You know that there are many ways to do event handling, but you don't know the difference between them and you certainly don't know which one is best suited for your application.

I've made this assumption in writing the book; it allows me to focus on what's important about the book, and separate it from the API. With understanding Dojo, the why of Dojo, you're now free to learn the how by looking at the API. Or, if you already know the API, you're free to learn why it exists in the first place.

Voice

Me

Though this book is a result of many people's work, I(we)'ll be speaking in the first person throughout this book. It not only allows a more personal interaction between the reader and the author, but quite often, describing an author's action is confusing when expressed in the plural form. "We're now opening our text editor" is an awkward sentence at best.

You

Saying "the reader" every sentence is dumb, and since you already know that you're the one reading it, I'll just refer to you as "you".

We

Decisions on the coding of Dojo aren't made by a single person. Almost every significant change to Dojo is done after discussion of how it is engineered. Because of this, I'll run into situations where I want to discuss how something was decided on. In this case, I'll be using the word "we". As in, "we decided that we wanted Dojo to be awesome."

The Tree Structure

On the way to a final topic, you'll be going through some higher-level topics. In order to understand the lower-level topics, and where they fit in to Dojo, you need to have some explanation of how you got way down there. To do this, each of the points along the tree, all the way down to the edge of the branch will have a few paragraphs of explanation. These are overviews for all topics contained underneath. It's worthwhile, if you have a specific topic that you want to read about, to go down the tree, reading each of the brief descriptions, before you read the article itself.

Articles

Readability

I want this to be more a book than a user manual. Therefore, I've tried to use fun analogies and brief stories. Many topics of this book are very difficult to process, and using existing knowledge to bring you up to speed is a great way to make these easy to digest. As a general guideline, I'll try to start an article with a paragraph, followed by a brief analogy or story, flowing into content. Because I don't want you to feel overwhelmed by code, examples will not be back to back. I think that if I have multiple examples, it's important to explain why I provided each one and the differences between them.

Length

I think that the moral of the story of Goldilocks and the Three Bears is that things should neither be lacking, nor in excess, they should be "just right". That said, there's nothing worse than sitting down to get your learn on and be constantly switching from one topic to another, from one page to another, when you want to stay focused on what originally brought you to the article to begin with. Likewise, you don't want to get halfway through an article and realize that you missed both lunch and dinner. To prevent this, as a general guideline, each article in this book should take you about twenty minutes to read. That sounds just right to me.

Sections

I discuss in the book how Dojo is a toolkit, a framework, and everything in between. It's overwhelming just to learn what Dojo can do for you, much less learn what you can do to Dojo. Because of this, the book is split into three different parts.

Part 1 is all about using Dojo, the toolkit. That is, looking at a set of functions and objects that are available to you "out of the box" that don't require any tinkering. Ideally, you should be able to call a function, or initialize and object, without providing any custom logic to it.

Part 2 is meant to focus on more than just using things. We want you to know how to build your own widgets, packages, extend CSS and HTML and get into the nitty gritty of things, such as replacing the data provider for a widget.

Part 3 is a "look into the engine" explaining not only how thing work but why the Dojo developers designed them that way. Much of Dojo's code seems to work based on voodoo. For the advanced programmer, knowing this voodoo will allow you to write tighter, better code.

How to Create Pages

On any page where the dojo.book sidebar appears (including this page) click "create new page". The new page will have the currently viewed page selected as its parent by default

What Dojo gives you

Because Dojo is a toolkit, it's potential uses are unlimited. The only real restrictions are that you're using it in an envornment that uses JavaScript. Though many of you will be reading this in the context of a browser, it's important to remember that JavaScript isn't limited to just that specific use.

Code Simplification

With "Ajax" becoming such a popular buzzword, many are looking for an end-all solution to its complexities that not only work well in existing environments, but will allow much more complicated interaction in the future, allowing for very complicated transfer of data between client and server. With the aformentioned widget functionality, and an easy way to implement your own widgets, Dojo works very well alongside HTML.

Dojo also abstracts many of the differences between browsers that have pained developers for years. Things such as differing event objects and HTTP transport systems are a worry that will be forgotten.

Reusable Code

Dojo provides a launching point for developing code. This means that you can quickly throw a project together for a client or boss without having to reinvent the wheel. We've built Dojo to be highly reusable, so code you have created for one project can be quickly moved to another without any refactoring.

Portable Tools

Responsive applications make many calls to the back-end of web applications which have different call and response characteristics. Standardizing on a portable set of tools for this is beneficial to understanding and predicting overall system behavior.

Because Dojo's widget system sits on top of standard HTML, designers will be able to dive right in with a very shallow learning curve. Dojo allows for designers to add degradable functionality to their (already existing) page without having to implement any logic or strange programming language.

Additional Resources

This book describes what Dojo provides and how to use the toolkit. You will find detailed information about the Dojo APIs in the API Reference Doc.

What is a Toolkit?

Many people see the words framework, library, and toolkit as synonymous. This is true in the sense that they are all descendants of the same parent. Understanding the difference allows you to go beyond that widely scoped overview.

Three words are used to describe a stereotypical developer: geek, nerd, and dork. Many people assume that these words all mean the same thing when, in fact, they each have very specific meanings. Once you learn the meanings of each of these words, you'll quickly be able to run down the list of all of your friends listening to techno in dimly lit rooms and sort them into each category. Even better, you now have the power of more accurately describing a person.

Geeks, Nerds, and Dorks: A geek has a very focused knowledge of a subject (that guy that memorized the language of myst), a nerd is a master at many subjects (that girl you go to when you need homework help), and a dork is just plain socially inept (Napoleon Dynamite).

Framework

In software development, a framework is a defined support structure in which other project can be organized and developed. A framework typically consists of several smaller components; support programs, libraries, and a scripting language. There may also be other software involved to aid in development and meshing of the different components of a project. As you can see, dojo could be part of a framework, but it isn't a framework in itself.

Library

A library is defined as a collection of related functions and subroutines used to develop software. They are distinguished from executables in that they are not independant programs; rather, they are "helper" code that provide access to common functions in one easy to manage location. After reading this you are probably saying, "Hey! dojo is a collection of libraries!", and you would be correct; however, dojo is much more than just a collection of libraries.

Toolkit

Now on to toolkits. A toolkit is generally used in reference to graphical user interface (GUI) toolkits. Basically, a library that is mainly focused on creating a GUI. Yes, dojo could also fall under this category, in fact our name implies it. Why do we call dojo a toolkit? Certainly not because it focuses mainly on GUI development, right? Well quite simply, because dojo is so much more than just a collection of libraries.

None of the Above?

The previous paragraphs have probably left you still wondering what exactly we consider dojo. Obviously it is not a framework, but is it a toolkit or a library? Let's solve this once and for all. Typically, a library is a predetermined file that you include into your application, and that is how you gain access to those functions. However, with dojo, we have wrapped a package system around our libraries. This brings a slight twist to the idea of a library.

With this system we have broken each library up into several pieces. You have the core functions, and then several sub libraries where related, but less often used, functions are stored. This helps keep dojo's footprint based entirely on your needs as a developer. More about that will be covered later in the book but, for now, know that because of this flexibility, dojo is more than just a library, which falls into the realm of a toolkit with a few added functionalities. So as the name implies, dojo is a toolkit... and yet is more.

Part 2: "Out of the Box" Dojo

Want to know what Dojo is and how it can help you with your javascript development? In this section we will walk through the process of putting Dojo to use with its collection of pre-packaged "Out of the Box" widgets that can get you using Dojo right away. We will focus on developing programs using existing dojo components. This section will not get into any advance features, as they are included in future chapters. If you are new to Dojo or even new to JavaScript, then this chapter is for you. If, however, you are a seasoned programmer, you can still find reading this section purposeful as it will provide a helpful overview to the Dojo toolkit.

The sample application is the familiar Hello World app however, it does introduce the main features of Dojo and will build the foundation for developing much more sophisticated web applications.

Thanks to Lance Duivenbode and Seth Fair for help in writing this chapter.

Development and Debugging Tips

This section talks about some of the tools available to help develop JavaScript programs. With the increasing popularity ofJavaScript there surely will be alot of changes in this space in a relatively short time. In this section you will find helpful tools that may or may not be part of Dojo.

Also remember to check the Dojo FAQs especially the Common Pitfalls section.

Debugging JavaScript

There are excellent tools to help write and debug Javascript - it isn't all about liberally using alert() any more!

IDEs

IDEs are available which support a wide range of web development activity, including editing Javascript and HTML files, deploying code to servers, and integration with existing features like source control. In addition, some include runtime tools and browser integration to assist in debugging (for example, myeclipse and ATF)

If you use one of the JavaScriptEditors that checks your syntax as you enter your code, you can be warned immediately of simple errors and save yourself a lot of time. Some Eclipse plugins even specifically support Dojo idioms by giving you tooltips for common Dojo functions and doing more complex analysis for errors (not just normal syntax checking).

Browser specific tools

Mozilla/Firefox

  • The Web Developer Toolbar is brilliant.
  • The Firebug extension is a must for debugging and inspecting html pages - dojo.debug can also be configured to output directly to Firebug's console. It contains a simple Javascript debugger too. just use dojo.require("dojo.debug.Firebug") in your pages.
  • Venkman is the mozilla javascript debugger - ugly and cantankerous, but it can be useful if you need to debug in FF. Note that in general the IE debugger is much better. Use the venkman port for FF1.5.
  • Live HTTP Headers is a good extension for debugging HTTP traffic (You may prefer to use the equivalent functionality that exists in the in Firebug extension).
  • JavaScript Shell - While it's not a debugger, I've found the JavaScript Shell to be a really great tool for analyzing problems, and even just exploring JavaScript libraries like dojo. Works best as a firefox bookmarklet, in which case you can open it in the context of any given page and invoke javascript functions yourself, evaluate expressions, redefine functions, etc.

Debugging on Firefox may need you to use the djConfig flag debugAtAllCosts (see further below for information). The debugAtAllCosts flag is sometimes necessary to locate exceptions or syntax errors. Even without the debugger, Mozilla and Firefox are unable to locate a line of code loaded by dojo.require() due to a flaw in the way eval() debugging hooks are implemented in Spidermonkey. Currently, the Javascript console will report all source references as the location of the eval() call itself (in the bootstrap code), but with an additional line offset equal to the offset in the corresponding *.js file.

Firefox Safe Mode

If you are having wierd problems with Firefox, it is often worthwhile running Firefox in safe mode.

This is because installed extensions can interfere with the DOM tree, CSS, or even with javascript. In Windows there is a shortcut to start Firefox in safe mode from within the Mozilla Firefox folder, from the Start button.

Internet Explorer

If you are using a debugger with IE, go to Tools | Options | Advanced and make sure that Disable Script Debugging is not ticked. Using debugAtAllCosts can also help significantly - read about it below.

Safari

The debugger is Drosera.

The Safari Developer FAQ has some general information about developing with Safari, as well as instructions on how to turn on a debug menu that allows showing a Javascript console.

There is a "dom inspector" type tool, but it requires using a nightly build of Safari.

debugAtAllCosts

debugAtAllCosts may have unobvious side-effects - you should only use it if you are actually debugging. If you hit problems with files not loading or __package__.js then check that you are using writeIncludes() correctly, and try removing this flag to ensure that the flag is not the issue.

You generally should not use a packaged build if you want to debug, because in a packaged build the majority of code will end up in your dojo.js file (and usually be obfuscated due to compression).

The easiest way to understand how it helps with debugging is to see it's effect within a debugger. For example within Visual Web Developer Express the image on the left is when using debugAtAllCosts and the RHS image is without debugAtAllCosts being used:

To use it needs one more line in your page. Here's how you might use it:

<script>

djConfig = {

isDebug: true,

debugAtAllCosts: true

};

</script>
<script src="/path/to/dojo/dojo.js" />

<script>

// dojo includes here

dojo.require("dojo.myModule");

dojo.hostenv.writeIncludes(); // this is a new line

</script>





// ...

Once you've structured your code this way, if you open up your debugger, you will see all the constituent files listed and you can then set breakpoints. You may need to add in dojo.require() statements for files that you want the files to show, above the writeIncludes(). If you do not, then any javascript files that need loading after the call to writeIncludes().

You can see an example of using debugAtAllCosts with your own widgets within your own namespace in dojo/src/tests/widget/test_Custom_Widget_Debugging.html

How does debugAtAllCosts work?

When debugAtAllCosts is set to true, then dojo.require() does not actually include the package at that point. It only gets included in the page once you call dojo.hostenv.writeIncludes().

Normally when you dojo.require() a file that is not already loaded, it is fetched using using an xmlhttprequest, and loaded into your Javascript runtime environment using an eval() statement (each of the eval items in the RHS screenshot above is actually a js file). When the file is eval()'ed, dojo.require() calls will occur, and those then recursively load any further dependencies (those which are not already loaded).

When you set debugAtAllCosts to true, the file is still fetched using xmlhttprequest but it is not eval()'ed. Instead a regexp is used to find the dojo.require() dependencies, and required files may be fetched and searched recursively for dependencies. Each of the required javascript filenames is added into a list of pending files that need to be loaded (the list is in order so that dependent files are loaded in the correct order). When you then call dojo.writeIncludes(), inside the head of the document script tags are appended with src attributes set to the js files that need to be loaded. The script tags cause the files to be loaded by the browser: files loaded this way are understood by debuggers much better than when the files are eval()'ed.

What alternatives are there to debugAtAllCosts?

If you just need to debug one or two known files, then you can just include those specific files using script tags after dojo.js. e.g.

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

<script src="/mine/myWidget.js" type="text/javascript"></script>

You cannot do this for files that are packaged into your dojo.js (Of course, using packaged files makes debugging hard in other ways too!).

Profiling

Javascript is slow and you want to speed it up?

Use a ProfilingJavascript tool to help you find the functions where all the time is spent, and optimise those routines.

Traffic analysis

A great many problems can be resolved by watching the traffic between the browser and the server. If you are having any problems with Ajax calls such as bind() or with js/html/css/jpg files not loading as you would expect, this is often the best way to diagnose them quickly. Also if you are having problems with required files not loading then this is a good starting point to find out why.

  • Fiddler is a fantastic HTTP header and content inspector for Windows. It understands HTTP and presents the information very clearly (once you get used to its slightly quirky interface). Well integrated with IE, but work s with any browser. With FF a useful extension to help use Fiddler is the Switch Proxy extension (scroll down that page to find it).
  • Ethereal is great for sniffing all kinds of network traffic.

How do I debug syntax errors? aka How can I find this syntax error in bootstrap?

Sometimes Dojo's error messages about syntax errors are really cryptic due to how dojo loads files via dojo.require(), however you can get a better message by simply directly including the js file with the [script] tag.

The debugAtAllCosts flag can also be used.

There's also a lint program that Brian has recommended.

You can also find the debug error message in the dojo source code and remove the corresponding try/catch statement so that when the error occurs you get a debugger breakpoint instead of a dojo debug message.

Javascript debugger statement

Javascript has a debugger keyword that forces a breakpoint to occur. Just insert debugger; and if you have a debugger for your browser, then it will stop at the debugger keyword.

This is especially useful when using Venkman, because otherwise it can be difficult to get Venkman into debugging mode (e.g. you try to click on a line of source and it puts in a [F] future breakpoint).

It also works with the Firebug extension for Firefox.

Debug Messages

You can debug the old fashioned way (print statements in the code). There are three functions for this:

  • dojo.debug - prints a message
  • dojo.debugShallow - prints all the members in an object
  • dojo.debugDeep - opens new window w/tree showing structure of an object

Debugging output:

  • FireBug object - this will print debugging output to the Firebug console
  • DebugConsole - will capture all your debug messages in a floating pane.

Alternately, in djConfig, you can specify which element they are appended to by

providing an id of that element: i.e.:

var djConfig = {

isDebug: true,

debugContainerId : "dojoDebug"

};

and have a div

<div id="dojoDebug"></div> Author: Carla

JavaScript Editors

Editors/IDEs

ATF (Eclipse)

Ajax Toolkit Framework is an incubator project within the Eclipse Web Tools Project. It is also a pluggable framework for other AJAX tools. It provides Javascript syntax checking, server deployment, Mozilla embedding, runtime tools such as XHR Monitor, and a debugger based on Mozilla Spidermonkey, JSD, and the Eclipse debug UI. Eclipse integration provides access to existing plugins like ant, subclipse for SVN, server development tools, etc. AJAX "Personalities" provide the potential for tighter integration with Dojo and other toolkits, although so far very little has been done in this area.

There's visual Javascript validation built into ATF. It includes both basic syntax validation and optionally Jslint validation for less obvious potential syntax problems. It works just like MS Word as-you-type spellchecking and Eclipse as-you-type Java validation - as you type if you make a syntax error (or just do something somewhat sloppy) you'll get a red or yellow squiggly under the warning/error and an explanation in the margin. A background task will run validation against all files and place markers in the code such that you can see errors across a project.



You can download and use ATF and its prerequisite Eclipse components (Eclipse SDK, WTP, EMF, GEF, JEM, xulrunner) and choose to use all of ATF or just install the "javascript" feature which implements this validation.



Note - you have to fetch and manually install jslint.js, Dojo and xulrunner due to Eclipse policies - make sure to read the ATF readme to get the full functionality of ATF.

JSEclipse

JSEclipse is a commercial Eclipse plugin which provides a rich Javascript editor with support for syntax validation, code completion and Dojo idioms.

MyEclipseIDE

To be written...

JS-Sourceror (Eclipse)

JS-Sourceror performs syntax checking and variable type and flow analysis on JavaScript files.

JavaScript plugin for jEdit

See http://skrul.com/blog/projects/javascript

It also does syntax checking, as well as scope checking and structure browsing.

Aptana

Aptana is an open-source, JavaScript-focused IDE, including code assist for Dojo. It works as a stand-alone app on Mac, Linux, or Windows, or as a plug-in for Eclipse.

Profiling JavaScript

Profiling is the term for looking at where time is spent by any Javascript code. If you have a problem with code taking too long, then it helps to use a profiling tool to diagnose exactly where all the time is being used.

When using some profiling tools you may need to use debugAtAllCosts and not a packaged version of Dojo (see DebuggingJavascript). Using debugAtAllCosts will enable the profiling tool to allocate time spent per function to the correct source file -- otherwise you will end up with the elapsed times being allocated to anonymous functions which will make it difficult for you to understand!

Profiling Tools

dojo.profile

dojo.profile is a package that implements timing primitives for recording how much time is spent in particular functions. To learn how to use it, the best resource is to search the tests directory and look at how it is used by various tests.

FireBug 1.0

Displays the time it took to load each file.

Venkman (for Firefox)

Free but a bit buggy to use. I have found it easiest to get into debugging mode with Venkman by using a debugger keyword in your sourcecode. Run the Venkman debugger, then run your code and it will stop at the breakpoint.

Venkman contains a profiling tool, although the reports are a bit difficult to use. It does work.

Tito web studio

It seems it does not work with Dojo. It modifies JavaScript, and obviously in some manner incompatible with Dojo.

Manually do it yourself

Get the time at the start and end of a routine, and calculate the difference. Not a great technique, because you have to make educated guesses as to where the inefficient areas are, and it may take quite a lot of work to home in on the problem area.



But it is easy to do if you are measuring a single function:

function() {

var startTime = new Date();

// do something here

dojo.debug("Total time: " + (new Date() - startTime));

}



Or another example of code to do this is on this page near the top under the heading "Measure your changes".

Getting Started

If you are new to Dojo or want a quick overview of the toolkit then take a look at the HelloWorld Tutorial. This tutorial describes step by step how to build a simple Dojo application. You will learn some basic concepts about widgets, events and how to connect to the server code. Each step builds on the previous until you have a working application. It takes about an hour to go through the tutorial.



Adding Dojo to Your Pages

Dojo offers many editions of its code base. At first, it might seem daunting to try to figure out exactly which one you need. To quickly dispel any worries, let me assure you that every single edition of dojo provides a fully functioning system. Whether you download one of our editions, or the full, uncompressed source code, you'll be able to perform any of the examples discussed in this book.

TODO: fold in information from the README

In order to use dojo in your HTML pages, you need three sections of code, in this order:

1. Flags

<script type="text/javascript">

djConfig = { isDebug: false };

</script>

The flags control various options of dojo; often developers will set isDebug to true in order to get debugging output on their page. (There are also some other flags related to debugging; see the Debugging section of the code for details.)

2. Include the dojo bootstrap

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

This includes the bootstrap section of dojo, and if you are using a release build, then dojo.js will also include code for some of the dojo modules.

3. Define what resources you are using

<script type="text/javascript">

dojo.require("dojo.event.*");

dojo.require("dojo.io.*");

dojo.require("dojo.widget.*");

</script>

This section is much like java's "import" statement. You specify every resources that you are using in your code. However, note that widgets are a special case and don't need to be declared explicitly, assuming that (as is the case with the built-in dojo widgets), a manifest file defines which widget is in which resource file.

Pre-Packaged Builds

Even though Dojo is made up of many different packages, it's frequently used in very specific ways. Because of this, we've created special editions of Dojo aimed toward these users. A visit to dojo's download page will show you which editions are currently available, such as the Ajax and Widget edition.

An edition is very simple, really. The important file is dojo.js, which is created by merging the most frequently used packages and compressing the resulting code. This means that when you have a script tag that calls dojo.js, you're getting not just the basic Dojo codebase, but the additional functionality that is most pertinent to your specific use.

You might wonder why so much additional code comes in each edition. This is the full code base, and allows you to use functionality that is outside of your specific build. It means that even if you have a very specifically tailored edition of Dojo, you aren't limited to only using that featureset. If your site uses the event and I/O systems heavily, but one of your pages uses a widget, then you don't have to worry that your widget will break. This also means that any of the examples in this book will work no matter what edition you've downloaded.

Introducing Dojo Events

Events in JavaScript or Dojo based applications are essential to making applications work. Connecting an event handler (function) to an element or an object is one of the most common things you will do when developing applications using Dojo. Dojo provides a simple API for connecting events via the dojo.event.connect() function. One important thing to note here is that events can be mapped to any property or object or element. Using this API you can wire your user interfaces together or allow for your objects to communicate. The dojo.event.connnect() API does not require that the objects be Dojo based. In other words, you can use this API with your existing interfaces.

Here we connect the event handler, helloPressed, to the onClick property of the hello button element. When the button is clicked the funtion helloPressed will be called.
      function helloPressed(){
        alert('You pressed the button');
      }

      function init(){
        var helloButton = dojo.widget.byId('helloButton');
        dojo.event.connect(helloButton, 'onClick', 'helloPressed')
      }

It is also possible to use the Dojo event model to connect simple objects. To demonstrate, lets define a simple object with a couple of methods:

var exampleObj = {
    counter: 0,
    foo: function(){ 
        alert("foo");
        this.counter++;
    },
    bar: function(){
        alert("bar");
        this.counter++;
    }
};

So lets say that I want exampleObj.bar() to get called whenever exampleObj.foo() is called. We can set this up the same way that we do with DOM events:

dojo.event.connect(exampleObj, "foo", exampleObj, "bar");

Now calling foo() will also call bar(), thereby incrementing the counter twice and alerting "foo" and then "bar". Any caller that was counting on getting the return value from foo() won't be disappointed. The source method should behave just as it always has. On the other hand, since there's no explicit caller for bar(), it's return value will be lost since there's no obvious place to put it.

In either case, each time dojo.event.connect is called with the same arguments it will result in multiple connections. Later we will discuss strategies on how to guard against this.

Notice that dojo.event.connect takes a different number of arguments in the examples above. dojo.event.connect determines the types of positional arguments based on usage.

The Dojo event system allows you to connect to DOM elements or nodes or plain JavaScript objects. The API is sophisticated enough that it allows you to connect multiple listeners to a single object so you can have multiple actions as a result of a single event such as a mouse click. Of course there is an API to disconnect the listeners too. The Connecting the Pieces chapter describes the Dojo Event system in more detail.

Introduction to dojo.io.bind

At Dojo, we're committed to making DHTML applications usable, both for authors and for users, and with a lot of help from our friends, particularly Aaron Boodman and Mark Anderson, we have come up with solutions to the usability problems outlined above. We're providing it in a single, easy to use API and a package that requires only two files to function. The dojo.io package provides portable code for XMLHTTP and other, more complicated, transport mechanisms. Additionally, the "transports" that plug into it each provide their own logic to make each of them easier to use.

Most of the magic of the dojo.io package is exposed through the bind() method. dojo.io.bind() is a generic asynchronous request API that wraps multiple transport layers (queues of iframes, XMLHTTP, mod_pubsub, LivePage, etc.). Dojo attempts to pick the best available transport for the request at hand, and in the provided package file, only XMLHTTP will ever be chosen since no other transports are rolled in. The API accepts a single anonymous object with known attributes of that object acting as function arguments. To make a request that returns raw text from a URL, you would call bind() like this:

dojo.io.bind({

url: "http://foo.bar.com/sampleData.txt",

load: function(type, data, evt){ /*do something w/ the data */ },

mimetype: "text/plain"

});

That's all there is to it. You provide the location of the data you want to get and a callback function that you'd like to have called when you actually DO get the data. But what about if something goes wrong with the request? Just register an error handler too:

dojo.io.bind({

url: "http://foo.bar.com/sampleData.txt",

load: function(type, data, evt){ /*do something w/ the data */ },

error: function(type, error){ /*do something w/ the error*/ },

mimetype: "text/plain"

});

Errors and Timeouts

Regular web requests and Ajax requests with dojo.io.bind are much alike. Both use URL's and both use the HTTP protocol. But with browser requests, it is always clear to user when something goes wrong. You may get a 404 - Page Not ound, or a Server Unavailable, or at least something that says "Error". Ajax requests happen in the background, so when they error out the user won't know. Even worse, if the response never comes the browser may appear to lock up.

That's why it's extremely important to provide an error handler and a timeout handler with dojo.io.bind. You should consider these as critical as URL or the load function

At the very least, you should alert the user that something went wrong. Here's an example:

var kw = {

url: "/cgi-bin/timeout.cgi",

load: function(type, data, evt){

document.myForm.myBox.value = data;

dojo.byId("boxLoadTime").innerHTML = new Date();

},

error: function(type, data, evt){

alert("Holy Bomb Box, Batman! An error occurred: " + data);

},

timeoutSeconds: 2,

timeout: function(type, data, evt){

alert("I am tired of waiting.");

}

};

The error() function takes the same arguments that load() does. But unlike load(), the only useful parameter is data, which contains the error message.

The timeoutSeconds and timeout parameters should be used together. timeoutSeconds defaults to 0, which means "wait forever". (In other Ajax libraries, this is called a synchronous request). 0 is not desirable. Even if you expect the request will take a long time, you should set a high value here (e.g. 3600 = 1 hour), not 0. The timeout function takes the same arguments as error() and load(), but they are rarely consulted.

Hello Ajax World

So let's apply this to a trivial example. Suppose you have a text file on the web server with url my_message.txt.

Hello Ajax World!

You would like to load the file contents in an INPUT box without refreshing the page. Here's how:

<html>
<head>
<title>Insert title here</title>
<script type="text/javascript" src="/js/dojo/dojo.js"></script>
<script type="text/javascript">
    function loadRemotely(e) {
        var kw = {
            url:    "my_message.txt",
            load:    function(type, data, evt) { 
                        document.myForm.myBox.value = data; 
                        dojo.byId("boxLoadTime").innerHTML = new Date();
                    },
            method: "GET"
        };   
        dojo.io.bind(kw);
    }
    function initAjax() {
        dojo.event.connect(dojo.byId("loadIt"), "onclick", "loadRemotely");
    }
    dojo.addOnLoad(initAjax);
</script>
</head>
<body>
    Form loaded at:
    <script type="text/javascript">document.write(new Date());</script>
    

    <form name="myForm">
    <input type="button" id="loadIt" value="Click here to load value.">
    

    <input type="text" name="myBox" size="50" />
    Text loaded at: <span id="boxLoadTime">N/A</span>
    </form>
</body>
</html>

Click the button and the value in my_message.txt automatically loads into the box. The date and time stamps on the page prove it does not reload when the user clicks the button.

This demonstrates the bare minimum you need for dojo.io to connect with Ajax. At the very least, you need an object of type dojo.io.Request. In our examples, this is the "kw" variable. dojo.io.Request needs the following:

  • url is the URL containing content - usually generated on the server, and often using a database
  • load(type, data, evt) is the function called after the URL has been retrieved. This is an example of a callback function. It must have both parameters defined, although you don't need to read both of them. data is the most important, and contains the entire content retrieved from the URL. type is always "load". evt captures data about the load event.
  • method is either "GET" or "POST". GET is common - we'll see an example of submitting a formful of data later on. That will require a POST.

There are many more optional parameters, and we'll see these in later examples.

Then just call dojo.io.bind with the dojo.io.Request variable. Here, bind means "connect this page with that URL and let things happen."

Why do all that for some static text? The answer is ... you won't. The URL is going to be a server-side program which returns content - mostly XML (the "X" in AJAX), but it could be text, HTML, or even binary data.

Sending Form Data

The Url of dojo.io.Request may contain parameters, like so:

url:  'myprogram.php?firstname=Chicken&lastname=Little&key=111111'

There are two problems: (1) it's difficult to URL encode everything, (2) it doesn't allow for dynamic parameters. The above works fine for everyone named Chicken Little, but ...

It's easier and more flexible to send an entire form of data. And you can do that with the formNode parameter of dojo.io.Request.

<script>

var kw = {

url: "myprogram.php",

load: function(type, data, evt){

document.myForm.myBox.value = data;

},

error: function(type, data, evt){

alert("Holy Bomb Box, Batman! An error occurred: " + data);

},

timeoutSeconds: 2,

timeout: function(type, data, evt){

alert("I am tired of waiting.");

}

formNode: dojo.byId("myForm");

};

dojo.io.bind(kw);

</script>
<form id="myForm">

<input type="hidden" name="key" value="111111" />

<input type="text" name="firstname" length="50" />

<input type="text" name="lastname" length="50" />




<input type="text" name="myBox" length="50" />

</form>

Modules, Resources, and Widget Namespaces

Modules

Dojo's code is split into logical units called modules. These are much like packages in Java, except that in Dojo a module can contain both constructors (like classes in Java) and simple functions.

For example, the "dojo.html" module contains a number of functions, such as dojo.html.getContentBox(). The "dojo.dnd" module contains a number of constructors for things like HtmlDragObject etc.

Note the naming convention - functions start with a lowercase letter, and constructors (which are technically functions but act more like classes) start with a capital letter.

Modules could be called "namespaces", except for the fact that "namespaces" has a different (but related) meaning w.r.t. widgets.

Resources

In the simple case, a Dojo module is defined in a single JavaScript file. But sometimes, a single module is split into multiple files.

For example, the dojo.html module, although originally defined in a single file, was getting too big, so we split into multiple files. This is for performance reasons, so that the browser only downloads the code it needs.

Unfortunately this implementation detail is not transparent to the Dojo user. You have to know which file contains the functions you need, and then include that file explicitly.

Each of these files is called a resource.

The line:

dojo.require("dojo.html.extras")

will include the file src/html/extras.js, which in turn defines some of the functions (but not all the functions) in the dojo.html module.

A single JavaScript file never defines multiple modules, although often a single file will define multiple constructors. In Java this would be equivalent to defining two classes in the same file.

All of this complication is for performance reasons, trying to balance

  • not downloading more stuff than you need
  • not downloading too many tiny files


Setting up Require Statments

How do you know what resources to dojo.require()?

1. modules

First, find out what modules you are using. In this example we'll assume you are using dojo.lfx.html.

2. resources

By reviewin the API doc you can see that dojo.lfx.html is defined in two files:

  • src/lfx/html.js
  • src/lfx/extras.js

Depending on what functions you are using, you will either do

dojo.require("dojo.lfx.html");

or

dojo.require("dojo.lfx.html");

dojo.require("dojo.lfx.extras");

Wildcards

There is a wild card include, such as dojo.lfx.* . New users might be surprised to learn that this may not necessarily include everything under lfx. Rather, there is an __package__.js file that defines what is included with the wild card, and this may also depend on the environment in which Dojo is loaded. For example, a browser will likely load different modules than Dojo would when loaded with Rhino on the command line.



dojo.provide()

Each file defining a resource should have (exactly) one line at the top defining the name of the resource.



Example:

  dojo.provide("dojo.html.extras")
For historical reasons, the dojo.provide() call serves two functions:

  1. define the name of the resource (and register that the resource is loaded)
  2. make sure that the resource's module exists (ex: make sure that dojo.html exists), so that statements like "dojo.html.foo = ..." don't fail with an error about dojo.html not existing.

Widget Namespaces

Widgets are combined into groups called namespaces. All the widgets built into Dojo are in the "dojo" namespace, but someone else could write their own widgets and put them in a different namespace. For example, you could write your own button and checkbox widgets, and put them into an "acme" namespace. Then "acme:Button" would be your button, and would be unrelated to the button object built into dojo, called "dojo:Button".



Information on writing your own widgets occurs later in this book.





Widgets

When browsing through web sites and online applications, there are hundreds of widgets that come across your screen. Each button in your web browser is a widget. Each text entry box is a widget. We all know what a limited set of widgets that standard HTML provides: an input box, a button, a hyperlink.

Dojo widgets take an item like a text input box and adds functionality of a more user friendly object, like a graphical calendar to choose a date from. And it does this without breaking the original item on which the new functionality is built on.

The Widget Object

The first thing that you'll notice about widgets is that the are somewhat similar to a macro expansion, such as C's #define. Your source HTML is a simple

<button dojoType="Button" id="foo"> Click me </button>

and yet a pretty blue button shows up, and when you look at the generated DOM, it's a complicated tree of DOM nodes with a lot of absolute positioning and background images.

See?

But, that's not all there is. For each widget, besides the visible manifestation, there's also a pure javascript object that manages that generated DOM tree.

In the above case, the generated javascript object is called, unsuprisingly, "foo". You can get it by doing:

var myButton = dojo.widget.byId("foo");

Turning Plain HTML Into Widgets

A Dojo widget wraps around your HTML. It looks at how the HTML is organized, what type of tags have been specified, what attributes they have, which tags are children of what other tags. All of these different variables allow a versatility in how skeletons are laid out, in what tags they use, in how the widget chooses to interpret them.

More Than One Way to...

You can think of a widget as the final form that covers a skeleton. The top widget layer reflects the structure and functionality of the skeleton it sits on rather than covering it up.The simplest example of a skeleton is a single tag. A form input box, for example, is designed to simply accept a value.

<inputvalue="default">

But what happens when we want to help the user choose from an existing list of items? Enter the ComboBox widget.

<input dojoType="ComboBox" value="default">

As you can see, this is a functional skeleton. Not only is there an input box if the user does not have JavaScript enabled, but we can use the widget as part of a normal form. After all, we've only added on to it, we haven't changed the original purpose of the input element.

But this widget provides no data for the combo box to use.

<input dojoType="ComboBox" value="default" dataUrl="comboBoxData.js">

If you want to produce valid W3C HTML, you will have to use an alternative method to building your skeletons. The dojoType attribute is not recognized by W3C and its validation tool will complain about it being their. Below are two examples that do not use invalid attributes to build on your skeletons.

<input class="dojo-ComboBox" value="default" dataUrl="comboBoxData.js">
<dojo:ComboBox value="default" dataUrl="comboBoxData.js">

When there are certain attributes (dataUrl in this example), this widget will use that information to process the information to be contained in the combo box.

Sometimes you'll have skeletons defined in code and not even know it. In fact, many of the widgets provided by dojo assume that the underlying HTML is the same that would be encountered in every day life. Making this select element into a widget is as simple as adding the dojoType attribute.

<select dojoType ="combobox">

<option value="foo">foo</option>

<option value="bar">bar</option>

<option value="baz">baz</option>

<option value="thud">thud</option>

</select>

As you can see, you've just gained a whole lot of something for nothing. And, the data that will be used in the combo box is provided in a way that any web designer would understand.

TODO: this section needs to differentiate between ComboBox and Select.

Why Use Widgets?

You may ask yourself, "Why would I use wigets?" I honestly couldn't have answered this a few months ago, before finding Dojo anyway. The answer is really quite simple once you see how widgets improve the functionality and appearance of your web applications, without taking a long time to implement.

Enhanced User Experience

Widgets "enhance the user experience". In layman's terms, that means that you can design web pages that are easier for people use, more quickly understandable, less error-prone, and flashier than web pages in plain html.

Easier to use - the Select widget for example, will narrow down the list of available choices based on keystrokes the user enters. That makes it faster to use than a normal HTML select box.

More quickly understandable - a web page with tabs will let the user easily navigate between different sections, and helps to make clear all the different sections of code that are on one page.

Less error prone - validation widgets will immediately notify users when they have entered an incorrect value, and/or automatically correct the value.

Flashier - dojo's menu code will fade in / out menus, or use some other effect, rather than a plain appear/disappear that you get with pure CSS menus

Faster Development

Widgets make it easy for web developers to add enhanced functionality. Here's why:

No Javascript Required

Web designers are generally very good with HTML. The really good ones are usually so involved in design that they don't even bother with learning the extra stuff that comes along with its dynamic aspect.

For these kinds of users, specifying widgets via HTML is a great solution. Not only is markup useful for being able to design with a placeholder element laying in wait, but many of the widgets actually analyze what they've laid out and use them as if properties were passed to the JavaScript object.

A great example of this is the tree widget. All that the designer has to do is lay out an HTML list, assign some attributes and they can have things going without having to touch a bit of code.

No worrying required

Widgets solve a bunch of issues (like cross-browser support) behind the scenes, so you don't have to worry it. See the next section for more detail about that.

Part 3: "The Dojo Programming Model"

Using Dojo to add dynamic capbilities to your web applications can be a little daunting at first.

Let's look at the programming model in more detail to better understand how to use Dojo to build some really cool apps. The programming model is object-oriented inspired and includes "classes" with methods and multi-level inheritance coupled with aspect-oriented event model famous in JavaScript. You will find the API doc quite useful to determine the methods and properties that are inherited from the parent "classes".



Thanks to Eugene Lazutkin and Bill Keese for help on this chapter.

Declarative vs Programmatic model

Dojo supports two programming models, declarative and programmatic. Which one you use depends on what you are doing. In most cases, the declarative model may be easier to use as it is markup but there are times when you will use the programmatic model. You can, of course, intermix the models on the same page as needed.

The best way to show the models is through the use of widgets which can be used either declaratively or programmatically. Although both models are available we will mainly use the declarative model through out this book when both are an option.

The tutorial used the declarative model to create a button on the page using the code below.

<BUTTON widgetId="helloButton" dojoType="Button">Hello World!</BUTTON>

The following declarative formats are equivalent.

	<?xml:namespace prefix = dojo /><dojo:widget></dojo:widget>

	<DIV dojoType="widget">

	<DIV class=dojo-widget></DIV></DIV>

We will discuss the declarative model in more detail shortly.

You can also declare widgets programmatically using the dojo.widget.create API as follows. When declaring widgets programmatically, the API returns the widget id which you use to call the appropriate methods.

var myTabPane= dojo.widget.createWidget("TabPane", {id: "myTabPane"}, srcDiv); 

Which approach to use is discussed later in the book but for now we want to introduce the idea that you have different options.

Infrastructure

Before we get into the declarative model let's look at the widget infrastructure to better understand what methods are available when using widgets in your pages.

  • Lifecycle methods are called by the infrastructure when a widget is created. They are not meant to be called by the user.
  • Internal methods are called by the widget class code for supporting functionality and are "private" and not meant to be called by the application developer. Unfortunately there is no easy way to identify the lifecycle or internal methods. We are working on conventions that will help identify these methods in future releases.
  • "on" methods begin with the string "on" and are available to application developers. These are called by the widget infrastructure based on an action or event. Application developers can provide application specific code for these methods and those that application specific code will be called automatically when the related event or action is triggered.
  • Developer methods are the rest of the methods in the widget. They are provided for use in the programmatic model.

In addtion to methods, each class has parameters that are useful. There are two types of parameters listed here.

  • init parms are set at initialization time and then are readonly
  • rest of the list should be in the API doc

Declarative model

dojoType instructs Dojo how to process the element when the page is loading. Keep in mind that Dojo manipulates the DOM as it renders the page so you must use the Dojo APIs to access the widget ids. Dojo keeps a reference of all widgets it has created that can be accessed with the dojo.widget.byId function - providing you specify either the widgetId or id attribute in your markup. Also you can use dojoAttachEvent using this method.

Namespace Details

In order to make namespaces practical and easy to use, Dojo has a concept of modules and resources. This concept was introduced in Part 2 Modules, Resources and Widget Namespaces when we first saw the HelloWorld tutorial. Resources are used to define a namespace and can be dynamically loaded on demand.

In order to load a resource you should request it using dojo.require(). It takes a string of text, which denotes a downloadable component. The content of this string is interpreted and a subject of Dojo conventions. First, it is traced to a single JavaScript file on disk (on web server). There are ways to affect this interpretation but out of the box it has a very sane behavior:



dojo.xxx => dojo/src/xxx.js

dojo.xxx.yyy => dojo/src/xxx/yyy.js

dojo.xxx.yyy.zzz => dojo/src/xxx/yyy/zzz.js



and so on. For example if you see a statement like that:



dojo.require("dojo.json");



It will load a file named dojo/src/json.js. If you don't know what it contains, you can go and look it up. To sum it up: a namespace hierarchy essentially reflects a file system hierarchy. By convention, if you see somebody using dojo.foo.bar.baz(), you can find it's definition in dojo/src/foo/bar.js, or, if it is not there, in one of files of dojo/src/foo/ (more on that case later), or in dojo/src/foo.js.



Dojo allows you to define your own resources and modules. For your custom resource you define your own top-level object. I will use "example" in my examples. If the Dojo loader sees that the first component is not "dojo", it applies following rule:



example.xxx => dojo/../example/xxx.js

example.xxx.yyy => dojo/../example/xxx/yyy.js

example.xxx.yyy.zzz => dojo/../example/xxx/yyy/zzz.js



Be sure to put the dojo.provide() call in your module resource, so that Dojo knows it found the right file. For instance, xxx/yyy/zzz.js should have dojo.provide("xxx.yyy.zzz") in it.



Essentially it means that on your web server next to the "dojo" folder there is an "example" folder, which files are interpreted in the same way.

There is more information about the namespace and how it is used in the Widgets chapter.

Object Oriented concepts and inheritance

JavaScript is at its heart an object oriented language, but it is a prototype based object oriented language which does not have the same structure as class based languages like Java.This concept can be hard for new programmers who are not familiar with its construct. Dojo brings the object orientedness into a more familiar domain by modeling concepts that can be followed from Java and letting the toolkit handle the prototyping, inheritance and odd procedures JavaScript requires to make it work. Because of this, it not only allows people to get programming in object oriented JavaScript quicker, but it makes it faster to program because you can let the toolkit handle all of the odd procedures JavaScript requires to make it work. It all begins with a simple dojo.declare() function.

Simple declaration

Classes in Dojo are declared with a declare statement and assigning it a Class Name.Within the body can be variables, methods and constructors (know in Dojo as an initializer).

dojo.declare("ClassName",null, {
//class body
});

(Note: ClassName is the basic name, but to avoid naming conflicts, use package names like my.class.ClassName. For simplicity sake, we will start out with using just the simple name.)

Let's add some more content to our class by giving it a name and showing what the initilizer can do.Following is a persons class with an initializer and a moveToNewCity() function:

dojo.declare("Person", null, {
		//acts like a java constructor
		initializer: function(name, age, currentResidence){
		this.name=name;
		this.age=age;
		this.currentResidence=currentResidence;
	},
	moveToNewCity: function(newState) 
	{
		this.currentResidence=newState;
	} 

});

To create an object of this class you use the new keyword:

//create an instance of a new person

var matt= new Person('Matt', 25, 'New Mexico');

The initializer function is called once the object is created and the arguments are passed to it initializing the object.Our Matt object who is 25 currently lives in New Mexico, but let's say he moves a little further west to California.We can set his new currentResidence with the Person class method moveToNewCity(): matt.moveToNewCity('California');

Now the current value of matt.currentResidence shows that he now lives in California.

Inheritance

A person can only do so much, so let's create an Employee class that extends the Person class.The second argument in the dojo.declare() function is for extending subclasses.

dojo.declare("Employee",Person, {
	//acts like a constructor
	initializer:function(name, age, currentResidence, position)
	{
		Employee.superclass.initializer(name, age, currentResidence);
		this.password="";
		this.position=position;
	},

	login: function()
	{
		if(this.password!="" && this.password!=null){
		alert('you have successfully loged in with the password '+this.password);
	}
	else
	{
		alert('please ask the administrator for your password');
	}
}});

The first line in the initializer calls Employee.superclass.initializer, the Person class constructor. Dojo handles all of the requirements for setting up the inheritance chain.Methods or variables can be overridden by setting the name to the same as it is in the parent class. The Employee class can override the Person class moveToNewCity(), perhaps by letting the company pay for moving expenses.

You initialize the sub class the same as the Person class with the new keyword.

var kathryn=new Employee(' Kathryn ', 26, 'Minnesota', 'Designer');

The Employee class passes the first three arguments down to the Person class, and sets the position.Kathryn has access to the login() function found in the Employee class, and also the moveToNewCity() function by calling kathryn.moveToNewCity(‘Texas’); Matt on the other hand, does not have access to the Employee login() function.

matt.login() // ERROR can’t log in because he is not an Employee

Array/Object Declarations

If your class contains arrays or other complex objects, they should be declared in the initializer, due to some subtleties of object inheritance in javascript. Note that simple types (strings, numbers) are fine to declare in the class directly.

dojo.declare("my.classes.bar", my.classes.foo, {
	// coupledObjects: [1, 2, 3, 4]	- doesn't do what I want; 
	//                                      ends up being like a static!!
	numItem : 5,        // one per bar
	strItem : "string", // one per bar

	 initializer: function() {
		this.coupledObjects = [ ]; // each bar should have it's own array
		this.expensiveResource = new expensiveResource(); // one per bar
	}
});

Statics

On the other hand, if you want an object or array to be static (shared between all instances of my.classes.bar), then you should do something like this:

dojo.declare("my.classes.bar", my.classes.foo, {
	initializer: function() {
		dojo.debug("this is bar object # " + this.statics.counter++);
	},

	statics: { counter: 0, somethingElse: "hello" }
});

Mixins

The example below inherits from my.classes.foo and then mixes in "my.mixin". This is similar to multiple inheritance but there are some subtle differences, namely that this.inherited can only reference my.classes.foo, not my.mixin.

dojo.declare("my.classes.bar", [my.classes.foo, my.mixin], { initializer: function() { my.mixin.call(this /*, args*/); // invoke some mixin constructor // (note: my.mixin.prototype is ignored) }, valueForPrototype: 3, methodForPrototype: function() { } });

Design Notes

Constructor vs Initializer

In non-trivial cases, constructor definitions contain code. The constructor code performs initialization tasks and defines instance-only properties (properties whose values belong to a particular object, as opposed to prototype-properties which are shared by all objects using the prototype).

However, there is an issue with respect to constructor code in any simple JavaScript inheritence system. The constructor function of an object must be executed to create a prototype object for an inheritor. Therefore the constructor function must serve as both prototype-initializer and instance-initializer. The double duty of inherited constructors can be non-obvious and lead to subtle bugs.

Given the constructor above, when a bar object is created to use as a prototype, the mixin properties and properties created in the constructor become members of the inherited object's prototype. Almost always these properties are not intended to be part of a prototype.

As a practical matter, the extra prototypical properties are usually ignored as matching instance properties are created at object-instantiation time. However, for example, having an extra expensiveResource can be costly. And errors can result if the environment is not ready to create an expensiveResource at inherits-time. Errors caused by these conditions can be hard to track down, especially if the developer is not aware of how constructors are used when inheriting prototypes.

Separating instance-initializer tasks from prototype-initializer tasks eliminates these concerns. Therefore dojo.declare creates a standard, controlled constructor and separates instance-initialization tasks into a separate, optional initializer method.

Note: dojo.declare cannot inherit from an object that has a non-trivial constructor because dojo.declare does not allow constructors to also perform instance initialization.However, you can inherit from a dojo.declare created constructor without restriction

Calling Inherited (Ancestor) Methods

Sometimes one wants to invoke a method on an object from an ancestor prototype. JavaScript allows any function to call any other function in any context via the call and apply built-ins. So there are techniques like:

my.classes.bar.prototype.someMethod == function() {
	// invoke any function in our context
	anyFunction.call(this);
	 // invoke inherited version of this method in our context
	my.classes.foo.someMethod.apply(this, arguments);
}

(Note: in these examples, the == indicates an assertion that the named property is equivalent to the function shown. Actual assignment is done via dojo.lang.extend or dojo.declare.)

As a convenience, dojo.inherits puts a reference to the ancestor prototype into the descendent constructor, and a reference to the descendent constructor into the descendent prototype. These extra references allow a great deal of extra flexibility in general, and also allow calling ancestor methods without explicitly naming the ancestor:

// invoke inherited version of this method in our context this.constructor.superclass.someMethod.apply(this, arguments);

However, the above technique will cause an infinte loop if someMethod is once removed. E.g., if we have foo -> bar -> zot, you can run into an issue like this:

my.classes.foo.prototype.identify == function() { return "I'm a foo"; }

my.classes.bar.prototype.identify == function() { return "I'm a bar and " + this.constructor.superclass.identify.apply(this, arguments); }

my.classes.zot.prototype.identify == function() { return "I'm a zot and " + this.constructor.superclass.identify.apply(this, arguments); } bar = new my.classes.bar(); alert(bar.identify()); // "I'm a bar and I'm a foo" zot = new my.classes.zot(); alert(zot.identify()); // stack overflow

The error results because this.constructor.superclass referenced in bar's identify function refers to zot's superclass (causing bar.identify to call itself).

To resolve these issues, objects created from dojo.declare constructors include a function called inherited that safely invokes an ancestor method.

inherited: function(methodName /*string*/, arguments /* arrayLike */)

inherited correctly handles the problem scenario above:

my.classes.foo.prototype.identify == function() { return "I'm a foo"; } my.classes.bar.prototype.identify == function() { return "I'm a bar and " + this.inherited('identify', arguments); } my.classes.zot.prototype.identify == function() { return "I'm a zot and " + this.inherited('identify', arguments); } bar = new my.classes.bar(); alert(bar.identify()); // "I'm a bar and I'm a foo" zot = new my.classes.zot(); alert(zot.identify()); // "I'm a zot and I'm a bar and I'm a foo"

Syntax

The syntax is:

dojo.declare(className /*string */, superClass /*function*/ [, initializer /* function*/]);

or

dojo.declare(className /*string */, [superClass /*function*/, mixin /* function */, ...] [, initializer /* function*/]);

Including the target className in the argument list allows the object path to be created automatically (i.e. intermediate namespaces are created as needed). Also, dojo.declare stores className in an eponymous property in the created object's prototype (e.g. my.classes.foo.prototype.className == "my.classes.foo").

Naming

Technically speaking, JavaScript does not have classes: object construction is based on prototypes. For this reason reference to the term class has been (mostly) avoided above.

It seems that the difference is not of great practical importance. It's true that constructor functions in JavaScript are actual objects, but they operate like classes in the sense that they generally have no other purpose than as a mold for object instantiation. It is noted that classes are typically compile-time (or at least meta-) constructs and JavaScript constructors exist as Objects at runtime and contain actual data.

The name dojo.declare was chosen after much debate. The name is vague but easy to remember, read, and type. The method name inherited is lifted (at least) from ObjectPascal.ÂÂ

Order matters

In general, a script should do the following in the ... section:

  1. (Optional) set the djConfig options
  2. Load the Dojo script
  3. Call dojo.require(...) for all libraries used in the page
  4. (Optional) define initialization functions and call addOnLoad
As in this example:

<!-- Step 1 (Optional) Set djConfig -->
<SCRIPT type=text/javascript>
	djConfig = {
	  debug: true
	};
</SCRIPT>

<!-- Step 2: Load dojo -->

<SCRIPT src="js/dojo/dojo.js" type=text/javascript></SCRIPT>
<!-- Step 3: call dojo.require -->
<SCRIPT>
   dojo.require("dojo.book.myWidget.*");
   <!-- Step 4 (Optional): define initialization functions -->
   function initMyStuff() {
      ...
   }
   dojo.addOnLoad(initMyStuff);
</SCRIPT>

The order is important! If you do the steps out of order, dojo may not initialize properly, and your page will be a mess.

This script element is responsible for loading the base Dojo script that provides access to all the other Dojo functionality. Following this we add the requires statements which pulls in functionality needed by the application.

Use the dojo.addOnLoad to call functions which use the widget ids because Dojo must completely load the page and finish parsing the HTML before a reference can be made to the id. So, for example, the following will not work:

<BUTTON widgetId="helloButton" dojoType="Button">Hello World!</BUTTON>
<SCRIPT>
// ILLEGAL!!  helloButton does not exist yet
dojo.byId("helloButton").width2height = 0.5;
</SCRIPT>

Instead, place the script in an initialization function:

   
    <SCRIPT src="js/dojo/dojo.js" type=text/javascript></SCRIPT>
    <SCRIPT>
       function initMyStuff() {
          dojo.byId("helloButton").width2height = 0.5;
       }
       dojo.addOnLoad(initMyStuff);
    </SCRIPT>
<BUTTON widgetId="helloButton" dojoType="Button">Hello World!</BUTTON>

The global Dojo Objects

Dojo defines a global object called "dojo" which serves as an umbrella for everything Dojo-related. It simulates a namespace and was created to prevent clashes in the global JavaScript? namespace between the code in Dojo and other toolkits or user supplied code. Unfortunately it cannot be used during a bootstrap process, so special global variables should be used. All of them are prefixed with "dj".

You will need to use exactly two top-level Dojo-defined objects: "dojo", which serves as a namespace, and "djConfig", which is used to supply initialization parameters to Dojo, and should be created before Dojo's bootstrap.

For example, to turn off global widget searching, add these lines just *before* you include dojo.js:
<script type="text/javascript">

djConfig = {

parseWidgets: false

};

</script>

Part 4: "More on Widgets"

P

Advanced ContentPane Usage

Introduction

A common use case for DHTML/ajax is to fetch a fragment of html using XHR or some other way, and change the innerHTML of a div with that content. Problem with this is that it doesn't instanciate widgets and doesn't fire scripts. ContentPane was created to make widgets and scripts work and reduce the potential for memory leaks. ContentPane is a base widget for many (Html)widgets, it handles remote loading as well as local setting of content and instanciating widgets in that content. Think of it as islands in your page that can easily switch content using setContent() or setUrl().

Many other widgets inherits ContentPane, like Tooltip, Dialog, FloatingPane etc. That means that all the methods and properties of ContentPane also applies to them.

ContentPane is often used as children of Layout widgets like LayoutContainer, TabContainer, AccordionContainer

Dont misstake it for a Iframe though, It should not be used on very large html fragments.

Usage

Simple usage ... <div id="cpane" dojoType="contentPane" href="initialContent.html"><div> <a href="javascript:dojo.widget.byId('nextContent.html')">Goto nextPage</a> ...

Basic options

  • loadingMessage Default: "Loading..." Set a custom loading message, see onDownloadStart to avoid showing this message completely
  • adjustPaths Default: true When content is setUrl'ed from a different folder paths to images, links etc. is adjusted so the point to the correct dir
  • href Default: "" Use this to grab initial content when contentpane is created.
  • extractContent Default: true Only insert the html that is inside Script and style tags are not affected by this setting
  • parseContent Default: true Create widgets inside content
  • cacheContent Default: true Use dojo.io.bind javascript cache and, if it exists, browsers cache
  • preload Default: false Lazyload switch, if true it will download content even if domNode is hidden Note: To make use of the default lazyload setting you need to hide your domNode Like this: <div dojoType="Dialog" style="display:none;"></div>
  • bindArgs Default: {} Send in a custom setting to the dojo.io.bind call, like: mypane.bindArgs = {sync: true, preventCache: false}; mypane.seetUrl('nextHtmlFragment.html');
  • refreshOnShow Default: false Re-download content each time ContentPane is shown again
  • executeScripts Default: false Fire scripts in content Note: see scriptSeparation
  • scriptSeparation Default: true Run scripts in a separete scope for ContentPane Note: set to false if you want similar behaviour as a normal pageload
  • handler Default: "" Java function name, generate pane content
  • isLoaded Default: false Tells wheather we are loaded or not, see also: onLoad() and addOnLoad()

Methods apart form those provided by ContentPane's superclass HtmlWidget

  • setContent(String or DomNode) Use this instead of innerHTML
  • setUrl(String or dojo.uri.Uri) Use this to set a new href and download and diplay that href
  • refresh() Re-download and display href
  • loadContents() Like refresh but only when isLoaded is false
  • setHandler(Function) Set a function callback for javacontent generation
  • abort() Abort a async download
  • addOnLoad(Object, "functionname" or Function) Push a callback that will be run when content the next onLoad occurs. It's a fire and forget stack, if you want a callback each onLoad, see onLoad() Works for setContent as well
  • addOnUnload(Object, "functionname" or Function) Same as addOnLoad but for onUnLoad event

Methods (Intended as event hooks using dojo.event.connect)

  • onLoad() Called when everything rendered initialized and ready
  • onUnload() Called before content is cleared
  • onDownloadStart(e) preventDefault'able Called before a download occurs To prevent showing the loading message, do like this:
  • onDownloadEnd(url, string) Called when download is completed, before it is setContent'ed
  • onDownloadError(e) preventDefault'able Called when a load error occures, before The load error message is displayed. Prevent it the same way as onDownloadEnd Tip: During debug, you can display debug info like responseHeaders, responseText etc.
  • onContentError(e) preventDefault'able Called when content insertion generates a error, before error mesage is displayed, like DOM faults, dojo.require() *syntax* faults etc.
  • onExecError(e) Called when there is errors evaling script, doing java setContent and download errors of external scripts
  • In order to prevent the default messages you can do something like this:

    <script>
    	var myLoadMessage = {
    		show: function(event){
    			event.preventDefault();
    			... custom code here
    		}, 
    		hide: function(){...}
    	}
    
    	dojo.addOnLoad(function(){
    		var pane = dojo.widget.byId('myPaneId');
    			dojo.event.connect(pane, "onDownloadStart", myLoadmessage, "show");
    	});
    </script>
    <div dojoType="ContentPane" id="myPaneId">...startcontent...</div>
    
    or
    
    <div dojoType="ContentPane" 
    	onDownloadStart="myLoadMessage.show(arguments[0]);">...startcontent...</div>
    		

When used as a child to TabContainer, AccordionContainer or PageContainer TabContainer, AccordionContainer or PageContainer extends Widgets with these extra options

  • label Tab text
  • selected Preselect this tab after creation
  • closable Display close button
  • Note:
  • Height and width settings is done on the Container, not the ContentPane.
  • In order for lazyload to work you have to hide your domNode initialy

When used as a child of LayoutContainer LayoutContainer package extends Widgets with this option

  • layoutAlign "left", "right", "bottom", "top", or "client" see layout section of the book for more info

FAQ

  • Why doesn't my widgets show up? Most likely you have used mypane.domNode.innerHTML = htmlstr; Use setContent instead: mypane.setContent(htmlstr);
  • Why doesn't lazy load work? You have to hide your domNode, style="display:none;", initialy while creating ContentPane
  • ContentPane displays strange looking characters when loaded remotly in some browsers, why? Like all server communication your browser need to know what charset your html is encoded with. Make sure your server is sending the correct Content-type header. example in php: header("Content-type: text/html; charset=utf-8"); Make sure you type utf-8 and not utf8, else IE will generate a warning and bail out.
  • Why is ContentPane so slow? You probaly send it a big chunk of html with deeply nested tags.
    • Send it a html fragment, not a complete page with doctype and everything
    • Try to make the HTML simpler and use css for styling
    • Turn off the options you dont need: adjustPaths, extractContent, executeScripts, parseContent
    • Consider redesigning your page with serveral ContentPanes which grabs a smaller portion of your html that way you dont have to scan, render and create as many DomNodes/Widgets on each update.
    • Perhaps dojo.io.updateNode("nodeId", "myUrl") is all you need, and ContentPane is to heavy for your needs
  • dojo.addOnLoad() is called to early, before my Content is loaded See onLoad event and addOnLoad for ContentPane, it is usualy easier to do this using <script>_container_.addOnLoad(..)</script> in your downloaded page, just be sure to set executeScripts=true
  • My inline scripts doesnt work when loaded in ContentPane, I have turned executeScripts to true? Short answer: set scriptSeparation=false Long answer: ContentPane separates scope of scripts between different ContentPane's see: scriptScope page in dojo book
  • When I press submit in my form inside a ContentPane, the whole page unloads, why? ContentPane doesn't have a form handling feature, look at dojo.widget.Form or see sample use case below
ContentPane examples

    scriptScope

    Executing scripts in ContentPane in dojo-0.3.1





    This is a explanation about scripthandling in a ContentPane in other words when you set executeScripts to true, it is false by default.


    ContentPane has some convenience functions related to scripts that makes life easier:



    • .addOnLoad()
    • .addOnUnLoad()
    • And the replacement for scriptScope to dojo.widget.byId('thisWidgetId').scriptScope in html content attributes.


    All scripts within content is evaled in the ContentPane property scriptScope, this means that you can have 2 or more content panes in the same page with the same name without risk of collision. This implementation does have its pros and cons. but correctly handled they will be useful. Also the scripts evals before widgets is parsed and after html is inserted.



    So the content scripts is evaled inside a freestanding scope that inherits window. Take this function declaration.



    <script>
        var i = 0;
        function addToI( j ){
            i = i + j;
            return i;
        }
    </script>
    
    becomes (from window scope):
    
    (function( ){
        var i = 0;
        function addtoI( j ){
            i = i + j;
            return i;
        }
    })
    


    Due to the way javascript works addToI will be private and you cant reach it. Read Douglas Crockford excellent description of this. http://javascript.crockford.com/private.html



    You can fix this in a couple of ways, one is to append it to global



    <script>
        i = 0; // note lack of var
        addToI = function( j ){ // we could also do window.addToI = function( j ){ ...
            i = i + j;
            return i;
        }
    </script>
    
    becomes (from window scope)
    
    i = 0;
    function addtoI( j ){
        i = i + j;
        return i;
    }
    


    This is'nt recommended, if you want global scripts It is better to include them in the main page the old fashion way.



    A better way would be to use Privileged functions:



    <script>
        this.i = 0;
        this.addToI = function( j ){
            this.i = this.i + j;
            return this.i;
        }
    </script>
    
    becomes (from window scope)
    
    (function(){
         this.i = 0; // now it is a property of this function and can be reached from the outside.
         this.addToI = function( j ){
            this.i = this.i + j;
            return this.i;
         }
    })
    


    As you might have guessed by now the (function(){...}) is the function scope that is reference held by ContentPane.scriptScope.

    So to call the addToI function from the outside we can do:

    var added = dojo.widget.byId('myPaneId').scriptScope.addToI( 10 );
    dojo.debug(added) // prints 10
    
    added = dojo.widget.byId('myPaneId').scriptScope.addToI( 10 );
    dojo.debug(added); // prints 20
    
    and so on...
    
    Now lets say we have html that would like to alert the value of i (this.i) in plain html that would be:
    <button onclick="alert(i);">Tell me i !</button> 
    // As explained above this wont work in ContentPane(unless you set it to global by omitting var).
    
    Now if we now the ID of the contentPane that pulls in this content we could do:
    <button onclick="alert(dojo.widget.byId('myPaneId').scriptScope.i);">Tell me i !</button>
    // this will work in ContentPane
    
    That is'nt very useful as we don't always know the ID of the contentPane that pulls in the html when we write the content.



    ContentPane has a convenience replacer function the scans the html and replaces all occurrences of the keyword scriptScope in html attributes. So to achieve the above:
    <button onclick=" scriptScope.i">Tell me i !</button>
    // this will work in ContentPane
    // NOTE: Due to a bug in ContentPane 0.3.1 you need to add a extra space before the keyword
    // Thank you Sasha Firsov for finding that! 
    
    The parent scope of scriptScope is window, the reason for that is to avoid messing with widget internals. Just imagine the disaster a redefinition of setUrl function would cause otherwise.



    To enable the content scripts to talk to the containing ContentPane there is set a private variable on scriptScope construction.

    That is the _container_ variable. Lets say we have a widget in our content that we would like to connect a event callback on:
    ... some content
    <div dojoType="DatePicker" id="myPicker"></div>
    ... rest of content
    
    A content script could look like:
    <script>
        var o = {
            storeDate: function( ){
                var datePick = dojo.widget.byId('myPicker');
                var date = datePick.storedDate;
                // save date somewhere
            }
        };
        _container_.addOnLoad(function(){
            var picker = dojo.widget.byId('myPicker');
            dojo.event.connect(picker, "onSetDate", o, "storeDate");
        });
    
        // remember to disconnect onUnLoad, very important!!
        _container_.addOnUnLoad(function(){
            var picker = dojo.widget.byId('myPicker');
            dojo.event.disconnect(picker, "onSetDate", o, "storeDate");
        });
    </script>
    


    When the content is cleared in ContentPane the scriptScope is unreferenced, this means that if there are no other variables that holds reference to any of the scriptScope objects (like event connects, varible connection etc), the script will be garbage collected by the javascript engine (memory freed).



    Different browsers are more or less conservative about GC (garbage collect), IE and Mozilla beeing the more relaxed browsers, khtml and Presto (Opera) engines are more conservative.



    Some usecase samples

    Lets say you have page that you need to run in as both stand alone and within a ContentPane.

    Then you can do something similar to this.

    Courtesy of Sasha Firsov for a pointer to this example!
    <html>
    <head>
    <script>
        var djConfig = {isDebug: true};
    </script>
    <script src="dojo/dojo.js"></script>
    <script>
        var scriptScope = this;
        if(typeof _container_ == 'undefined'){
            var _container_ = dojo;
        }
    
        _container_.addOnLoad(function(){
            dojo.debug("Successfully loaded!");
        });
    
        this.doWhenClicked = function(txt){
            dojo.debug(txt);
        }
    </script>
    <body>
        <a href="javascript:scriptScope.doWhenClicked('You clicked a link!');">Click here!</a>;
    </body>
    </html>
    




    Perhaps you want to prevent all <a href='...' link clicks with a ContentPane from clearing your page, and use the href to set your client ContentPane.
    *********Your mainpage*********** 
    <html>
    <head>
    <script src="dojo/dojo.js"></script>
    <script>
        dojo.require("dojo.widget.ContentPane");
        dojo.require("dojo.widget.LayoutContainer");
    
        function changeUrlInClient(url){
            var client = dojo.widget.byId("client");
            client.setUrl(url);
        }
    </script>
    </head>
    <body>
        <div dojoType="LayoutContainer" layoutChildPriority='none' style="border: 1px solid blue; width: 800px; height: 300px;">
            <div dojoType="ContentPane" layoutAlign="left" style="width: 200px;" executeScripts="true" href="linkpage.html"></div>
            <div widgetId="client" dojoType="ContentPane" layoutAlign="client" style="border:1px solid red;"></div>
        </div>
    </body>
    </html>
    
    *******linkpage.html************
    <html>
    <head>
    <script>
        var o = {
            listen: function(evt){
                // if the onclick came from a 
    </head>
    <body>
        <a href="content1.html">content1</a>
    <a href="content2.html">content2</a>
    <a href="content3.html">content3</a>
    <a href="content4.html">content4</a> </body> </html>




    A simple example of using a form in ContentPane. NOTE! dont use this login example in real world applications, password is sent in cleartext
    **********mainpage************
    <html>
    <head>
    <script src="dojo/dojo.js"></script>
    <script>
        dojo.require("dojo.widget.FloatingPane");
        dojo.require("dojo.widget.Button");
    </script>
    </head>
    <body>
        <div dojoType="FloatingPane"
            title="Login example"
            style="width: 300px; height: 300px;"
            executeScripts="true"
            cacheContent="false"
            href="login.php">
        </div>
    </body>
    </html>
    
    *********login.php**********
    <?php
        session_start();
    
        // are we trying to login?
        if(isset($_GET["login"])){
            // this could of be a database instead
            $users = array(
                    "JohnDoe"=>
                        array("pass"=>"foo", "id"=>1),
                    "JaneDoe"=>
                        array("pass"=>"bar", "id"=>2),
                    "JuniorDoe"=>
                        array("pass"=>"baz", "id"=>3)
                    );
    
            if(isset($_POST["user"]) && isset($_POST["pass"])){
                $pass = $_POST["pass"];
                $user = $_POST["user"];
                if(isset($users[$user]) && ($users[$user]["pass"] == $pass)){
                    $_SESSION["id"] = $users[$user]["id"];
                    exit("(true);");
                }
            }
    
            //if we get here we have failed to login
            exit("(false);");
        }
    
        // logout?
        if(isset($_GET["logout"])){
            unset($_SESSION["id"]);
        }
    
        if(isset($_SESSION["id"])){
            // it is safe to show secret content
    ?>
    
        <script type="text/javascript">
            this.logout = function(){
                _container_.setUrl("login.php?logout=true");
            }
        </script>
        <h3>You have successfully logged in!</h3>
        showing secret content here
    <a href="#" onclick="scriptScope.logout();">log out</a> <?php }else{ //no it wasnt safe, show our login script ?> <script type="text/javascript"> this.ok = function(){ _container_.domNode.style.cursor = "wait"; dojo.io.bind({ formNode: dojo.byId("login"), mimetype: "text/javascript", handler: function(type, data){dojo.debug(data); _container_.domNode.style.cursor = ""; if(type=="load"){ if(data){ _container_.setUrl("login.php"); }else{ dojo.byId("message").innerHTML = "Wrong username or password"; } }else{ dojo.byId("message").innerHTML = "An error occured while login, please try again."; } } }); } this.quit = function(){ _container_.hide(); } </script> <form name="login" id="login" method="post" action="login.php?login=true"> <div id="message" style="text-align:center; color: red;">You need to login</div> <label for="user">Username: <input type="text" name="user"/>
    <label for="pass">Password:</label> <input type="password" name="pass"/> <button dojoType="Button" onClick="scriptScope.ok();"/>login</button> <button dojoType="Button" onClick="scriptScope.quit();">quit</button> </form> <?php } ?>




    In the follwing scenario you wont need executeScripts.

    In fact it wont affect the script at all, the script will run just as any other regular script in ordinary page
    <html>
    <head>
        <script src="dojo/dojo.js"></script>
        <script>
            dojo.require("dojo.widget.ContentPane");
        </script>
    </head>
    <body>
        <div dojoType="ContentPane" >
            <script>
                // this script will fire before dojo makes our parent a ContentPane widget, so it wont be 
                // affected by executeScripts at all.
                // i wont have a _container_ variable and scriptScope wont hide any variables
                // it will work just as a inlne javascript block always has
    
                alert("This alert will fire event if you have executeScripts=false");
            </script>
        </div>
    </body>
    </html>
    






    It should be fairly easy to pull in some small customized scripts that is tweaked to the content, like a form validation script or a button callback.

    The executeScripts and scriptScope has the potential to be very usefull, I cant think of all the possible implementations but probably you can.



    Catches:



    • If you event.connect to _container_ be sure to disconnect onUnLoad, else you get all sorts of strange errors
    • Be sure to unref. all references into and out of scriptScope before setting new content, else there will be a memleak
    • <div dojoType="dijit.form.Button"> <img src="images/flatScreen.gif" width="32" height="32"> <span style="font-size:xx-large">big</span> </div>

      Like HTML buttons, the dojo button sizes to fit its content. Usually, you will provide an onclick="..." attribute to specify what happens when the button is pressed.


      This needs to be rewritten for 0.9

      Using Your Own Backgrounds

      By default, dojo uses a blue gradient background. But you can provide your own. You will need to create three .gif images: one for the left, one for the right, and one for the center. The filenames must end with l, r, or c, respectively. You can specify image sets for four different conditions:

      • activeImg - the mouse pointer is over the button
      • inactiveImg - the mouse pointer is not over the button
      • pressedImg - the button is being pressed
      • disabledImg - the button cannot be pressed

      For example, you can use these files:

      • /images/buttons/disabled-l.gif
      • /images/buttons/disabled-r.gif
      • /images/buttons/disabled-c.gif

      as the disabled image of your button like this:

      <button dojoType="Button" disabledImg="/images/buttons/disabled" >
         Quit
      </button>
      

      API Reference: dojo.widget.Button

      See Also: DropDownButton, comboButton

    comboButton

    Used in HTML Element:button

    A combination Button and DropDownButton. Use this for a button that has a common action (e.g. "Make Regular Dinner") and less common related actions (e.g. "Make Romantic Dinner" and "Make TV Dinner")

    Example

    <button dojoType="comboButton" menuId='saveMenu'>
       <img src="images/editIcon.gif" width="32" height="32">
       Save
    </button>
    
    <div dojoType="PopupMenu2" id="editMenu" toggle="wipe">
    	<div dojoType="MenuItem2" iconSrc="images/save.gif" caption="Save" accelKey="Ctrl+S" onclick="mySave();" />
    	<div dojoType="MenuItem2" iconSrc="images/saveAs.gif" caption="Save As...." accelKey="Ctrl+A" onclick="mySaveAs();" />
    </div>
    
    

    You can also specify your own background images, as in Button.

    API Reference: dojo.widget.ComboButton

    See Also: Button, DropDownButton, PopupMenu2, MenuItem2

    Editor2 (RichText) Widget

    Introduction

    Editor2 Widget in dojo provides a WYSIWYG editor for HTML content. The core is compact and lightweight, while a plugin framework ensures that any functionality can be achieved by plugins.

    Basic html editing capacity is implemented in the core, which is the RichText widget. Currently keyboard shortcuts are also hardcoded in this widget (TODO