How does image pasting in imgur work in Firefox?
clipboard, firefox, html, imgur, javascript
Solution
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:
- Wait the user to make the Ctrl-V action
- When it's fired, make the `contenteditable` div seen before in focus, to retrieve data
- Wait data are completely sent (it can be long with high-res photo)
- Analyze the base64 string obtained.
Here'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 = ""
},
Problem
- Open an image editing program, copy an image (don't copy from a browser - I'll explain why later). - Open Firefox and go to http://imgur.com - Press Ctrl+V - Look with utter amazement at the image you copied before being uploaded. 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?