Écrit par Neil Deakin.
Traduit par Laurent Jouanneau (11/11/2004).
Page originale :
http://www.xulplanet.com/tutorials/xultu/dragex.html
Un exemple de l'implémentation du glisser-déposer est montré dans cette section.
Ici, nous créérons un simple panneau où des items peuvent y ê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.
Une taille maximum est aussi spécifiée, ainsi elle ne sera pas redimensionnée lorsque de nouveaux
éléments seront déposés dessus.
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 coté droit de la fenêtre. Elle contiendra
trois boutons, un pour créer des 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 débuteront un glisser-déposer.
<vbox>
<button label="Button"
elem="button" ondraggesture="nsDragAndDrop.startDrag(event,listObserver)"/>
<button label="Check Box"
elem="checkbox" ondraggesture="nsDragAndDrop.startDrag(event,listObserver)"/>
<button label="Text Box"
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éfiniera la donnée à transférer.
Notez que chaque bouton ici a un attribut supplémentaire elem
.
C'est 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 avons besoin de ça pour
savoir quel est le type d'é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
quand cela sera nécéssaire. 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 élement 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 de la dépose. Dans notre cas, elle
accepte juste 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 contenu.
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. Cela nous permet de placer le nouvel élément
à la même position que la souris quand le bouton a été relaché.
Ce n'est pas tout a fait le bon moyen de faire cela puisque nous devons en fait
calculer les coordonnées de l'évènement relativement à la pile.
Mais cela 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 plutôt que 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é en dessous :
Exemple 8.7.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="Zone de saisie"
elem="textbox" ondraggesture="nsDragAndDrop.startDrag(event,listObserver)"/>
</vbox>
</window>
Exemple 8.7.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 verrons l'utilisation des feuilles de styles avec les fichiers XUL.