如何使用更改和删除事件在 firefox 和 chrome/chromium 上上传和列出目录

     2023-02-23     212

关键词:

【中文标题】如何使用更改和删除事件在 firefox 和 chrome/chromium 上上传和列出目录【英文标题】:How to upload and list directories at firefox and chrome/chromium using change and drop events 【发布时间】:2017-02-01 13:03:04 【问题描述】:

mozilla 和 webkit 浏览器现在都允许上传目录。当在<input type="file">元素处选择一个或多个目录或在一个元素处拖放时,如何在firefox和chrome/chromium中按照它们在实际目录中出现的顺序列出所有目录和文件,并在所有上传目录时对文件执行任务迭代了吗?

【问题讨论】:

你还缺少什么信息? @KScandrett 没有关于从 firefox 或 chromium 的目录创建文件数组,这是我知道的。 Answer 中的listDirectory()listFile() 函数可能仍需要改进,以便在每个浏览器中获取和列出准确的结果。上次处理这些函数时,如果没记错的话,要获得文件对象的正确父目录是一项挑战,其中包含文件的目录也包含目录。 Answer 有一个TODO,主要尝试了chromium的listDirectories()listFiles() @KScandrett 如果您开发了与当前答案不同的方法来满足要求,请发布您的答案 @KScandrett 决定不选择“要求的规范答案”,这可能是适用的,因为已经编写了自己的答案来获取文件作为问题的单个数组部分;潜在地查看其他 SO 查看器和用户如何处理将文件作为单个数组获取并在 HTML 中创建呈现的目录和文件树的要求,从而在 chromium/chrome 和 firefox 浏览器中一致地准确反映上传的文件夹的目录树。 【参考方案1】:

您可以在<input type="file">元素处设置webkitdirectoryallowdirs属性;将changedrop 事件附加到<input type="file"> 元素;在 mozilla 中使用 .getFilesAndDirectories().createReader().readEntries() webkitArray.prototype.reduce()Promise,递归。

注意 firefox drop 事件不会将选择列为Directory,而是将File 对象列为具有size 0 的对象,因此在firefox 中删除目录不提供已删除文件夹的表示,即使在@使用 987654340@。当设置allowdirs 属性时,firefox 还提供了两个输入元素;第一个元素允许上传单个文件,第二个元素允许上传目录。 chrome/chromium 提供单个 <input type="file"> 元素,其中只能选择单个或多个目录,而不是单个文件。

在同时包含文件和目录的目录中,首先读取目录。

<!DOCTYPE html>
<html>

<head>
  <style type="text/css">
    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 or folders here!\aOr click to select files folders";
      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;
    

    #result li span 
      font-weight: bold;
      color: navy;
    
  </style>
</head>


