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 :

  1. Avoir fait le tutoriel « mon premier widget Dojo » (où au moins avoir télécharger le code source du tutoriel)
  2. # 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/
  3. Créer ensuite le répertoire exemple2 en effectuant un simple copier/coller du dossier exemple1.
    Arborescence du projet.
  4. Editer les fichiers Search.js et searchWidget.html pour modifier le namespace

    Search.js

    1. /**********************************************/
    2. /*                                            */
    3. /* Widget : Search                            */
    4. /* Author : Berthenet Cyril                   */
    5. /*                                            */
    6. /**********************************************/
    1. dojo.provide("exemple2.widget.Search");
    2.  
    3. dojo.require("dijit._Templated");
    4. dojo.require("dijit._Widget");
    5.  
    6. dojo.require("dijit.form.Button");
    7. dojo.require("dijit.Menu");
    8.  
    9. dojo.requireLocalization("exemple2", "Locale");
    10. dojo.requireLocalization("exemple2", "Ressources");
    11.  
    12. /* Class: Search */
    13. dojo.declare("exemple2.widget.Search", [dijit._Widget,dijit._Templated], {
    14.  
    15. /* Object: _nls
    16. stockage du wording et des ressources du widget */
    17. _nls:{locale:null,ressources:null},
    18.  
    19. /* String: templatePath
    20. chemin d'acces vers le template du widget */
    21. templatePath: dojo.moduleUrl("exemple2.widget", "template/Search.html"),
    22.  
    23. /* Object: _dropdown
    24. Bouton de selection du moteur de recherche */
    25. _dropdown:null,
    26.  
    27. /* Array: _engines
    28. Liste des moteurs de recherche */
    29. _engines:null,
    30.  
    31. /* Function: constructor
    32. Constructeur */
    33. constructor: function(){
    34. console.log("exemple2.widget.Search::constructor");
    35. this._nls.locale=
    36. dojo.i18n.getLocalization("exemple2","Locale").searchWidget;
    37. this._nls.ressources=
    38. dojo.i18n.getLocalization("exemple2","Ressources").searchWidget;
    39. this._engines=this._nls.locale.engines;
    40. this._dropdown={};
    41. },
    42.  
    43. /* Function: destroy
    44. Destructeur */
    45. destroy: function(){
    46. console.log("exemple2.widget.Search::destroy");
    47. this.inherited("destroy",arguments);
    48. if(this._dropdown){this._dropdown.destroy();}
    49. delete this._nls;
    50. delete this._engines;
    51. },
    52.  
    53. /* Function: startup
    54. Methode publique appelee apres l'instanciation du widget et la creation de tous
    55. ses noeuds DOM dans document.body */
    56. startup: function(){
    57. console.log("exemple2.widget.Search::startup");
    58. this.inherited("startup",arguments);
    59.  
    60. this.searchField.value=(this.text==null||this.text=="")?
    61. this._nls.locale.text:this.text;
    62.  
    63. var menu = new dijit.Menu();
    64.  
    65. dojo.forEach(this._engines, function(engine){
    66.  
    67. var menuItem = new dijit.MenuItem({
    68. label: engine,
    69. onClick: dojo.hitch(this, function(param) {
    70. this._dropdown.attr("label",param);
    71. this._dropdown.attr("engine",param);
    72. },engine)
    73. });
    74.  
    75. menu.addChild(menuItem);
    76.  
    77. },this);
    78.  
    79. this._dropdown = new dijit.form.DropDownButton({
    80. label: this._engines[0],
    81. engine: this._engines[0],
    82. dropDown: menu
    83. }, dojo.byId(this.id+"Selector"));
    84.  
    85. this._dropdown.startup();
    86.  
    87. },
    88.  
    89. /* Function: _onKeyPress
    90. Methode privee executee lors de la saisie d'un caractere dans le champs de recherche */
    91. _onKeyPress: function(/*Object*/evt) {
    92. console.log("exemple2.widget.Search::_onKeyPress");
    93. if(evt.keyCode == dojo.keys.ENTER){
    94. this._search();
    95. dojo.stopEvent(evt);
    96. return;
    97. }
    98. },
    99.  
    100. /* Function: _clear
    101. Methode privee permettant d'effacer le texte du champs de saisie */
    102. _clear: function() {
    103. console.log("exemple2.widget.Search::_clear");
    104. if(this.searchField.value==this._nls.locale.text||this.searchField.value==this.text) {
    105. this.searchField.value="";
    106. }
    107. },
    108.  
    109. /* Function: _search
    110. Methode privee executant la recherche */
    111. _search: function() {
    112. console.log("exemple2.widget.Search::_search");
    113.  
    114. if(  this.searchField.value!=this._nls.locale.text &&
    115. this.searchField.value!=this.text &&
    116. this.searchField.value != "") {
    117.  
    118. var url = "";
    119. var fieldValue = this.searchField.value;
    120. var engines = this._nls.ressources.engines;
    121.  
    122. switch(this._dropdown.attr('engine')){
    123. case this._engines[0]:
    124. url = engines.google;
    125. break;
    126. case this._engines[1]:
    127. url = engines.yahoo;
    128. break;
    129. case this._engines[2]:
    130. url = engines.wikipedia;
    131. break;
    132. }
    133.  
    134. dojo.byId("viewer").src=url+escape(fieldValue);
    135.  
    136. }
    137. else {
    138.  
    139. var dialogbox = dijit.byId("dialogbox");
    140.  
    141. var content = this._nls.ressources.popup;
    142. dialogbox.attr("title",this._nls.locale.popup.title);
    143. dialogbox.attr("content",dojo.string.substitute(content,{
    144. message:this._nls.locale.popup.message,
    145. btnLabel:this._nls.locale.popup.btnLabel
    146. }));
    147.  
    148. dialogbox.show();
    149. }
    150. }
    1. });

    searchWidget.html

    1. <script type="text/javascript">// <![CDATA[
    2.  
    3.  
    4.       dojo.require("dojo.i18n");
    5.       dojo.require("dijit.Dialog");
    6.  
    7. 	  dojo.require("exemple2.widget.Search"); 
    8.  
    9.       dojo.addOnLoad(init);
    10.  
    11.       function init(){ 
    12.  
    13.         var _search = new exemple2.widget.Search({
    14. 		  id:"search",
    15.           text:"saisir votre texte ici..."
    16.         }, dojo.byId("search"));
    17.  
    18.         _search.startup();
    19.  
    20.         var dialog = new dijit.Dialog({
    21.           title: "title" 
    22. 		}, dojo.byId("dialogbox"));
    23.  
    24.         dialog.startup();
    25.  
    26.       }
    27.  
    28.  
    29. // ]]></script>

