'HTML5 drag and drop and multiple file upload

I have an HTML form that contains a file input field with multiple file selection and I also have a drag and drop feature that I am working on as well. My question is how to integrate both of these features seamlessly if it is even possible?

Ideally, I would like the user to select their files either through drag'n'drop or through the file dialog box. Once the user is done selecting their files, click the form submit button to upload.

I guess the main uncertainty that I have is how to bind the files that were dragged and dropped to a file input field for form submission.



Solution 1:[1]

I wrote some jQuery code that does just that, tell me if it works for you.

<!DOCTYPE html>
<html>
  <head>
    <title>Multiple DnD Uploader</title>
    <link rel="stylesheet" href="style.css" />
    <script type = "text/javascript" src = "../music/jquery.js"></script>
    <script type="text/javascript">
      $(document).ready(function(){
        $('#drop').change(function(event){
          files = event.target.files;
          $('#drop').css('display', 'none');
          for(var i = 0, len = files.length; i < len; i++) {
            if((files[i].fileName+"").substring((files[i].fileName+"").length-4,(files[i].fileName+"").length)=='.mp3'){
            $.ajax({
              type: "POST",
              url: "uploader.php?id="+i,
              contentType: "multipart/form-data",
              headers: {
                "X-File-Name" : files[i].fileName,
                "X-File-Size" : files[i].fileSize,
                "X-File-Type" : files[i].type
              },
              beforeSend:  function() {
                $('#info').append('<li class="indicator"><span class="label">File Name :</span> '+files[i].fileName+' | <span class="label">Size :</span> ' + files[i].fileSize + ' | <img id="'+i+'" src="loading.gif" /></li>');
              },
              processData: false,
              data: files[i],
              success: function(data){
                $('#'+data).attr('src', 'check.png');
              },error: function(data){
                $('#info').append('Error: ' + data + '<br />');
              }
            });
            }else{
              $('#info').append('Error: Incorrect file type. Looking for .mp3');
            }
          }
        });
      });
    </script>
  </head>
  <body>
    <div id="drop">
      <h1>Drop files here</h1>
      <p>To add them as attachments</p>
      <input type="file" multiple="true" id="filesUpload" />
    </div>
    <div id="info">
    </div>
  </body>
</html>

And the PHP file looks like this:

<?php
  $headers = array();
  foreach ($_SERVER as $k => $v){   
    if(substr($k, 0, 5) == "HTTP_"){
      $k = str_replace('_', ' ', substr($k, 5));
      $k = str_replace(' ', '-', ucwords(strtolower($k)));
      $headers[$k] = $v;
    }
  } 
  $file = new stdClass;
  $file->name = basename($headers['X-File-Name']);
  $file->size = $headers['X-File-Size'];
  $file->content = file_get_contents("php://input");
  if(file_put_contents('files/'.$file->name, $file->content))
    echo $_GET['id'];
?>

Solution 2:[2]

I'm not entirely sure how you're doing it, so I'll tell you the way I do it and then try to answer your question.

  1. Set up event listeners for dropping and <input>'s change event.
    • for dropping: filesUpload.addEventListener("change", function () {traverseFiles(this.files);}, false);
    • for <input>: dropArea.addEventListener("drop", function (evt) {traverseFiles(evt.dataTransfer.files);}, false);
  2. traverseFiles that you see above is a function that gets a FileList (an array of Files), which are a part of the File API. This function then calls a function uploadFile for each File.
  3. uploadFile sends the File asynchronously via ajax (XMLHttpRequest.send(file)).

Now to answer your question how to bind the dropped files to an input field: you don't, you just do it the other way. You create an API or a wrapper for uploading files and then if the user drops files, you call this wrapper function. If the user clicks on the <input> field, you again call this wrapper (like I did with traverseFiles).

Makes sense? If it doesn't, tell me which part and I'll edit this answer / expand on it.

Solution 3:[3]

<input type=file multiple>
<div id='dropzone'>Drop Files Here</div>

onchange and ondrop events shuld bind a function with the variable to get file list.

var files=e.target.files||e.dataTransfer.files

Read This

Solution 4:[4]

You could use "HTML5-File-Uploader" which purports to do what you need as well as gracefully degrade for older browsers:

https://github.com/gre/HTML5-File-Uploader/wiki

I haven't tried it myself.

Alternatively, you could take a look at this page, which supplies all the code you need to do it yourself:

http://robertnyman.com/2010/12/16/utilizing-the-html5-file-api-to-choose-upload-preview-and-see-progress-for-multiple-files/

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Vap0r
Solution 2 duality_
Solution 3 kongaraju
Solution 4 james.garriss