Sun und IBM zanken sich ja immer wieder mal, wenn es darum geht, wer die bessere Strategie zur Weiterentwicklung der Java-Plattform hat. Umso bemerkenswerter ist es, dass sich die beiden Großen gerade im recht jungen Bereich der Web-Toolkits einig sind. Beide sind offizielle Sponsoren des Dojo Toolkit und unterstützen das Projekt mit Code Contributions und Tool-Support. Aber auch andere Frameworks sind Partner von Dojo, wie etwa WebWorks 2.2 (bald Struts Action Framework) und OpenLazlo. Ebenso wird versucht, Dojo stärker in der Ruby on Rails-Community zu etablieren, die bis dato auf Prototype setzt.
Mit etwa 600 JavaScript-Dateien und weit über 1.000 Funktionen sollte das Toolkit für die meisten Anwendungsfälle die passende Unterstützung bieten. Besonders erwähnenswert sind die folgenden Module:
- ein Event-System, welches nicht nur DOM-Events unterstützt, sondern die Möglichkeit schafft, beliebige Funktionen an andere Funktionen zu binden; Damit wird ein aspektorientiertes Programmieren ermöglicht. Außerdem eliminiert es alle Memory-Leak-Probleme des Internet Explorer.
- Das Widget-System ermöglicht die Entwicklung komplexer wiederverwendbarer Komponenten und bietet eine Reihe von vorgefertigten Widgets, die man sofort einsetzen kann. Dazu gehören auch Komponenten, mit denen das Layout einer Seite gesteuert werden kann.
- eine mächtige, browserneutrale AJAX-Abstraktion, die auch Features wie Cross Domain Scripting und File Uploads unterstützt.
- eine Animations- und Effektbibliothek sowie viele Hilfsfunktionen zur Manipulation von DOM-Objekten, Positionierung von Elementen und Umgang mit Browser-Inkompatibilitäten.
Das Package-System stellt die Infrastrukturgrundlage des Toolkits. Es unterstützt das dynamische Nachladen von JavaScript-Dateien. Um das Package-System zu verstehen, müssen wir einen kurzen Blick auf die Verzeichnisstruktur von Dojo werfen:
dojo/ dojo.js src/ animation/ collections/ ArrayList.js Collections.js ... ...
Möchte man die Funktionalität der Klasse ArrayList nutzen, muss diese durch dojo.require(„dojo.collections.ArrayList“) angefordert werden. Ist die Funktionalität noch nicht geladen, sucht das Toolkit unterhalb seines Source-Verzeichnisses nach dem entsprechenden Dateinamen. Dojo unterstützt außerdem Package Imports, um den Import von mehreren Dateien zu ermöglichen.
Zu Beginn ein Wort zum Projekt-Setup: Statt Funktionen und Klassen im Dojo Sourcetree zu implementieren, sollte man einen eigenen Namespace einführen. Damit vermeidet man Probleme beim Update von Dojo und der Versionierung des eigenen Projektes. Das folgende Beispiel zeigt ein Projekt mit dem Namen webcrm.
/js/ dojo/ dojo.js src/ ... webcrm/ src/ ...
Der Verzeichnisbaum für die eigenen Projektdateien wird neben das Dojo-Verzeichnis gesetzt. Alle benötigten Dateien werden in den eigenen Verzeichnissen abgelegt.

Das Widget-Framework stellt das Herzstück von Dojo dar. Dojo bietet eine Reihe vorgefertigter Widgets mit eigener Demo auf der Dojo-Website. Um aber Widgets entwickeln zu können, gehe ich an dieser Stelle auf die zugrunde liegenden Mechanismen ein. Listing 1 zeigt einen beispielhaften HTML Header, der auch als Grundlage für eigene Versuche dienen kann. Über das globale Objekt djConfig werden zentrale Konfigurationen vorgenommen und das System für die Entwicklung konfiguriert, indem die Debugging-Funktionalitäten aktiviert werden. Außerdem wird der eigene Namespace webcrm über die Funktion dojo.setModulePrefix() beim Package-System angemeldet.
Listing 1 -----------------------------------------------------------------------------------------------------------------------------------
Den Rest des Artikels widmen wir der Entwicklung eines eigenen kleinen Adressenbuch-Widgets. Abbildung 2 zeigt das fertige Ergebnis. Sobald der Benutzer auf der linken Seite einen Kontakt auswählt, lädt das Widget die Kontaktdaten über einen AJAX Request und zeigt sie rechts unter „Contact Detail“ an.