Conventions de codage adoptées dans ce tutoriel

  1. commentaires : /* commentaire sur une ou plusieurs lignes */
  2. 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
  3. les méthodes privées sont préfixées par un underscore
  4. 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 :

  1. un div container qui nous permettra par la suite de définir le style de notre widget
  2. d’une iframe pour l’affichage

Viewer.html

 

  1. <div class="viewer">class="iframe"<br />           src="${_nls.ressources.defaultPage}"<br />           dojoAttachPoint="viewer"<br />           scrolling="yes"<br />           frameborder="no"><br /></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

  1. },
  2. "viewerWidget" : {
  3. "defaultPage": "static/empty.html"
  4. }

Définition du style du widget ‘Viewer’

viewer.css

  1. .viewer .iframe {
  2. width: 800px;
  3. height: 400px;
  4. border:3px solid #B0B0B0;
  5. }

Modification de la page statique

empty.html

  1.  
  2.  
  3.  
  4.  
  5. Le résultat de votre recherche s'affichera dans ce viewer

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. /* Widget : Viewer                            */
  4. /* Author : Berthenet Cyril                   */
  5. /*                                            */
  6. /**********************************************/
  1. dojo.provide("exemple2.widget.Viewer");
  2.  
  3. dojo.require("dijit._Templated");
  4. dojo.require("dijit._Widget");
  5.  
  6. dojo.requireLocalization("exemple2", "Ressources");
  7.  
  8. /* Class: Search */
  9. dojo.declare("exemple2.widget.Viewer", [dijit._Widget,dijit._Templated], {
  10.  
  11. /* Object: _nls
  12. stockage du wording et des ressources du widget */
  13. _nls:{ressources:null},
  14.  
  15. /* String: templatePath
  16. chemin d'acces au template du widget */
  17. templatePath: dojo.moduleUrl("exemple2.widget", "template/Viewer.html"),
  18.  
  19. /* Function: constructor
  20. Constructeur */
  21. constructor: function(){
  22. console.log("exemple2.widget.Viewer::constructor");
  23. this._nls.ressources=
  24. dojo.i18n.getLocalization("exemple2","Ressources").viewerWidget;
  25. },
  26.  
  27. /* Function: destroy
  28. Destructeur */
  29. destroy: function(){
  30. console.log("exemple2.widget.Search::destroy");
  31. delete this._nls;
  32. },
  33.  
  34. /* Function: setContent
  35. Modification du contenu du viewer */
  36. setContent: function(/*String*/url) {
  37. console.log("exemple2.widget.Viewer::setContent");
  38. this.viewer.src=url;
  39. },
  40.  
  41. /* Function: reset
  42. Remise a zero du contenu du viewer */
  43. reset: function() {
  44. console.log("exemple2.widget.Viewer::setContent");
  45. this.setContent(this._nls.ressources.defaultPage);
  46. }
  1. });

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.  
  1. <script type="text/javascript">// <![CDATA[
  2.  
  3.  
  4.       var djConfig = {
  5.         parseOnLoad: false,
  6.         isDebug: true
  7.       }; 
  8.  
  9.  
  10. // ]]></script>
  11.  
  12. <script src="../dojo/dojo.js" type="text/javascript"></script>
  13.  
  14. <script type="text/javascript">// <![CDATA[
  15.  
  16.  
  17.       dojo.require("dojo.i18n");
  18.  
  19.       dojo.require("exemple2.widget.Viewer"); 
  20.  
  21.       dojo.addOnLoad(init);
  22.  
  23.       function init(){
  24.  
  25.          var _viewer = new exemple2.widget.Viewer({
  26.           id:"viewer"
  27.         }, dojo.byId("viewer"));
  28.  
  29.         _viewer.setContent("http://www.google.fr");        
  30.  
  31.       }
  32.  
  33.  
  34. // ]]></script>
  1.  

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. /* Widget : Mon application                   */
  4. /* Author : Berthenet Cyril                   */
  5. /*                                            */
  6. /**********************************************/
  1. dojo.provide("exemple2.widget.MonAppli");
  2.  
  3. dojo.require("dijit._Templated");
  4. dojo.require("dijit._Widget");
  5.  
  6. dojo.require("dijit.layout.ContentPane");
  7. dojo.require("dijit.layout.BorderContainer");
  8. dojo.require("dijit.Dialog");
  9.  
  10. dojo.require("exemple2.widget.Search");
  11. dojo.require("exemple2.widget.Viewer");
  12.  
  13. dojo.requireLocalization("exemple2", "Ressources");
  14.  
  15. /* Class: Search */
  16. dojo.declare("exemple2.widget.MonAppli", [dijit._Widget,dijit._Templated], {
  17.  
  18. /* Boolean: widgetsInTemplate
  19. affichage de widgets dans un template (false par defaut) */
  20. widgetsInTemplate: true,
  21.  
  22. /* String: templatePath
  23. chemin d'acces au template du widget */
  24. templatePath: dojo.moduleUrl("exemple2.widget", "template/MonAppli.html"),
  25.  
  26. /* Function: constructor
  27. Constructeur */
  28. constructor: function(){
  29. console.log("exemple2.widget.MonAppli::constructor");
  30. }
  1. });

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. <div>
  2. <div>
  3.  
  4. &nbsp;
  5.  
  6. </div>
  7. <div>
  8.  
  9. &nbsp;
  10.  
  11. </div>
  12. </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

  1. dojo.byId("viewer").src=url+escape(fieldValue);