<body>
  <label id="dropArea" class="area">
    <input id="file" type="file" directory allowdirs webkitdirectory/>
  </label>
  <output id="result">
    <ul></ul>
  </output>
  <script>
    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) 
      var webkitResult = [];
      var mozResult = [];
      var files;
      console.log(event);
      event.stopPropagation();
      event.preventDefault();
      dropArea.className = "area";

      // do mozilla stuff
      // TODO adjust, call `listDirectory()`, `listFile()`
      function mozReadDirectories(entries, path) 
        console.log("dir", entries, path);
        return [].reduce.call(entries, function(promise, entry) 
            return promise.then(function() 
              return Promise.resolve(entry.getFilesAndDirectories() || entry)
                .then(function(dir) 
                  return dir
                )
            )
          , Promise.resolve())
          .then(function(items) 
            var dir = items.filter(function(folder) 
              return folder instanceof Directory
            );
            var files = items.filter(function(file) 
              return file instanceof File
            );
            if (files.length) 
              // console.log("files:", files, path);
              files.forEach(function(file) 
                console.log(file)
              );
              mozResult = mozResult.concat.apply(mozResult, files);
            
            if (dir.length) 
              // console.log(dir, dir[0] instanceof Directory);
              return mozReadDirectories(dir, dir[0].path || path);

             else 
              if (!dir.length) 
                return Promise.resolve(mozResult).then(function(complete) 
                  return complete
                )
              
            

          )

      ;

      function handleEntries(entry) 
        let file = "webkitGetAsEntry" in entry ? entry.webkitGetAsEntry() : entry
        return Promise.resolve(file);
      

      function handleFile(entry) 
        return new Promise(function(resolve) 
          if (entry.isFile) 
            entry.file(function(file) 
              listFile(file, entry.fullPath).then(resolve)
            )
           else if (entry.isDirectory) 
            var reader = entry.createReader();
            reader.readEntries(webkitReadDirectories.bind(null, entry, handleFile, resolve))
           else 
            var entries = [entry];
            return entries.reduce(function(promise, file) 
                return promise.then(function() 
                  return listDirectory(file)
                )
              , Promise.resolve())
              .then(function() 
                return Promise.all(entries.map(function(file) 
                  return listFile(file)
                )).then(resolve)
              )
          
        )

        function webkitReadDirectories(entry, callback, resolve, entries) 
          console.log(entries);
          return listDirectory(entry).then(function(currentDirectory) 
            console.log(`iterating $currentDirectory.name directory`, entry);
            return entries.reduce(function(promise, directory) 
              return promise.then(function() 
                return callback(directory)
              );
            , Promise.resolve())
          ).then(resolve);
        

      
      // TODO: handle mozilla directories, additional directories being selected dropped and listed without
      // creating nested list at `html` where different directory selected or dropped
      function listDirectory(entry) 
        console.log(entry);
        var path = (entry.fullPath || entry.webkitRelativePath.slice(0, entry.webkitRelativePath.lastIndexOf("/")));
        var cname = path.split("/").filter(Boolean).join("-");
        console.log("cname", cname)
        if (!document.getElementsByClassName(cname).length) 
          var directoryInfo = `<li><ul class=$cname>
                      <li>
                      <span>
                        Directory Name: $entry.name<br>
                        Path: $path
                        <hr>
                      </span>
                      </li></ul></li>`;
          var curr = document.getElementsByTagName("ul");
          var _ul = curr[curr.length - 1];
          var _li = _ul.querySelectorAll("li");
          if (!document.querySelector("[class*=" + cname + "]")) 
            if (_li.length) 
              _li[_li.length - 1].innerHTML += `$directoryInfo`;
             else 
              _ul.innerHTML += `$directoryInfo`
            
           else 
            ul.innerHTML += `$directoryInfo`
          
        
        return Promise.resolve(entry);
      
       // TODO: handle mozilla files
      function listFile(file, path) 
        path = path || file.webkitRelativePath || "/" + file.name;
        var filesInfo = `<li>
                        Name: $file.name</br> 
                        Size: $file.size bytes</br> 
                        Type: $file.type</br> 
                        Modified Date: $file.lastModifiedDate<br>
                        Full Path: $path
                      </li>`;

        var currentPath = path.split("/").filter(Boolean);
        currentPath.pop();
        var appended = false;
        var curr = document.getElementsByClassName(`$currentPath.join("-")`);
        if (curr.length) 
          for (li of curr[curr.length - 1].querySelectorAll("li")) 
            if (li.innerHTML.indexOf(path.slice(0, path.lastIndexOf("/"))) > -1) 
              li.querySelector("span").insertAdjacentHTML("afterend", `$filesInfo`);
              appended = true;
              break;
            

          
          if (!appended) 
            curr[curr.length - 1].innerHTML += `$filesInfo`;
          
        
        console.log(`reading $file.name, size: $file.size, path:$path`);
        webkitResult.push(file);
        return Promise.resolve(webkitResult)
      ;

      function processFiles(files) 
        Promise.all([].map.call(files, function(file, index) 
            return handleEntries(file, index).then(handleFile)
          ))
          .then(function() 
            console.log("complete", webkitResult)
          )
          .catch(function(err) 
            alert(err.message);
          )
      

      if ("getFilesAndDirectories" in event.target) 
        return (event.type === "drop" ? event.dataTransfer : event.target).getFilesAndDirectories()
          .then(function(dir) 
            if (dir[0] instanceof Directory) 
              console.log(dir)
              return mozReadDirectories(dir, dir[0].path || path)
                .then(function(complete) 
                  console.log("complete:", complete);
                  event.target.value = null;
                );
             else 
              if (dir[0] instanceof File && dir[0].size > 0) 
              return Promise.resolve(dir)
                    .then(function(complete) 
                      console.log("complete:", complete);
                    )
               else 
                if (dir[0].size == 0) 
                  throw new Error("could not process '" + dir[0].name + "' directory"
                                  + " at drop event at firefox, upload folders at 'Choose folder...' input");
                
              
            
          ).catch(function(err) 
            alert(err)
          )
      

      // do webkit stuff
      if (event.type === "drop" && event.target.webkitdirectory) 
        files = event.dataTransfer.items || event.dataTransfer.files;
       else if (event.type === "change") 
        files = event.target.files;
      

      if (files) 
        processFiles(files)
      

    
    dropArea.addEventListener("dragover", dragHandler);
    dropArea.addEventListener("change", filesDroped);
    dropArea.addEventListener("drop", filesDroped);
  </script>
