7.9 Conteneur JavaScript pour le Glisser-Déposer

Écrit par Neil Deakin .
Traduit par Laurent Jouanneau (11/11/2004), mise à jour par Alain B. (04/04/2007) .

Attention : Ce tutoriel est ancien et n'est pas mis à jour. Bien que beaucoup d'informations soient encore valables pour les dernières versions de gecko, beaucoup sont aussi obsolètes. Il est préférable d'aller consulter cette page sur la version française de ce tutoriel sur developer.mozilla.org.

Attention, cette page est maintenue dans la version française, mais elle a été enlevée par son auteur sur la version anglaise.

Cette section décrit l'utilisation d'un conteneur JavaScript pour le glisser-déposer.

Le conteneur JavaScript glisser-déposer

Le conteneur JavaScript pour le glisser-déposer simplifie le processus en appelant toutes les interfaces XPCOM pour vous. Il fonctionne en fournissant un objet qui implémente les gestionnaires d'événements. Tout ce que vous avez à faire est d'écrire quelques fonctions simples qui travaillent sur les données qui sont glissées.

L'interface glisser-déposer est stockée dans le paquetage "global", dans le fichier chrome://global/content/nsDragAndDrop.js. Vous pouvez inclure ce fichier dans votre fichier XUL avec la balise script de la même manière que pour vos scripts. La bibliothèque dépend aussi d'autres scripts, que vous aurez également à inclure, habituellement au début de votre page XUL. Vous pouvez regarder le contenu de ces fichiers pour voir comment fonctionne le glisser-déposer au plus bas niveau.

Notez que vous ne pouvez utiliser ces bibliothèques qu'à l'intérieur de fichiers XUL chargés avec un URL chrome.

<script src="chrome://global/content/nsDragAndDrop.js"/>
<script src="chrome://global/content/nsTransferable.js"/>

