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` (en-US)*) 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 (en-US) possède un gestionnaire d'évènement global (une méthode `on...`) (en-US) :

| Évènement | Gestionnaire d'évènement global | Déclenchement |
| --- | --- | --- |
| `drag` | `ondrag` (en-US) | …un objet déplaçable (que ce soit un élément ou une sélection de texte) est déplacée. |
| `dragend` | `ondragend` (en-US) | …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 (en-US)) |
| `dragenter` | `ondragenter` (en-US) | …un élément en cours de déplacement arrive sur une zone de dépôt valide (voir indiquer une cible de destination (en-US)). |
| `dragexit` | `ondragexit` (en-US) | …un élément n'est plus la sélection immédiate du déplacement. |
| `dragleave` | `ondragleave` (en-US) | …un élément en cours de déplacement quitte une zone de dépôt valide. |
| `dragover` | `ondragover` (en-US) | …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` (en-US) | …l'utilisateur commence à déplacer un élément (voir démarrer une opération de glissement (en-US)). |
| `drop` | `ondrop` (en-US) | …un élément est déposé sur une cible valide (voir déposer un élément (en-US)). |

**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

* `DragEvent` (en-US),
* `DataTransfer`,
* `DataTransferItem` (en-US)
* `DataTransferItemList` (en-US).

L'interface `DragEvent` (en-US) possède un constructeur et une propriété `dataTransfer` (en-US) 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` (en-US) 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` (en-US) qui est une liste (`list` (en-US)) d'objets `DataTransferItem` (en-US). Un objet `DataTransferItem` (en-US) représente un seul objet déplacé, avec une propriété `kind` (en-US) qui indique s'il s'agit d'un texte (`string`) ou d'un fichier (`file`) et une propriété `type` (en-US) qui correspond au type MIME de la donnée déplacée. L'objet `DataTransferItem` (en-US) possède également des méthodes pour consulter les données de l'objet déplacé.

L'objet `DataTransferItemList` (en-US) est une liste d'objets `DataTransferItem` (en-US). 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` (en-US) est l'utilisation de la méthode synchrone `getData()` (en-US) pour la première et de la méthode asynchrone `getAsString()` (en-US) pour la deuxième.

**Note :** `DragEvent` (en-US) et `DataTransfer` sont largement prises en charge par les navigateurs de bureau tandis que `DataTransferItem` (en-US) et `DataTransferItemList` (en-US) 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` (en-US) :


```html
<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 (en-US) 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` (en-US) possède une propriété `dataTransfer` (en-US) 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()` (en-US) permet d'ajouter un objet aux données transportées :


```js
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 (en-US). Pour plus d'informations sur les informations transportées, voir Drag Data (en-US).

### 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()` (en-US) :


```js
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 (en-US).

### Définir l'effet de déplacement

La propriété `dropEffect` (en-US) 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é.


```js
function dragstart\_handler(ev) {
  ev.dataTransfer.dropEffect = "copy";
}
```


See Drag Effects (en-US) 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` (en-US) et `ondrop` (en-US) comme attributs. Dans l'exemple suivant, on montre comment utiliser ces attributs et on fournit des gestionnaires d'évènements simples associés :


```html
<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 (en-US).

### 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()` (en-US) 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` (en-US) 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 :


```html
<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 (en-US).

### 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` (en-US) 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 (en-US).

Interopérabilité
----------------

Comme on peut le voir dans le tableau de compatibilité pour l'interface `DataTransferItem` (en-US), la prise en charge du *drag-and-drop* est assez répandue parmi les navigateurs de bureau à l'exception des interfaces `DataTransferItem` (en-US) et `DataTransferItemList` (en-US). Ce tableau montre également que la prise en charge sur mobile est assez faible.

Exemples et démos
-----------------

* Copier et déplacer des éléments avec l'interface `DataTransfer`
* Copier et déplacer des éléments avec l'interface `DataTransferListItem`
* JSBin : Glisser-déposer des fichiers
* Un parking réalisé avec l'API Drag and Drop (lien pour éditer le code)
Voir aussi
----------

* Les opérations de déplacement
* Glisser-déposer plusieurs objets
* Types de déplacement recommandés (en-US)
* Spécification HTML5 : Drag and Drop
* Données d'interopérabilité pour l'API Drag and Drop sur CanIUse