HTML5 - L'attribut draggable

Après avoir évoqué l'attribut contentEditable d'HTML5, je vous propose cette fois de nous intéresser à l'API de drag and drop de cette prochaine version.

Présentation

L'attribut draggable peut être associé à n'importe quel élément HTML et placé à trois valeurs: 'false' (par défaut) , 'true' afin de rendre le déplacement possible et enfin 'auto' dont le comportement dépendra du navigateur. Il représente la mise en application de l'API de drag and drop d'HTML5.

Avec cet API et cet attribut, il existe un certain nombre d'évènements qui sont déclenchés par les actions de l'utilisateur et qui peuvent être écoutés pour exécuter des actions:

  • dragstart (ondragstart pour l'attribut HTML): qui se déclenche lorsqu'un drag and drop d'une zone est commencé.
  • drag (ondrag pour l'attribut HTML): déclenché pendant le déplacement (et donc potentiellement à répétition...).
  • dragenter (ondragenter pour l'attribut HTML): déclenché lorsqu'un drag and drop entre au dessus de la zone concernée.
  • dragleave (ondragleave pour l'attribut HTML): déclenché lorsqu'un drag and drop quitte la zone concernée.
  • dragover (ondragover pour l'attribut HTML): déclenché lorsqu'un drag and drop se situe au dessus de la zone concernée (et donc potentiellement à répétion...).
  • drop (ondrop pour l'attribut HTML): déclenché lorsqu'un élément en cours de déplacement est relaché au dessus de la zone concernée.
  • dragend (ondragend pour l'attribut HTML): déclenché lorsqu'un drag and drop a été réalisé ou annulé.

La preuve par l'exemple

Scénario de l'exemple

Afin de rendre tout ça plus "buvable" nous allons utilisez pour l'exemple un scénario très simple basé sur ces évènements et ces actions:

  1. L'utilisateur commence le déplacement d'une "boite" depuis une source de contenu représentée par une plus grosse "boite". Du coup l'évènement "dragstart" est déclenché pour cette boite. On ne s'occupera pas de l'évènement "drag" pour la suite.
  2. Il la déplace sur la page et arrive au dessus de la "boite" cible. L'évènement "dragenter" est déclenché par la cible.
  3. En déplaçant la petite "boite" au dessus de la cible, cette dernière déclence des évènements "dragover".
  4. L'utilisateur relâche la petite "boite" sur la cible qui déclenche l'évènement "drop". Cet évènement nous servira de référence pour retirer l'objet déplacé de sa source et le placer dans la cible de façon concrête.

Le code HTML

Nous allons créer 2 div qui nous serviront de source ('src') ou de cible ('tgt'). À l'intérieur de la boite 'src' nous aurons une petite boite nommée 'box' qui pourra être déplacée dans 'src'.

<!-- just a container -->
<div class="bordered">
    <!-- our drag source container -->
    <div class="half-width source" id="src">
        <!-- our box to drag and drop -->
        <div class="box" id="box"
             draggable="true">
            Simple Box 1
        </div>
    </div>
    <!-- our drag and drop target -->
    <div class="half-width target" id="tgt"></div>
</div>

Rien de plus simple jusque là. À noter toutefois, l'utilisation de l'attribut draggable à la valeur 'true' pour autoriser le déplacement de la boite 'box'.

CSS

Juste un peu de mise en forme et un 'hack' pour le moteur WebKit (Safari entre autres) nécessaire pour activer le drag and drop (cette situation ne saurait être définitive je pense car elle ne respecte pas la norme HTML5.)

.bordered {
    border: 1px solid #888888;
}
.half-width {
    float:left;
    width:50%;
    min-height:160px;
}
.target {
    background-color:#BFFF80;
}
.source {
    background-color:#FFDF80;
}
.box {
    background-color:#FF8080;
    margin:5px;
    padding:5px;
    border: 1px solid #888888;
    height:100px;
    width:100px;
    text-align:center;
}
*[draggable=true] {
    -khtml-user-drag: element; /* WebKit hack */
    cursor:move;               /* a move cursor */
    -moz-user-select:none;     /* disabled content selection
                                  on mozilla browsers */
}

dragstart

Comme expliqué plus haut, l'évènement dragstart se déclenche lorsqu'un drag and drop d'une zone est commencé. Nous allons donc associer à l'évènement dragstart de la boite à déplacer, la création de notre drag and drop.

/* on associe le démarrage du drag and drop à la fonction
   dragStartHandler */
document.getElementById('box').addEventListener("dragstart", dragStartHandler, false);

function dragStartHandler(event) {
    /* autoriser les drag and drop de type "copy" */
    event.dataTransfer.effectAllowed = 'copy';
    /* transmettre en donnée de drag and drop l'id de la boite
       déplacée */
    event.dataTransfer.setData('Text', event.target.id);
    return false;
}

dragenter

Cette fois-ci nous allons associer une fonction javascript à l'entrée dans la zone cible:

/* on associe l'entrée du drag and drop sur la cible à la fonction
   dragEnterHandler */
document.getElementById('tgt').addEventListener("dragenter", dragEnterHandler, false);

function dragEnterHandler(event) {
    /* éviter le comportement par défaut du navigateur (déplacement
       de sélection) */
    event.preventDefault();
    return false;
}

dragover

Ici nous nous intéressons à ce qu'il se passe lorsqu'on survole la cible. Conformément à ce que nous avons mis dans la fonction dragStartHandler nous allons donner au déplacement la zone la capacité à recevoir les drag and drop de type 'copy':

/* on associe le survole de la cible à la fonction
   dragOverHandler */
document.getElementById('tgt').addEventListener("dragover", dragOverHandler, false);

function dragOverHandler(event) {
    /* verification de la cible au cas où l'on survole un autre
       objet */
    if (event.target != document.getElementById('tgt')) {
        return false;
    } else {
        /* on attribue l'effet de curseur qui correspond au type
           accepté plus haut */
        event.dataTransfer.dropEffect = 'copy';
        /* éviter le comportement par défaut du navigateur
           (déplacement de sélection) */
        event.preventDefault();
    }
    return false;
}

drop

Nous y voilà. L'étape finale du déplacement et l'action de "relaché" plus communément appelée "drop" va être connectée à une fonction qui déplacera la zone déplacée dans la cible.

/* on associe le 'laché' d'un élément sur la cible à la fonction
   dropHandler */
document.getElementById('tgt').addEventListener("drop", dropHandler, false);

function dropHandler(event) {
    /* on se sert de l'id transporté en donnée pour déplacer
       l'élément dans son nouveau parent DOM */
    event.target.appendChild(document.getElementById(event.dataTransfer.getData('Text')));
    /* et voila, on a finit et pour s'assurer on coupe manuellement
       la propagation de l'évènement (pas forcément nécessaire !) */
    event.stopPropagation();
    return false;
}

Le résultat

Voila donc notre exemple prêt à marcher :

Simple Box 1

Références de l'article

Vus : 1723
Publié par Creasy : 8