- Open an image editing program, copy an image (don't copy from a browser - I'll explain why later).
- Open Firefox and go to
- 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?
- 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.
- 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?
Share Improve this question edited May 23, 2017 at 12:09 CommunityBot 11 silver badge asked Jan 27, 2014 at 10:00 RomanRoman 6,4281 gold badge30 silver badges49 bronze badges1 Answer
Reset to default 18Disclaimer: 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: {
$puterButton: $("#gallery-upload-buttons #file-wrapper"),
$webButton: $("#gallery-upload-buttons #url"),
$puterButtonGlobal: $("#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 pletely sent (it can be long with high-res photo)
- Analyze the base64 string obtained.
Here's the code extracted from the global.js
and mented 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 = ""
},