Pat Biker
20,21 juillet 2006
Adobe Spry Ajax
Adobe Spry est un paquet logiciel (framework) permettant de simplifier la programmation Ajax. Rappelons qu'Ajax est une technique de programmation permettant la mise à jour partielle d'une page HTML. Illustrons ce concept par un exemple simple. Soit une page HTML contenant les deux éléments suivants:
Avec Ajax, la sélection d'une ville dans la combobox provoque automatiquement l'affichage des vignettes correspondantes dans le DIV.
Avec Adobe Spry, ce traitement est réalisé sans aucune ligne de programmation. La combobox est associée à un "dataset" décrivant les villes et les vignettes. Le DIV est abonné au changement de l'élément courant du dataset.
Vous commençez à avoir l'eau à la bouche mais tout cela vous paraît encore trop abstrait. Nous allons voir en détails et progressivement comment mettre en place la technologie Spry de Adobe avec des exemples concrets.
Le langage XHTML permet de séparer la structure de la page et sa mise en forme. D'un coté, les balises HTML décrivent le contenu de la page. De l'autre coté, la feuille de style CSS, définit la présentation (couleur, police, disposition, ...).
Ainsi dans WDGalerie, il est possible d'obtenir des présentations biens différenciées (couleur, disposition, taille des vignettes) simplement en choisissant une feuille de style. Le code HTML restant lui inchangé.
Sauf que, chaque galerie contient dans son code HTML les données (vignettes, images, dimensions de ces éléments).
Adobe Spry pousse la séparation des contituants encore plus loin. Ici les données (nom des images, leurs dimensions, les commentaires) sont stockées dans un fichier XML séparé.
Voici le fichier XML que nous utiliserons dans nos exemples (les indentations sont inutiles et n'ont pour but que de souligner la structure hiérarchisée des données).
<gallery> <photos id = "images"> <photo path = "2006-07-16_25.jpg" width = "400" height = "397" thumbpath = "2006-07-16_25.jpg" thumbwidth = "80" thumbheight = "79" comment = "photo 2">photo 1 : Sissi par terre </photo> <photo path = "2006-07-16_47.jpg" width = "400" height = "399" thumbpath = "2006-07-16_47.jpg" thumbwidth = "120" thumbheight = "120" comment = "photo 3">photo 2 : Sissi dans le poirier </photo> </photos> </gallery>
Voici le code d'une page XHTML minimale permettant de démarrer une session Spry. C'est le canevas de base pour démarrer. Dans la partie HEAD de la page, on trouve les includes nécessaires (attention aux minuscules/majuscules dans les noms).
Page1.html : Les includes javascript
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://ns.adobe.com/spry" xml:lang="fr" lang="fr"> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-15" /> <meta http-equiv="Content-Language" content="fr" /> <title>Ajax avec le framework Spry de Adobe</title> <!-- Includes pour les librairies SPRY --> <script type="text/javascript" src="./includes/xpath.js"></script> <script type="text/javascript" src="./includes/SpryData.js"></script> </head> <body> <h1>Hello Spry!</h1> </body> </html>
Un dataSet est décrit de la manière suivante (ces lignes peuvent être placées indifféremment dans la partie HEAD ou dans la partie BODY du document).
<!-- Définition d'un dataset --> <script type="text/javascript"> var monDataSet = new Spry.Data.XMLDataSet("photos.xml", "gallery/photos/photo"); </script>
La DataSet décrit ici exploite le fichier XML décrit plus haut (photos.xml). Ce dataset contient deux éléments de type <photo>. Chacun possède des attributs (path, width, height) et une valeur (Le premier élément a pour valeur "photo 1 : Sissi par terre").
Pour afficher des données du DataSet, nous allons créer un DIV dans la partie BODY. C'est au niveau du DIV que l'on réalise l'association avec le DataSet avec l'attribut Spry :region. Pour accéder à une valeur, on utilise une notation entre accolades {}. Si la valeur est celle d'un attribut, elle doit être précédée d'un symbole @. Cet arobas est inutile pour accéder à une valeur directe. Il se trouve qu'ici, le nom de l'image est mémorisé dans l'attribut nommé "path".
Page2.html : Affichage des données
<div spry:region="monDataSet"> Nom de la première photo du dataset {@path} </div>
Allons plus loin en voyant comment remplir une combobox. Rappelons-nous qu'une combobox est définie par l'élément HTML <select> et que chaque ligne est définie par un élément <option>. Dans l'élément <select> nous utilisons l'instruction de répétition "repeatchildren" (ignorons pour l'instant le "onchange"). Spry va donc réaliser une itération sur les éléments du DataSet. Pour chaque élément, une ligne <option> sera générée.
Nous voyons pourtant que le code montre deux lignes <option>. Cependant une seule ligne sera générée à chaque itération et ceci grâce à la commande if de Spry. Ce "if" a pour but de définir l'option qui sera sélectionnée par défaut. On a choisi, ici, de sélectionner le premier élément du DataSet. C'est celui dont le numéro de ligne (ds_RowNumber) vaut zéro.
Page3.html : Chargement d'une combobox
<select spry:repeatchildren="monDataSet" onchange="monDataSet.setCurrentRow(this.value)"> <option spry:if="{ds_RowNumber} == 0" value="{ds_RowID}" selected="selected">{photo}</option> <option spry:if="{ds_RowNumber} != 0" value="{ds_RowID}">{photo}</option> </select>
Nous savons maintenant remplir une combobox, il est temps de faire parler la "magie de Ajax". A chaque nouvelle sélection dans la combobox, nous allons maintenant afficher des informations complémentaires.
Nous pouvons maintenant revenir sur le "onchange" que nous avions laissé de coté. Cette instruction permet de sélectionner un élément dans le DataSet à partir de la valeur de la ligne.
Remarquons que cette valeur est l'identifiant (ds_RowID} automatiquement généré par Spry.
Comme nous l'avions réalisé plus haut avec le DIV, il est nécessaire de disposer d'un élément conteneur (ici un élément <span>) dans lequel nous allons définir la provenance des données. C'est l'attribut Spry :detailregion qui permet d'associer le conteneur avec les données du DataSet.
Plus haut, dans le DIV, nous avions utilisé l'attribut Spry :region. L'attribut Spry :detailregion va plus loin que la simple association. Il établit un lien "chaud" avec la base de données. A chaque changement de l'élément courant dans la base de données, toutes les valeurs associées dans le conteneur seront réaffichées automatiquement.
C'est incroyablement puissant et simple à la fois. Testez la page : à chaque sélection dans la combobox, les informations complémentaires sont réaffichées. Regardez le code source de la page : zéro ligne de code.
Page4.html : Affichage d'informations reliées
<span spry:detailregion="monDataSet"> <p> Nom du fichier image {@path}<br /> Hauteur {@height}<br /> largeur {@width}<br /> </p> </span>
Notre DataSet contient toutes les informations permettant de décrire un élément <img>. C'est ce que nous allons réaliser en affichant maintenant une nouvelle image à chaque sélection dans la combobox. Bien sûr, l'élément <img> doit être placé dans le conteneur <span>.
Les images sont disponibles dans le dossier "images/".
Page5.html : Affichage dynamique d'une image
<img src="images/{@path}" width="{@width}" height="{@height}" alt="Image affichée avec Spry"/>
Nous allons maintenant aborder une partie plus en relation avec WDGalerie : l'affichage de vignettes. Une vignette est, bien sûr, un champ image et nous savons déjà afficher une image. Nous allons ici nous concentrer sur la notion d'itération.
Voici une première manière pour afficher une vignette pour chaque élement. L'attribut :region dans l'élément <p> définit le DataSet à utiliser. Nous sommes maintenant familier de cette notation. Remarquons au passage qu'il n'est pas nécessaire de définir un conteneur de type <div>, l'attribut Spry peut être ajouté sur toutes balises HTML.
La répétition est réalisée avec l'attribut Spry :repeatchildren, que nous avons déjà utilisé pour remplir une combobox.
Page6.html : Affichage de vignette avec :repeatchildren
<p spry:region="monDataSet"> <span spry:repeatchildren="monDataSet" > <img src="thumbnails/{@thumbpath}" /> *** </span> </p>
Voyons une autre manière de coder la répétition.
Page7.html : Affichage de vignette avec :repeat
<span spry:repeat="monDataSet" > <img src="thumbnails/{@thumbpath}" /> *** </span>
Le résultat est apparemment identique pourtant le code généré est notablement différent. Avec :repeatchildren, c'est le contenu du tag <span> qui est répété. Avec :repeat, le tag <span> lui-même et son contenu sont répétés. Dans ce dernier cas, le code HTML généré contient plusieurs blocs <span> ... </span>.
Une balise <noscript> a été rajoutée dans le BODY des exemples. Cette balise permet d'afficher un message dans le cas où le Javascript a été désactivé.
<noscript> <h1>L'activation de JavaScript est nécessaire pour l'affichage de cette page. Activez JavaScript et rechargez la page.</h1> </noscript>
Cette pratique est à conseiller car certains navigateurs, dont IE6, ont le Javascript désactivé par défaut.
Dans une galerie photo comme WDGalerie, le clic sur une vignette permet d'afficher l'image dans une taille supérieure. Voyons maintenant comment rendre une vignette cliquable. Il faut faire appel à javascript et ajouter un attribut onclick dans l'élément <img>.
La variable Spry ds_RowID permet d'obtenir le numéro de la vignette.
Page8.html : Vignette cliquable
<img src="thumbnails/{@thumbpath}" onclick="alert('Vignette {ds_RowID}');" />
Pour terminer cette mini galerie photo, il faut ajouter un élément <img> pour l'affichage de l'image en grande taille. Nous savons le faire.
Page9.html : Affichage de vignettes et image liée
<div spry:detailregion="monDataSet"> <img src="images/{@path}" width="{@width}" height="{@height}" alt="Image affichée avec Spry"/> </div>
Il manque encore un petit détail, car le clic sur une vignette n'a aucun effet. Evidemment, il faut modifier le code du "onclick" afin de sélectionner l'élément correspondant à la vignette dans le DataSet.
onclick="monDataSet.setCurrentRow('{ds_RowID}');"
Et voilà une mini galerie photo cent pour cent Ajax.
Page10.html : Mini galerie photo
<p spry:region="monDataSet"> <span spry:repeatchildren="monDataSet" > <img src="thumbnails/{@thumbpath}" onclick="monDataSet.setCurrentRow('{ds_RowID}');" /> *** </span> </p> <div spry:detailregion="monDataSet"> <img src="images/{@path}" width="{@width}" height="{@height}" alt="Image affichée avec Spry"/> </div>
Remarquons que nous disposons maintenant de toutes les briques nécessaires pour construire une galerie photo dynamique. Regardez donc celle proposée sur le site Adobe Labs.