Glisser et déposer
L'interface HTML Drag and Drop (pour glisser-déposer) permet à des applications d'utiliser des fonctionnalités de glisser-déposer dans le navigateur.
L'utilisateur pourra sélectionner des éléments déplaçables à la souris et les déplacer vers un élément où on peut déposer en relâchant le bouton de la souris. Une représentation translucide de l'élément déplacé suit le pointeur lors de l'opération.
Pour les sites web et les extensions, on peut personnaliser les éléments qui peuvent être déplacés, la façon dont ceux-ci sont signalés et les éléments qui peuvent servir de destination.
L'aperçu de cette API inclut une description des interfaces, les étapes à suivre pour prendre en charge ces fonctionnalités dans une application et un aperçu de l'interopérabilité de ces interfaces.
Évènements de déplacement
L'API HTML Drag and Drop utilise le modèle d'évènements du DOM (Event
) ainsi que les éléments de déplacements (DragEvent
) hérités des évènements liés à la souris (MouseEvent
). Une opération de déplacement commence généralement lorsqu'un utilisateur sélectionne un élément déplaçable puis qu'il le déplace sur un élément de destination avant de relâcher l'élément déplacé.
Lors des opérations de déplacement, plusieurs évènements sont déclenchés (dont certains qui sont déclenchés à plusieurs reprises comme drag
et dragover
).
Chaque type d'évènement de déplacement possède un gestionnaire d'évènement global (une méthode on...
) :
Évènement | Gestionnaire d'évènement global | Déclenchement |
---|---|---|
drag |
ondrag |
…un objet déplaçable (que ce soit un élément ou une sélection de texte) est déplacée. |
dragend |
ondragend |
…une opération de déplacement se termine (en relâchant le bouton de la souris ou en utilisant la touche Echap, voir Terminer un déplacement) |
dragenter |
ondragenter |
…un élément en cours de déplacement arrive sur une zone de dépôt valide (voir indiquer une cible de destination). |
dragexit |
ondragexit |
…un élément n'est plus la sélection immédiate du déplacement. |
dragleave |
ondragleave |
…un élément en cours de déplacement quitte une zone de dépôt valide. |
dragover |
ondragover |
…un élément en cours de déplacement est en cours de survol d'une zone de dépôt valide (cet évènement est déclenché toutes les quelques centaines de millisecondes). |
dragstart |
ondragstart |
…l'utilisateur commence à déplacer un élément (voir démarrer une opération de glissement). |
drop |
ondrop |
…un élément est déposé sur une cible valide (voir déposer un élément). |
Note :
Les évènements dragstart
et dragend
ne sont pas déclenchés lors qu'on glisse-dépose un fichier de l'appareil dans le navigateur.
Interfaces
Les interfaces fournies par cette API sont
L'interface DragEvent
possède un constructeur et une propriété dataTransfer
qui est un objet DataTransfer
.
Les objets DataTransfer
incluent l'état du glisser-déposer, le type de déplacement (copy
ou move
), les données déplacées (un ou plusieurs objets) et le type MIME de chaque objet déplacé. Les objets DataTransfer
possèdent également des méthodes permettant d'ajouter ou de retirer des objets aux données déplacées.
Les interfaces DragEvent
et DataTransfer
sont standard et suffisent à apporter des fonctionnalités de glisser/déposer. Toutefois, Firefox prend en charge quelques extensions spécifiques à Gecko (cf. ci-après) pour l'objet DataTransfer
(bien entendu, ces extensions ne fonctionneront que dans Firefox et pas dans les autres navigateurs).
Chaque objet DataTransfer
possède une propriété items
qui est une liste (list
) d'objets DataTransferItem
. Un objet DataTransferItem
représente un seul objet déplacé, avec une propriété kind
qui indique s'il s'agit d'un texte (string
) ou d'un fichier (file
) et une propriété type
qui correspond au type MIME de la donnée déplacée. L'objet DataTransferItem
possède également des méthodes pour consulter les données de l'objet déplacé.
L'objet DataTransferItemList
est une liste d'objets DataTransferItem
. La liste possède des méthodes pour ajouter un objet en déplacement à la liste, pour retirer un objet de la liste ou pour vider la liste de tout ses objets.
La différence principale entre DataTransfer
et DataTransferItem
est l'utilisation de la méthode synchrone getData()
pour la première et de la méthode asynchrone getAsString()
pour la deuxième.
Note : DragEvent
et DataTransfer
sont largement prises en charge par les navigateurs de bureau tandis que DataTransferItem
et DataTransferItemList
ont une compatibilité plus restreinte. Voir la section ci-après sur l'interopérabilité.
Interfaces spécifiques à Gecko
Mozilla / Firefox prend en charge certaines fonctionnalités qui ne font pas partie du modèle standard. Ce sont des fonctions utilitaires pour aider au déplacement de plusieurs objets ou de données qui ne sont pas du texte (des fichiers par exemple). Pour plus d'informations, voir Glisser-déposer plusieurs objets. Voir aussi la page de référence de DataTransfer
pour la liste de l'ensemble des propriétés spécifique à Gecko et des méthodes spécifiques à Gecko.
Bases
Dans cette section, nous allons voir les premières étapes nécessaires aux fonctionnalités de glisser-déposer dans une application.
Identifier ce qui peut être déplacé
Pour qu'un élément puisse être déplacé, il faut lui ajouter l'attribut draggable
ainsi que le gestionnaire d'évènement global ondragstart
:
<script>
function dragstart_handler(ev) {
// On ajoute l'identifiant de l'élément cible à l'objet de transfert
ev.dataTransfer.setData("text/plain", ev.target.innerText);
}
</script>
<p id="p1" draggable="true" ondragstart="dragstart_handler(event)">
Cet élément est déplaçable.
</p>
Voir la page de référence sur l'attribut draggable
et le guide sur les opérations de déplacement pour plus d'informations.
Définir les données déplacées
Une application peut inclure plusieurs objets dans une opération de glisser/déposer. Chaque objet est une chaîne de caractères (DOMString
) ayant un type MIME particulier (indiqué par son attribut type
) tel que text/html
.
Chaque DragEvent
possède une propriété dataTransfer
contenant les données transportées. Cette propriété (un objet DataTransfer
) possède des méthodes pour gérer les données transportées. La méthode setData()
permet d'ajouter un objet aux données transportées :
function dragstart_handler(ev) {
// On ajoute différents types de données transportées
ev.dataTransfer.setData("text/plain", ev.target.innerText);
ev.dataTransfer.setData("text/html", ev.target.outerHTML);
ev.dataTransfer.setData(
"text/uri-list",
ev.target.ownerDocument.location.href,
);
}
Pour connaître la liste des types de donnée communément utilisées lors d'un glisser/déposer (texte, HTML, liens, fichiers, etc.), voir les types recommandés. Pour plus d'informations sur les informations transportées, voir Drag Data.
Définir l'image pour le déplacement
Par défaut, le navigateur fournit une image qui apparaît à côté du pointeur lors de l'opération de déplacement. Toutefois, une application peut définir une image personnalisée grâce à la méthode setDragImage()
:
function dragstart_handler(ev) {
// On crée une image qu'on utilise pour le déplacement
// Note : on changera "example.gif" vers une vraie image
// (sinon l'image par défaut sera utilisée)
var img = new Image();
img.src = "example.gif";
ev.dataTransfer.setDragImage(img, 10, 10);
}
Pour en savoir plus, voir Définir l'image de feedback pour le glisser-déposer.
Définir l'effet de déplacement
La propriété dropEffect
est utilisée pour fournir un retour à l'utilisateur qui effectue l'opération de glisser/déposer. Généralement, cela se traduit par la modification du curseur affiché par le navigateur lors du déplacement.
Il est possible de définir trois effets :
copy
: indique que les données déplacées seront copiées depuis l'emplacement source vers la cible.move
: indique que les données déplacées seront déplacées depuis l'emplacement source vers la cible.link
: indique qu'une relation ou une connexion sera créée entre la source et la cible.
Lors de l'opération de déplacement, les effets peuvent être modifiés afin d'indiquer que certains effets sont autorisés à certains emplacements.
Voici un exemple illustrant l'utilisation de cette propriété.
function dragstart_handler(ev) {
ev.dataTransfer.dropEffect = "copy";
}
See Drag Effects for more details.
Définir la zone où déposer l'élément déplacé
Par défaut, le navigateur empêche de déposer quoi que ce soit sur la plupart des éléments HTML. Pour modifier ce comportement, il faut qu'un élément devienne une zone cible ou qu'il soit identifié comme "droppable". L'élément doit avoir les deux gestionnaires d'évènements ondragover
et ondrop
comme attributs. Dans l'exemple suivant, on montre comment utiliser ces attributs et on fournit des gestionnaires d'évènements simples associés :
<script>
function dragover_handler(ev) {
ev.preventDefault();
ev.dataTransfer.dropEffect = "move";
}
function drop_handler(ev) {
ev.preventDefault();
// On récupère l'identifiant de la cible et on ajoute l'élément déplacé au DOM de la cible
var data = ev.dataTransfer.getData("text/plain");
ev.target.appendChild(document.getElementById(data));
}
</script>
<p
id="target"
ondrop="drop_handler(event)"
ondragover="dragover_handler(event)">
Zone pour déposer
</p>
On voit ici que chaque gestionnaire invoque preventDefault()
afin d'éviter toute gestion d'évènement ultérieure (comme les évènements tactiles ou les évènements de pointeur).
Pour plus d'information, voir Indiquer une cible pour un glisser-déposer.
Gérer le dépôt de l'objet
Le gestionnaire de l'évènement drop
permet de gérer les données déposées avec la logique de l'application. Généralement, une application utilisera getData()
afin de récupérer les données déplacées et les traitera. L'application peut choisir d'avoir un comportement différent selon la valeur de dropEffect
et/ou celles des autres propriétés.
Dans l'exemple suivant, on montre un gestionnaire pour le dépot de l'objet : on récupère l'identifiant (id
) de l'élément déplacé puis on utilise celui-ci afin de le déplacer depuis la source vers la cible :
<script>
function dragstart_handler(ev) {
// On ajoute l'identifiant de l'élément cible à l'objet de transfert
ev.dataTransfer.setData("application/my-app", ev.target.id);
ev.dataTransfer.dropEffect = "move";
}
function dragover_handler(ev) {
ev.preventDefault();
ev.dataTransfer.dropEffect = "move";
}
function drop_handler(ev) {
ev.preventDefault();
// On obtient l'identifiant de la cible et on ajoute l'élément déplacé
// au DOM de la cible
var data = ev.dataTransfer.getData("application/my-app");
ev.target.appendChild(document.getElementById(data));
}
</script>
<p id="p1" draggable="true" ondragstart="dragstart_handler(event)">
Cet élément peut être déplacé.
</p>
<div
id="target"
ondrop="drop_handler(event)"
ondragover="dragover_handler(event)">
Zone pour le dépôt
</div>
Pour plus d'information, voir Gérer le dépôt lors d'une opération de glisser-déposer.
Terminer l'opération de glisser/déposer
À la fin de l'opération, c'est l'évènement dragend
qui est déclenché sur l'élément source (celui qui a été "saisi" au début). Cet évènement est déclenché lorsque l'opération est terminée ou qu'elle a été annulée. Le gestionnaire d'évènement pour dragend
peut vérifier la valeur de la propriété dropEffect
afin de déterminer si l'opération a réussi ou non.
Pour plus d'informations sur la gestion de la fin d'une opération de glisser-déposer, voir Terminer un glisser-déposer.
Interopérabilité
Comme on peut le voir dans le tableau de compatibilité pour l'interface DataTransferItem
, la prise en charge du drag-and-drop est assez répandue parmi les navigateurs de bureau à l'exception des interfaces DataTransferItem
et DataTransferItemList
. Ce tableau montre également que la prise en charge sur mobile est assez faible.