Le glisser-déposer (drag'n drop)
Présentation des éléments utilisés pour la gestion du glisser-déposer
Sous XUL, le drag & drop passe par :
- Un ensemble d'événements sur les éléments XUL,
- 2 objets XPCOMs qui gèrent la session de glisser-déposer (un service, et un objet qui représente la session de glisser-déposer).
- *Il existe un objet Javascript qui simplifie les échanges avec les objet XPCOM. Voir la section correspondante.**
Quelques remarques évidentes avant d'aller plus loin :
- On ne crée pas de session de glisser-déposer (drag & drop) quand on ne veut pas autoriser le glisser-déposer,
- Comme l'utilisateur n'a qu'une souris, il n'y a qu'une seule session de glisser-déposer à la fois,
- La session de glisser-déposer a pu être initiée à l'exterieur de Mozilla (par une autre application, ou le bureau), Mozilla intègre automatiquement et de manière transparente l'action du glisser-déposer.
Les événements du glisser-déposer
références sur xulplanet
- ondraggesture : intervient quand l'utilisateur a appuyé sur le bouton de la souris, et commence à la bouger sans relâcher le bouton. C'est cet événement qui devra créer la session de glisser-déposer.
- ondragover : intervient pour un objet que l'on survole en glisser-déposer (faut-il que la session ait été déclarée pour que cet événement soit appellé ?). Si l'on peut lâcher l'élément sur cet objet, il faut prévenir la session.
- ondragenter : intervient la première fois que l'on entre dans la zone de survol de l'objet en question en glisser-déposer. Cela permet de modifier l'apparence du curseur ou de l'objet afin d'indiquer (par exemple) la possibilité ou non de lâcher l'objet en glisser-déposer sur l'objet survolé.
- ondragexit : intervient quand on quitte la zone de survol de l'objet en question en glisser-déposer. Cela permet de modifier l'apparence du curseur ou de l'objet afin d'enveler (par exemple) les éléments graphiques que l'on avait changé en entrant dans la zone pour indiquer la possibilité de lâcher l'objet ou non.
- ondragdrop : intervient lorsqu'on lâche finalement le bouton de la souris à la fin d'un glisser-déposer. Cela clôt la session de glisser-déposer. (doit on fermer cette session d'une manière ou d'une autre ?)
Interfaces XPCOM
- nsIDragService : c'est le service qui permet de créer des nsIDragSession quand on en a besoin, et de les détruire en fin d'utilisation. Il permet d'accéder à des constantes durant les sessions de glisser-déposer.
- nsIDragSession : représente une session de glisser-déposer.
Pour créer une session de glisser-déposer (ceci se fait couramment lors de l'événement ondraggesture) :
- *invokeDragSession**(elementXUL, tabTransferable, region, actions)
- elementXUL : C'est une référence à l'objet XUL qui a initié le glisser-déposer. Notons que dans le cadre de ondraggesture, cette référence est tout simplement event.target.
- tabTransferable : C'est un tableau d'instances d'objets nsITransferable. C'est un tableau car il en faut 1 par objet transféré (en effet, vous pouvez glisser-déposer plusieurs objets d'un seul coup — plusieurs fichiers par exemple). mais que représente cette interface (nsITransferable) ?
- region : C'est une zone de feedback. Elle est souvent mise a la valeur null. C'est un objet XUL ? comment utilise-t-on le feedback ?
- actions : Le mode de glisser-déposer (si c'est pour une copie, un déplacement, pour un lien ou autre…). Cela devrait être initialisé à l'une des constantes suivantes, ou plusieurs simplement additionnées. Notons que le mode de glisser-déposer est modifiable par la suite (par exemple, on peut vouloir modifier le mode suivant si une touche est appuyée ou encore suivant l'objet sur lequel on passe…)
- nsIDragSession.DRAGDROP_ACTION_NONE (glisser-déposer invalide)
- nsIDragSession.DRAGDROP_ACTION_COPY
- nsIDragSession.DRAGDROP_ACTION_MOVE
- nsIDragSession.DRAGDROP_ACTION_LINK
L'interface nsIDragService permet de récupérer la session en cours avec la fonction getCurrentSession. Elle est utilisée couramment pour récupérer la session courante dans les événements des objets sur lesquels on passe. Cela permet alors de modifier l'état de celle-ci.
L'interface nsIDragSession permet de modifier les propriétés du glisser-déposer en cours.
Voici quelques méthodes :
Propriétés:
- (en consultation/écriture) canDrop : l'initialiser à "true" si l'élément peut être laché. Si ca n'a aucun sens de lacher l'objet mettre cette propriété à "false". Note : c'est souvent à la suite des événements ondragover et ondragenter qu'on modifie cette propriété.
- (en consultation/écriture) dragAction : c'est un accès direct au mode de glisser-déposer que l'on a pu initialiser via invokeDragSession. On peut modifier cette variable à la volée pour changer le mode de glisser-déposer.
- (en consultation uniquement) numDropItems : renseigne sur le nombre
- (en consultation uniquement) sourceDocument : le document d'où à été initié le glisser-déposer.
- (en consultation uniquement) sourceNode : le node DOM d'où a été initié le glisser-déposer.
Méthodes:
- getData (transfer,index) : Accès aux données transférées.
- transfer est un tableau de nsITransferable qui va recevoir les données du glisser-déposer.
- index est l'index de l'élément que l'on veut retirer dans le tableau des éléments en glisser-déposer.
- isDataFlavorSupported (flavor) : renvoie "true/false" selon si le type mime (flavor) est supporté.
Reste à documenter
- l'interface nsITranferable. Son principe.
- Exemples complets minimaux de drag n drop. (avec et sans nsDragnDrop.js?)
- Codes venant de firefox à commenter en exemple.
- Un tutorial (pas à pas) pour ajouter le drag n drop à une application. (avec une check liste des éléments intervenants dans le drag n drop).
Résolution de problèmes
- Attention à la syntaxe, dans le nom des fonctions ou des variables, c'est parfois "flavor" (isDataFlavorSupported), et parfois "flavour" (getSupportedFlavours)... Dans les fonctions utilisées, c'est bien "flavour" qui est le plus utilisé...
- Les exceptions dans les Observeurs sont cachées par l'objet nsDragAndDrop, entourez donc le corps des fonctions de vos observeurs par des blocs try/catch afin d'afficher les erreurs eventuelles ! cela simplifie grandement tout débuggage. Evitez l'utilisation de alert, et privilégiez le dump : ces fonctions sont appellée par des composants XPCOM, et dans le getSupportedFlavours, je plantais immanquablement firefox en utilisant "alert".
- Utilisez dump pour auditer l'appels des fonctions de vos objects , vous aurez peut-être des surprises.
- Exemple de code d'une fonction d'un observeur prêt à être débuggé (Utilisation du try/catch et du dump)
var boxObserver = {
getSupportedFlavours : function () {
dump("<boxObserver>.getSupportedFlavours\n");
try {
var flavours = new FlavourSet();
flavours.appendFlavour("text/unicode");
} catch (e) {
dump("exception: " + e + "\n"); // Don't use alert !!!
};
return flavours;
}
};
- L'object nsDragAndDrop ne fonctionnera pas en dehors d'une application installée. Il faudra pour que le glisser-déposer soit disponible dans une application non enregistrée dans le chrome :
- copier les fichiers nsDragAndDrop.js, et nsTransferable.js dans votre application
- Modifier ces 2 fichiers afin d'ajouter des lignes demandant les privilèges nécessaires avant toute instruction en ayant besoin.
- modifier les préférences de firefox pour autoriser les demandes de privilèges
- Ligne pour demander les droits avant une instruction qui en a besoin (code de nsDragAndDrop de firefox 1.0.4 modifié)
...
for (var i = 0; i < count; i++)
{
var trans = supportsArray.GetElementAt(i);
if (!trans) continue;
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
trans = trans.QueryInterface(Components.interfaces.nsITransferable);
...
- Ligne dans le pref.js a modifier pour autoriser aux applications non installées de demander des privilège
pref("signed.applets.codebase_principal_support", true);
- si vous utilisez un fichier nsDragAndDrop.js personnalisé, il semblerait qu'il y ait parfois confusion entre le fichier nsDragAndDrop.js modifié et celui de firefox. Ainsi si les modifications que vous faites ne semblent pas prises en compte, pensez y. (Je ne sais pas comment j'ai réussi à m'en débarrasser...).