将文件复制并粘贴到内容可编辑div时出错

时间:2018-01-31 00:06:00

标签: javascript firefox safari

我有一个内容可编辑的元素,我有文本和位图数据粘贴工作但是当有人将实际文件粘贴到元素中时,图标被加载而不是图像。

报告了正确的图像名称,类型和大小,但加载时只有Firefox中的图标和Safari中的图标仅适用于某些图像。  enter image description here

这在Firefox和Safari中发生。我已经创建了一个通用的jsfiddle和示例here以及下面的示例。

我正在使用各种方法来获取剪贴板数据,因为某些浏览器的工作方式略有不同(下面的代码)。

在某些情况下,我能够获得一个FileError代码4,其中代码4,FileError.NOT_READABLE_ERR也可能与某些图像在控制台中显示的错误相同。

  

无法加载资源:无法完成操作。   WebKitBlobResource错误4。

重现步骤:
1.从Finder中复制anyimage.png 2.右键单击内容可编辑div并选择粘贴(或使用Command + v)

显示的是图像图标。

  // Handle pasting into content editable element
  // 
  // three methods
  // 1. get image data from the clipboard items
  // 2. get image data from clipboard files
  // 3. wait and get image data from content editable div

  // handling these cases test
  // 1. get text pasted from clipboard
  // 2. get image pasted from clipboard
  // 3. get text from content editable element
  // 4. get image from content editable element
  // 5. get dropped file reference from Finder
  // 6. get pasted file reference from Finder
  // 
  // Item 6, get pasted file reference doesn't work in Firefox or Safari

processPaste = function(pasteData) {
  console.log("ProcessPaste called");
  var application = document.getElementById("application");
  var image = document.getElementById("image");
  var output = JSON.stringify(pasteData);
  console.log(pasteData);
  image.src = pasteData.dataURI;
  //image.style.width = "100px";
  //image.style.height = "100px";
  //document.body.appendChild(image);
  //console.log(pasteData);
  //console.log(output);
  application.innerHTML = output.split(",").join(",\n\t");
}

