Laboratorio: realizar drag and drop de elementos HTML
Dentro de la Web 2.0 se intentan hacer cosas menos web y más tipo aplicación de escritorio. Una de estas cosas es realizar un drag and drop. Esto nos puede ser útil para interactuar con elementos, por ejemplo, tenemos una lista de productos, pinchamos en uno y arrastramos en otro, obteniendo una comparativa de los productos. Bueno, las aplicaciones que le podemos dar depende de nuestras necesidades y de nuestra imaginación. Eso sÃ, la forma de realizarlo es la misma.
En el ejemplo que hemos creado, hacemos que el elemento seleccionado se posicione encima del elemento sobre el que realizamos el drop. También hay que tener en cuenta, que en este caso, el drag&drop que hacemos es pinchando-moviendo-pinchando, no pinchando-moviendo-soltando. Realmente también se podrÃa hacer asÃ, pero como lo hemos hecho válido para texto, si lo hacemos de la manera normal, se podrÃa ir seleccionando el texto según se mueve el ratón.
El método es sencillo, capturamos el evento onclick y el evento onmouseover del body del documento, para que cuando se pinche con el ratón en un elemento HTML podamos tratarlo, y que una vez pulsado, el moviemiento del ratón sea utilizado para posicionar el efecto drag & drop.
El efecto drag & drop consiste en ver una copia recortada y semitransparente del elemento seleccionado que acompaña al ratón. Para ello, al pinchar en el objeto, lo clonamos (cloneNode()), lo añadimos al documento y lo colocamos según la posición del ratón. Los estilos del elemento harán que aparezca recortado y semitransparente.
Lo primero que hay que hacer es capturar los eventos del body:
<body onclick="drag(event, 0)" onmousemove="drag(event, 1)">
El método que se encarga de tratar el drag&drop realiza las siguientes acciones:
- Si se pincha sobre un objeto (empieza el drag), se crea una copia del elemento, se mete en un contenedor que tiene los estilos para que parezca recortado y transparente, y lo posicionamos junto al puntero del ratón.
- Si ha comenzado el drag, al moverse el ratón se moverá el elemento que muestra el efecto D&D.
- Si se pincha sobre un objeto cuando se estaba realizando el D&D, se elimina el objeto “efecto” y se posiciona el elemento sobre el que se hacÃa el D&D antes del objeto pinchado (insertBefore(node, node)).
var nuevo = null; // El objeto efecto drag&drop
var obj = null; // El objeto seleccionado
var okDrag = false; // Si se hace drag&drop
// Trata el drag&drop
function drag(evt, estado) {
switch (estado) {
// Inicio o fin de drag&drop
case 0:
// Fin drag
if (okDrag) {
// Eliminamos el elemento que hemos creado para el efecto d&d
nuevo.parentNode.removeChild(nuevo);
// Obtenemos el elemento destino del evento del ratón
var destino = evt.srcElement? evt.srcElement : evt.target;
// Dependiendo de ciertos elementos, obtenemos su padre
// Por ejemplo, una celda no nos vale, nos vale la tabla
if (destino.tagName == "TD") {
destino = destino.parentNode;
}
if (destino.tagName == "TR") {
destino = destino.parentNode;
}
if (destino.tagName == "TBODY") {
destino = destino.parentNode;
}
// Si no se trata del mismo objeto,
// recolocamos el objeto encima del destino
if (destino != obj) {
destino.parentNode.insertBefore(obj, destino);
}
nuevo = null;
okDrag = false;
// Inicio drag
} else {
// Obtenemos el elemento destino del evento del ratón
obj = evt.srcElement? evt.srcElement : evt.target;
// Si no se trata del BODY o del HTML, para evitar problemas...
if (obj.tagName != "BODY" && obj.tagName != "HTML") {
// Dependiendo de ciertos elementos, obtenemos su padre
// Por ejemplo, una celda no nos vale, nos vale la tabla
if (obj.tagName == "TD") {
obj = obj.parentNode;
}
if (obj.tagName == "TR") {
obj = obj.parentNode;
}
if (nuevo != null) {
nuevo.parentNode.removeChild(nuevo);
nuevo = null;
}
// Creamos un contenedor para el elementro efecto D&D
nuevo = document.createElement("DIV");
nuevo.id = "nuevo";
nuevo.className = "nuevo";
// Añadimos el clon
nuevo.appendChild(obj.cloneNode(true));
// Posicionamos
nuevo.style.top = (evt.clientY+5)+"px";
nuevo.style.left = (evt.clientX+5)+"px";
// Lo incluimos en el BODY
document.body.appendChild(nuevo);
okDrag = true;
}
}
break;
case 1: // Movimiento drag
if (okDrag) {
// Posicionamos
nuevo.style.top = (evt.clientY+5)+"px";
nuevo.style.left = (evt.clientX+5)+"px";
}
break;
}
}