Cette bibliothèque glisser-déposer crée un objet stocké dans la variable nsDragAndDrop. L'objet contient une série de fonctions, une pour chaque gestionnaire d'événements (excepté pour dragenter où il n'y a rien de spécial à faire). Chacune de ces fonctions prend deux arguments : le premier est l'objet event et le second est un objet observateur que vous créez. Vous trouverez plus d'explications par la suite.

L'exemple suivant est un exemple d'appel de l'objet nsDragAndDrop :

<button label="Glissez-moi" ondraggesture="nsDragAndDrop.startDrag(event,buttonObserver);" />

La fonction startDrag sera appelée quand le glisser-déposer débutera à partir du bouton. Le premier paramètre est l'objet event, disponible dans tous les gestionnaires d'événements. Le second paramètre de cette fonction est l'observateur, que nous créerons bientôt. Dans cet exemple, nous ne faisons rien d'autre quand débute le glisser du bouton. Si nous voulions aussi prendre en compte les autres cas, nous pourrions appeler les autres fonctions, comme dans l'exemple suivant :

<description value="Cliquez et glissez ce texte."
    ondraggesture="nsDragAndDrop.startDrag(event,textObserver)"
    ondragover="nsDragAndDrop.dragOver(event,textObserver)"
    ondragexit="nsDragAndDrop.dragExit(event,textObserver)"
    ondragdrop="nsDragAndDrop.drop(event,textObserver)"/>

Comme mentionné plus haut, rien n'est spécialement à faire pendant l'événement dragenter, aussi pouvez-vous l'écrire vous-même.

Les fonctions sont implémentées par l'objet nsDragAndDrop, qui est déclaré dans le fichier nsDragAndDrop.js inclu par l'une des balises script. Elles prennent en charge les événements, les appels aux interfaces XPCOM et passent une structure de données simple aux fonctions de l'objet observateur.

L'observateur est un objet que vous déclarez vous-même. Dans les exemples ci-dessus, cet observateur est stocké dans les variables buttonObserver et textObserver. L'observateur est déclaré dans un script que vous devez inclure dans votre fichier XUL avec la balise script. Il doit avoir un certain nombre de propriétés, chacune s'occupant d'un aspect particulier du glisser-déposer. Cinq fonctions peuvent être définies. Vous pouvez simplement définir celles dont vous avez besoin.

onDragStart (event , transferData, action)
Définissez cette fonction pour déclencher une action quand le glisser commence. Elle prend trois arguments : l'objet event qui a été passé au gestionnaire d'événement, les données à transférer, le type d'action du glisser. Cette fonction doit ajouter les données à transférer à l'objet transferData.
onDragOver (event, flavour, session)
Cette fonction doit être définie quand vous voulez que quelque chose se produise lorsque le glisser passe au-dessus de l'élément. Le premier argument est l'objet event, le deuxième est le type de donnée et le troisième l'objet de session du glisser qui fournit plus de détails sur le glisser-déposer en cours. Vous devez définir cette fonction pour les éléments qui autorisent la dépose de données « glissées » sur eux-mêmes.
onDragExit (event, session)
Cette fonction doit être définie quand quelque chose se produit lorsque le glisser quitte l'élément. Elle a deux arguments, l'objet event et la session du glisser-déposer.
onDrop (event, dropData, session)
Cette fonction doit être définie quand vous voulez faire quelque chose lorsque l'objet est déposé. Le premier argument est l'objet event et le deuxième est la donnée qui était glissée. Le troisième argument est la session du glisser-déposer.
getSupportedFlavours ( )
Cette fonction doit retourner la liste des types de données que peut accepter l'objet sur lequel on fait le glisser. Cette fonction ne prend pas d'arguments. Elle est nécessaire car elle permet au conteneur de déterminer le meilleur type de données à passer aux autres fonctions.

Pour un observateur lié à un élément qui peut débuter un glisser-déposer, vous devriez définir au moins la fonction onDragStart. Pour les éléments qui peuvent recevoir des objets glissés, vous devriez définir onDragOver, onDrop et getSupportedFlavours (et si vous le voulez, onDragExit).

Le type des données pouvant être glisser-déposer est stocké comme un ensemble de type. Souvent, un objet glissé peut être disponible dans un certain nombre de types. Ce faisant, un élément cible peut accepter le type qu'il trouve le mieux adapté. Par exemple, un fichier peut être transmis dans deux types, le fichier lui-même et son nom. Si le fichier est glissé et déposé sur un répertoire, le type 'fichier' sera utilisé. Si le fichier est glissé sur un champ de saisie, le type 'nom de fichier' sera utilisé. Le texte du nom du fichier est par conséquent utilisé quand les fichiers ne peuvent être déposés directement.

Un type d'objet a un nom, qui est formaté comme un type MIME, comme text/unicode. À l'intérieur de la fonction onDragStart, vous spécifiez quels types sont disponibles pour l'élément en cours de glisser-déposer. Pour ce faire, ajoutez les données et les types à l'objet transferData, qui est le deuxième argument de onDragStart.

L'exemple ci-après devrait vous aider. La fonction onDragStart ajoute des données à l'objet transferData.

var textObserver = {
  onDragStart: function (evt , transferData, action){
    var htmlText="<strong>Cabbage</strong>";
    var plainText="Cabbage";

    transferData.data=new TransferData();
    transferData.data.addDataForFlavour("text/html",htmlText);
    transferData.data.addDataForFlavour("text/unicode",plainText);
  }
};

Ici, un observateur a été déclaré et stocké dans la variable textObserver. Il a une propriété appelée onDragStart (en JavaScript, les propriétés peuvent être déclarées avec la syntaxe nom : valeur). Cette propriété est une fonction qui définit les données qui seront transférées.

Une fois appelé, il commence le glisser-déposer pour la chaîne Cabbage. Bien sûr, vous voudrez calculer cette valeur à partir de l'élément sur lequel on a cliqué. Cet élément est disponible dans la propriété target de l'objet event. Cet objet event est passé en premier argument à onDragStart.

Nous créons un objet transferData qui peut être utilisé pour contenir toutes les données à transférer. Nous ajoutons deux données à celui-ci. La première est une chaîne de texte HTML et la seconde une chaîne de texte brut. Si l'utilisateur dépose sur une zone qui accepte le HTML (comme la fenêtre d'édition HTML de Mozilla), le type HTML sera utilisé et le texte apparaîtra en gras. Sinon, c'est la version en texte brut qui sera utilisée.

En général vous devrez fournir une version texte de la donnée, ainsi de nombreuses applications pourront l'accepter. L'ordre dans lequel vous définissez les types devra s'établir de la meilleure correspondance vers la moins bonne. Dans le cas ci-dessus, le type HTML (text/html) vient en premier, et le type texte (text/unicode) en second.