addPasteListeners = function (id, debug) {
  var useCapture = true;
  var eventName = "paste";
  var element;

  if (id=="body") {
    element = document.body;
  }
  else if (id=="window") {
    element = window;
  }
  else {
    element = document.getElementById(id);
  }

  if (debug) {
    console.log("Adding listener for: " + eventName + " to " + element);
  }

  if (element==null) {
    if (debug) console.log("Element was not found: " + id);
    return true;
  }

  if (application==null) {
    if (debug) console.log("application was not found: " + objectId);
    return true;
  }


  var pasteFunction = function(event) {
    var isDefaultPrevented = false;
    var items = [];
    var numberOfItems = 0;
    var numberOfFiles = 0;
    var numberOfNodes = 0;
    var files;
    var fileObject;
    var reader;
    var clipboardData;
    var itemType;
    var itemKind;
    var blob;
    var types;
    var type;
    var quality = 1;
    var clipboardItems = [];
    var clipboardFiles = [];
    var useFileArray = false;
    var childNodes;
    var loadedFile;
    const PLAIN_TEXT = "text/plain";
    const IMAGE_PNG = "image/png";
    const INVALID = "invalid";


    if (debug) console.log("Paste event handler");

    clipboardData = event.clipboardData || event.originalEvent.clipboardData;
    types = clipboardData.types;

    if (clipboardData.items && clipboardData.items.length) {
      items = clipboardData.items; // DataTransferItem in DataTransferItemList
      for(var k=0;k<items.length;k++) {
        clipboardItems.push({kind:items[k].kind, type:items[k].type});
      };
      numberOfItems = items.length;
    }

    // if files available use them instead of clipboard
    if (clipboardData.files && clipboardData.files.length) {
      items = clipboardData.files; // File in FileList
      for(var m=0;m<items.length;m++) {
        clipboardFiles.push({name:items[m].name,type:items[m].type,size:items[m].size}); // file
      };
      numberOfFiles = items.length;
    }

    if (numberOfItems!=0 && numberOfFiles!=0 && useFileArray) {
      items = clipboardData.items;
    }

    files = {};
    fileObject = {};
    fileObject.type = INVALID;

    if (debug) console.log("Item count:" + items.length);
    if (debug) console.log(event);

    // dispatch before paste event
    fileObject.types = types;
    fileObject.numberOfItems = numberOfItems;
    fileObject.numberOfFiles = numberOfFiles;
    fileObject.clipboardItems = clipboardItems;
    fileObject.clipboardFiles = clipboardFiles;
    fileObject.numberOfNodes = 0;				
    fileObject.eventType = "paste";
    //debugger;

    // if no items in the clipboard loop through the container elements
    if (numberOfItems==0) {
      childNodes = element.childNodes;
      numberOfNodes = childNodes ? childNodes.length : 0;

      // we call this after a frame 
      getImageDataURI = function() {
        if (debug) console.log("GetImageDataURI");
        childNodes = element.childNodes;
        numberOfNodes = childNodes ? childNodes.length : 0;

        fileObject.numberOfNodes = numberOfNodes;

        for (var j = 0; j < numberOfNodes; j++) {
          var child = childNodes[j];
          var nodeType = child && "nodeType" in child ? child.nodeType : null;
          var tag = child && "tagName" in child && child.tagName ? child.tagName.toLowerCase() : "";
          var nodeName = child && "nodeName" in child && child.nodeName ? child.nodeName.toLowerCase() : "";

          fileObject.index = j;

          // type 3 is text node, 1 is html element
          if (debug) console.log("Text node:" + nodeName);

          // pasted file
          if (nodeName=="attachment" && child.file) {
            reader = new FileReader();
            reader.file = child.file;

            // file load handler
            reader.addEventListener("loadend", function (e) {
              var currentReader = e.target;

              loadedFile = currentReader.file; // our reference

              fileObject.origin = "fileFromContentEditable";
              fileObject.dataURI = currentReader.result;
              fileObject.name = loadedFile.name;
              fileObject.type = loadedFile.type;
              fileObject.kind = "kind" in loadedFile ? loadedFile.kind : null;


              if (debug) console.log("File loaded:" + fileObject.type);
              if (debug) console.log(loadedFile);
              if (debug) console.log(currentReader);

              processPaste(fileObject);
            });

            // file error handler
            // FileError.code is 4; FileError.NOT_READABLE_ERR = 4
            reader.addEventListener("error", function (e) {
              var currentReader = e.target;

              loadedFile = currentReader.file; // our reference

              fileObject.name = loadedFile.name;
              fileObject.error = e;
              if (debug) console.log("File loaded error:" + loadedFile.type);
              if (debug) console.log(loadedFile);
              if (debug) console.log(currentReader);

              processPaste(fileObject);
            });

            if (debug) console.log("Reading file as data URL");
            reader.readAsDataURL(reader.file);

          }

          else if (nodeName=="#text" || nodeType==3) {
            if (debug) console.log("Text data");
            type = PLAIN_TEXT;
            fileObject.value = child.nodeValue;
            fileObject.name = "";
            fileObject.type = type;
            fileObject.origin = "nodeValue";

            //fileObject.size = canvas.toBlob(callback); // convert to blob to get size

            processPaste(fileObject);
          }
          else if (tag === "img") {
            // fetching the blob via the URL - is returning TIFF on Safari
            var fetchFromURL = false;
            var image = child;
            type = IMAGE_PNG;

            // default is to draw to canvas. alternative is fetch from url
            if (!fetchFromURL) {

              var drawImage = function() {
                if (debug) console.log("Drawing image");
                var canvas = document.createElement("canvas");
                canvas.width = image.naturalWidth;
                canvas.height = image.naturalHeight;
                canvas.getContext("2d").drawImage(image, 0, 0);

                fileObject.dataURI = canvas.toDataURL(IMAGE_PNG, quality);
                fileObject.name = "";
                fileObject.type = type;
                fileObject.origin = "canvas";
                fileObject.width = image.naturalWidth;
                fileObject.height = image.naturalHeight;

                //fileObject.size = canvas.toBlob(callback); // convert to blob to get size
                if (debug) console.log("Image captured:" + type);

                processPaste(fileObject);
              }

              if (image.naturalWidth) {
                drawImage();
              } 
              else {
                image.onload = drawImage;
              }
            }
            else {
              var url = child.src;

              // read blob url into data uri
              if (url && url.indexOf("blob")===0) {
                if (debug) console.log("Parsing blob URL into DataURI");
                fileObject.origin = "DataURIFromBlobURI";

                var getDataURIFromBlobURI = function(url) {
                  return fetch(url).then(function(response) {
                    return response.blob();
                  }).then(function (blob) {
                    type = blob.type;
                    size = blob.size;
                    return new Promise(function(resolve, reject) {
                      const reader = new FileReader();
                      reader.onerror = reject;
                      reader.onloadend = function(progressEvent) {
                        return resolve(reader.result);
                      }
                      reader.readAsDataURL(blob);
                    }
                                      )}
                         )}

                getDataURIFromBlobURI(url).then(function(dataURI) {
                  if (debug) console.log("DataURI:" + dataURI);
                  fileObject.dataURI = dataURI;
                  fileObject.type = type;
                  fileObject.size = size;
                  processPaste(fileObject);
                }, function(err) {
                  if (debug) console.log("Read as URL error");
                  fileObject.name = null;
                  fileObject.dataURI = null;

                  processPaste(fileObject);
                })
              }
            }
          }
        }
      }

      window.key = setTimeout(getImageDataURI, 1);
      return;
    }

    //debugger;

    // loop through items in the clipboard - not supported in safari osx atm
    // item in items can be DataTransferItem or File
    for (var i = 0; i < numberOfItems; i++) {
      if (items[i]==null) continue; // clipboard items may be emptied
      // when item is DataTransferItem the value is "string" or "file". when item is File value is null
      itemKind = items[i].kind;
      itemType = Object.prototype.toString.call(items[i]).slice(8, -1);
      type = items[i].type; // mime type
      if (debug) console.log("Item["+i+"]: " + type);

      // local references seem to be overwritten when in a loop for some reason
      files[i] = items[i];

      if (debug) console.log(items[i]);

      // if DataTransferItem and is string
      if (itemKind=="string" && "getAsString" in items[i]) {
        items[i].getAsString(function(value) {
          fileObject.origin = "stringFromClipboard";

          fileObject.value = value;
          //fileObject.name = name;
          fileObject.type = type;
          fileObject.kind = itemKind;

          if (debug) console.log(itemKind + " from clipboard:" + value.slice(0, 100)+"...");

          processPaste(fileObject);
        });

        continue;
      }
      // if not string - DataTransferItem or File 
      else if (itemKind=="file" || itemType=="File") {
        if (debug) console.log("Pasted item is not string");

        if ("getAsFile" in items[i]) {
          blob = items[i].getAsFile();
        }
        else if ("webkitGetAsEntry" in items[i]) {
          blob = items[i].webkitGetAsEntry();
        }
        else if ("getData" in items[i]) {
          blob = items[i].getData();
          // is DataTransferItem
        }
        else if (items[i] instanceof File) {
          blob = items[i];
        }

        if (debug) console.log(blob);
      }

      if (blob==null) {
        fileObject.error = "content is null";
        fileObject.type = type;
        fileObject.kind = itemKind;
        processPaste(fileObject);
        continue;
      }

      reader = new FileReader();
      reader.file = files[i]; // keep a reference when out of loop

      // file load handler
      reader.addEventListener("loadend", function (e) {
        var currentReader = e.target;

        loadedFile = currentReader.file; // our reference

        if (clipboardFiles.length) {
          fileObject.origin = "fileFromClipboard";
        }
        else {
          fileObject.origin = "itemFromClipboard";
        }
        fileObject.dataURI = currentReader.result;
        fileObject.name = loadedFile.name;
        fileObject.type = loadedFile.type;
        fileObject.kind = "kind" in loadedFile ? loadedFile.kind : null;


        if (debug) console.log("File loaded:" + fileObject.type);
        if (debug) console.log(loadedFile);
        if (debug) console.log(currentReader);
        
        processPaste(fileObject);
      });

      // file error handler
      reader.addEventListener("error", function (e) {
        var currentReader = e.target;

        loadedFile = currentReader.file; // our reference

        fileObject.name = loadedFile.name;
        fileObject.error = e;
        if (debug) console.log("File loaded error:" + loadedFile.type);
        if (debug) console.log(loadedFile);
        if (debug) console.log(currentReader);

        processPaste(fileObject);
      });

      // if blob found read as data URI
      // typically image/png but could also be text/rtf, text/plain, text/html
      if (blob) {
        if (debug) console.log("Reading blob as data URL");
        reader.readAsDataURL(blob);
      }
    }

    if (debug) console.log("End of paste event handler");
  }

  element.addEventListener(eventName, pasteFunction, useCapture);


  if (debug) console.log("End of add paste listener");
  return true;
}

addPasteListeners("editor", true);
#image {
  outline: 1px solid blue;
  vertical-align: top;
  max-height:100%;
  max-width:100%;
}
#editor {
  background-color:rgb(220,220,220);
  height:120px;
  width:50%;
  display:inline-block;
  vertical-align:top;
}
#container {
  height:120px;
  width:100%;
}
#application {
  background-color:rgb(220,220,250);
  height:120px;
  width:99%;
  display:block;
}
[contenteditable]:focus {
  outline: none;
  border: 1px dashed black;
}
<div>Click on area below and then paste</div>
<div id="container">
  <div id="editor" contenteditable="true"></div>
  <img id="image">
</div>
<textarea id="application" contenteditable="true"></textarea>

这是JSFiddle

0 个答案:

没有答案