Tutoriel : Ma première application Dojo
Tutoriel original par Cyril Berthenet
Pour bien commencer...
Avant de commencer à implémenter l'exemple présenté dans ce tutoriel, il vous faut tout d'abord :
- Avoir fait le tutoriel "mon premier widget Dojo" (où au moins avoir télécharger le code source du tutoriel)
- # Copier les librairies dijit, dojo et dojox du framework Dojo dans le répertoire tutoDojo
Télécharger le framework Dojo à cette adresse http://download.dojotoolkit.org/ - Créer ensuite le répertoire exemple2 en effectuant un simple copier/coller du dossier exemple1.
- Editer les fichiers Search.js et searchWidget.html pour modifier le namespace
Search.js
1 2 3 4 5 6 7 89 10 11 12 13 14 15 161718 19 2021 22 23 24 25 26 27 2829 30 31 32 33 34 35 36 37 38 39 40 41 42 4344 4546 47 48 49 50 51 52 5354 55 56 57 58 59 60 61 62 63 6465 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99100 101 102 103 104 105 106 107 108 109 110111 112 113 114 115 116 117 118 119120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
/**********************************************/ /* */ /* Widget : Search */ /* Author : Berthenet Cyril */ /* */ /**********************************************/ dojo.provide("exemple2.widget.Search"); dojo.require("dijit._Templated"); dojo.require("dijit._Widget"); dojo.require("dijit.form.Button"); dojo.require("dijit.Menu"); dojo.requireLocalization("exemple2", "Locale"); dojo.requireLocalization("exemple2", "Ressources"); /* Class: Search */ dojo.declare("exemple2.widget.Search", [dijit._Widget,dijit._Templated], { /* Object: _nls stockage du wording et des ressources du widget */ _nls:{locale:null,ressources:null}, /* String: templatePath chemin d'acces vers le template du widget */ templatePath: dojo.moduleUrl("exemple2.widget", "template/Search.html"), /* Object: _dropdown Bouton de selection du moteur de recherche */ _dropdown:null, /* Array: _engines Liste des moteurs de recherche */ _engines:null, /* Function: constructor Constructeur */ constructor: function(){ console.log("exemple2.widget.Search::constructor"); this._nls.locale= dojo.i18n.getLocalization("exemple2","Locale").searchWidget; this._nls.ressources= dojo.i18n.getLocalization("exemple2","Ressources").searchWidget; this._engines=this._nls.locale.engines; this._dropdown={}; }, /* Function: destroy Destructeur */ destroy: function(){ console.log("exemple2.widget.Search::destroy"); this.inherited("destroy",arguments); if(this._dropdown){this._dropdown.destroy();} delete this._nls; delete this._engines; }, /* Function: startup Methode publique appelee apres l'instanciation du widget et la creation de tous ses noeuds DOM dans document.body */ startup: function(){ console.log("exemple2.widget.Search::startup"); this.inherited("startup",arguments); this.searchField.value=(this.text==null||this.text=="")? this._nls.locale.text:this.text; var menu = new dijit.Menu(); dojo.forEach(this._engines, function(engine){ var menuItem = new dijit.MenuItem({ label: engine, onClick: dojo.hitch(this, function(param) { this._dropdown.attr("label",param); this._dropdown.attr("engine",param); },engine) }); menu.addChild(menuItem); },this); this._dropdown = new dijit.form.DropDownButton({ label: this._engines[0], engine: this._engines[0], dropDown: menu }, dojo.byId(this.id+"Selector")); this._dropdown.startup(); }, /* Function: _onKeyPress Methode privee executee lors de la saisie d'un caractere dans le champs de recherche */ _onKeyPress: function(/*Object*/evt) { console.log("exemple2.widget.Search::_onKeyPress"); if(evt.keyCode == dojo.keys.ENTER){ this._search(); dojo.stopEvent(evt); return; } }, /* Function: _clear Methode privee permettant d'effacer le texte du champs de saisie */ _clear: function() { console.log("exemple2.widget.Search::_clear"); if(this.searchField.value==this._nls.locale.text||this.searchField.value==this.text) { this.searchField.value=""; } }, /* Function: _search Methode privee executant la recherche */ _search: function() { console.log("exemple2.widget.Search::_search"); if( this.searchField.value!=this._nls.locale.text && this.searchField.value!=this.text && this.searchField.value != "") { var url = ""; var fieldValue = this.searchField.value; var engines = this._nls.ressources.engines; switch(this._dropdown.attr('engine')){ case this._engines[0]: url = engines.google; break; case this._engines[1]: url = engines.yahoo; break; case this._engines[2]: url = engines.wikipedia; break; } dojo.byId("viewer").src=url+escape(fieldValue); } else { var dialogbox = dijit.byId("dialogbox"); var content = this._nls.ressources.popup; dialogbox.attr("title",this._nls.locale.popup.title); dialogbox.attr("content",dojo.string.substitute(content,{ message:this._nls.locale.popup.message, btnLabel:this._nls.locale.popup.btnLabel })); dialogbox.show(); } } });
searchWidget.html
26 27 28 29 30 3132 33 34 35 36 3738 39 40 41 42 43 44 45 46 47 48 49 50 51 52
<script type="text/javascript" language="javascript"> dojo.require("dojo.i18n"); dojo.require("dijit.Dialog"); dojo.require("exemple2.widget.Search"); dojo.addOnLoad(init); function init(){ var _search = new exemple2.widget.Search({ id:"search", text:"saisir votre texte ici..." }, dojo.byId("search")); _search.startup(); var dialog = new dijit.Dialog({ title: "title" }, dojo.byId("dialogbox")); dialog.startup(); } </script>
Conventions de codage adoptées dans ce tutoriel
- commentaires : /* commentaire sur une ou plusieurs lignes */
- ajout d'une ligne console.log en début de fonction pour identifier les méthodes appelées lors de l'exécution du code
- les méthodes privées sont préfixées par un underscore
- afin d'éviter les problèmes d'encodage, les caractères accentués sont proscrit du code Dojo
Définition du template du widget 'Viewer'
Ce composant graphique va nous permettre d'afficher le résultat de la recherche sous forme d'une page HTML.
Il est composé des éléments suivants :
- un div container qui nous permettra par la suite de définir le style de notre widget
- d'une iframe pour l'affichage
Viewer.html
1 2 3 4 5 6 7 8 9 | <div class="viewer"> <iframe name="iframe" class="iframe" src="${_nls.ressources.defaultPage}" dojoAttachPoint="viewer" scrolling="yes" frameborder="no"> </iframe> </div> |
lignes :
4 : url de la page qui sera affichée par défaut dans le viewer (gestion du lien dans les ressources)
Modification des ressources
nls/Ressources.js et nls/fr/Ressources.js
20 212223 | }, "viewerWidget" : { "defaultPage": "static/empty.html"} |
Définition du style du widget 'Viewer'
viewer.css
1 2 3 4 5 | .viewer .iframe { width: 800px; height: 400px; border:3px solid #B0B0B0; } |
Modification de la page statique
empty.html
1
2
3
4
56
7
| <html> <head> </head> <body> Le résultat de votre recherche s'affichera dans ce viewer </body> </html> |
Définition de la classe 'Viewer'
Diagramme de classe
Viewer
- _nls : object
- templatePath : string
- _topics : array
+ constructor()
+ destroy()
+ postCreate()
+ setContent()
+ reset()
Viewer.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | /**********************************************/ /* */ /* Widget : Viewer */ /* Author : Berthenet Cyril */ /* */ /**********************************************/ dojo.provide("exemple2.widget.Viewer"); dojo.require("dijit._Templated"); dojo.require("dijit._Widget"); dojo.requireLocalization("exemple2", "Ressources"); /* Class: Search */ dojo.declare("exemple2.widget.Viewer", [dijit._Widget,dijit._Templated], { /* Object: _nls stockage du wording et des ressources du widget */ _nls:{ressources:null}, /* String: templatePath chemin d'acces au template du widget */ templatePath: dojo.moduleUrl("exemple2.widget", "template/Viewer.html"), /* Function: constructor Constructeur */ constructor: function(){ console.log("exemple2.widget.Viewer::constructor"); this._nls.ressources= dojo.i18n.getLocalization("exemple2","Ressources").viewerWidget; }, /* Function: destroy Destructeur */ destroy: function(){ console.log("exemple2.widget.Search::destroy"); delete this._nls; }, /* Function: setContent Modification du contenu du viewer */ setContent: function(/*String*/url) { console.log("exemple2.widget.Viewer::setContent"); this.viewer.src=url; }, /* Function: reset Remise a zero du contenu du viewer */ reset: function() { console.log("exemple2.widget.Viewer::setContent"); this.setContent(this._nls.ressources.defaultPage); } }); |
lignes :
30 et 31 : chargement des ressources du widget
43 à 46 : méthode permettant de modifier le contenu de l'iframe avec une url passée en paramètre
50 à 53 : remise à zéro du contenu du viewer par l'affichage de la page par défaut
Création d'un sample de test
viewerWidget.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset="utf-8" /> <title>Viewer</title> <link rel="stylesheet" type="text/css" href="./css/viewer.css" /> <script type="text/javascript"> var djConfig = { parseOnLoad: false, isDebug: true }; </script> <script type="text/javascript" src="../dojo/dojo.js" charset="utf-8"></script> <script type="text/javascript" language="javascript"> dojo.require("dojo.i18n"); dojo.require("exemple2.widget.Viewer"); dojo.addOnLoad(init); function init(){ var _viewer = new exemple2.widget.Viewer({ id:"viewer" }, dojo.byId("viewer")); _viewer.setContent("http://www.google.fr"); } </script> </head> <body> <div id="viewer"></div> </body> </html> |
lignes :
8 : chargement du style
31 à 33 : instanciation du widget "Viewer"
35 : affichage par défaut du moteur google
Définition de la classe de notre application
Nous avons fait le choix dans ce tutoriel de construire notre exemple à partir d'une classe appelant un template regroupant les widgets de base de notre application. Les widgets qui pourraient avoir d'autres fonctions que celle de la rechercher dans une application plus complète seront déportés vers le sample de test (ex: la boîte de dialogue)
MonAppli.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | /**********************************************/ /* */ /* Widget : Mon application */ /* Author : Berthenet Cyril */ /* */ /**********************************************/ dojo.provide("exemple2.widget.MonAppli"); dojo.require("dijit._Templated"); dojo.require("dijit._Widget"); dojo.require("dijit.layout.ContentPane"); dojo.require("dijit.layout.BorderContainer"); dojo.require("dijit.Dialog"); dojo.require("exemple2.widget.Search"); dojo.require("exemple2.widget.Viewer"); dojo.requireLocalization("exemple2", "Ressources"); /* Class: Search */ dojo.declare("exemple2.widget.MonAppli", [dijit._Widget,dijit._Templated], { /* Boolean: widgetsInTemplate affichage de widgets dans un template (false par defaut) */ widgetsInTemplate: true, /* String: templatePath chemin d'acces au template du widget */ templatePath: dojo.moduleUrl("exemple2.widget", "template/MonAppli.html"), /* Function: constructor Constructeur */ constructor: function(){ console.log("exemple2.widget.MonAppli::constructor"); } }); |
ligne :
27 : la variable widgetsInTemplate est très importante car elle permet l'interprétation des widgets à l'intérieur d'un template
Définition du template de notre application
Le template de notre application regroupe les composants graphiques permettant la mise en page (dijit.layout) et ceux liés à la fonction de recherche (Search et Viewer).
MonAppli.html
1 2 3 4 5 6 7 8 | <div dojoType="dijit.layout.BorderContainer" design="screenDesign"> <div dojoType="dijit.layout.ContentPane" region="top"> <div dojoType="exemple2.widget.Search"></div> </div> <div dojoType="dijit.layout.ContentPane" region="center"> <div dojoType="exemple2.widget.Viewer"></div> </div> </div> |
Distribution des données dans l'application
Les widgets publient leurs données et/ou s'abonnent pour en obtenir.
remplacer la ligne :
Search.js
139 | dojo.byId("viewer").src=url+escape(fieldValue); |
par :
Search.js
139 | dojo.publish("displayResult",[url+escape(fieldValue)]); |
Viewer.js
262728 29 30 31 32 33 34 3536 37 38 39 40 41 42 4344 45 4647484950 | /* Array: topics */_topics:null, /* Function: constructor Constructeur */ constructor: function(){ console.log("exemple2.widget.Viewer::constructor"); this._nls.ressources=dojo.i18n.getLocalization("exemple2","Ressources") .viewerWidget; this._topics=[]; }, /*Function: destroy Destructeur */ destroy: function(){ console.log("exemple2.widget.Search::destroy"); delete this._nls; delete this._topics; }, /* Function: postCreate Methode appelee apres la creation du widget */ postCreate: function() { this._topics[0]=dojo.subscribe("displayResult", this, "setContent");}, |
lignes :
27 : définition d'un tableau pour le stockage des topics.
35 : initialisation du tableau de topics.
43 : destruction du tableau de topics.
48 à 50 : méthode appelée automatiquement après la création du widget.
49 : déclenchement de la méthode setContent() du Viewer lorsque un topic "displayResult" est publié dans l'application.
note : le widget 'Search' envoi un topic "displayResult" avec l'url de recherche dans toute l'application. Le widget 'Viewer' qui a souscrit à ce topic va exécuter sa méthode setContent() avec l'url passée en argument du topic
Modification des styles
Séparation des styles propres à chacun des widgets et ceux pouvants être réutilisé dans toute l'application. On a préféré faire ici plusieurs fichiers css qui seront compressés en un seul fichier css par le processus de buid.
search.css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | .search { height:30px; } .search .btn { background: url(../images/loupe.png) no-repeat; width:20px; height:19px; border-left:0px; cursor:pointer; } .search input{ height:21px; font:13px verdana, sans-serif; } |
monappli.css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | .floatLeft { float:left; } .greyBorder { border:1px solid #B0B0B0; } /****************************************/ /* Surcharge theme nihilo de Dojo */ /****************************************/ .nihilo .dijitDropDownButton .dijitReset { height:16px; } .nihilo .dijitDropDownButton { float: left; margin:0 !important; } .nihilo .dijitDropDownButton span { font:10px verdana, sans-serif; } .nihilo .dijitButtonNode { width:80px; border:1px solid #B0B0B0 !important; border-right:0px !important; } |
Test
monApplication.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset="utf-8" /> <title>mon application</title> <link rel="stylesheet" type="text/css" href="./css/viewer.css" /> <link rel="stylesheet" type="text/css" href="./css/search.css" /> <link rel="stylesheet" type="text/css" href="./css/monappli.css" /> <style type="text/css" title="text/css"> @import "../dijit/themes/dijit.css"; @import "../dijit/themes/nihilo/nihilo.css"; </style> <script> var djConfig = { parseOnLoad: false, isDebug: true }; </script> <script type="text/javascript" src="../dojo/dojo.js" charset="utf-8"></script> <script type="text/javascript" language="javascript"> dojo.require("dojo.i18n"); dojo.require("exemple2.widget.MonAppli"); dojo.addOnLoad(init); function init(){ var _appli = new exemple2.widget.MonAppli({}, dojo.byId("appli")); var dialog = new dijit.Dialog({}, dojo.byId("dialogbox")); dialog.startup(); } </script> </head> <body class="nihilo"> <div id="appli"></div> <div id="dialogbox"></div> </body> </html> |
lignes :
8 : chargement du style du widget 'Viewer'
9 : chargement du style du widget 'Search'
10 : chargement des styles communs partagés par toute l'application
12 à 15 : chargement des thèmes dijit et nihilo pour la création du bouton à menu déroulant
38 : instanciation de l'application
40 : instanciation de la boîte de dialogue pour l'affichage des erreurs. On aurait pu inclure ce widgets dans le template de notre application en imaginant qu'il puisse avoir une autre fonction que l'affichage des erreurs liées à la recherche dans une application plus complète.

Berthenet Cyril
http://www.life-behind-the-mirror.com/codes/tutoDojo/myFirstDojoAppli.php
- Vous devez vous identifier ou créer un compte pour écrire des commentaires


- Ben -