I know about the HTML5 Clipboard API, that works great with Chrome. In Chrome, when you paste binary image data, the browser fires a paste
event containing event.clipboardData.types
which is equal to ['Files']
, I can therefore get my image in the clipboard with
var index = event.clipboardData.types.indexOf('Files');
if(index !== -1) {
var blob = event.clipboardData.items[index].getAsFile();
}
In Firefox, when I paste binary image data, the browser also fires a paste event, but event.clipboardData.types
is empty (has length === 0
) and event.clipboardData.getData('Files')
returns obviously ""
.
By the way, copying an image from a browser also sets a "text/html" item in clipboardData
that holds the copied <img>
element. So in those cases I could work around the problem by sending the remote url to the server, which would then download the image itself (if the server has access to the remote location, which isn't really guaranteed).
StackOverflow suggests this:
How to obtain data from clipboard in Firefox
(create a contenteditable <div>
, ask the user to paste into that and then copy the contents.)
However, imgur does not do that. How does that work?
Disclaimer: I didn't know the imgur upload system before posting, but I hope it'll help you. This post is written just by looking into the code and with some HTML/JS knowledge :)
imgur seems to use a different paste option for Firefox (and Gecko browsers in general). Indeed, there's a div with the upload-global-FF-paste-box
ID in the index HTML, with the attribute contenteditable="true"
. In the main js, we can found the initialization of a property $FFPasteBox
:
init: function (a) {
this._ = $.extend({
el: {
$computerButton: $("#gallery-upload-buttons #file-wrapper"),
$webButton: $("#gallery-upload-buttons #url"),
$computerButtonGlobal: $("#upload-global-file"),
$FFPasteBox: $("#upload-global-FF-paste-box") // <--- this line
}
}, a)
},
Then, by digging a little in the global.js
file, I found these functions (see above). Basically, the process is:
contenteditable
div seen before in focus, to retrieve dataHere's the code extracted from the global.js
and commented by myself:
// When a paste action is trigger, set the focus on this div and wait the data to be sent
initPasteUploadMozilla: function () {
$(document).on("paste", _.bind(function (a) {
$(a.target).is("input") || this.isInView() && (Imgur.Upload.Index && this.showColorBox(), this._.el.$FFPasteBox.focus(), this.waitForPasteData(this._.el.$FFPasteBox[0]))
}, this))
},
// Listen the user, and waiting that the node is created by the paste action
waitForPasteData: function (a) {
a.childNodes && a.childNodes.length > 0 ? this.processPaste(a) : setTimeout(this.waitForPasteData.bind(this, a), 20)
},
// Check data sent
processPaste: function (a) {
var b = a.innerHTML,
// Check if the thing pasted is a <img tag or a png or at least base64 stuff
c = {
image: -1 != b.indexOf("<img") && -1 != b.indexOf("src="),
base64: -1 != b.indexOf("base64,"),
png: -1 != b.indexOf("iVBORw0K")
};
if (c.image && c.base64 && c.png) {
var d = b.split('<img src="');
d = d[1].split('" alt="">');
var b = {
dataURL: d[0],
file: {
size: this.bytesizeBase64String(d[0].length)
}
};
this.addBase64(b)
} else {
var e = $(a).find("img"),
f = null;
if (e.length > 0 && e.attr("src").length > 0 ? f = e.attr("src") : b.length > 0 && (f = b), null !== f && f.match(this._.urlRegex)) this.queueUrl(f);
else if (null !== f) {
var g = $(f).filter("a");
g.length && g.attr("href").match(this._.urlRegex) ? this.queueUrl(g.attr("href")) : this.showError(this._.messages.urlInvalidError)
}
}
a.innerHTML = ""
},