How can I filter out directories from upload handler in Firefox?

后端 未结 3 917
慢半拍i
慢半拍i 2021-01-18 22:37

Problem

I have following code snippet that is used to get file information during file drag and drop upload:

var files = event.dataT         


        
相关标签:
3条回答
  • 2021-01-18 23:16

    You can read a little about this in here (including Firefix). Here is a function (not made by me but I edited maybe a half of it) that detects whether drop is file or folder and shows its name, size and what type (tested in FireFox):

    function handleDrop(e)
    {
        e.stopPropagation();
        e.preventDefault();
        var filesInfo = "";
    
        var files = e.dataTransfer.files,
            folder;
    
        for (var i = 0, f; f = files[i]; i++)
        {
            if (!f.type && f.size % 4096 == 0)
                folder = true;
            else
                folder = false;
    
            filesInfo += 'Name: ' +  f.name;
            filesInfo += '<br>Size: ' +  f.size + ' bytes';
            filesInfo += '<br>Type: ' +  (folder ? 'folder ' : 'file');
    
            output.innerHTML = filesInfo;
        }
    }
    

    I hope that's what you were looking for. Good luck!

    0 讨论(0)
  • 2021-01-18 23:29

    Solution

    I came up with following dirty workaround that works on Firefox version - 46.0.1

    It uses FileReader API to check if uploaded file is directory or not.

    Code

    <div id="dropArea" style="border: 1px solid; padding: 50px; text-align: center;">
        Drop your files here!
    </div>
    
    <script>
        // Get target elements.
        var dropArea = document.getElementById("dropArea");
    
        // To be defined.
        function notDirectory(file) {
            return new Promise(function(resolve, reject) {
                var reader = new FileReader();
    
                // Can read files, but not directories.
                reader.onprogress = function(event) {
                    if ('progress' === event.type) {
                        resolve(file);
                        reader.abort();
                    }
                };
    
                // Wait for result.
                reader.readAsDataURL(file);
            });
        }
    
        // Attach drop listener.
        dropArea.addEventListener("drop", function (event) {
            // Stop propagation.
            event.stopPropagation();
            event.preventDefault();
    
            // Loop files to filter out directories and print files.
            var files = event.dataTransfer.files;
            for (var i = 0; i < files.length; i++) {
                var file = files[i];
    
                // I need notDirectory(file) function.
                notDirectory(file).then(function(file) {
                    // Print info.
                    console.log({
                        name: file.name,
                        size: file.size,
                        type: file.type
                    });
                });
            }
        });
    
        // Attach drag move listener.
        dropArea.addEventListener("dragover", function (event) {
            // Stop propagation.
            event.stopPropagation();
            event.preventDefault();
        });
    </script>

    Related Links

    • FileReader API
    • JavaScript Promise
    0 讨论(0)
  • 2021-01-18 23:42

    My question would be is there any workaround for latest stable Firefox version to detect directories? Because on stable version that feature is disabled by default or do I miss something?

    Directory upload was not enabled by default at firefox 47, where tried html, javascript at stacksnippets, jsfiddle.

    See Firefox 42 for developers Interfaces/APIs/DOM

    The Directory interface has been experimentally extended (bug 1177688). The two members Directory.path and Directory.getContents can be exposed by setting the dom.input.dirpicker preference to true.

    A workaround to detect folder upload could include

    1. Use <input type="file"> with directory and allowdirs attributes set, possibly including multiple attribute, see Note, for drag and drop or user selection on click of container;
    2. Open prefs.js or about:config and set dom.input.dirpicker preference to Boolean true;
    3. Use modified version of "Code example" for "1. File input" at Directory Upload Demo;
    4. To check if upload is a Directory and not a single File object, use if with condition (filesAndDirs[0] && filesAndDirs[0].constructor.name === "Directory") or (filesAndDirs[0] instanceof Directory) inside of .then(function(filesAndDirectories){}) at chained to .getFilesAndDirectories();
    5. Substitute <label> element for <div> element as parent of <input type="file">. Adjust css of input type="file" to fill parent droppable container and set opacity to 0; adjust css at parent element of input type="file" to display text at :before pseudo-element, over input type="file" child element.

    See also New API for directory picking and drag-and-drop.

    Note, approach was tried at firefox 47, where both directories and individual files were successfully uploaded.

    var dropArea = document.getElementById("dropArea");
    var output = document.getElementById("result");
    var ul = output.querySelector("ul");
    
    function dragHandler(event) {
      event.stopPropagation();
      event.preventDefault();
    
      dropArea.className = "area drag";
    }
    
    function filesDroped(event) {
      event.stopPropagation();
      event.preventDefault();
      dropArea.className = "area";
    
      var uploadFile = function(file, path) {
        // handle file uploading
        console.log(file, path);
        var filesInfo = `<li>
                            Name: ${file.name}</br> 
                            Size: ${file.size} bytes</br> 
                            Type: ${file.type}</br> 
                            Modified Date: ${file.lastModifiedDate}
                          </li>`;
        ul.innerHTML += `${filesInfo}`;
      };
    
      var iterateFilesAndDirs = function(filesAndDirs, path) {
        for (var i = 0; i < filesAndDirs.length; i++) {
          if (typeof filesAndDirs[i].getFilesAndDirectories === 'function') {
            var path = filesAndDirs[i].path;
    
            // this recursion enables deep traversal of directories
            filesAndDirs[i].getFilesAndDirectories()
              .then(function(subFilesAndDirs) {
                // iterate through files and directories in sub-directory
                iterateFilesAndDirs(subFilesAndDirs, path);
              });
          } else {
            uploadFile(filesAndDirs[i], path);
          }
        }
      };
      if ("getFilesAndDirectories" in event.target) {
        event.target.getFilesAndDirectories()
          .then(function(filesAndDirs) {
            // if directory
            var dir = filesAndDirs;
            if (dir[0] && dir[0].constructor.name === "Directory") {
              
              console.log(dir);
              var directoryInfo = `<li>
                            Directory Name: ${dir[0].name}</br> 
                            Path: ${dir[0].path}
                          </li>`;
              ul.innerHTML += `${directoryInfo}`;
              alert("isDirectory:true");
            }
            iterateFilesAndDirs(dir, "/");
          })
    
      } else {
        // do webkit stuff
      }
    }
    
    dropArea.addEventListener("dragover", dragHandler);
    dropArea.addEventListener("change", filesDroped);
    input[type="file"] {
      width: 98%;
      height: 180px;
    }
    
    label[for="file"] {
        width: 98%;
      height: 180px;
    }
    
    .area {
      display:block;
      border: 5px dotted #ccc;
      text-align: center;
    }
    
    .area:after {
      display: block;
      border:none;
      white-space: pre;
      /*content: "Drop your files here!\aOr click to select files";*/
      position: relative;
      left: 0%;
      top: -75px;
      text-align:center;
    }
    
    .drag {
      border: 5px dotted green;
      background-color: yellow;
    }
    
    #result ul {
      list-style: none;
      margin-top: 20px;
    }
    
    #result ul li {
      border-bottom: 1px solid #ccc;
      margin-bottom: 10px;
    }
    <label id="dropArea" class="area">
      <input id="file" type="file" allowdirs directory webkitdirectory/>
    </label>
    <output id="result">
      <ul></ul>
    </output>

    jsfiddle https://jsfiddle.net/exs3ta25/31/

    0 讨论(0)
提交回复
热议问题