Does HTML5/Javascript support dragging an image onto a webpage?
i.e.
Can I create a webpage to allow user to drag an image from another site directly onto a placeholder on my site (all client side), then use another button to upload that image back to server?
I can't tell for sure how all browsers did / do / will behave in such a case, but what I've seen is that when you drag an image from a webpage and drop it to a webpage (the same or an other one), browsers won't create a File (or Blob) from it, but only its markup.
This means that you will still be tied by cross-origin policies in this case, i.e you won't be able to access the data of the image file, and thus won't be able to send it to your server either.
But this won't prevent you from displaying this image on your page, nor to grab its src
.
So what you can do, is a two cases handling:
<img>
element and set its src
to a blobURI made from the File.text/html
item. If so, try to parse it and look for existing <img>
elements. If there are, you can adopt them in your current document for display. However to save it on your server, you will have to fetch from your server directly (which is not tied by the same-origin policies), and thus you will have to send this URIs to your server.var dropzone = document.getElementById('dropzone'),
send_btn = document.getElementById('send'),
res = document.getElementById('res'),
imgList = [];
dropzone.ondragover = function ondragover(e) {
e.preventDefault();
dropzone.classList.add('dragover');
};
dropzone.ondrop = function ondrop(e) {
e.preventDefault();
dropzone.classList.remove('dragover');
// try to get images from this dropevent
var imageObjects = retrieveImageData(e.dataTransfer);
if (!imageObjects) return;
imageObjects.forEach(function appendToDoc(imgObj) {
res.appendChild(imgObj.element);
});
// store it
imgList = imgList.concat(imageObjects);
if (imageObjects.length)
send_btn.disabled = false;
};
dropzone.ondragexit = function(ondragexit) {
dropzone.classList.remove('dragover');
};
function retrieveImageData(dT) {
// first try to get Files
var files = getFiles(dT);
if (files.length) {
return files;
}
// if none, try to get HTMLImage or SVGImage
var elems = getHTMLMarkup(dT);
if (elems && elems.length) {
return elems;
}
// we could also try to getData('text/plain') hoping for an url
// but this might not be such a good idea...
console.warn('unable to retrieve any image in dropped data');
}
function getFiles(dT) {
// quite simple: won't traverse folders
var files = [],
imgObj;
if (dT.files && dT.files.length) {
for (var i = 0; i < dT.files.length; i++) {
// only image Files
if (dT.files[i].type.indexOf('image/') === 0) {
imgObj = {
type: 'file',
element: new Image(),
file: dT.files[i]
};
imgObj.element.onerror = onIMGError;
imgObj.element.src = URL.createObjectURL(imgObj.file);
files.push(imgObj);
}
}
}
return files;
}
function getHTMLMarkup(dT) {
var markup = dT.getData('text/html');
if (markup) {
var doc = new DOMParser().parseFromString(markup, 'text/html');
var imgs = doc && doc.querySelectorAll('img,image') || [];
imgs.forEach(toImageObject);
return Array.prototype.map.call(imgs, toImageObject);
}
function toImageObject(element) {
var img;
if (element instanceof SVGImageElement) {
img = new Image();
img.src = element.getAttributeNS('http://www.w3.org/1999/xlink', 'href') ||
element.getAttribute('href');
} else {
img = document.adoptNode(element);
}
img.onerror = onIMGError;
return {
type: 'element',
element: img
};
}
}
// Once we got everything, time to retrieve our objects
send_btn.onclick = function sendData() {
var fD = new FormData();
// send Files data directly
var files = imgList.filter(function isFile(obj) {
return obj.type === 'file';
});
files.forEach(function appendToFD(obj) {
fD.append('files[]', obj.file);
});
// for elems, we will need to grab the data from the server
var elems = imgList.filter(function isElem(obj) {
return obj.type === "element";
});
var urls = elems.map(function grabURL(obj) {
return obj.element.src;
});
if (urls.length)
fD.append('urls', JSON.stringify(urls));
sendFormData(fD);
};
function sendFormData(fD) {
var xhr = new XMLHttpRequest();
xhr.open('POST', 'your_url');
// you would normally send it
//xhr.send(fD);
// but here we will just log the formData's content
var files = fD.getAll('files[]');
console.log('files: ', files);
var urls = fD.get('urls');
console.log('urls', urls);
}
// in case we can't load it
function onIMGError() {
var img = this;
var index = -1;
imgList.forEach(function search(obj, i) {
if (index < 0 && obj && obj.element === img)
index = i;
});
// remove from our list
if (index > -1) {
imgList.splice(index, 1);
if (img.parentNode) img.parentNode.removeChild(img);
}
}
#dropzone {
width: 300px;
height: 150px;
border: 1px solid black;
}
#dropzone.dragover {
background: rgba(0, 0, 0, .5);
}
#res {
border: 1px solid black;
}
<div id="dropzone">drop here</div>
<button id="send" disabled>log saved objects</button>
<div id="res">results:<br></div>
Also note that the default of a contenteditable
container would be to display this <img>
. I didn't wanted to integrate this case in this long enough example, but I'm sure you'll find a way to handle it if needed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With