xulfr.org

6.6 Gabarits

Écrit par Neil Deakin. Traduit par Laurent Jouanneau (12/08/2004).
Page originale : http://www.xulplanet.com/tutorials/xultu/templates.html xulplanet.com

Dans cette section, nous allons voir comment peupler des éléments avec des données.

Peuplement des éléments

XUL apporte une méthode permettant de créer des éléments à partir de données fournies par RDF, que ce soit à partir d'un fichier RDF ou à partir d'une source de données interne. Nombre de source de données sont fournies avec Mozilla comme les marque-pages, l'historique et les messages emails. Plus de détails seront donnés dans la prochaine section.

Habituellement, les éléments tels que les treeitem et menuitem seront peuplés avec des données. Cependant, vous pouvez utiliser d'autres éléments si vous le voulez, bien qu'ils soient utilisés pour des cas spécifiques. Néanmoins nous commencerons avec ces autres éléments parce que les arbres et menus nécessitent plus de code.

Pour permettre la création d'éléments basés sur des données RDF, vous avez besoin de fournir un gabarit simple (Ndt : template) qui sera dupliqué pour chaque élément devant être crée. En gros, vous fournissez juste le premier élément et les suivants seront construit sur le même modèle.

Le gabarit est crée en utilisant l'élément template. À l'intérieur de celui-ci, vous pouvez placer les éléments que vous voulez utiliser pour chaque élément construit. L'élément template doit être placé à l'intérieur du conteneur qui contiendra les éléments construits. Par exemple, si vous utilisez un tree, vous devez placer la balise template à l'intérieur de l'élément tree.

C'est mieux quand on explique avec un exemple. Prenons un exemple simple où nous voulons créer un bouton pour chaque marque-page principal. Mozilla fourni une source de données pour les marque-pages, pouvant être ainsi utilisée pour récupérer les données. Cet exemple ne récupérera que les marque-pages principaux car nous allons créer des boutons. Pour les marque-pages fils, nous devrions utiliser un élément qui affiche une hierarchie tel qu'un arbre ou un menu.

Cet exemple et tous les autres qui font référence à des sources de données RDF interne, ne fonctionneront que si vous les chargez à partir d'une url chrome. Pour des raisons de sécurité, Mozilla ne permet pas d'y accéder à partir de fichiers extérieurs.

Pour voir cet exemple, vous devrez créer un paquet chrome contenant le fichier à charger. Vous pouvez alors entrer l'URL chrome dans le champs de saisie des URLs du navigateur.

Exemple 6.6.1 : Source

<vbox datasources="rdf:bookmarks" ref="NC:BookmarksRoot" flex="1">
  <template>
    <button uri="rdf:*" label="rdf:http://home.netscape.com/NC-rdf#Name"/>
  </template>
</vbox>
   

Ici une boîte verticale a été créée contenant une colonne de boutons, un pour chaque marque-page principal. Vous pouvez voir que le template ne contient qu'un seul button. Cet unique bouton est utilisé comme modèle pour tout les autres boutons qu'il sera nécessaire de créer. Vous pouvez voir sur l'image qu'un ensemble de boutons a été créé, un pour chaque marque-page.

Essayez d'ajouter un marque-page dans le navigateur pendant que vous avez cet exemple ouvert dans une fenêtre. Vous noterez que les boutons seront mis à jour instantanément (Vous devez mettre le focus sur la fenêtre pour voir le changement).

Le gabarit lui-même est placé à l'intérieur d'une boîte verticale. La boîte a deux attributs qui lui permet d'être utilisée pour les gabarits, indiquant d'où les données proviennent. Le premier attribut de la boîte est datasources. Il est utilisé pour déclarer la source de données RDF qui fournira les données pour créer les éléments. Dans le cas présent, rdf:bookmarks est indiqué. Vous devinez probablement que cela signifie qu'il faut utiliser la source de données des marque-pages. Cette source de données est fournie par Mozilla. Pour utiliser votre propre source de données, spécifiez l'URL d'un fichier RDF dans l'attribut datasources, comme le montre l'exemple suivant :

<box datasources="chrome://zoo/content/animals.rdf"
     ref="http://www.some-fictitious-zoo.com/all-animals">
   

