Glisser-déposer en HTML5

Alexandre Niveau
GREYC — Université de Caen

Drag and drop

  • Faire glisser certains éléments et les déposer ailleurs
  • Typiquement utilisé pour déplacer, mais également pour copier, ouvrir, etc.
  • API HTML5 pour gérer le drag and drop
    • conçue par Microsoft pour IE en 1999
    • de qualité fort discutable…
    • malheureusement adoptée quasiment telle quelle pour HTML5
  • Supporté par les navigateurs desktop, pas les mobiles
    • Cependant, quelques différences de comportement entre les navigateurs (notamment Chrome et Firefox)

Principe du glisser-déposer

  • Un élément glissé contient des données : ce sont elles qui sont transmises
  • Objets « glissables » sur le web :
    • images et liens (c'est leur URL qui est transmise)
    • sélections de texte
  • Lâcher la souris sur certaines zones produit un effet
    • sur la barre d'adresse : « ouvre » l'objet
    • sur une zone de texte : colle une représentation textuelle de l'objet (typiquement une URL)
  • Possible avec des éléments de la page, mais aussi des éléments externes (e.g. fichiers à uploader)

Événements

  • dragstart et dragend : lancés sur l'objet glissé au début/à la fin de la glissade
  • drag : lancé sur l'objet glissé lors d'un mouvement
  • dragenter et dragleave : lancés sur un élément au début/à la fin de son survol par un objet glissé
    • attention, se comportent malheureusement comme mouseover/mouseout (et pas mouseenter/mouseleave), ce qui les rend très désagréables à utiliser…
  • dragover : lancé sur la zone survolée lors d'un mouvement
  • drop : lancé sur la zone de lâcher (si c'est une zone de lâcher valide !)
  • NB, on peut voir aussi dragexit : différence avec dragleave subtile, et pas implémenté partout -> ignorer

Démos:

  • dragstart/end : mettre une bordure de couleur (différente)
  • drag : mettre une progressbar (+0.01 par événement drag)
  • dragenter/dragleave: fond de couleur
  • dragover : progressbar, ou trace sur canvas
  • drop : démo sur inputfile, pour éviter le preventdefault

Données

  • Attribut dataTransfer de l'événement, contient les données transférées par le biais de l'objet glissé, dans une instance de DataTransfer
  • dataTransfer.getData(type_mime), dataTransfer.setData(type_mime, data) pour manipuler les données
  • dataTransfer.files : tableau des fichiers présents dans les données (notamment si l'on fait glisser un fichier depuis l'extérieur du navigateur)
  • Attention, dans Chrome les données ne sont accessibles depuis une zone de dépôt que lors de l'événement drop, pas dragenter/dragleave (pour des raisons de sécurité : l'internaute peut faire passer un objet devant la fenêtre du navigateur sans vouloir communiquer les données à la page web ouverte)
  • Interface plus récente :
    • dataTransfer.items contient un tableau des DataTransferItems contenus dans l'objet
    • dataTransfer.types contient un tableau de leurs types (MIME)
  • Explorer avec la console, mais attention à Chrome, qui réévalue le contenu de dataTransfer au moment où il est exploré dans la console, ce qui fait qu'il apparaît comme vide (alors qu'il ne l'était pas pendant la glissade) !

Démo de tout ça sur une image ou un lien. dropzone: input file et/ou textarea.

Feedbacks

  • Attribut dropEffect de DataTransfer : modifie notamment l'indice visuel à côté de l'élément glissé, en fonction de l'effet voulu du drop (copie, déplacement ou lien).
    • à modifier dans dragenter/dragleave
    • NB : les catégories sont fixées, mais c'est vous qui définissez et implémentez l'effet.
  • Attribut effectAllowed de DataTransfer : pour contrôler le type d'effet qui est autorisé, copie, déplacement ou lien (ou une combinaison)
    • à positionner dans le dragstart uniquement
    • utile notamment pour le feedback visuel : on voit en passant sur une zone de dépôt si l'effet est possible ou non.
  • DataTransfer.setDragImage(): pour modifier la ghost image. Peut être une image ou un canevas, ou un autre élément (mais il faut que cet élément soit visible pour que ça fonctionne sous Firefox…) peut-être setDragImage est obligatoire pour avoir l'effet par défaut sur certains browsers? je ne pense pas.

Définir ses propres éléments glissables

  • N'importe quel élément peut être rendu glissable
  • Il faut que l'élément ait l'attribut draggable à true
    • -> cela permet de lancer un dragstart
  • Pour Firefox, il faut utiliser ce dragstart pour placer des données dans le dataTransfer, sinon la glissade s'arrête ici (aucun autre événement n'est lancé)

Définir ses propres cibles de dépôt

  • (Presque) n'importe quel élément peut être une cible de dépôt (mais pas les images, par exemple)
  • Par défaut, la plupart des éléments ne le sont pas : ils ne génèrent jamais d'événement drop
  • Pour leur permettre de le faire, il est nécessaire d'appeler la méthode preventDefault sur les événements dragover
  • Il faut aussi le faire pour l'événement drop, sinon Firefox essaie d'ouvrir l'objet glissé
Démo de dépôt d'une image externe sur un canevas ?