par :

Search.js

  1. dojo.publish("displayResult",[url+escape(fieldValue)]);

Viewer.js

  1. /* Array: topics */
  2. _topics:null,
  1. /* Function: constructor
  2. Constructeur */
  3. constructor: function(){
  4. console.log("exemple2.widget.Viewer::constructor");
  5. this._nls.ressources=dojo.i18n.getLocalization("exemple2","Ressources")
  6. .viewerWidget;
  7. this._topics=[];
  8. },
  9.  
  10. /*Function: destroy
  11. Destructeur */
  12. destroy: function(){
  13. console.log("exemple2.widget.Search::destroy");
  14. delete this._nls;
  15. delete this._topics;
  16. },
  1.  /* Function: postCreate
  2. Methode appelee apres la creation du widget */
  3. postCreate: function() {
  4. this._topics[0]=dojo.subscribe("displayResult", this, "setContent");
  5. },

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. .search {
  2. height:30px;
  3. }
  4. .search .btn {
  5. background: url(../images/loupe.png) no-repeat;
  6. width:20px;
  7. height:19px;
  8. border-left:0px;
  9. cursor:pointer;
  10. }
  11. .search input{
  12. height:21px;
  13. font:13px verdana, sans-serif;
  14. }

monappli.css

  1. .floatLeft {
  2. float:left;
  3. }
  4. .greyBorder {
  5. border:1px solid #B0B0B0;
  6. }
  1. /****************************************/
  2. /*    Surcharge theme nihilo de Dojo       */
  3. /****************************************/
  1. .nihilo .dijitDropDownButton .dijitReset {
  2. height:16px;
  3. }
  4. .nihilo .dijitDropDownButton {
  5. float: left;
  6. margin:0 !important;
  7. }
  8. .nihilo .dijitDropDownButton span {
  9. font:10px verdana, sans-serif;
  10. }
  11. .nihilo .dijitButtonNode {
  12. width:80px;
  13. border:1px solid #B0B0B0 !important;
  14. border-right:0px !important;
  15. }