Vous pouvez spécifier plusieurs sources de donnée à la fois, en les séparant avec un espace dans la valeur de l'attribut. Cela permet d'afficher des données provenant de multiples sources.

L'attribut ref indique l'endroit dans la source de données à partir duquel vous voulez récupérer les données. Dans le cas des marque-pages, la valeur NC:BookmarksRoot est utilisée pour indiquer la racine de la hiérarchie des marque-pages. Les autres valeurs que vous pouvez indiquer dépendront de la source de données que vous utiliserez. Si vous utilisez votre propre fichier RDF, la valeur correspondra à la valeur d'un attribut about d'un élément RDF Bag, Seq ou Alt.

En ajoutant ces deux attributs à la boîte du dessus, cela permet la génération d'éléments en utilisant le gabarit. Cependant, les éléments à l'intérieur du gabarit nécessite une déclaration différente. Vous noterez dans l'exemple du dessus que le bouton a un attribut uri et a une valeur inhabituelle pour l'attribut label.

Un attribut à l'intérieur d'un gabarit qui commence par rdf: indique que la valeur doit être prise à partir de la source de données. Dans l'exemple plus haut, c'est le cas de l'attribut label. Le reste de la valeur réfère au nom de la propriété dans la source de donnée. Elle est construite en prenant l'URL de l'espace de nom utilisé par la source de données et en y ajoutant le nom de la propriété. Ici, nous utilisons seulement le nom du marque-page mais d'autres champs sont disponibles.

L'attribut label des boutons est renseigné avec cet URI spécial parce que nous voulons que les libellés des boutons aient le nom des marque-pages. Nous pouvons mettre cet URI sur n'importe quel attribut de l'élément button, ou n'importe quel élément. Les valeurs de ces attributs sont remplacés par les données fournies par la source de données, qui, ici, sont les marque-pages.

L'exemple du dessous montre comment nous pourrions assigner d'autres attributs d'un bouton à partir de la source de données. Bien sûr, cela implique que la source de données fournisse les ressources appropriées. Si une ressource particulière est inexistante, la valeur de l'attribut sera une chaîne vide.


    <button class="rdf:http://www.example.com/rdf#class"
     uri="rdf:*"
     label="rdf:http://www.example.com/rdf#name"
     crop="rdf:http://www.example.com/rdf#crop"/>
    

Comme vous pouvez le voir, vous pouvez générer dynamiquement une liste d'éléments avec les attributs fournis par une source de données séparée.

L'attribut uri est utilisé pour spécifier l'élément où la génération du contenu commencera. Le contenu extérieur ne sera généré qu'une seule fois, tandis que le contenu intérieur sera généré pour chaque ressource. Nous en verrons plus à ce propos quand nous créerons des gabarits pour les arbres.

En ajoutant ces fonctionnalités au conteneur dans lequel est le gabarit, qui dans ce cas est une boîte, et aux éléments à l'intérieur du gabarit, nous pouvons générer de multiples listes de contenu à partir de données externes. Nous pouvons bien sûr mettre plus d'un élément à l'intérieur du gabarit, et ajouter une référence RDF spéciale dans les attributs sur n'importe quel élément. L'exemple suivant le montre :

Exemple 6.6.2 : Source

<vbox datasources="rdf:bookmarks" ref="NC:BookmarksRoot" flex="1">
  <template>
    <vbox uri="rdf:*">
      <button label="rdf:http://home.netscape.com/NC-rdf#Name"/>
      <label value="rdf:http://home.netscape.com/NC-rdf#URL"/>
    </vbox>
  </template>
</vbox>
    

Cet exemple créé une boîte verticale avec un bouton et un libellé pour chaque marque-page. Le bouton aura le nom du marque-page et le libellé aura l'URL.

Les nouveaux éléments qui sont crées ne sont fonctionnellement pas différents de ceux que vous mettez directement dans le fichier XUL. L'attribut id est ajouté à tous les éléments crées au travers du gabarit, et il est assigné à la valeur qui identifie la ressource. Vous pouvez l'utiliser pour identifier la ressource.

