Dojo - unice.fr

Download Report

Transcript Dojo - unice.fr

Dojo
Carol McDonald, Java Architect,
Updated and adapted by Michel Buffa
Problèmes avec Ajax
• JavaScript
> Support inconsistant entre
browsers
> Nécessite des tests cross browsers
> Le code peut devenir difficile à
developper, debugger, et
maintenir
2
Dojo Client Side
JavaScript Library
3
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
• http://dojotoolkit.com/
• Indépendant de la techologie serveur et des
langages utilisés (java, c#, python, ruby...)
source: dojotoolkit.org
4
Les librairies du Toolkit Dojo
5
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
>
Widgets, Contrôles avancés d'interface
utilisateur,système de template
dijit
dojoX
>
innovations: graphiquess, support du mode offline, widgets
évolués comme les tableaux (grid), etc
6
Intégrer dojo à une
application
7
1) L'application télécharge des morceaux de Dojo
depuis le net :
Google:
<SCRIPT TYPE="text/javascript" SRC=
”http://ajax.googleapis.com/ajax/libs/dojo/1.3/dojo/dojo.xd.js">
</SCRIPT>
La balise script est utilisée pour
charger le script dojo.js, toujours
obligatoire.
8
2) Ajouter Dojo dans son application (il sera
déployé avec l'application)
• Downloader depuis
http://dojotoolkit.org/downloads
• 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">
</script>
Pas de “/” ici ! Le système de chargement des packages chargera
toutes les dépendances s'il y en a !
9
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)
10
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-1.3.2
C:\Program Files\Apache Software
Foundation\Apache Tomcat
6.0.18\webapps\ROOT\dojo-release-1.3.2
• Et l'inclure dans l'application :
<script type="text/javascript"
djConfig="parseOnLoad: true"
src=“/dojo-release-1.3.2/dojo/dojo.js">
</script>
“/” obligatoire ici, l’inverse de ce qu’on a
vu précédemment !
11
Dojo contient plusieurs
Démonstrations
Par exemple :
themeTester.html
12
Exemples de widgets issus de dijit
13
Choses à faire dans une page pour utiliser Dojo
Charger la CSS Dojo
<head>
<style type="text/css">
@import "js/dojo/resources/dojo.css";";
</style>
<script type="text/javascript"
src="js/dojo/dojo.js"
djConfig="parseOnLoad: true"
isDebug: true >
</script>
</head>
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 !
14
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");
15
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");
16
Dijit = dojo Widget
17
Les widgets Doko
dijit est une couche au-dessus de Dojo
18
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
19
Exemple déclaratif de button
Charger la CSS de Dijit
<head>
<style type="text/css">
@import "js/dijit/themes/tundra/tundra.css";
@import "js/dojo/resources/dojo.css";
</style>
<script type="text/javascript"
Pour les widgets déclaratifs
djConfig="parseOnLoad: true"
src="js/dojo/dojo.js" ></script>
<script type="text/javascript">
dojo.require("dijit.form.Button");
</script>
</head>
<body class="tundra">
Charger le module
Style/thème pour les widgets
<button dojoType="dijit.form.Button"
onclick="call_function">
Log Button
</button>
20
Même exemple mais par programmation
<head>
...
<script type="text/javascript">
dojo.require("dijit.form.Button");
var myButton = new dijit.form.Button(
{title:"Log Button"}, dojo.byId("someDiv"));
</script>
...
</head>
<body class="tundra">
<div id="someDiv"></div>
</body>
21
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)
22
Exemple dijit.form.DateTextBox
<script>
dojo.require("dijit.form.DateTextBox");
</script>
<body>
<input type="text" name="date1"
value="2005-12-30"
dojoType="dijit.form.DateTextBox"
required="true" />
23
Dijit, widgets de Layout
• Accordion Container,Content Pane, Layout
Container, Split Container, Stack Container, Tab
Container
24
Exemple dijit.layout.AccordionContainer
<script>
dojo.require("dojo.parser");
dojo.require("dijit.layout.AccordionContainer");
</script>
<body>
<div dojoType="dijit.layout.AccordionContainer" duration="200"
style="margin-right: 30px; width: 400px; height: 300px; overflow:
hidden">
<div dojoType="dijit.layout.AccordionPane" selected="true"
title="Pane1">
<p > some text ...</p >
</div>
<!-- contenu html -->
<div dojoType="dijit.layout.AccordionPane"
title="Pane2"
href="tab1.html" > <!-- c'est un URL !
Chargé en Ajax ! -->
</div>
</div>
25
Dijit menus et boutons
• Button, ComboButton, DropDownButton, Menu,
Toolbar
26
Exemple dijit.Menu
<script>
dojo.require("dojo.parser");
dojo.require("dijit.Menu");
</script>
<body>
<div dojoType="dijit.Menu" id="submenu1"
contextMenuForWindow="true" style="display:
none;">
<div dojoType="dijit.MenuItem" iconClass="myIcon"
onClick="alert('Hello world');"> Enabled Item
</div>
<div dojoType="dijit.PopupMenuItem" id="submenu2">
Enabled Submenu
<div dojoType="dijit.Menu">
<div dojoType="dijit.MenuItem"
onClick="alert('Submenu 1!')">
Submenu Item One</div>
...
</div>
27
Fonctions dojo
indispensables
28
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.
29
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");
30
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
31
Dojo et les événements
32
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
<a href>.
> 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.
33
dojo.event.connect(srcObj,"srcFunc",
targetFunc);
function myFunction() {
alert("dojo.connect handler");
}
var link = dojo.byId("mylink");
dojo.event.connect(link, "onclick", myFunction);
<a href="#" id="mylink">Click Me</a>
34
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”
35
Déconnecter des Fonctions
objectConnections[1]=
dojo.connect(someObject, "baz",
anotherObject, "afterBaz");
dojo.disconnect(objectConnections[1]);
36
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]);
37
Appels Ajax :
XMLHttpRequest (XHR):
dojo.xhrDelete(),
dojo.xhrGet(),
dojo.xhrPost(),
dojo.xhrPut()
38
Web traditionnel
AJAX
within a browser,
there is AJAX engine
39
Envoie de requête, récupérer la réponse d'un
serveur
Appeler un url
<script type="text/javascript">
Fonction de callback
dojo.xhrGet({
url: 'sayHello',
En cas d'erreur, on appelle
load: helloCallback,
cette fonction.
error: helloError,
content: {name: dojo.byId('name').value }
});
Contenu à envoyer
</script>
40
Dojo Hello World
41
Connecter un événement à un Widget (bouton ici)
<head>
...
<script type="text/javascript">
dojo.require("dijit.form.Button");
</script>
...
</head>
<body class="tundra">
Name: <input name="Name" id="name" type="text" />
<button dojoType="dijit.form.Button" id="helloButton">
Hello World!
<script type="dojo/method" event="onClick">
makeAjaxCall();
</script>
</button>
</body>
On déclare un écouteur avec le
type dojo/method
42
Suite...
<head>
<script type="text/javascript">
call url
Callback function
function makeAjaxCall(){
dojo.xhrGet({
On error function
url: 'sayHello.jsp',
load: helloCallback,
Content to send
error: helloError,
content: {name: dojo.byId('name').value }
});
}
function helloCallback(data,ioArgs) {
dojo.byId("returnMsg").innerHTML = data;
}
</script>
</head>
<body>
Name: <input name="Name" id="name" type="text" />
<button dojoType="dijit.form.Button"
<script type="dojo/method" event="onClick">
makeAjaxCall();
...
<p id=returnMsg></p>
43
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);
}
%>
44
dojo.xhrPost pour envoyer un formulaire
<head>
<script type="text/javascript">
function makeAjaxCall(){
xhrPost
dojo.xhrPost({
url: 'sayHello',
load: helloCallback,
error: helloError,
form: 'myForm'
Formulaire
});
}
function helloCallback(data,ioArgs) {
dojo.byId("returnMsg").innerHTML = data;
}
</script>
</head>
<body>
<form id="myForm" method="POST">
Name: <input type="text" name="name">
</form>
<button dojoType="dijit.form.Button"
<script type="dojo/method" event="onClick">
makeAjaxCall();
<p id=returnMsg></p>
</body>
45
Dojo MVC
46
Echange de données JSON
Objets javascript
Dans le code
var cobblers = [
{"filling": "peach", "timeToBake": 30 },
{"filling": "cherry", "timeToBake": 35 },
{"filling": "blueberry", "timeToBake": 30}
];
{ "cobblers": [
Ce qui est envoyé
sur le réseau,
{"filling": "peach", "timeToBake": 30 },
Presque pareil !
{"filling": "cherry", "timeToBake": 35 },
{"filling": "blueberry", "timeToBake": 30}
]
}
47
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...
});
48
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"}
]}
49
Exemple dijit.form.FilteringSelect
<script>
dojo.require("dojo.parser");
dojo.require("dijit.form.FilteringSelect");
dojo.require("dojo.data.ItemFileReadStore");
</script>
</head>
<body>
<div dojoType="dojo.data.ItemFileReadStore"
jsId="stateStore"
Lecture des donnés,
url="states.json"></div>
c'est le modèle
<form method="post">
<input dojoType="dijit.form.FilteringSelect"
store="stateStore"
searchAttr="name"
Le menu select est la vue
name="state1"
autocomplete="true"
/>
<input type="submit" value="Go!" />
</form>
50
Autre exemple de modèle:
pantry_items.json
Ce fichier est sur le
{ identifier: 'name',
serveur
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' }
]}
51
Simple data source read store
<script>
dojo.require("dojo.parser");
dojo.require("dijit.form.FilteringSelect");
dojo.require("dojo.data.ItemFileReadStore");
On donne un URL !
<div dojoType="dojo.data.ItemFileReadStore"
jsId="pantryStore"
url="pantry_items.json">
Ici on définit une vue
</div>
<label for="setvaluetest">spices :</label>
<div name="pantry_item"
dojoType="dijit.form.FilteringSelect"
store="pantryStore" searchAttr="name"
value="Vinegar" autoComplete="true">
</script>
52
Widget Grid et Store
53
Grid et Store, ici un ItemFileReadStore
VUE !
{"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"}
…
]
}
MODELE (un Store Dojo,
format JSON!)
54
Simple data source read store
<script>
dojo.require("dojox.grid.DataGrid");
dojo.require("dojo.data.ItemFileReadStore");
</script>
<table align="center" dojoType="dojox.grid.DataGrid" jsid="grid" id="grid"
store="jsonStore" width="auto" >
<thead>
<tr>
<th field="id" width="auto" >Id</th>
<th field="login" width="auto" >Login</th>
<th field="lastname" width="auto" >LastName</th>
<th field="firstname" width="auto" >FirstName</th>
</tr>
</thead>
</table>
55
Appel Ajax pour remplir le Store et mettre
à jour la vue
<script type="text/javascript">
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 });
}
</script>
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
l’associe à une Grid (Vue)
56
CRUD sur des Web Services REST
function getUsers() {
dojo.xhrGet({
url: "/user/all/",
handleAs: "json",
headers: {"Accept": "application/json"},
load: handleResponse,
error: handleError
});
}
@GET
@Path("/all/")
@Produces({"application/json", "application/xml"})
public bmserv.model.handlers.UserHandler getAllUsers() {
return Server.uh;
}
57
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)
});
}
58
CRUD sur des Web Services REST
@PUT
@Path("/id/{userid}")
@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
l’on ait annoté en JAXB la classe User.java pour indiquer la
conversion Java vers XML/JSON
59
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) {…}
});
}
60
CRUD sur des Web Services REST
@POST
@Path("/createjs")
@Consumes("application/json")
public void post(User user) {
System.out.println("createJS a reçu un user :" + user.getId());
Server.uh.addUser(user);
return;
}
61
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 d’objet en paramètre, on appelle juste l’URI
contenant l’Id du user à supprimer.
62
CRUD sur des Web Services REST
@DELETE
@Path("/id/{userid}")
public void delete(@PathParam("userid") String id) {
System.out.println("Je supprime le user d'id : " + id);
Server.uh.removeUserFromId(id);
}
63
JAXB pour la sérialisation / déserialisation
XML et JSON
Les deux formats sont pris en compte.
@XmlRootElement(name = "user")
public class User {
@XmlElement(name = "id") // facultatif car valeur par défaut
private String id;
private String lastname;
private String firstname;
private String login;
64
Users sérialisés en JSON
Donne du XML, mais aussi du JSON (en fonction du
@Produces{…} 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"}
]
}
@XmlRootElement(name = "users")
public class UserHandler {
@XmlElement(name = "user", required = true)
private static List<User> users = new ArrayList<User>();
65
Drag and Drop
Drag and Drop
<script>
dojo.require("dojo.dnd.source");
dojo.require("dojo.parser");
</script>
source
<h3>Source 1</h3>
<div dojoType="dojo.dnd.Source" jsId="c1" class="container">
<div class="dojoDndItem">Item Alpha</div>
<div class="dojoDndItem">Item Beta</div>
<div class="dojoDndItem">Item Gamma</div>
<div class="dojoDndItem">Item Delta</div>
target
</div>
<h3>Pure Target 2</h3>
<div dojoType="dojo.dnd.Target" jsId="c2" class="container">
<div class="dojoDndItem">One item</div>
</div>
67
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.)
68
Ressources web intéressantes
• Le livre “The Book of dojo” sur le site officiel:
> http://dojotoolkit.org/
• Cours et Tps sur :
• http://www.javapassion.com/ajaxcodecamp
• Très nombreux exemples à copier/coller sur
• http://www.dojocampus.org
• En particulier suivre le lien “dojo explorer”
69