xulfr.org

10.8 Exemple XBL

Écrit par Neil Deakin. Traduit par Nadine Henry (17/09/2004), mise à jour par Laurent Jouanneau (20/09/2004) .
Page originale : http://www.xulplanet.com/tutorials/xultu/xblex.html xulplanet.com

Cette section va décrire un exemple d'élément XBL.

Un élément de présentation

Construisons un exemple complet d'un élément XBL. Ce sera un élément graphique qui stocke un ensemble d'objets, un seul d'entre eux étant affiché à un moment donné. Les boutons de navigation le long du bas vont permettre à l'utilisateur d'afficher les objets les uns aprés les autres (NdT : comme si c'était des pages ) tandis qu'un élément graphique textuel entre les boutons affichera le numéro de la page courante. Vous pourriez mettre n'importe quoi dans les pages, cependant, cet élément graphique pourrait être utile pour afficher une boîte d'images. Nous appellerons cela un élément de présentation (NdT : un 'slideshow').

Tout d'abord, déterminons quels sont les éléments qui ont besoin d'aller dans le contenu XBL. Puisque nous voulons un changement de page, un élément deck serait le plus approprié pour contenir les pages. Le contenu des pages sera spécifié dans le fichier XUL, et non dans XBL, mais nous aurons besoin de l'ajouter au sein du paquet (deck). La balise children devra être utilisée. En bas, nous aurons besoin d'un bouton pour aller à la page précédente, d'un élément graphique pour afficher la numéro de la page courante, et d'un bouton pour aller à la page suivante.

Exemple 10.8.1 : Source


<binding id="slideshow">

  <content>
    <xul:vbox flex="1">
      <xul:deck xbl:inherits="selectedIndex" selectedIndex="0" flex="1">
        <children/>
      </xul:deck>
      <xul:hbox>

        <xul:button xbl:inherits="label=previoustext"/>
        <xul:label flex="1"/>
        <xul:button xbl:inherits="label=nexttext"/>
      </xul:hbox>
    </xul:vbox>
  </content>

</binding>

Cette liaison crée la stucture de la présentation que nous souhaitons. L'attribut flex a été ajouté à un nombre d'éléments pour qu'il s'étende de la bonne manière. Les attributs label sur les deux boutons héritent leur valeur de l'élément qui leur est attaché. Ici, ils héritent de deux attributs personnalisés, previoustext et nexttext. Cela rend le changement des libellés des boutons simple. Les fils de l'élément auquel l'élément XBL est relié seront placés au sein de l'élément deck. L'attribut selectedIndex est hérité par le paquet, ainsi nous pouvons déclarer la page initiale dans XUL.

Le fichier XUL suivant produit le résultat affiché dans l'image.


<box class="slideshow" previoustext="Précédent" nexttext="Suivant"
flex="1">
  <button label="Bouton 1"/>
  <checkbox label="Boîte de dialogue 2"/>

  <textbox/>
</box>

Le style CSS utilisé ici est :


.slideshow {
  -moz-binding: url("slideshow.xml#slideshow");
}

Le premier bouton, 'Bouton 1' a été utilisé comme première page du paquet. L'élément graphique label (NdT : celui du XBL) n'est pas apparu puisqu'aucun attribut value ne lui a été spécifié. Nous pourrions déclarer une valeur, mais elle sera plutôt calculée plus tard.

Ensuite, une propriété contenant le numéro de la page courante est ajoutée. Lorsqu'on obtient cette propriété personnalisée, il est nécessaire de rechercher la valeur de l'attribut selectedIndex du paquet, qui contient le numéro de la page affichée. De façon similaire, lorsqu'on modifiera cette propriété, il sera nécessaire de changer l'attribut selectedIndex du paquet. De plus, l'élément graphique textuel devra être mis à jour pour afficher le numéro de la page courante.


<property name="page"
    onget="return
parseInt(document.getAnonymousNodes(this)[0].childNodes[0].getAttribute('selectedIndex'));"
    onset="return this.setPage(val);"/>

La propriété page obtient sa valeur en observant le premier élément du tableau anonyme. Elle renvoie la boîte verticale, aussi, pour obtenir le paquet, nous devons obtenir le premier noeud fils de la boîte. Le tableau anonyme n'est pas utilisé puisque le paquet n'est pas anonyme à partir de la boîte. Finalement, la valeur de l'attribut selectedIndex est récupérée. Pour spécifier la page, une méthode setPage qui sera définie plus tard est appelée.

Un gestionnaire oncommand devra être ajouté aux boutons "Précédent" et "Suivant" pour que la page soit changée lorsque les boutons sont pressés. Nous pouvons changer facilement la page en utilisant la propriété personnalisée page qui vient d'être ajoutée :


<xul:button xbl:inherits="label=previoustext"
               oncommand="parentNode.parentNode.parentNode.page--;"/>
<xul:description flex="1"/>
<xul:button xbl:inherits="label=nexttext"
               oncommand="parentNode.parentNode.parentNode.page++;"/>

Etant donné que la propriété page est dans l'élément XUL externe, nous devons utiliser la propriété parentNode pour l'obtenir. La première propriété parentNode retourne l'élément parent du bouton qui est la boîte horizontale, la seconde son parent, la boîte verticale, et la dernière son parent qui est la boîte externe. La propriété page est incrémentée ou décrémentée. Elle va appeler le script onget pour obtenir la valeur, incrémentera ou décrémentera la valeur, et enfin appelera le gestionnaire onset pour enregistrer la valeur.

Définissons à présent la méthode setPage. Elle prendra un paramètre, le numéro de page qui sert à spécifier la page. Il sera nécessaire de vérifier que le numéro de page n'est pas en dehors des limites et ensuite modifier les attributs selectedIndex du paquet et l'attribut label de l'élément graphique textuel.


