我有一个内容可编辑的元素,我有文本和位图数据粘贴工作但是当有人将实际文件粘贴到元素中时,图标被加载而不是图像。
报告了正确的图像名称,类型和大小,但加载时只有Firefox中的图标和Safari中的图标仅适用于某些图像。
这在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。