Recently I've been looking into adding a simple HTML5 drag and drop to my already simple php file upload script.
I have read lots of tutorials and other solutions but I can't seem to understand the whole sending the file to server part.
From what I understand, XMLHttpRequest will send the data, but it will do it without reloading the page. This, I do not want. Currently the script I'm using will take the POST data and produce the file upload output, eg. server download link, thumbnail if image etc.
How can I have the drag and drop submit the POST data and either access the upload output or reload the page?
Edit:
I'm using the following for the drag and drop:
<div id="drop_zone">Drag and drop a file here</div>
<script>
function handleFileSelect(evt) {
evt.stopPropagation();
evt.preventDefault();
var files = evt.dataTransfer.files; // FileList object.
uploadFile(files[0]); //<-- This is where most examples will use XMLHttpRequest to construct form and send data
}
function handleDragOver(evt) {
evt.stopPropagation();
evt.preventDefault();
document.getElementById('drop_zone').style.backgroundColor = "#faffa3";
evt.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
}
function handleDragLeave(evt) {
document.getElementById('drop_zone').style.backgroundColor = "";
}
// Setup the dnd listeners.
var dropZone = document.getElementById('drop_zone');
dropZone.addEventListener('dragover', handleDragOver, false);
dropZone.addEventListener('drop', handleFileSelect, false);
dropZone.addEventListener('dragleave', handleDragLeave, false);
</script>
If you use JQuery or some other event-capable javascript library you should be able to catch the drag event and submit your form.
http://docs.jquery.com/UI/API/1.8/Draggable
http://api.jquery.com/on/
But no XMLHttpRequest involved...
After more reading and searching around I've come to the conclusion that what I originally wanted cannot be done.
The solution I am going with is to simply have a large transparent/hidden <input type="file"> covering the drop zone. The dropped filename will be read from the input with javascript and displayed in the drop zone. This of course will rely on the browser to support the drag and drop files into html file inputs.
From there my upload script will pretty much operate as if the user had used the visible file selector.
Apologies for not being too clear on what I wanted. I wasn't so sure myself. And thanks for the replies/comments.
Related
I have a php file generating a diagram as an image - this is working fine
This php file has to communicate with javascript (via ajax) to load this image in the html
Initially I got it working by placing this in the javascript:
document.getElementById("img3").src="ajax.php?area=" +encodeURIComponent(area);
where img3 is the image in the html and ajax.php is the php file generating the image
The problem with this code however is there are a few lines after the code above executing before the image is loaded - a timing problem.
Changed javascript/ajax code to:
ar = new XMLHttpRequest();
if(ar.readyState == 4 || ar.readyState == 0)
{
ar.open("GET", "ajax.php?area=" +encodeURIComponent(area), true);
ar.send(null);
ar.onreadystatechange = function()
{
if(ar.readyState == 4)
{
document.getElementById("img3").src = ar.response;
}// end if
}// end function
}// end if
Was with the hope I could place my lines of code inside the if(ar.readyState == 4) block which will solve the timing problem. But the image isn't loading. Any ideas?
I understand that you don't really care how the image is loaded (using src or ajax) but what you want is to execute a piece of code after an image has loaded.
There are several (some better than others) ways of checking if an image is loaded. This tread covers some of them.
For instance you could use the onload event to trigger a piece of code
document.getElementById("img").onload = function() {
//do the code which has to be executed after loading the image.
}
They describe some problems with the event not firing when the image loads from cache, but a browser (almost) never caches a .php file with get parameters. You should check if caching is an issue for your project, based on what i understand from your project i think it is not a problem.
They suggest other options which are interesting to investigate. There is one i find interesting where they suggest using imageloaded. That solution looks very solid.
I'm a java guy trying my hand in javascript and need some help. I came across an amazing tutorial on image uploads here Mozilla Tutorial and need some help figuring it out. I am currently working on the drag and drop image upload feature. Every time I drag an image onto my area the mouse turns green so it's activated. But then when I let go it should send me an alert that says one image was found. However it always just alerts 0. So the size of the array is 0. Any ideas? Thanks for taking a look. What I've tried with no success...
Copying and pasting the code from the tutorial into my javascript file exactly
Moving the code to add the listeners outside of a function and into a window onload
Every browser I have
...
function toggleStrideMedia()
{
if(getDisplay("strideMediaWrapper") == "" || getDisplay("strideMediaWrapper") == "none")
{
show("strideMediaWrapper");
getElement("strideMediaDropZone").addEventListener("dragenter", dragenter, false);
getElement("strideMediaDropZone").addEventListener("dragover", dragover, false);
getElement("strideMediaDropZone").addEventListener("drop", drop, false);
}
else
{
hide("strideMediaWrapper");
}
}
function dragenter(e)
{
e.stopPropagation();
e.preventDefault();
}
function dragover(e)
{
e.stopPropagation();
e.preventDefault();
}
function drop(e)
{
e.stopPropagation();
e.preventDefault();
var dt = e.dataTransfer;
var files = dt.files;
// THIS SHOULD BE GIVING ME A ONE BUT IT ALWAYS GIVES ME A ZERO INSTEAD
alert(files.length);
handleFiles(files);
}
.
UPDATE - Fiddle Results
UPDATE
The actual problem turned out to be that if you try to drag images directly from one web browser tab to this web based drag and drop interface, the event will fire but no files will be dropped. The asker noted this issue on OSX and I was able to replicate the same behavior in Windows 7.
Without seeing your HTML, it's hard to tell what you were having difficulty with. If the ondragover/ondragenter piece wasn't set up correctly then dropping won't work, but you wouldn't see an alert at all, you'd just see the browser render the image from the local filesystem. That also means that you're almost certainly successfully adding the drop event to the correct element.
Try this Fiddle and see if it works for you: http://jsfiddle.net/qey9G/4/
HTML
<div>
<div id="dropzone" style="margin:30px; width:500px; height:300px;
border:1px dotted grey;">
Drag & drop your file here...
</div>
</div>
JavaScript
var dropzone = document.getElementById("dropzone");
dropzone.ondragover = dropzone.ondragenter = function(event) {
event.stopPropagation();
event.preventDefault();
}
dropzone.ondrop= function drop(e)
{
e.stopPropagation();
e.preventDefault();
var dt = e.dataTransfer;
var files = dt.files;
alert(files.length);
}
Is there by any chance a way of letting the user select an image from his hard drive and without submitting it to the server use this image in the browser?
I need this because I want the users to be able to crop an image before sending this cropped image to the server (thus saving a post and some bytes of data).
What I tried to do is using an input type file and then capturing the submit event, but the value from the input is just a fake path (useless).
Any help would be greatly appreciated.
Here is a very basic example (with many globals, without input validation...) of image scaling: http://jsfiddle.net/89HPM/3/ . It's using the File API and a canvas element.
As #anu said the save can be done using toDataUrl method of the canvas.
In similar way you can achieve crop.
JavaScript
(function init() {
document.getElementById('picture').addEventListener('change', handleFileSelect, false);
document.getElementById('width').addEventListener('change', function () {
document.getElementById('canvas').width = this.value;
renderImage();
}, false);
document.getElementById('height').addEventListener('change', function () {
document.getElementById('canvas').height = this.value;
renderImage();
}, false);
}());
var currentImage;
function handleFileSelect(evt) {
var file = evt.target.files[0];
if (!file.type.match('image.*')) {
alert('Unknown format');
}
var reader = new FileReader();
reader.onload = (function(theFile) {
return function(e) {
currentImage = e.target.result;
renderImage();
};
})(file);
reader.readAsDataURL(file);
}
function renderImage() {
var data = currentImage,
img = document.createElement('img');
img.src = data;
img.onload = function () {
var can = document.getElementById('canvas'),
ctx = can.getContext('2d');
ctx.drawImage(this, 0, 0, can.width, can.height);
};
}
HTML
<input type="file" name="picture" id="picture" /><br />
<input type="text" id="width" value="200" />
<input type="text" id="height" value="200" /><br />
<canvas width="200" height="200" style="border: 1px solid black;" id="canvas"></canvas>
Here is a blog post which I made about that basic example: blog.mgechev.com
New HTML5 File API is probably the closest solution to what your looking for:
http://www.html5rocks.com/en/tutorials/file/dndfiles/
It allows you to browse for and read files within Javascript. Do whatever processing you like, and then upload to the server. Anything besides this is going to be very tricky indeed, and probably an unavoidable trip to the server and back.
Downside here is browser support.....as always
I am not sure which browsers work perfectly but HTML5 got DnD and File API. Let me give you steps which can work for you using FileAPI.
DnD API: Starts with the drop event when the user releases the mouse and the mouse-up event occurs.
DnD API: Get the DataTransfer object from the drop event
File API: Call DataTransfer.files to get a FileList, representing the list of files that were dropped.
File API: Iterate over all the individual File instances and use a FileReader object to read their content.
File API: Using the FileReader.readAsDataURL(file) call, every time a file is completely read, a new “data URL” (RFC 2397) formatted object is created and an event wrapping it is fired to the onload handler on the FileReader object.
FYI: The “data URL” object is Base64-encoded binary data, with a spec-defined header sequence of chars. Browsers understand them.
HTML5 DOM: set the image href to the File Data URL
You can't, for the following reasons:
For the reasons stated in this post: Full path from file input using jQuery
The fact that if you even try to create an img element loading a
local file path you'll get the error Not allowed to load local
resource: in your browser's console.
The fact that once you have an image in place you can only alter it's
appearance on screen and not alter the file on the system or send the altered image up to the server
You've stated that you need cross browser support, so HTML5 File API and Canvas API are out, even though they would only allow part of the functionality anyway.
I've just solved a problem closed to yours.
As everybody said you can't got the real image file address. But, you can create a temporary path and show the image in your page without submiting it to server. I'll show how easy it is, next to next paragraph.
Once you show it you can use some javascripts events to "pseudo-crop-it" and get the crop params (corners). Finaly you can add the params to some hidden field and submit the form. As a result you may use som php to crop the submited image at server and to save the result using a number of image formats as .png, jpg, gif, etc. Sorry if i do not write a complete solution, have not enough time.
/* some scripting to bind a change event and to send the selected image
to img element */
$(document.ready(function(){
$("input:file").each(function(){
var id = '' + $(this).attr('id');
var idselector = '#'+id, imgselector=idselector+'-vwr';
$(idselector).bind("change", function( event ){
(imgselector).fadeIn("fast").attr('src',
URL.createObjectURL(event.target.files[0]));
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<!-- create a img element to show the selected image and an input file element to select the image.
ID attribute is the key to have an easy and short scripting
note they are related suffix -vwr makes the difference
-->
<img src="" id="image-input-vwr" alt="image to be cropped">
<input type="file" id="image-input" name="image_input">
Hope it help some body as it is a very old question.
Luis G. Quevedo
In Javascript, I know how to set up a drag & drop target that accepts file uploads from the user's computer. How can I set up a drop target that accepts images that are dragged from another website? All I need to know is the URL of the image that they've dragged.
I know this is possible, since Google Docs accepts image drops from other websites. Any idea how they're doing it?
UPDATE:
It looks like there are differences between Chrome on Windows and MacOS. On Windows dataTransfer.getData('Text'); works but not on MacOS. dataTransfer.getData('URL'); should work on both.
OLD answer:
You could define a drop zone:
<div id="dropbox">DropZone => you could drop any image from any page here</div>
and then handle the dragenter, dragexit, dragover and drop events:
var dropbox = document.getElementById('dropbox');
dropbox.addEventListener('dragenter', noopHandler, false);
dropbox.addEventListener('dragexit', noopHandler, false);
dropbox.addEventListener('dragover', noopHandler, false);
dropbox.addEventListener('drop', drop, false);
function noopHandler(evt) {
evt.stopPropagation();
evt.preventDefault();
}
function drop(evt) {
evt.stopPropagation();
evt.preventDefault();
var imageUrl = evt.dataTransfer.getData('Text');
alert(imageUrl);
}
It is inside the drop event handler that we are reading the image data from the dataTransfer object as Text. If we dropped an image from some other webpage this text will represent the url of the image.
And here's a live demo.
function drop(evt) {
evt.stopPropagation();
evt.preventDefault();
var imageUrl = evt.dataTransfer.getData('URL'); // instead of 'Text'
alert(imageUrl);
}
Seems to work in Firefox, Safari, and Chrome on Mac. Also works in Firefox, IE, and Chrome in Windows.
Updated fiddle
Although you are able to accept the drag and drop of an image from another website, you are unable to do any processing of it (e.g. converting it to a base64 string using the canvas) (as of 21st August 2014) because of various cross-origin policy issues.
var dt = event.dataTransfer;
var url = dt.getData('url');
if (!url) {
url = dt.getData('text/plain');
if (!url) {
url = dt.getData('text/uri-list');
if (!url) {
// We have tried all that we can to get this url but we can't. Abort mission
return;
}
}
}
Even Google can't get around this - If you use gmail, you can drag and drop an image from another location in to the email body, but all this does is create an <img/> element with its src set to url (from the code above).
However, I've created a plugin that allows you to fake it cross-origin drag and drop. It requires a PHP backend.
Read the article I wrote on it here https://coderwall.com/p/doco6w/html5-cross-origin-drag-and-drop
Here's my solution to the problem: Dropzone js - Drag n Drop file from same page
Please do keep in mind that ability to drag an image from another domain depends on their CORS setup.
Some browsers use text/plain some use text/html as well
This code should pull any text or image source url on the latest Chrome, FF on Mac and PC.
Safari doesn't seem to give the URL so if someone knows how to get it let me know.
I'm still working on IE.
function getAnyText(theevent) {
//see if we have anything in the text or img src tag
var insert_text;
var location = theevent.target;
var etext;
var ehtml;
try {
etext = theevent.dataTransfer.getData("text/plain");
} catch (_error) {}
try {
ehtml = theevent.dataTransfer.getData("text/html");
} catch (_error) {}
if (etext) {
insert_text = etext;
} else if (ehtml) {
object = $('<div/>').html(ehtml).contents();
if (object) {
insert_text = object.closest('img').prop('src');
}
}
if (insert_text) {
insertText(insert_text,location);
}
}
As the other answers correctly state: It normally depends on the CORS-Settings of the server if drag & drop from another browser window is possible (Access-Control-Allow-Origin has to be set).
However I've just found out by chance that it's possible to drap & drop any images from a Firefox (current version 68.0.1) to a Chrome window (current version 76.0.3809) and process it in Javascript, regardless if CORS headers are set or not.
See working example (based on jsfiddle of Darin Dimitrov) which accepts and directly shows images from:
drag and drop from local computer (e.g. from file explorer)
drag and drop from other website, if CORS headers are set, e.g. an image from https://imgur.com/
drag and drop any images from Firefox window to Chrome window:
open jsfiddle demo in Chrome
open e.g. google image search in Firefox and search for any image
click on the image for bigger preview
drag & drop the preview image to the jsfiddle demo in Chrome
However this seems to be kind of a bug of Firefox and therefore I would not rely on this behaviour in an productive application.
I have a gallery I quickly coded up for a small site, and under Firefox 3 and Safari 3 works fine. But when I test on my old best friend IE7, it seems to not fire the imageVar.onload = function() { // code here }.. which I want to use to stop the load effect and load the image.
Please bear in mind...
I know the thumbnails are just scaled down version of the larger images. When the images are finalised by the client I am going to create proper thumbnails.
This is my first attempt to try and get out of procedural JavaScript for the most part.. so please go easy and kindly let me know where my code sucks!
For successful use of Image.onload, you must register the event handler method before the src attribute is set.
Related Information in this Question:
Javascript callback for Image Loading
Cross browser event support is not so straightforward due to implementation differences. Since you are using jQuery at your site, you are better off using its events methods to normalize browser support:
instead of:
window.load = function(){
//actions to be performed on window load
}
imageViewer.image.onload = function(){
//actions to be performed on image load
}
Do:
$(window).load(function(){
//actions to be performed on window load
});
$(imageViewer.image).load(function(){
//actions to be performed on image load
});
Just to add to the suggestion by Eran to use the jQuery's built in event handlers you can run code when the document is loaded and the DOM is created but before the images are downloaded with:
$(document).ready(function(){
//your code
});