Test 

monApplication.html

  1.  
  1.  <!--       @import "../dijit/themes/dijit.css";       @import "../dijit/themes/nihilo/nihilo.css";      --><script type="text/javascript">// <![CDATA[
  2.  
  3.  
  4.       var djConfig = {
  5.         parseOnLoad: false,        
  6. 		isDebug: true
  7.       };
  8.  
  9.  
  10. // ]]></script>
  11.  
  12. <script src="../dojo/dojo.js" type="text/javascript"></script>
  13.  
  14. <script type="text/javascript">// <![CDATA[
  15.  
  16.  
  17.       dojo.require("dojo.i18n");      
  18.  
  19.       dojo.require("exemple2.widget.MonAppli");
  20.  
  21.       dojo.addOnLoad(init);
  22.  
  23. 	  function init(){
  24.  
  25.         var _appli = new exemple2.widget.MonAppli({}, dojo.byId("appli"));
  26.  
  27.         var dialog = new dijit.Dialog({}, dojo.byId("dialogbox")); 
  28.  
  29.         dialog.startup();
  30.  
  31.       }
  32.  
  33.  
  34. // ]]></script>
  1.  

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.

L'application finale est composée des widgets 'Search' et 'Viewer'.


Berthenet Cyril

http://www.life-behind-the-mirror.com/codes/tutoDojo/myFirstDojoAppli.php

 

À propos de ben

Technophile passionné par le web, Je travaille actuellement en tant qu'Expert Dojo auprès de la banque ING aux Pays Bas. http://www.linkedin.com/in/santalucia
Cette entrée a été publiée dans Non classé. Vous pouvez la mettre en favoris avec ce permalien.

Laisser un commentaire