L'exemple ci-dessous montre comment spécifier les données à transférer à partir de l'attribut label de l'élément. Dans ce cas, nous fournissons la donnée dans un seul type.

var textObserver = {
  onDragStart: function (evt){
    var txt=evt.target.getAttribute("label");

    transferData.data=new TransferData();
    transferData.data.addDataForFlavour("text/unicode",txt);
  }
}

Il peut être utile lors de l'implémentation du glisser-déposer pour les cellules d'un arbre. Vous pouvez utiliser la valeur d'une cellule, ou d'une ressource du fichier RDF si l'arbre est construit à partir d'un gabarit (template), comme valeur pour le glisser-déposer. Si vous la stockez dans une chaîne, n'importe quel objet acceptant les chaînes pour un glisser-déposer pourra récupérer cette valeur.

Vous aurez besoin d'ajouter un observateur à chaque élément qui peut soit démarrer une action glisser-déposer, soit accepter des objets glissés. Vous pouvez réutiliser le même observateur sur plusieurs éléments. Pour un élément qui démarre un glisser-déposer, vous devez simplement implémenter onDragStart.

Pour un élément sur lequel on peut déposer, l'observateur aura besoin d'implémenter au moins les fonctions getSupportedFlavours, onDragOver et onDrop. Certains éléments pourraient être capables d'initier un glisser et d'accepter un déposer. Dans ce cas, onDragStart sera également nécessaire.

La fonction getSupportedFlavours doit retourner une liste de types que peut accepter pour une dépose l'élément sur lequel le glisser-déposer s'effectue. Une vue d'un répertoire de système de fichiers pourrait accepter des fichiers et peut-être du texte, mais ne devrait pas accepter du texte HTML. Ci-dessous, nous définissons la fonction getSupportedFlavours. Ici, nous n'autorisons qu'un seul type.

var textObserver = {
  getSupportedFlavours : function () {
    var flavours = new FlavourSet();
    flavours.appendFlavour("text/unicode");
    return flavours;
  }
}

La liste des types de données contient un seul type, qui est text/unicode. L'objet FlavourSet peut être utilisé pour contenir une liste de types. Dans certains cas, vous devez aussi fournir une interface XPCOM. Par exemple, pour les fichiers :

var textObserver = {
  getSupportedFlavours : function () {
    var flavours = new FlavourSet();
    flavours.appendFlavour("application/x-moz-file","nsIFile");
    flavours.appendFlavour("text/unicode");
    return flavours;
  }
}

La fonction onDragOver définit ce qui se produit lorsqu'un objet est glissé au-dessus. Vous pourriez alors changer l'apparence des éléments qui sont survolés. Dans la plupart des cas, la fonction ne fait rien. Cependant elle doit être définie pour les éléments qui acceptent des données glissées.

Ensuite, la fonction onDrop doit être créée. Son second argument est l'objet de transfert de données qui contient les données transférées. Avant d'appeler onDrop, le conteneur aura appelé getSupportedFlavours pour déterminer le meilleur type de données à déposer, aussi l'objet de transfert ne contient que les données du meilleur type déterminé.

L'objet de transfert a deux propriétés : data qui contient la donnée et flavour qui contient le type de la donnée. Une fois que vous avez la donnée, vous pouvez l'ajouter à l'élément de n'importe quelle façon. Par exemple, vous pourriez modifier la valeur d'un champ de saisie.

var textObserver = {
  onDrop : function (evt, transferData, session) {
    event.target.setAttribute("value",transferData.data);
  }
}

Le système de type utilisé permet à de multiples objets, de types variés, d'être glisser-déposer. Il permet également à des formes alternatives de données d'être utilisées. Le tableau suivant décrit quelques types de données que vous pourriez utiliser. Vous pouvez aussi définir votre propre type si nécessaire.

text/unicode Text data
text/html données HTML
application/x-moz-url une URL
application/x-moz-file Un fichier local

Dans la prochaine section, nous étudierons un exemple utilisant le glisser-déposer.


Mozilla® est une marque déposée de la fondation Mozilla.
Mozilla.org™, Firefox™, Thunderbird™, Mozilla Suite™ et XUL™ sont des marques de la fondation Mozilla.