Vous pouvez aussi spécifier de multiple ressource dans le même attribut en les séparant avec un espace, comme dans l'exemple qui suit ( en savoir plus sur la syntaxe des ressources).

Exemple 6.6.3 : Source

<vbox datasources="rdf:bookmarks" ref="NC:BookmarksRoot"
     flex="1">
  <template>
    <label uri="rdf:*" value="rdf:http://home.netscape.com/NC-rdf#Name rdf:http://home.netscape.com/NC-rdf#URL"/>
  </template>
</vbox>
    

Comment sont construits les gabarits

Quand un élément a un attribut datasources, cela indique que l'élément est susceptible d'être généré à partir d'un gabarit. Notez que ce n'est pas la balise template qui détermine si le contenu sera généré, mais bien l'attribut datasources. Quand cet attribut est présent, un objet que l'on appelle un constructeur est ajouté à l'élément. C'est cet objet qui est responsable de la génération du contenu à partir du gabarit. En javascript, vous pouvez accéder à l'objet constructeur par la propriété builder, bien qu'habituellement vous en aurez seulement besoin pour régénérer le contenu dans les situations où cela ne se fait pas automatiquement.

Il y a deux différents types de constructeur. Le premier est un constructeur de contenu utilisé dans la plupart des situations, et l'autre est un constructeur d'arbres utilisé uniquement avec les éléments tree.

Le constructeur de contenu prend le contenu situé à l'intérieur de l'élément template et le duplique pour chaque ligne. Par exemple, si l'utilisateur a dix marque-pages dans l'exemple du dessus, dix éléments label seront créés et ajoutés en tant que fils à l'élément vbox. Si vous utilisez les fonctions DOM pour traverser l'arbre, vous trouverez ces éléments ici et pourrez récupérer leurs propriétés. Ces éléments sont affichés, mais l'élément template lui-même non, bien qu'il existe encore dans l'arbre du document. De plus, l'attribut id de chaque libellé sera initialisé avec la ressource RDF de la ligne correspondante.

Le constructeur de contenu démarre toujours à partir de l'élément qui à l'attribut uri="rdf:*". Si l'attribut uri est placé à l'intérieur d'autres éléments, ces derniers ne seront crées qu'une seule fois. Dans l'exemple ci-dessous, un hbox sera crée et rempli avec un label pour chaque item.

<template>
  <hbox>
    <label uri="rdf:*" value="rdf:http://home.netscape.com/NC-rdf#Name"/>
  </hbox>
</template>

Si il y a du contenu à l'intérieur de l'élément qui a l'attribut datasources mais en dehors de l'élément template, ce contenu apparaîtra également. Ce faisant, vous pouvez mixer du contenu statique et dynamique dans un gabarit.

Le constructeur d'arbres, d'un autre coté, ne génère pas d'éléments DOM pour chaque ligne. À la place, il récupère les données directement à partir de la source de données RDF quand il en a besoin. Comme les arbres ont souvent besoins d'afficher des centaines de lignes de données, c'est plus efficace comme ceci. Créer un élément pour chaque cellule serait trop coûteux. Cependant, en contre partie, ces arbres ne peuvent afficher que du texte (NdT : ainsi que des images et des cases à cocher), et comme aucun élément n'est crée, vous ne pouvez pas utiliser les propriétés CSS de manière habituelle pour décorer les cellules de l'arbre.

Le constructeur d'arbre est utilisé seulement pour les arbres. Les autres éléments n'utilisent que le constructeur de contenu. Ceci n'est pas un problème étant donné que les autres éléments comme les menus n'ont généralement pas besoin d'afficher beaucoup d'items. Il est possible également d'utiliser le constructeur de contenu pour les arbres, ainsi un élément treeitem et d'autres seront crées pour chaque ligne.

Règles

Dans l'image du précédent exemple, vous avez pu noter que le troisième bouton est simplement un bouton avec des tirets comme libellé. C'est un séparateur dans la liste des marque-pages. Au cas où nous l'utiliserions, la source de données RDF des marque-pages stocke les séparateurs comme si ils étaient des marque-pages normaux. Ce que nous voulons faire est d'ajouter un petit espace à la place d'un bouton pour les ressources "séparateur". Ce qui signifie que nous voulons avoir deux différents types de contenu à créer, un type pour les marque-pages normaux, et un autre type pour les séparateurs.