<method name="setPage">

  <parameter name="newidx"/>
  <body>
    <![CDATA[
      var thedeck=document.getAnonymousNodes(this)[0].childNodes[0];
      var totalpages=this.childNodes.length;

      if (newidx<0) return 0;
      if (newidx>=totalpages) return totalpages;
      thedeck.setAttribute("selectedIndex",newidx);
      document.getAnonymousNodes(this)[0].childNodes[1].childNodes[1]
              .setAttribute("value",(newidx+1)+" sur "+totalpages);
      return newidx;
    ]]>
  </body>
</method>

Cette fonction est appelée setPage et prend un paramètre newidx. Le corps de la méthode a été encapsulé entre <![CDATA[ et ]]>. C'est le mécanisme général dans tous les fichiers XML qui peut être utilisé pour échapper tout le texte à l'intérieur. De cette manière, vous n'avez pas besoin d'échapper tous les signes "inférieur" et "supérieur" à l'intérieur.

Décomposons le code morceau par morceau.

var thedeck=document.getAnonymousNodes(this)[0].childNodes[0];
Obtient le premier élément du tableau de contenu anonyme, qui sera la boîte verticale, puis obtient son premier fils, qui sera l'élément deck (paquet).
var totalpages=this.childNodes.length;
Obtient le nombre de fils que détient la boîte qui est liée. Cela donnera le nombre total de pages qui s'y trouve.
if (newidx<0) return 0;
Si le nouvel index est avant la première page, ne pas changer la page et retourner 0. La page ne devrait pas donner une valeur plus petite que la première page.
if (newidx>=totalpages) return totalpages;
Si le nouvel index est après la dernière page, ne pas changer la page et retourner le dernier index de page. La page ne devrait pas devenir celle qui est après la dernière.
thedeck.setAttribute("selectedIndex",newidx);
Changer l'attribut selectedIndex du paquet. Cela entraîne l'affichage de la page demandée.
document.getAnonymousNodes(this)[0].childNodes[1].childNodes[1].setAttribute("value", (newidx+1)+" sur "+totalpages);
Cette ligne modifie l'élément label pour qu'il affiche l'index de la page courante. L'élément label peut être récupéré en obtenant le premier élément du contenu anonyme (la boîte verticale), le second fils de cet élément (la boîte horizontale), et enfin le second élément de cette boîte. L'attribut value est modifié pour indiquer 1 sur 3 ou quelque chose de similaire. Notez que l'index est incrémenté de un parce que l'indice commence à 0.

Nous allons aussi avoir besoin d'un constructeur pour initialiser l'élément label afin qu'il s'affiche correctement la première fois que la présentation est affichée. Nous utilisons un code similaire à la méthode ci-dessus pour déclarer le numéro de page. La référence à 'this.page' va appeler le script onget de la propriété page, qui à son tour va recupérer la page initiale à partir de l'attribut selectedIndex.


<constructor>
  var totalpages=this.childNodes.length;
  document.getAnonymousNodes(this)[0].childNodes[1].childNodes[1]
          .setAttribute("value",(this.page+1)+" sur "+totalpages);
</constructor>

Nous pouvons aussi ajouter quelques caractéristiques supplémentaires. Certains raccourcis claviers peuvent être utilisés pour les boutons "Précédent" et "Suivant", (disons le retour chariot et la touche Entrée). Les boutons "Premier" et "Dernier" peuvent être ajoutés pour aller à la première et à la dernière page. L'élément label pourrait être changé en un champ de saisie où l'utilisateur pourrait entrer la page à afficher, ou une fenêtre surgissante pourrait être ajoutée pour permettre la sélection de la page à partir d'un menu. Nous pourrions aussi ajouter une bordure autour de la boîte avec CSS pour la rendre plus jolie.

Le code final est le suivant :

Exemple 10.8.2 :Source


<binding id="slideshow">
  <content>

    <xul:vbox flex="1">
      <xul:deck xbl:inherits="selectedIndex" selectedIndex="0" flex="1">
        <children/>
      </xul:deck>
      <xul:hbox>
        <xul:button xbl:inherits="label=previoustext"
                    oncommand="parentNode.parentNode.parentNode.page--;"/>

        <xul:description flex="1"/>
        <xul:button xbl:inherits="label=nexttext"
                    oncommand="parentNode.parentNode.parentNode.page++;"/>
      </xul:hbox>
    </xul:vbox>
  </content>

  <implementation>

    <constructor>
      var totalpages=this.childNodes.length;
      document.getAnonymousNodes(this)[0].childNodes[1].childNodes[1]
              .setAttribute("value",(this.page+1)+" of "+totalpages);
    </constructor>

    <property name="page"
          onget="return
parseInt(document.getAnonymousNodes(this)[0].childNodes[0].getAttribute('selectedIndex'));"
          onset="return this.setPage(val);"/>

    <method name="setPage">
      <parameter name="newidx"/>

      <body>
        <![CDATA[
          var thedeck=document.getAnonymousNodes(this)[0].childNodes[0];
          var totalpages=this.childNodes.length;

          if (newidx<0) return 0;
          if (newidx>=totalpages) return totalpages;
          thedeck.setAttribute("selectedIndex",newidx);
          document.getAnonymousNodes(this)[0].childNodes[1].childNodes[1]
                  .setAttribute("value",(newidx+1)+" of "+totalpages);
          return newidx;
        ]]>
      </body>
    </method>
  </implementation>

</binding>

Tester dans une fenêtre : Voir.


Nous allons voir ensuite quelques propriétés additionnelles d'une fenêtre.