Pennywise Pennywise - 27 days ago 5
Javascript Question

File drag and drop in IE11 and Firefox

I am trying to create a drop box where image files can be dragged for upload. This works fine in Chrome and Edge. However, I am having troubles in Firefox and IE 11. For example, in IE 11, when I click on the browse button, a window pops up titled, "Choose File to Upload." If I click an Image and click "open" it works fine, but I can't drag any files out of the window. However, if I open my file explorer, I can drag and drop images just fine from the File Explorer window. A similar thing happens in Firefox. I can drag images from File Explorer just fine, but when I try to drag from the popup window titled "File Upload", I get a ghost image with a circle and red slash. Some threads here have suggested using a dragstart function, but that does not seem to be working, probably because the documentation says "Note that dragstart and dragend events are not fired when dragging a file into the browser from the OS." https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API

So is there a way I can drag files from the file upload window in these browsers as opposed to having to open file explorer? Again, I can drag and drop from the popup in Chrome and Edge.

Here is my HTML:

Files: <input type="file" id="fileInput" name="files" multiple><br />

<div id="selectedFiles"></div>

<div class="picList">
<div id="dropbox" style="border:1px solid black;height:500px;">
Drop Here
</div>
</div>


Here is my javascript:

dropbox = document.getElementById("dropbox");
dropbox.addEventListener("dragenter", dragenter, false);
dropbox.addEventListener("dragover", dragover, false);
dropbox.addEventListener("drop", drop, false);
function dragenter(e) {
e.stopPropagation();
e.preventDefault();
}

function dragover(e) {
e.stopPropagation();
e.preventDefault();
}
function drop(e) {
e.stopPropagation();
e.preventDefault();

var dt = e.dataTransfer;
var files = dt.files;

handleFiles(files);
}


Any advice?

Edit:

Here is my handleFiles function (dupCheck is an array to check for duplicates and stored files is an array of files to be uploaded, which I need because I want users to be able to delete a file by deleting the preview image and HTML FileReader is read only so I can't delete single images directly from the file stack.):

function handleFiles(files) {
for (var i = 0; i < files.length; i++) {
var file = files[i];
var imageType = /^image\//;

if (!imageType.test(file.type)) {
continue;
}
var img = document.createElement("img");
img.classList.add("obj");
img.file = file;
$(img).addClass('selFile');
$(img).attr('data-file', file.name);
var A = [];
for (var z = 0; z < dupCheck.length; z++) {
A.push(dupCheck[z].name)
}
if (!A.includes(file.name)) {
storedFiles.push(file);
var _checker = { name: file.name };
dupCheck.push(_checker);
dropbox.appendChild(img);
var reader = new FileReader();
reader.onload = (function (aImg) { return function (e) { aImg.src = e.target.result; }; })(img);
reader.readAsDataURL(file);
A = [];
};
}
}

Answer

You can substitute using two <input type="file"> elements for drag and drop events. Drop selected files at <label> element having <input type="file"> control having opacity set to 0.

<!DOCTYPE html>
<html>

<head>
  <style type="text/css">
    #drop {
      opacity: 0;
    }
    #drop,
    label[for="drop"] {
      height: 500px;
      width: 500px;
    }
    label[for="drop"] {
      display: block;
      border: 1px solid black;
    }
  </style>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.js">
  </script>
  <script>
    $().ready(function() {
      var selectedFiles = $("#selectedFiles");
      
      function handleFiles(e) {
        var files = e.target.files;
        var input = this;

        for (var i = 0; i < files.length; i++) {
          (function(i, input) {
            var file = files[i];
            var figure = $("<figure></figure>", {
              append: $("<figcaption></figcaption>", {
                html: file.name
              })
            });

            var img = $("<img>").on("load", function() {
              selectedFiles.append(figure.prepend(img));
              input.value = null;
            });

            var reader = new FileReader();
            reader.onload = function(e) {
              img.attr("src", e.target.result);
            };
            reader.readAsDataURL(file);
          })(i, input);

        }
      }
      $(".fileInput").change(handleFiles);

    })
  </script>
</head>

<body>
  Files:
  <input type="file" 
         accept="image/*" 
         class="fileInput" 
         name="files0" 
         multiple="multiple" />
  <br />

  <div class="picList">

    <label for="drop" id="dropbox">
      Drop Here
      <input type="file" 
             accept="image/*" 
             id="drop" 
             class="fileInput" 
             name="files1" 
             multiple="multiple" />
    </label>
  </div>
  <div id="selectedFiles"></div>
</body>

  
</html>