</body>

</html>

plnkrhttp://plnkr.co/edit/ff5vmuuIMzSapu6MiUJ3?p=preview

【讨论】:

见File and Directory Entry API

在 NextJs 中如何使用更改事件更改 getServerSideProps

】在NextJs中如何使用更改事件更改getServerSideProps【英文标题】:InNextJshowtochangegetServerSidePropswithchangeevent【发布时间】:2021-01-1303:10:14【问题描述】:这里我正在尝试根据类别更改产品数据,我有一个索引页和两个名为Products和Cat... 查看详情

使用 FireFox、Safari 和 Chrome 在剪贴板上复制/放置文本

】使用FireFox、Safari和Chrome在剪贴板上复制/放置文本【英文标题】:Copy/PuttextontheclipboardwithFireFox,SafariandChrome【发布时间】:2010-09-1217:25:12【问题描述】:在InternetExplorer中,我可以使用clipboardData对象访问剪贴板。如何在FireFox、Sa... 查看详情

如何使用 C# 在文件观察器中捕获剪切和粘贴操作

】如何使用C#在文件观察器中捕获剪切和粘贴操作【英文标题】:HowtocapturecutandpasteactioninfilewatcherusingC#【发布时间】:2012-05-2312:31:11【问题描述】:我编写了文件观察器功能来专注于特定的目录活动。我可以阅读所有事件,如创... 查看详情

如何在 C++ 中监听智能卡插入和删除事件?

】如何在C++中监听智能卡插入和删除事件?【英文标题】:HowdoIlistenforsmartcardinsertandremoveeventinC++?【发布时间】:2011-11-2307:55:29【问题描述】:我想监听智能购物车的插入和删除事件...该应用程序适用于Windows,智能卡使用x.509证... 查看详情

在firefox中使用'deviceorientation'事件会发出警告(代码片段)

在firefox60控制台中运行以下代码时,会给我一条警告消息“不推荐使用方向传感器”。window.addEventListener('deviceorientation',function(event)console.log(event.alpha+':'+event.beta+':'+event.gamma););在firefox60和61(Beta)上在Windows和Mac上试过这个。警... 查看详情

如何在sqlalchemy中的值更改后触发事件

