2011-12-10 22 views
12

Estoy tratando de reproducir la forma en que GMail maneja los archivos adjuntos arrastrar/soltar html5, donde tan pronto como arrastra archivos sobre la página, muestra un nuevo elemento para usted para dejarlos caer. Entendí esa parte (no fue tan sencillo como pensé que sería).Cambio del cursor del mouse para HTML5 Arrastrar y soltar archivos (GMail Arrastrar y soltar)

Ahora estoy tratando de pulir cambiando el cursor del mouse cuando el mouse está sobre cualquier otro elemento que no sea el elemento desplegable, para decirle al usuario que no está permitido dejar caer aquí. Me imagino que puedo hacerlo con un cursor personalizado, pero eso no parece ser lo que está haciendo GMail. The spec sugeriría que es posible cambiar el cursor del mouse también, pero parece que no puedo hacerlo funcionar correctamente, usando dropzone/effectAllowed.

se agradecería cualquier ayuda, aquí está mi configuración actual: http://jsfiddle.net/guYWx/1/

ETA: Esto es lo que terminé con: http://jsfiddle.net/guYWx/16/

<body style="border: 1px solid black;"> 
    <div id="d0" style="border: 1px solid black;">drag files onto this page</div> 
    <div id="d1" style="border: 1px solid black; display: none; background-color: red;">-&gt; drop here &lt;-</div> 
    <div id="d2" style="border: 1px solid black;">and stuff will happen</div> 
    <div style="float: left;">mouse them all over&nbsp;</div> 
    <div style="float: left;">these elements</div> 
    <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/> 
    <div>end page</div> 
</body> 
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> 
<script type="text/javascript"> 
    var resetTimer; 

    var reset = function() 
    { 
     $('#d1').hide(); 
    }; 

    var f = function(e) 
    { 
     var srcElement = e.srcElement? e.srcElement : e.target; 

     if ($.inArray('Files', e.dataTransfer.types) > -1) 
     { 
      e.stopPropagation(); 
      e.preventDefault(); 

      e.dataTransfer.dropEffect = (srcElement.id == 'd1') ? 'copy' : 'none'; 

      if (e.type == "dragover") 
      { 
       if (resetTimer) 
       { 
        clearTimeout(resetTimer); 
       } 
       $('#d1').show(); 
       console.info('dropped on <' + srcElement.tagName.toLowerCase() + ' id="' + srcElement.id + '">\n\ne.dataTransfer.types is ' + e.dataTransfer.types + '\n\ne.dataTransfer.files.length is ' + e.dataTransfer.files.length); 

      } 
      else if (e.type == "dragleave") 
      { 
       resetTimer = window.setTimeout(reset, 25); 
      } 
      else if (e.type == "drop") 
      { 
       reset(); 
       alert('dropped on <' + srcElement.tagName.toLowerCase() + ' id="' + srcElement.id + '">\n\ne.dataTransfer.files.length is ' + (e.dataTransfer.files ? e.dataTransfer.files.length : 0)); 
      } 
     } 
    }; 

    document.body.addEventListener("dragleave", f, false); 
    document.body.addEventListener("dragover", f, false); 
    document.body.addEventListener("drop", f, false); 
</script> 
+0

Hola, he estado batallando con esto por horas. Tu código funciona mucho mejor que el mío. ¿Puede explicar para qué sirve el retraso de tiempo de espera en el restablecimiento? – benb

+1

Impide falsos positivos para el evento dragleave. Cuando unes dragover/dragleave a un elemento con un conjunto de subelementos, los eventos se dispararán cuando muevas el mouse del subelemento al subelemento. Reemplacé el tiempo de espera con una llamada a 'restablecer', para que pueda ver qué tan malo es cuando arrastra sobre: ​​http://jsfiddle.net/guYWx/20/ (un montón de ocultar/mostrar en Chrome). – Langdon

Respuesta

24

Hizo algunas búsquedas en la fuente y descubrió que se supone que debe establecer event.dataTransfer.dropEffect = 'move'; dentro de su controlador de eventos dragover. Buscado en Google para dropEffect a leer más y encontró:

dataTransfer.dropEffect

Controla la retroalimentación que se da al usuario durante el dragenter y eventos dragover. Cuando el usuario pasa el cursor sobre un elemento objetivo, el cursor del navegador indicará qué tipo de operación va a tomar el lugar (por ejemplo, una copia, un movimiento, etc.). El efecto puede tomar uno de los siguientes valores de : none, copy, link, move.

de: http://www.html5rocks.com/en/tutorials/dnd/basics/

Editar: Esto es lo que terminé con: http://jsfiddle.net/guYWx/16/

tenía que hacer un truco adicional para que funcione a la perfección. Hizo esto para que el gotero no aparecería al seleccionar el texto y se arrastra alrededor de la página:

if ($.inArray('Files', e.dataTransfer.types) > -1) 
-3

usted tiene que cambiar cursor propiedad CSS.

Encontrará una lista de los diferentes valores de cursorhere.

También puede especificar una imagen de cursor personalizada con cursor: url('foo.png');.

+0

Sé que puedo cambiar el cursor, pero GMail no está haciendo esto. Hay una enorme diferencia entre cursor: no-drop y cómo se ve el cursor en GMail. – Langdon

4

@Langdon - Gracias por señalar exactamente lo que necesitaba! Lo he votado arriba.

Después de pasar tantas horas conseguí que la sugerencia funcionara exactamente como estaba previsto.

I hicieron uso de effectAllowed en combinación con dropEffect para proporcionar indicaciones visuales al realizar operaciones de arrastrar y soltar. ¡Completamente navegador cruzado!

$(document).on('dragstart dragenter dragover', function(event) {  
    // Only file drag-n-drops allowed, http://jsfiddle.net/guYWx/16/ 
    if ($.inArray('Files', event.originalEvent.dataTransfer.types) > -1) { 
     // Needed to allow effectAllowed, dropEffect to take effect 
     event.stopPropagation(); 
     // Needed to allow effectAllowed, dropEffect to take effect 
     event.preventDefault(); 

     $('.dropzone').addClass('dropzone-hilight').show();  // Hilight the drop zone 
     dropZoneVisible= true; 

     // http://www.html5rocks.com/en/tutorials/dnd/basics/ 
     // http://api.jquery.com/category/events/event-object/ 
     event.originalEvent.dataTransfer.effectAllowed= 'none'; 
     event.originalEvent.dataTransfer.dropEffect= 'none'; 

     // .dropzone .message 
     if($(event.target).hasClass('dropzone') || $(event.target).hasClass('message')) { 
      event.originalEvent.dataTransfer.effectAllowed= 'copyMove'; 
      event.originalEvent.dataTransfer.dropEffect= 'move'; 
     } 
    } 
}).on('drop dragleave dragend', function (event) { 
    dropZoneVisible= false; 

    clearTimeout(dropZoneTimer); 
    dropZoneTimer= setTimeout(function(){ 
     if(!dropZoneVisible) { 
      $('.dropzone').hide().removeClass('dropzone-hilight'); 
     } 
    }, dropZoneHideDelay); // dropZoneHideDelay= 70, but anything above 50 is better 
});