Die Implementierung eines Widgets erfolgt in JavaScript. Optional dient ein HTML Template als Strukturinformation für das Widget sowie CSS für die benötigten Layout-Informationen. Listing 2 zeigt die entsprechende JavaScript-Datei.
Listing 2 ----------------------------------------------------------------------------------------- dojo.provide("webcrm.widget.ContactsWidget"); dojo.require("dojo.widget.*"); dojo.widget.defineWidget( "dojo.widget.ContactsWidget", // My class name "html", // The renderer dojo.widget.HtmlWidget, // My superclass function() {}, // My Ctor (null not allowed!) { // URIs for the html and css templates templatePath: dojo.uri.dojoUri( "../webcrm/src/widget/templates/ContactsWidget.html"), templateCssPath: dojo.uri.dojoUri( "../webcrm/src/widget/templates/ContactsWidget.css"), // yes we can contain other widgets isContainer: true, // these properties are already defined in the base class DomWidget // domNode: null, containerNode: null, // Nodes that will show contact detail information. The corresponding // dom nodes will be attached to these properties automatically contactName: null, contactEmail: null, // Called by the toolkit after the template html is attached // to this.domNode and the template css is loaded. fillInTemplate: function(args, frag) {...}, // This method expects a contactId and will trigger an // ajax request to load and display the contact details showContact: function(contactId) {...} });
Da die Implementierung des Widget-Systems über eine objektorientierte Klassenhierarchie erfolgt und in JavaScript die prototypische Vererbung mühsam ist, stellt Dojo mit dojo.widget.defineWidget() eine Hilfsfunktion bereit. Diese meldet das neue Widget sofort am Widget-System an, sodass es später automatisch initialisiert werden kann. Das erste Argument ist der Klassenname des neuen Widgets. Dieser lautet dojo.widget.ContactsWidget anstatt webcrm.widget.ContactsWidget, da die Version 0.3.1 nur mit solchen Widgets umgehen kann, die im Dojo Namespace implementiert sind. Dieses kleine Problem ist bereits behoben, und die Lösung wird mit der Version 0.4 zur Verfügung stehen. Funktional ergeben sich daraus auch in der aktuellen Version keine Einschränkungen. Die eigentlichen Methoden und Eigenschaften des Widgets werden im letzten Argument als Objekt übergeben. Alle sichtbaren Komponenten auf einer Webseite benötigen ein HTML-Fragment und entsprechende CSS-Layout-Information. Die dazugehörenden Dateien werden über die beiden Template-Attribute referenziert. Für das Adressenbuch benötigen wir ein Layout mit zwei Boxen. Die Datei ContactsWidget.html enthält die HTML-Struktur der Komponente. Listing 3 zeigt eine leicht vereinfachte Darstellung des HTML Template ohne CSS-Attribute, um das automatische Node Attachment zu betonen.
Listing 3: Vereinfachtes HTML Template für das ContactsWidget ----------------------------------------------------------------------------------------------------------------Contact ListContact DetailName
Jedes Widget erbt von seinen Superklassen die Eigenschaften domNode und, falls es sich um eine Container-Komponente handelt, containerNode. Der domNode ist das Root-Element des Templates und benötigt daher keine spezielle Auszeichnung. Benötigt man schnellen Zugriff auf andere Knoten des HTML Template, dann müssen diese explizit mit dem Attribut dojoAttachPoint gekennzeichnet werden. Dojo weist diese dann automatisch den Attributen der Widget-Instanz zu (Listing 2). Eine besondere Funktion hat der containerNode. Enthält eine Komponente Sub-Widgets, so werden diese automatisch unterhalb dieses Knotens während der Initialisierungsphase des Widgets eingehängt. Nachdem diese beendet ist, wird die Methode fillInTemplate aufgerufen, in der man das Widget programmatisch verändern kann.