】如何在sqlalchemy中的值更改后触发事件【英文标题】:Howtotriggeraneventaftervaluechangeinsqlalchemy【发布时间】:2020-12-0417:56:38【问题描述】:我正在使用sqlalchemy定义一个映射类。它包含三个用户定义的值(a、b、c)和一个依赖值(ab... 查看详情

如何在 Firefox 中删除 SELECT/OPTION 下拉控件上的虚线?

】如何在Firefox中删除SELECT/OPTION下拉控件上的虚线?【英文标题】:HowcanIremovethedottedlinesonaSELECT/OPTIONdropdowncontrolinFirefox?【发布时间】:2011-06-2206:06:34【问题描述】:在Chrome和其他浏览器中,我的下拉菜单看起来很好:但是,在Fi... 查看详情

如何存储在Java中执行事件后更改的变量的最终值

】如何存储在Java中执行事件后更改的变量的最终值【英文标题】:howtostorethefinalvalueofavariablewhichchangesafteraneventisperformedinJava【发布时间】:2021-05-0919:22:26【问题描述】:我正在使用Swing和AWT组件开发Java睡眠周期计算器应用程序... 查看详情

在 firefox 中设置复选框的样式 - 删除检查和边框

】在firefox中设置复选框的样式-删除检查和边框【英文标题】:Styleacheckboxinfirefox—removecheckandborder【发布时间】:2013-10-0908:14:38【问题描述】:如何在Firefox中设置复选框的样式,并使复选标记和边框消失?http://jsfiddle.net/moneyloti... 查看详情

在 xul 和 javascript 中通过按钮单击事件上的另一个工具提示文本更改工具提示文本

...发布时间】:2011-03-0206:09:13【问题描述】:嗨我正在创建Firefox插件。我在Firefox网络浏览器的工具栏上创建了一个按钮图像。我已经为按钮分配了一个toolti 查看详情

检查设备更改(添加/删除)事件

...标或其他任何东西。我尝试四处搜索,但找不到任何说明如何执行此操作的内容。有什么想法吗?【问题讨论】:我制作了一个适用于Windows、MacOS和Linux的N 查看详情

检查设备更改(添加/删除)事件

...标或其他任何东西。我尝试四处搜索,但找不到任何说明如何执行此操作的内容。有什么想法吗?【问题讨论】:我制作了一个适用于Windows、MacOS和Linux的N 查看详情

如何使用 css 和/或 javascript 动态更改样式

】如何使用css和/或javascript动态更改样式【英文标题】:Howtodynamicchangestyleswithcssand/orjavascript【发布时间】:2019-08-1809:58:59【问题描述】:我有一个按钮,我需要在单击它时更改一些样式。我可能可以通过添加和删除一些类轻松... 查看详情

如何在 Selenium 的无头 Firefox 中使用 --screenshot 和 python

】如何在Selenium的无头Firefox中使用--screenshot和python【英文标题】:Howtouse--screenshotinheadlessfirefoxinSeleniumwithpython【发布时间】:2018-06-2301:07:50【问题描述】:使用@DebanjanB在HowtomakefirefoxheadlessprogramaticallyinSeleniumwithpython?中的回复,... 查看详情

在页面内容更改时停止自动滚动

...页面,它在滚动事件中向自身添加和删除一些内容。现在使用Chrome时(IE11似乎没有这种行为),每当向页面添加和删除内容时,都会生成滚动事件(我猜是为了保持客户端视图在页面更改时保持一致)。我不想要这个。内容变... 查看详情

如何使用 JavaScript 在 Firefox 中触发鼠标滚轮事件?

】如何使用JavaScript在Firefox中触发鼠标滚轮事件?【英文标题】:HowtofiremousewheeleventinFirefoxwithJavaScript?【发布时间】:2011-10-0719:52:21【问题描述】:我正在尝试使用WebDriver进行自动化测试,但它目前无法模拟鼠标滚轮事件。作为... 查看详情

更改视图的 y 位置会删除点击事件

...齐,并偏移-154,因此它在屏幕外)。当应用启动时,我使用一个按钮将整个根视图向上移动self.view.center.y-=154根视图和我的UIView都出现在预 查看详情

知道如何在 Firefox 和 ie 上使用可用的 webkit 填充吗?

】知道如何在Firefox和ie上使用可用的webkit填充吗?【英文标题】:Anyideahowtousewebkitfillavailableworkingonfirefoxandie?【发布时间】:2019-03-0404:51:45【问题描述】:我使用css:width:-webkit-fill-available;height:-webkit-fill-available;对于我的图像,... 查看详情