Dojo Carol McDonald, Java Architect, Updated and adapted by Michel Buffa
2 Problèmes avec Ajax JavaScript > Support inconsistant entre browsers > Nécessite des tests cross browsers > Le code peut devenir difficile à developper, debugger, et maintenir
3 Dojo Client Side JavaScript Library Dojo Client Side JavaScript Library
4 Qu'est-ce que le Dojo Toolkit? Ensemble Open Source de librairies JavaScript Simplifie le code javascript Appartient à Google aujourd'hui (qui a racheté Jot) Supporté par > IBM, Sun, JotSpot, SitePen, Renkoo, AOL TurboAjax, OpenLaszlo, Nexaweb, Bea Systems Indépendant de la techologie serveur et des langages utilisés (java, c#, python, ruby...) source: dojotoolkit.org
5 Les librairies du Toolkit Dojo
6 Dojo 3 parties : Dojo > Support cross-browser, chargement des packages, accès et manipulation du DOM, debugger Firebug Lite, évènements, composants MVC, Drag and drop, appels Ajax asynchrones, encodage, décodage JSON dijit > Widgets, Contrôles avancés d'interface utilisateur,système de template dojoX > innovations: graphiquess, support du mode offline, widgets évolués comme les tableaux (grid), etc
7 Intégrer dojo à une application Intégrer dojo à une application
8 1) L'application télécharge des morceaux de Dojo depuis le net : Google: La balise script est utilisée pour charger le script dojo.js, toujours obligatoire.
9 2) Ajouter Dojo dans son application (il sera déployé avec l'application) Downloader depuis Unzipper le fichier à côté des pages web ou jsp du projet. Inclure dojo comme ceci dans les pages qui l'utilisent <script type="text/javascript" djConfig="parseOnLoad: true" src="dojo-release-1.3.2/dojo/dojo.js"> Pas de / ici ! Le système de chargement des packages chargera toutes les dépendances s'il y en a !
10 Dojo dans son application Ici dojo a été mis sous le répertoire js (classique lorsque on utilise plusieurs frameworks), dans le répertoire qui contient les pages web ou jsp (le repertoire web du projet netbeans par exemple)
11 3) Installer une fois pour toute Dojo sur le serveur (recommandé) Que ce soit Tomcat ou Glassfish, dézipper Dojo dans le docroot du serveur, par exemple > C:\Sun\AppServer\domains\domain1\docroot\doj o-release > C:\Program Files\Apache Software Foundation\Apache Tomcat \webapps\ROOT\dojo-release Et l'inclure dans l'application : <script type="text/javascript" djConfig="parseOnLoad: true" src=/dojo-release-1.3.2/dojo/dojo.js"> / obligatoire ici, linverse de ce quon a vu précédemment !
12 Dojo contient plusieurs Démonstrations Par exemple : themeTester.html
13 Exemples de widgets issus de dijit
14 Choses à faire dans une page pour utiliser "js/dojo/resources/dojo.css";"; <script type="text/javascript" src="js/dojo/dojo.js" djConfig="parseOnLoad: true" isDebug: true > Cette ligne indique qu'on va activer le mode debug : cela va générer des messages en couleur pour firebug Mais si on est pas sous Firefox avec Firebug, Dijo inclut un mini debugger pour les autres browsers : firebug lite ! Charger la CSS Dojo
15 Exemple de traces dans le debugger : console.log("log button clicked"); console.debug("debug button clicked"); console.info("info button clicked"); console.warn("warn button clicked"); console.error("error button clicked");
16 Logging avec firebug lite dans IE console.log("log button clicked"); console.debug("debug button clicked"); console.info("info button clicked"); console.warn("warn button clicked"); console.error("error button clicked");
17 Dijit = dojo Widget Dijit = dojo Widget
18 dijit est une couche au-dessus de Dojo Les widgets Doko
19 Qu'est-ce qu'un widget Dojo ? Un élément de GUI comme un button, text box, scroll bar, calendar, tree etc > Facile à utiliser, déclaratif (comme xhtml) > On peut associer des événements (écouteurs) à des widgets > On ne se préoccupe plus de problèmes de compatibilité entre navigateurs HTML+CSS sont pris en compte par JavaScript via Dojo
20 Exemple déclaratif de "js/dojo/resources/dojo.css"; <script type="text/javascript" djConfig="parseOnLoad: true" src="js/dojo/dojo.js" > dojo.require("dijit.form.Button"); <button dojoType="dijit.form.Button" onclick="call_function"> Log Button Charger la CSS de Dijit Style/thème pour les widgets Charger le module Pour les widgets déclaratifs
21 Même exemple mais par programmation... dojo.require("dijit.form.Button"); var myButton = new dijit.form.Button( {title:"Log Button"}, dojo.byId("someDiv"));...
22 Widgets pour formulaires CheckBox, RadioButton,ComboBox, CurrencyTextBox, DateTextBox, NumberTextBox, Slider, ValidationTextBox, Textarea Attributs: disabled: Boolean Methodes: > focus donne le focus focus à ce widget > getValue donne la valeur du widget. > setValue modifie la valeur du widget. > reset reset de la valeur du widget > Undo remet la dernière valeur Points d'extension: onChange: ce sont des écouteurs (callbacks)
23 Exemple dijit.form.DateTextBox dojo.require("dijit.form.DateTextBox"); <input type="text" name="date1" value=" " dojoType="dijit.form.DateTextBox" required="true" />
24 Dijit, widgets de Layout Accordion Container,Content Pane, Layout Container, Split Container, Stack Container, Tab Container
25 Exemple dijit.layout.AccordionContainer dojo.require("dojo.parser"); dojo.require("dijit.layout.AccordionContainer"); <div dojoType="dijit.layout.AccordionContainer" duration="200" style="margin-right: 30px; width: 400px; height: 300px; overflow: hidden"> some text... <div dojoType="dijit.layout.AccordionPane" title="Pane2" href="tab1.html" >
26 Dijit menus et boutons Button, ComboButton, DropDownButton, Menu, Toolbar
27 Exemple dijit.Menu dojo.require("dojo.parser"); dojo.require("dijit.Menu"); <div dojoType="dijit.Menu" id="submenu1" contextMenuForWindow="true" style="display: none;"> <div dojoType="dijit.MenuItem" iconClass="myIcon" onClick="alert('Hello world');"> Enabled Item Enabled Submenu <div dojoType="dijit.MenuItem" onClick="alert('Submenu 1!')"> Submenu Item One...
28 Fonctions dojo indispensables Fonctions dojo indispensables
29 Fonctions Dojo dojo.byId("id"); > Equivalent à : document.getElementById("someid"); dijit.byId("id"); > renvoie une instance de Dijit widget; dojo.addOnLoad("functionname"); > Appelle la fonction une fois que toute la page et tous ses scripts ont été chargés.
30 Dojo Query // Query par tag xhtml. Equivalent à // document.getElementsByTagName("IMG"); dojo.query("img"); // Query par classe. dojo.query(".progressIndicator"); // Query par id. Equivalent à // document.getElementById("widget123"); // ou dojo.byId("widget123") dojo.query("widget123");
31 Dojo For Each dojo.forEach(collection, function(item) { console.debug(item); } ); > Execute une fonction dans une boucle for dojo.query("select", document).forEach("item.disabled = true;"); > désactive tous les tags SELECT de la page
32 Dojo et les événements Dojo et les événements
33 dojo et la gestion des événements Dojo Simplifie le système de gestion des événements de JavaScript Permet de connecter une fonction que vous avez écrite à : > Un événement DOM, par exemple un click sur un lien. > un événement généré par un objet, par exemple une animation qui démarre > Un autre appel de function : permet de déclencher des réactions en chaine. > Un topic, dans lequel d'autres objets peuvent publier.
34 dojo.event.connect(srcObj,"srcFunc", targetFunc); function myFunction() { alert("dojo.connect handler"); } var link = dojo.byId("mylink"); dojo.event.connect(link, "onclick", myFunction); Click Me
35 Connecter des Objects et des Fonctions var someObject = { bar: function() { console.debug("Bar fired!"); return 14; } } var anotherObject = { anotherBar: function () { console.debug("anotherBar fired!"); } } dojo.connect(someObject, "bar", anotherObject, "anotherBar"); sourceObj, "sourceFunc", targetObj, targetFunc
36 Déconnecter des Fonctions objectConnections[1]= dojo.connect(someObject, "baz", anotherObject, "afterBaz"); dojo.disconnect(objectConnections[1]);
37 S'abonner et publier dans un Topic (équivalent de messages qui déclenchent des actions, cf JMS) var unObjet = { method1: (param1, param2) { console.debug("f1 appelée avec: "+ param1+" et : " + param2); return; }, } topics[1] = dojo.subscribe("MesMessages", "unObjet", method1); dojo.publish("MesMessages", ["Alex", "Russell"]); dojo.unsubscribe(topics[1]);
38 Appels Ajax : XMLHttpRequest (XHR): dojo.xhrDelete(), dojo.xhrGet(), dojo.xhrPost(), dojo.xhrPut()
39 Web traditionnel AJAX within a browser, there is AJAX engine
40 Envoie de requête, récupérer la réponse d'un serveur dojo.xhrGet({ url: 'sayHello', load: helloCallback, error: helloError, content: {name: dojo.byId('name').value } }); Appeler un url Fonction de callback Contenu à envoyer En cas d'erreur, on appelle cette fonction.
41 Dojo Hello World Dojo Hello World
42 Connecter un événement à un Widget (bouton ici)... dojo.require("dijit.form.Button");... Name: Hello World! makeAjaxCall(); On déclare un écouteur avec le type dojo/method
43 Suite... function makeAjaxCall(){ dojo.xhrGet({ url: 'sayHello.jsp', load: helloCallback, error: helloError, content: {name: dojo.byId('name').value } }); } function helloCallback(data,ioArgs) { dojo.byId("returnMsg").innerHTML = data; } Name: <button dojoType="dijit.form.Button" makeAjaxCall();... call url Callback function Content to send On error function
44 La page sayHello.jsp (attention, jdk 1.6 !) <% String returnString = request.getParameter("name"); if (returnString == null || returnString.isEmpty()) { // Return error message returnString = "Name is required."; out.print("Error: " + returnString); } else { // Return the name out.print("Hello: " + returnString); } %>
45 dojo.xhrPost pour envoyer un formulaire function makeAjaxCall(){ dojo.xhrPost({ url: 'sayHello', load: helloCallback, error: helloError, form: 'myForm' }); } function helloCallback(data,ioArgs) { dojo.byId("returnMsg").innerHTML = data; } Name: <button dojoType="dijit.form.Button" makeAjaxCall(); xhrPost Formulaire
46 Dojo MVC Dojo MVC
47 Echange de données JSON var cobblers = [ {"filling": "peach", "timeToBake": 30 }, {"filling": "cherry", "timeToBake": 35 }, {"filling": "blueberry", "timeToBake": 30} ]; { "cobblers": [ {"filling": "peach", "timeToBake": 30 }, {"filling": "cherry", "timeToBake": 35 }, {"filling": "blueberry", "timeToBake": 30} ] } Objets javascript Dans le code Ce qui est envoyé sur le réseau, Presque pareil !
48 Envoi de paramètre en JSON dojo.xhrGet( { // ici l'URL de ma servlet par exemple. url: "validateServlet", handleAs: "json", load: function(responseObject, ioArgs) { // Prints "peach" console.dir(responseObject.cobblers[0].filling); return responseObject; } // More properties for xhrGet... });
49 Exemple dijit.form.FilteringSelect Le fichier states.json contient : {identifier:"abbreviation", items: [ {name:"Alabama", label:"Alabama",abbreviation:"AL"}, {name:"Alaska", label:"Alaska",abbreviation:"AK"},... {name:"Wisconsin", label:"Wisconsin",abbreviation:"WI"}, {name:"Wyoming", label:"Wyoming",abbreviation:"WY"} ]}
50 Exemple dijit.form.FilteringSelect dojo.require("dojo.parser"); dojo.require("dijit.form.FilteringSelect"); dojo.require("dojo.data.ItemFileReadStore"); <div dojoType="dojo.data.ItemFileReadStore" jsId="stateStore" url="states.json"> <input dojoType="dijit.form.FilteringSelect" store="stateStore" searchAttr="name" name="state1" autocomplete="true" /> Le menu select est la vue Lecture des donnés, c'est le modèle
51 Autre exemple de modèle: pantry_items.json { identifier: 'name', items: [ { name: 'Adobo', aisle: 'Mexican' }, { name: 'Balsamic vinegar', aisle: 'Condiments' }, { name: 'Basil', aisle: 'Spices' }, { name: 'Bay leaf', aisle: 'Spices' }, { name: 'Beef Bouillon Granules', aisle: 'Soup' }, { name: 'Vinegar', aisle: 'Condiments' }, { name: 'White cooking wine', aisle: 'Condiments' }, { name: 'Worcestershire Sauce', aisle: 'Condiments' } ]} Ce fichier est sur le serveur
52 Simple data source read store dojo.require("dojo.parser"); dojo.require("dijit.form.FilteringSelect"); dojo.require("dojo.data.ItemFileReadStore"); <div dojoType="dojo.data.ItemFileReadStore" jsId="pantryStore" url="pantry_items.json"> spices : <div name="pantry_item" dojoType="dijit.form.FilteringSelect" store="pantryStore" searchAttr="name" value="Vinegar" autoComplete="true"> On donne un URL ! Ici on définit une vue
53 Widget Grid et Store Widget Grid et Store
54 Grid et Store, ici un ItemFileReadStore {"user":[{"id":"fgandon","login":"fgandon","lastname":"Gandon","firstname":"Fabien"}, {"id":"flimpens","login":"flimpens","lastname":"Limpens","firstname":"Freddy"}, {"id":"gereteo","login":"gereteo","lastname":"Erétéo","firstname":"Guillaume"} … ] } VUE ! MODELE (un Store Dojo, format JSON!)
55 Simple data source read store dojo.require("dojox.grid.DataGrid"); dojo.require("dojo.data.ItemFileReadStore"); Id Login LastName FirstName
56 Appel Ajax pour remplir le Store et mettre à jour la vue var jsonStore; function handleResponse(responseObject, ioArgs){ jsonStore = new dojo.data.ItemFileReadStore({data:{items: [responseObject.user]}}); grid.setStore(jsonStore); } function getDataFromWS() { dojo.xhrGet({ url: "/user/all/«, handleAs: "json", headers: {"Accept": "application/json"}, load: handleResponse, error: handleError }); } Appel Ajax à /user/all, On demande du JSON (header), on veut que la réponse soit interprétée par Dojo comme du JSON (handleAs), enfin la fonction appelée lors de la réponse crée un Store (Modèle) et lassocie à une Grid (Vue)
57 CRUD sur des Web Services REST function getUsers() { dojo.xhrGet({ url: "/user/all/", handleAs: "json", headers: {"Accept": "application/json"}, load: handleResponse, error: handleError @Produces({"application/json", "application/xml"}) public bmserv.model.handlers.UserHandler getAllUsers() { return Server.uh; }
58 CRUD sur des Web Services REST function updateUser() { var newItem = { id: store.getValue(item,"id"), login : store.getValue(item,"login"), firstname : store.getValue(item,"firstname"), lastname : store.getValue(item,"lastname") }; dojo.xhrPut({ url: "/user/id/"+id+"/", headers: { "Content-Type" : "application/json" }, putData: dojo.toJson(newItem) }); }
59 CRUD sur des Web @Consumes("application/json") public void update(User user) { System.out.println("J'update le user : " + user.getId()); Server.uh.updateUser(user); } Note : la conversion JSON vers Java est automatique pour peu que lon ait annoté en JAXB la classe User.java pour indiquer la conversion Java vers XML/JSON
60 CRUD sur des Web Services REST function addUser() { var item = { id: dojo.byId('login').value, login : dojo.byId('login').value, firstname: dojo.byId('firstname').value, lastname: dojo.byId('lastname').value }; dojo.xhrPost({ url: "/user/createjs", handleAs: "json", headers: {"Content-Type" : "application/json »}, postData: dojo.toJson(item), handle: function(response, ioargs) {…} }); }
61 CRUD sur des Web @Consumes("application/json") public void post(User user) { System.out.println("createJS a reçu un user :" + user.getId()); Server.uh.addUser(user); return; }
62 CRUD sur des Web Services REST function deleteUser(id) { dojo.xhrDelete({ url: "/user/id/" + id, handleAs: 'text', handle: function(error, ioargs) {…}} }); } Note : on ne passe pas dobjet en paramètre, on appelle juste lURI contenant lId du user à supprimer.
63 CRUD sur des Web public void String id) { System.out.println("Je supprime le user d'id : " + id); Server.uh.removeUserFromId(id); }
64 JAXB pour la sérialisation / déserialisation XML et JSON Les deux formats sont pris en = "user") public class User = "id") // facultatif car valeur par défaut private String id; private String lastname; private String firstname; private String login;
65 Users sérialisés en JSON Donne du XML, mais aussi du JSON (en fonction dans la fonction qui renvoie un User : {"user":[{"id":"fgandon","login":"fgandon","lastname":"Gandon","firstname":"Fabien"}, {"id":"flimpens","login":"flimpens","lastname":"Limpens","firstname":"Freddy"}, {"id":"gereteo","login":"gereteo","lastname":"Erétéo","firstname":"Guillaume"} ] = "users") public class UserHandler = "user", required = true) private static List users = new ArrayList ();
Drag and Drop Drag and Drop
67 Drag and Drop dojo.require("dojo.dnd.source"); dojo.require("dojo.parser"); Source 1 Item Alpha Item Beta Item Gamma Item Delta Pure Target 2 One item source target
68 Conclusion Dojo = gros support, très puissant, Modulaire (on ne charge pas toute la librairie à chaque fois) Bon choix si besoin en GUI importants Nombreux modèles disponibles (stores pour flickr, google, youtube, etc.)
69 Ressources web intéressantes Le livre The Book of dojo sur le site officiel: > Cours et Tps sur : Très nombreux exemples à copier/coller sur En particulier suivre le lien dojo explorer