Nous pouvons le faire en utilisant un élément rule. Nous définissons une règle pour chaque version d'élément que nous avons à créer. Dans notre cas, nous aurons besoin d'une règle pour les marque-pages, et une règle pour les séparateurs. Les attributs placés sur l'élément rule déterminent quelle règle s'applique sur quelle ressource RDF.

Pour savoir quelle règle s'applique sur les données, chaque élément rule est analysé en séquence pour une vérification de concordance. Cela veut dire que l'ordre dans lequel vous définissez les règles est important. Les règles du début ont priorité sur les règles suivantes.

L'exemple suivant montre l'exemple précédant avec deux règles.

Exemple 6.6.4 : Source

<window
  id="example-window"
  title="Liste des marque-pages"
  xmlns:html="http://www.w3.org/1999/xhtml"
  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

 <vbox datasources="rdf:bookmarks" ref="NC:BookmarksRoot" flex="1">
   <template>

    <rule rdf:type="http://home.netscape.com/NC-rdf#BookmarkSeparator">
     <spacer uri="rdf:*" height="16"/>
    </rule>

    <rule>
      <button uri="rdf:*" label="rdf:http://home.netscape.com/NC-rdf#Name"/>
    </rule>

  </template>
 </vbox>

</window>

En utilisant deux règles, nous permettont au contenu du gabarit d'être généré sélectivement. Dans le premier rule, les séparateurs de marque-pages sont sélectionnés, comme nous pouvons le voir par l'attribut rdf:type. Le second rule n'ayant aucun attribut, il sélectionne tout le reste.

Tout les attributs placés dans la balise rule, sont utilisés comme critère de sélection. Dans notre cas, la source de données des marque-pages fournis une propriété rdf:type pour distinguer les séparateurs. Cet attribut contient une valeur spéciale pour les séparateurs dans la source de données RDF. C'est ainsi qu'on peut les distinguer des marque-pages. Vous pouvez utiliser une technique similaire pour n'importe quel attribut que l'on peut mettre sur un élément RDF Description.

La valeur spéciale d'URL donnée dans l'exemple du dessus pour la première règle, est utilisée pour les séparateurs. Cela signifie que les séparateurs s'appliqueront à la première règle et un élément spacer d'une hauteur de 16 pixels sera généré. Les éléments qui ne sont pas des séparateurs ne correspondront pas à la première règle, et atterriront dans la deuxième règle. Celle-ci n'a aucun attribut. Cela veut dire qu'elle correspond à n'importe quelle donnée. Ce qui bien sûr, est ce que nous voulons pour le reste des données.

Vous avez du noter que, parce que nous voulons un attribut provenant de l'espace de nom du RDF (rdf:type), nous avions besoin d'ajouter la déclaration de cet espace de nom dans la balise window. Si nous n'avions pas fait cela, l'attribut serait attribué à l'espace de nom XUL. Parce qu'il n'existe pas dans cet espace, la règle ne s'appliquerait pas. Si nous utilisons des attributs provenant de notre propre espace de nom, vous devez ajouter la déclaration de votre espace de nom pour qu'ils soient reconnus.

Vous devez deviner ce qui arriverait si la seconde règle était enlevée. Le résultat serait alors un simple spacer, sans aucun marque-page puisqu'ils ne correspondent à aucune règle.

Dit plus simplement, une règle correspond si tous les attributs placés dans l'élément rule correspondent aux attributs de la ressource RDF. Dans le cas d'un fichier RDF, les ressources seraient les éléments Description.

Il y a cependant quelques petites exceptions. Vous ne pouvez pas faire la correspondance avec les attributs id, rdf:property ou rdf:instanceOf. Mais puisque vous utiliserez vos propres attributs dans votre propre espace de noms, cela n'aura probablement pas d'importance de toute façon.

Notez qu'un gabarit sans règle, comme dans le premier exemple, est équivalent fonctionnellement à un gabarit qui possède un seul rule sans attribut.


Nous allons voir maintenant l'utilisation des gabarits avec les arbres.