É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.
Un exemple de l'implémentation du glisser-déposer est montré dans cette section.
Ici, nous créérons un simple panneau où des éléments peuvent être glisser-déposer à partir
d'une palette.
L'utilisateur peut cliquer sur l'un des nombreux éléments XUL de la palette et les glisser
au-dessus d'un élément stack
pour créer un élément d'un type particulier.
Tout d'abord, nous ajouterons les scripts du conteneur javascript :
<script src="chrome://global/content/nsDragAndDrop.js"/>
<script src="chrome://global/content/nsTransferable.js"/>
<script src="dragboard.js"/>
Un script supplémentaire dragboard.js
est inclus et contiendra le code
que nous allons écrire nous-même.
Le panneau sera créé en utilisant un élément stack
.
Nous utiliserons quelques propriétés de style pour spécifier la largeur et la hauteur de la pile.
Sa taille maximale est aussi spécifiée, ainsi elle ne sera pas redimensionnée lorsque de nouveaux
éléments y seront déposés.
Le panneau devra répondre à l'événement dragdrop
, en créant un élément
lorsque l'utilisateur en déposera un dessus.
<stack id="board"
style="width:300px; height: 300px; max-width: 300px; max-height: 300px"
ondragover="nsDragAndDrop.dragOver(event,boardObserver)"
ondragdrop="nsDragAndDrop.drop(event,boardObserver)">
</stack>
Le panneau a juste besoin de répondre aux événements dragdrop
et dragover
.
Nous ajouterons un observateur boardObserver
dans le fichier dragboard.js
dans un moment.
Ensuite, une palette sera ajoutée sur le côté droit de la fenêtre. Elle contiendra
trois boutons, un pour créer de nouveaux boutons, un pour créer des cases à cocher,
et un autre pour créer des champs de saisie. Ces boutons répondront à l'événement
draggesture
et initialiseront une session de glisser-déposer.
<vbox>
<button label="Bouton"
elem="button" ondraggesture="nsDragAndDrop.startDrag(event,listObserver)"/>
<button label="Case à cocher"
elem="checkbox" ondraggesture="nsDragAndDrop.startDrag(event,listObserver)"/>
<button label="Champ texte"
elem="textbox" ondraggesture="nsDragAndDrop.startDrag(event,listObserver)"/>
</vbox>
L'objet nsDragAndDrop
sera appelé pour faire la plupart du travail. Nous
créerons un observateur listObserver
qui définira la donnée à transférer.
Notez que chaque bouton ici a un attribut supplémentaire elem
.
Il s'agit d'un attribut inventé. XUL ne le reconnait pas et l'ignorera, mais nous pourrons toujours
le récupérer avec la fonction DOM getAttribute
. Nous en avons besoin pour
savoir de quel type est l'élément à créer lors du glisser-déposer.
Ensuite nous définirons deux observateurs. Premièrement, listObserver
qui a besoin d'une fonction pour gérer le démarrage du glisser.
var listObserver = {
onDragStart: function (evt,transferData,action){
var txt=evt.target.getAttribute("elem");
transferData.data=new TransferData();
transferData.data.addDataForFlavour("text/unicode",txt);
}
};
Une seule fonction a été définie, onDragStart
, et elle sera appelée
par l'objet nsDragAndDrop
lorsque ce sera nécessaire. La fonction ajoute
la donnée à transférer à l'objet transferData
.
L'attribut elem
est récupéré à partir de la cible de
l'événement du glisser-déposer. La cible sera l'élément sur lequel le glisser-déposer
a commencé. Nous utiliserons la valeur de cet attribut comme donnée pour le glisser.
L'objet boardObserver
aura besoin de trois fonctions,
getSupportedFlavours
, onDragOver
et onDrop
.
La fonction onDrop
récupérera la donnée à partir de la session du glisser-déposer
et créera un nouvel élément du type approprié.
var boardObserver = {
getSupportedFlavours : function () {
var flavours = new FlavourSet();
flavours.appendFlavour("text/unicode");
return flavours;
},
onDragOver: function (evt,flavour,session){},
onDrop: function (evt,dropdata,session){
if (dropdata.data!=""){
var elem=document.createElement(dropdata.data);
evt.target.appendChild(elem);
elem.setAttribute("left",""+evt.pageX);
elem.setAttribute("top",""+evt.pageY);
elem.setAttribute("label",dropdata.data);
}
}
};
La fonction getSupportedFlavours
a seulement besoin de retourner
une liste de type que la pile peut accepter lors du déposer. Dans notre cas, elle
accepte seulement du texte. Nous n'avons pas besoin de faire quelque chose de spécial pour
la fonction onDragOver
, ainsi aucun code ne sera ajouté dans son corps.
Le gestionnaire onDrop
utilise tout d'abord la fonction createElement
pour créer
un nouvel élément du type stocké dans la session. Ensuite, appendChild
est appelée
pour ajouter un nouvel élément à la pile, qui est la cible de l'événement.
Enfin, nous ajoutons quelques attributs à ce nouvel élément.
La position des éléments dans la pile est déterminée par les attributs
left
et top
.
Les valeurs des propriétés pageX
et
pageY
contiennent les coordonnées du pointeur de la souris
sur la fenêtre lorsque la dépose a lieu. Ils nous permettent de placer le nouvel élément
à la même position que la souris quand le bouton a été relâché.
Ce n'est pas tout a fait la bonne méthode puisque nous devons en fait
calculer les coordonnées de l'événement relativement à celles de la pile.
Mais elle fonctionne ici parce que le panneau est dans le coin en haut à gauche de la fenêtre.
L'attribut label
est défini avec la donnée issue du glisser-déposer,
ainsi le bouton a un libellé par défaut.
Cet exemple est assez simple. Un changement possible est d'utiliser un type personnalisé pour les données, au lieu du texte. Le problème avec l'utilisation du texte est que si le texte provenant d'un glisser-déposer externe est le mot button, un bouton sera créé sur le panneau. Un type personnalisé signifie que le panneau acceptera uniquement les glisser-déposer en provenance de la palette.
Le code final est montré ci-dessous :
Exemple 7.10.1 : Source
<window title="Composant à déplacer" id="test-window"
orient="horizontal"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script src="chrome://global/content/nsDragAndDrop.js"/>
<script src="chrome://global/content/nsTransferable.js"/>
<script src="dragboard.js"/>
<stack id="board"
style="width:300px; height: 300px; max-width: 300px; max-height: 300px"
ondragover="nsDragAndDrop.dragOver(event,boardObserver)"
ondragdrop="nsDragAndDrop.drop(event,boardObserver)">
</stack>
<vbox>
<button label="Bouton"
elem="button" ondraggesture="nsDragAndDrop.startDrag(event,listObserver)"/>
<button label="Case à cocher"
elem="checkbox" ondraggesture="nsDragAndDrop.startDrag(event,listObserver)"/>
<button label="Champ de saisie"
elem="textbox" ondraggesture="nsDragAndDrop.startDrag(event,listObserver)"/>
</vbox>
</window>
Exemple 7.10.2 : Source
var listObserver = {
onDragStart: function (evt,transferData,action){
var txt=evt.target.getAttribute("elem");
transferData.data=new TransferData();
transferData.data.addDataForFlavour("text/unicode",txt);
}
};
var boardObserver = {
getSupportedFlavours : function () {
var flavours = new FlavourSet();
flavours.appendFlavour("text/unicode");
return flavours;
},
onDragOver: function (evt,flavour,session){},
onDrop: function (evt,dropdata,session){
if (dropdata.data!=""){
var elem=document.createElement(dropdata.data);
evt.target.appendChild(elem);
elem.setAttribute("left",""+evt.pageX);
elem.setAttribute("top",""+evt.pageY);
elem.setAttribute("label",dropdata.data);
}
}
};
Dans la section suivante, nous allons voir comment créer des arbres.
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.