3
votes

I'd like to be able to detect when a user drags a file into the window and pop up an overlay over the whole app that shows the various folders the user could upload the file to.

So far, I understand that I can listen to the window for "dragenter" and show my overlay, and listen to the overlay for "dragleave" to hide it, but the problem seems to be that dragging over the drop zones causes the overlay's dragleave event to fire, which makes the overlay hide (which makes the window dragenter event show the overlay, and so on).

I'm using Dropzone.js for my folder dropzones. I've looked around and seen similar problems to mine, but none that solved this problem.

Edit: I found a solution (of sorts) elsewhere on StackOverflow: jQuery Drag-and-Drop Flickering on Hover (Webkit only)

The solution is to check the event on dragleave and, if the pageX and pageY are both 0, then it means the dragleave was because the user left the window, rather than dragged over one of the dropzones.

2
For which purpose to you want to show the overlay? To stop file upload?Sarath Kumar
The page, by default, will show files that have already been uploaded. When the user drags a file onto the screen, the overlay will show the available folders they can upload to (kind of like how imgur.com handles file upload overlays, except with multiple dropzones and no global dropzone). So, the purpose of the overlay is to show the folder dropzones to the user.Buns of Aluminum
You simply want to show the overlay or expecting user input like selecting folder from the overlay?Sarath Kumar
I want to show the overlay when the user drags a file. The overlay contains the dropzones for the file. The user would then drop the file onto one of the overlay's dropzones and the overlay would go away.Buns of Aluminum
This answer gives a little bit more details about this issue stackoverflow.com/questions/12945307/…Heni Székely

2 Answers

0
votes

The dragleave event fires very quick than we thought so we can delay the process.

 Dropzone.autoDiscover = false;
$("div#upload").dropzone({
    url: "upload.php",
    addRemoveLinks:true,
    paramName:"composeUpload",
    init: function() {
        myDropZone = this;
        this.on('dragover', function(e,xhr,formData){
           $('.overlay').fadeIn();
          stopLoading(); //stops local file opens
            return false;
        });
      this.on('dragleave', function(e,xhr,formData){
           setTimeout(function(){
             $('.overlay').fadeIn();
           },8000);
        });           
    }
});

if you drop files on empty div or a overlay the browser will open the file locally so we have to stop the default

function stopLoading(){
   window.addEventListener("dragover",function(e){
    e = e || event;
    e.preventDefault();
   },false);
  window.addEventListener("drop",function(e){
    e = e || event;
    e.preventDefault();
  },false);
}

I don't this is the answer you looking for but definitely it will give you a idea.thanks.

0
votes

In this specific scenario (using Dropzone instances in an fullscreen overlay that's only visible when dragging a file and where you only want users to drop files onto the dropzones and not the whole overlay), here is what I did to solve the problem.

  • Listen on the window for "dragenter"
    • if the event dataTransfer object has a types array with 1 item present and types[0] == "Files" then show the overlay (this way we don't show the overlay if something like text is being dragged)
  • Listen on the overlay for "dragleave"
    • if the dragleave event pageX and pageY are both 0, then the user dragged out of the document and we should hide the overlay, otherwise they are dragging over one of the dropzones
  • Listen on the overlay for "dragover"
    • if there are any elements on the screen with a class of "dz-drag-hover" then set the event dataTransfer.dropEffect to "copy" because we're hovering over a dropzone
    • else set the event dataTransfer.dropEffect to "none" and preventDefault()

Here's some untested javascript for the above:

function handleDragEnter( e ) {
    // make sure we're dragging a file
    var dt = ( e && e.dataTransfer );
    var isFile = ( dt && dt.types && dt.types.length == 1 && dt.types[0] == "Files" );
    if ( isFile ) {
        // and, if so, show the overlay
        showOverlay();
    }
}

function handleDragLeave( e ) {
    // was our dragleave off the page?
    if ( e && e.pageX == 0 && e.pageY == 0 ) {
        // then hide the overlay
        hideOverlay();
    }
}

function handleDragOver(e) {
    // look for any dropzones being hovered
    var isHovering = document.getElementsByClassName( "dz-drag-hover" ).length > 0;
    if ( isHovering ) {
        // found some? then we're over a dropzone and want to allow dropping
        e.dataTransfer.dropEffect = 'copy';
    } else {
        // we're just on the overlay. don't allow dropping.
        e.dataTransfer.dropEffect = 'none';
        e.preventDefault();
    }
}

function showOverlay() {
    // only show the overlay if it's not already shown (can prevent flickering)
    if ( getComputedStyle(overlay, null).display == "none" ) 
        overlay.style.display = "block";
    }
}

function hideOverlay() {
    overlay.style.display = "none";
}

// listen to dragenter on the window for obvious reasons
window.addEventListener("dragenter", handleDragEnter);
// our fullscreen overlay will cover up the window, so we need to listen to it for dragleave events
overlay.addEventListener("dragleave", handleDragLeave);
// same thing for dragover
overlay.addEventListener("dragover", handleDragOver);