This fragment is about to be reported (you'll remain on this page): You can enter a comment to clarify the mistake if you would like to: |
Self-contained cross-browser pure JavaScript class for Drag & Drop and AJAX (multi) file upload.
FileDrop is a lightweight JavaScript class for easy-to-use file uploading that works out of the box.
FileDrop uses some ideas and solutions from qq FileUploader (Github) which is similar to FileDrop but almost 3 times as large (although, perhaps, more elaborated).
FileDrop is released in public domain – feel free to use it however you like. I will always appreciate a back link and a comment, though :)
Latest FileDrop release has been on 5th September 2012.
Download FileDrop – includes demo page, minified (filedrop-min.js) and full (filedrop.js) JavaScript files.
FileDrop is getting a dedicated site soon. Meanwhile, a GitHub repository has been set up to help you fork, issue and contribute to the project.
You can alternatively report problems and suggestions to the comments.
See also on-line demo page and FileDrop project on JSClasses.org.
Remember that you can always hotlink to the latest script version:: http://proger.i-forge.net/filedrop-min.js
xml<input type="file"> with the dropped file namexml<iframe> (by clicking on Browse) works as usualxml<fieldset> was used as a drop zone in Firefox 13 and up.
Internet Explorer 6- – even if it fires ondrop it actually sends an empty POST body upon submission. Regular
xml<iframe> upload is still possible. Thanks to Andreas for reporting this.Note: if you want to use the latest version you can hotlink to it using this URL (it will be backwards compatibile as much as possible; remove -min to hotlink to the full version):
http://proger.i-forge.net/filedrop-min.js
The following is the minimum required to use FileDrop (check demo/minimum.html (live demo)in the archive for the working example; you’ll need a webserver):
xml<!DOCTYPE html> <html> <head> <title>Basic FileDrop example</title> <script type="text/javascript" src="http://proger.i-forge.net/filedrop-min.js"></script> <style type="text/css"> /* Essential FileDrop element configuration: */ .fd-zone { position: relative; overflow: hidden; width: 15em; text-align: center; } /* Hides <input type="file" /> while simulating "Browse" button: */ .fd-file { opacity: 0; font-size: 118px; position: absolute; right: 0; top: 0; z-index: 1; padding: 0; margin: 0; cursor: pointer; filter: alpha(opacity=0); font-family: sans-serif; } /* Provides visible feedback when user drags a file over the drop zone: */ .fd-zone.over { border-color: maroon; } </style> </head> <body> <!-- A FileDrop area. Can contain any text or elements, or be empty. Can be of any HTML tag too, not necessary fieldset. --> <fieldset id="zone"> <legend>Drop a file inside…</legend> <p>Or click here to <em>Browse</em>..</p> </fieldset> <script type="text/javascript"> // Tell FileDrop we can deal with iframe uploads using this URL: var options = {iframe: {url: 'your-upload-script.php'}}; // Attach FileDrop to an area: var zone = new FileDrop('zone', options); // Do something when a user chooses or drops a file: zone.on.send.push(function (files) { // if browser supports files[] will contain multiple items. for (var i = 0; i < files.length; i++) { files[i].SendTo('your-upload-script.php'); } }); </script> </body> </html>
The above code creates a FileDrop
xml<fieldset> area and sets it up so that it sends each chosen file to a server script (your-upload-script.php). It is self-sufficient and will work in any browser supported by FileDrop.
Download FileDrop | Demo | Page top. Don’t forget to give feedback!
An entire FileDrop facility is contained in window.fd. In itself, FileDrop in itself is split into 2 classes: DropHandle and FileDrop, plus one File class. Apart from these there are global options and functions (belonging to window.fd instead of a particular FileDrop class).
FileDrop uses event-driven approach for better flexibility. See also CallOf() and CallAll() functions that call event chains (sets of callbacks).
Global options are set in window.fd:
jsfunction (event, args), gets called before calling a chain of FileDrop events. this is set to the calling object.Download FileDrop | Demo | Page top. Don’t forget to give feedback!
This is an abstraction layer that provides FileDrop class with normalized events occurring on file Drag & Drop and Browse. It creates
xml<input type="file" /> and
xml<iframe> elements and handlers their activity.
DropHandle doesn’t do anything except handling node events – it doesn’t change the appearence of zone or respond to Browse or Drag & Drop, it only invokes corresponding event handlers.
js// zone - a DOM element or ID to hook file upload events for. // opt - optional options, see below. new fd.DropHandle(zone, opt);
xml<iframe> fallback settings. Currently has only one field (but FileDrop has more):xml<iframe> element to. Must be a server-side script that handles iframe upload.xml<input type="file" /> element.Note: you can access passed zone element using zone property of the DropHandle class.
Download FileDrop | Demo | Page top. Don’t forget to give feedback!
Events are stored in on property, e.g.
jsaDropHandle.on[dragEnter]. Each on member is an array of callbacks.
jsfunction (response). Occurs when an
xml<iframe> upload has finished. response is the object returned by the server script plus several XMLHttpRequiest-like response properties making it suitable to use one callback function both for this and File’s done event.jsfunction (iframe). Occurs when an
xml<iframe> element was constructed and can be set up. Currently there’s no default handler.jsfunction (input). Occurs when a
xml<input type="file" /> element was created and needs to be set up. Default handler adds opt.inputClass to it and sets its parent
xml<form>’s style.position to relative to avoid overflow problem in Firefox 10 (it would still show the presumably hidden part of the input even outside the container bounds).jsfunction (e). Occurs when a file is dropped to zone. It happens in Firefox and Google Chrome because they support dropping files on
xml<input type="file" />.
All handlers are of form
jsfunction (e) where e is the native browser event object. Most useful events are dragEnter and dragLeave because others either don’t work, are unstable or unclear.
For a detailed description of HTML 5 Drag & Drop events see this MozDev page.
Only methods of interest are listed here, others are easy to determine from the code.
jsHook (node)jsMultiple ()xml<input type="file"> element is configured for multiple file selection.jsMultiple (Toggles)xml<input type="file">. This affects «Browse» dialog popping up when user clicks on the drop zone (zone node DropHandle was constructed for).jsSendViaIFrame (url)xml<iframe> and
xml<form> elements. It will prepare the form and set up the response handler that will call iframeDone event.jsAbortIFrame ()xml<iframe>, if there was any happening.jsPrepareInput (node)This class provides the actual FileDrop features. It’s based on DropHandle that gives a good degree of cross-browser abstraction. FileDrop uses DropHandle’s events to respond to user actions and as such provides the same callbacks as that class.
Also, all DropHandle options, methods and other fields exist in FileDrop as well.
js// zone - a DOM element or ID to hook file upload events for. // opt - optional options, see below. new fd.FileDrop(zone, opt); // a global (window[]) alias exists - you should use it instead: new FileDrop(zone, opt);
Options (see also DropHandle options):
xml<iframe> upload will be forced even if browser supports AJAX upload using FileAPI or Chrome/Safari File false by default.Note: you can access DropHandle object by handle property of the FileDrop class.
Download FileDrop | Demo | Page top. Don’t forget to give feedback!
Events are stored in on property, e.g.
jsaFileDrop.on[send]. Each on member is an array of callbacks.
jsfunction (file). Occurs when a File object was constructed and can be set up. Currently there’s no default handler.jsfunction (files). Occurs when a set of files can be safely send – user agent supports some kind of FileAPI (of Firefox/, Chrome or Safari). An
xml<iframe> upload can still be done when handling// this event using DropHandle SendViaIFrame(), if desired. Currently there’s no default handler.Only methods of interest are listed here, others are easy to determine from the code.
jsGetFilesFrom (e)jsOnUpload (e)xml<iframe> upload if the browser doesn’t support any FileAPI.Browser-independent abstraction layer for dealing with File objects of supported browsers (currenly Firefox/, Chrome and Safari). Wraps around native browser File// object that it’s passed in the constructor.
It also provides a number of events wrapping around XMLHttpRequest (see SendTo() method).
js// file - a native File object returned by the browser from an event object. new fd.File(file);
File class has the following properties:
Download FileDrop | Demo | Page top. Don’t forget to give feedback!
Events are stored in on property, e.g.
jsaFile.on[error]. Each on member is an array of callbacks.
jsfunction (xhr, e). Occurs when the file has been uploaded (
jsxhr.readyState == 4 && xhr.status == 200) and server response was received. Note: DropHandle provides callback for
xml<iframe> upload – see SendViaIFrame() with simulated xhr structure.jsfunction (e, xhr). There was an error while uploading the file or reading file binary data – in this case xhr parameter will be undefined.jsfunction (current, total, xhr, e) where current might be null if can’t be determined; current and total are the number of bytes uploaded and total correspondingly.jsfunction (xhr, data) where data is an already read raw binary string (for Gecko and Chrome) or a native file object (for Safari). Occurs when a XMLHttpRequest object needs to be sent. Default handler (fd.File.SendXHR()) attempts to use sendAsBinary() if it’s available falling back to send() with possible sendAsBinary() imitation for Chrome.Only methods of interest are listed here, others are easy to determine from the code.
jsAbort ()jsHookXHR (xhr)jsSendTo (url)Download FileDrop | Demo | Page top. Don’t forget to give feedback!
9 May 2013
Rajan
Hi, I am trying to implement it with normal ASPX page.IS that possible.?How can i send the file details from client to my ASPX Page.I am not at all goo in Php.So i can’t understand the Php code.
9 May 2013
Proger_XP
I don’t know ASP so I can’t help you here. You can send additional data via GET request variables simply by adding them to your URL:
10 May 2013
Rajan
Thanks..:)
8 May 2013
Prakash
Hi, Thanks for the tutorial.I saw that scripts written in «Upload.Php».Can i see the code for that Php file.Coz i need to implement the concept in MVC.So that i can implement the logic on the button click event in the controller
8 May 2013
Proger_XP
What do you mean? upload.php’s source code is available on GitHub and included into the download archive.
26 April 2013
TechSupport
Hello- I am a network admin for a school, and I’m trying to create a browser-based file upload plugin which students can use off-site to upload files to an FTP server with an externally facing IP. The server is a Snow Leopard server.
What I’d like to do is make a simple HTML page with nothing but the upload box in it and directions on what to do.
I came across this site but I’m not sure if it will work for this purpose. I downloaded the package but there are a few things I cannot figure out: – How can I point this code to the FTP server? Or is it not possible to do this? – What portion of code do I need to put into the page I’m building to get the upload box?
Is what I want to do even possible?
26 April 2013
Proger_XP
You can do this both with and without FileDrop. As MrMan says you need a server to relay your file to whatever location it wants. FileDrop is an interface to upload files from client to server using regular HTTP upload (via POST). It can’t be used to upload files via FTP as there’s no built-in support in browsers I know.
What I would do is create a simple form (again, with or without FileDrop):
…then use PHP’s FTP functions to redirect the upload there:
<?php$h = ftp_connect('example.com') or die('No connection.');
ftp_login($h, 'login', 'pass') or die('Cannot log into FTP server.');
$src = $_FILES['upload']['tmp_name'];
ftp_put($h, 'remote.dat', $src, FTP_BINARY) or die('Cannot upload.');
ftp_close($h);
?>
This is, of course, a rough sample but it should be working.
26 April 2013
MrMan
I think what you want to do is possible, but you may be using the wrong tool. Without knowing your end to end setup or common use cases it’s hard to determine. Essentially this tool is usually used with web servers not FTP clients. Essentially you’d have a web server on the back-end accept the file and then place it where it needs to be. Unfortunately I’ve never tried to have an FTP act as a web server for anything other than drag and drop file placement. You could definitely stand up a web server which would take in a file and place it where it needs to go, but I’m not sure how to do that via only a public facing FTP
26 April 2013
MrMan
Not particularly…usually you need a standalone server handling it. I’m sure there are other ways, but none I know of. Maybe someone else can chime in and help you out.
26 April 2013
TechSupport
Thanks very much for the info. Do you know of any tool that I could use to do this? I’ve been looking at some php scripts which claim to be simple to set up but none of them appear to have any place to point to a server. There were also some flash-based and HTML5 tools I found which had the same problem.
Is there any way to do this?
17 April 2013
Sander
Despite having used d&d file uploads in Opera before, I can’t get it to work now. I’m using Opera 12.15 x64 on Windows 8, I think I used 12.15 x32 on Windows 7 x64 before. Could Windows 8 and/or x64 be an issue somehow?
17 April 2013
Proger_XP
I have no data on this one. I tried Opera 12 on WinXP SP3 x32 and it was as simple as dropping a file onto a FileDrop zone – Opera would ask if I want to upload it or open in browser (see screenshot in the comment below).
14 April 2013
Proger_XP
Reply to Tomer’s e-mail:
It’s only possible for XMLHttpRequest uploads (Firefox/Chrome/Opera 12+). Change your on.send handler to check for name and size of the File being sent, for example (taken from demo/minimum.html):
14 April 2013
Proger_XP
Great news – Opera 12 supports drag & drop!
14 April 2013
Proger_XP
Tested FileDrop in most recent browser versions. Support list:
13 April 2013
Anonymous
Browser: IE 9 I am not able to upload files by dragging on demo page (http://proger.i-forge.net/%D0%9C%D0%BE%D0%B8%20%D0%BF%D1%80%D0%BE%D0%B3%D0%B8/%D0%92%D0%B5%D0%B1/FileDrop/demo/index.html) When I upload file .pdf file using demo page, result shows zero bytes without filename. I got the same result when I use ASP.Net, IE to implement drag / drop funcationality.
14 April 2013
Proger_XP
Internet Explorer doesn’t support drag & drop uploads. Only Firefox and Chrome do.
30 March 2013
hossein
Hi
I try to upload a file by file drop plugin but I can not get the file in UploadHandler.ashx:
and UploadHandler.ashx:
context.Response.ContentType = "text/plain"; HttpFileCollection httpfiles = context.Request.Files; for (int i = 0; i < httpfiles.Count; i++) { HttpPostedFile file = httpfiles[i]; file.SaveAs(@"C:\"+ Path.GetFileName(file.FileName.ToString())); } context.Response.Write(httpfiles.Count.ToString());Where is the problem in my code?
14 April 2013
Proger_XP
Guys, Internet Explorer does not support drag & drop before version 10. There’s no support in its core. You can see drag events firing but it’s been like this since IE 6 – and yet when you «drop» the file IE doesn’t even fill the
xml<input type="file">with the name of dropped file. And there’s no FileAPI (in pre-10).I have added a check to FileDrop so now it won’t trigger upload in IE if someone attempts to drop a file. Hopefully this will stop the confusion. Regular upload via
xml<iframe>works just fine.10 April 2013
Anonymous
I am facing the same issue. FileName is empty, file content is empty. Did you get any resolution?
12 April 2013
Anonymous
Is anybody able to implement this solution with ASP.net in IE browsers?
15 February 2013
Proger_XP
GitHub repository is open – fall in.
https://github.com/ProgerXP/FileDrop
12 February 2013
Barney
Hi Proger, this is a fantastic project and I’m convinced this is the best single piece of code for unified front-end file upload. However, a number of things remain unclear.
1) Is it at all possible to make it such that drag-n-drop file input basically informs the value of a genuine input[type=file]? I’m assuming from reading between the lines that the file is sent to the server by itself asynchronously. Is it not possible to send it as part of a multi-part form post action?
2) What is achieved in which browser. The subtitle of the project is «cross-browser JavaScript Drag & Drop file upload», but your reply to the last comment says «(Safari, IE, Opera, etc.) only allow for traditional file upload – click on the button to open standard Open Dialog». This would suggest the description is misleading.
3) What is buggy, what isn’t. The comments are full of little notices akin to «basic functionality is broken in X», and you will later reply with «fixed just now». GitHub might be better for sorting issues and working out what functionality is pending, what’s been addressed, what won’t or can’t be fixed. Again, reading all the comments to try and work out what’s going on where is exhausting!
4) You mention «Browser-independent abstraction layer» or something similar several times, which makes me think you’re talking about functionality that works across all browsers… and then go on to talk about features limited to a selection browsers that use the same native API anyway. What it suggests is that FileDrop will provide a unified event and file sending API I could use across all browsers. In fact, it’s not quite clear what the focus of this plugin is. On the one hand the granularity of forked internal events API exposed suggests it’s a set of tools to be learnt and used to program for any real use case. But at the same time it comes with its own kind of DOM abstraction layer, which suggests that it’s being built for absolute beginners who don’t have a JS solution for managing markup. Really, I think you need to provide several layers of documentation for this: a feature / browser support table; a high-level step-by-step guide to building the demo; and finally a detailed API documentation (which is what you have above). At the moment it feels like this is the most powerful plugin for the functionality described, but it’s just difficult figuring out what it does and how to use it.
12 February 2013
Proger_XP
Thanks for your feedback, Barney, it’s nice to hear you liking my codework.
If by «the value of genuine input» you mean file path – then no, it’s not possible, no sane browser will provide you with this insight into the user’s system.
If you mean «raw data», i.e. reading dropped file’s content – then yes, it’s possible by hooking fd.File.sendXHR() event. I can give you an example. This will only work for drag&drop-enabled browsers, Firefox and Chrome for today.
Not in portable way. Some browsers (Safari if I recall correctly) require that you pass the file’s object directly to XMLHttpRequest.send(), you can’t read the data itself.
Not really. FileDrpo offers cross-browser way of AJAX upload (not involving page reload) but obviously it can’t offer drag&drop capabilities for browsers that don’t implement them natively. If a browser does support drag&drop it will be used – the user can drop a file onto the drop zone (FF) or document (Chrome) and it will be sent to the server, response fed back to your script. Otherwise the user can click on Browse (inside the drop zone) and standard File Open dialog will appear – once he chooses a file it will be, again, sent to the server via AJAX and you’ll handle the response.
So to summarize user can click on the Browse button and choose a file regardless of the browser he uses but if it’s FF/Chrome he’ll be able to also drop a file and it will work either way for your code (using FileDrop). This is what is meant by «cross-browser file upload».
Hopefully this explanation has clarified the situation.
I completely agree with you. You might have seen the comment about new dedicated FileDrop site. It will feature:
I truly wish I had more time to finish it. 80% of the work is already finished but I can’t put it only just yet without clearing all the hanging tails.
What makes you think so? There are at least two more or less different File APIs – for Firefox and Chrome. And FireFox 3 had yet different FileAPI. Drag&drop mechanics also slightly differ in both.
For heaven’s sake, AJAX support and DOM methods have been consistent for years but you understand file uploading isn’t just about them.
It does, check the event descriptions. You can react on file being dropped, file being uploaded, upload error, upload progress, etc. regardless of the browser client uses.
Do you mean fd.ByID() and other helpers? They were not meant for using outside of FileDrop, it’s not a replacement for Prototype or any other framework. FileDrop targets a very specific problem.
Once again I totally relate to that but I have to manage my time table which given its freelancing nature can sometimes be tricky and not allow for sideways projects.
And yes, I agree that FileDrop has to offer a lot but its documentation is very, very sparse for its features and only features low-level API hoping that the reader can figure the rest from the sources. That is, until the new site is live.
15 February 2013
Proger_XP
Great, I’ll consider getting GitHub up in the next couple of days, it doesn’t need a complete site to start up anyway.
Why are you concerned about trimming old code away? You don’t need IE 6 support? At any rate there’s not much of that legacy code and it doesn’t impact performance at all.
14 February 2013
Barney
Woops. Not at all the case. I tried ripping out the utilities to decouple DOM and event handling, but taking out even the first line of that code resulted in no event triggers for IE. Weird!
Meanwhile, I’m carrying on my refactoring exercise (when you do get this up on GitHub, you’re going to get a lot of pull requests!) — but during experimentation I found the script crashed with no options provided due to a bug on line 205: form = res.form.parentNode should be form = form.parentNode.
13 February 2013
Barney
Well, I’m stripping these out for now and everything still seems to kinda work. I’ll let you know how I get on ;)
13 February 2013
Proger_XP
I’m very glad to read reviews like yours, thanks for sharing your impression.
That’s an old trick, really old :)
Regarding AddEvent – it’s simply a cross-browser wrapper. Its form might be confusing to you because (like NewXHR) it’s written for IE 6 compatibility (it had a non-W3C event model) and isn’t something you’ll see these days.
The two lines before attachEvent() are remnants of that support and I can’t even say now what they were supposed to fix because this function (AddEvent()) is very old. Blame me if you must but when it’s about IE 6 I’m inclined to leave things as they are, gained by hard trial back then.
13 February 2013
Barney
Thanks for your reply! I’m sorry for the critical tone — I think I’m channeling my frustrations at the inevitable browser disparities that make a consistent UX impossible. But as I said, FileDrop goes further than anything else I’ve seen. gg_fileUploader is actually less streamlined out of the box as it doesn’t register drops with IE7 & 8.
Having had a closer look at the events and done a bit of cross-browser trials on your demo page, I’m actually very pleased with the whole package — and once the inexorable browser API differences become clear, it’s also clear why it’s not possible to create a wrapper any more unified than what’s provided (I particularly like the way you emulate XHR response for iframe callbacks though — that’s very nice).
I’m currently trying to refactor the plugin to accept arbitrary, pre-determined markup (so strip out all the DOM stuff) so that I can extract the meaningful stuff, and bind the events into my own lib. But the fact that there’s no scoped encapsulation, and everything is a property, is confusing (when I write code, everything’s a var or a function). In particular, could you explain why fd.AddEvent creates obj['e' + type + fn] = fn and obj[type + fn]?
25 January 2013
Mark
Love your code, and it works just great in firefox & chrome. I have ActiveX functions that force me to use ie as a browser, and can’t get your file drop to work there (although upload file does). Thought I would try the new beta of ie10 – this goes a bit further, but crashes out of filedrop-min.js with the error message:
SCRIPT438: Object doesn’t support property or method ’readAsBinaryString’ filedrop-min.js, line 1 character 7329
Is this something that might be fixable??
Regards Mark
26 January 2013
Proger_XP
Drag & drop mechanism must be supported by the browser and to the best of my knowledge only Firefox and Chrome support it. Other browsers (Safari, IE, Opera, etc.) only allow for traditional file upload – click on the button to open standard Open Dialog, pick file(s), click OK and they will be sent to the server.
As for IE 10 error I currently haven’t tested it. I’ll do extensive testing with the launch of the new FileDrop site which should be near February if my time permits.
10 January 2013
Peter
Hi Proger, I was wondering if you have any implemtation in jsp or jspx instead of php?
11 January 2013
Proger_XP
Nope, I don’t code in Java.
9 January 2013
Proger_XP
A large update is going to happen to FileDrop. A new dedicated site and API docs will be launched along with script bug fixes and new functions including the one to integrate FileDrop into jQuery. Entire browser compatibility sheet will also be revised and improved. Stay tuned.
4 January 2013
Troy
Hey Proger. When forcing the FileDrop to use iFrame, dropping the file will not upload a file.
After click the browse and uploading a file, then the drag and drop works. Any way around this?
Thank you.
4 January 2013
Proger_XP
IFrame is a legacy way of uploading files; as of today only Firefox and Chrome support AJAX upload and drag & drop, all other browsers don’t and for them IFrame is used. In other words IFrame works if a browser doesn’t support FileAPI (AJAX upload) and/or drag & drop.
4 January 2013
Troy
I was thinking I was doing something wrong, but this is also the case for the demo page (on every browser).
15 December 2012
Vinum
Can you post a sample with a progress bar?
15 December 2012
Proger_XP
It depends on your application. Hook on.progress event to get notifications and then update your progress bar however it’s implemented:
zone.on.send.push(function (files) { for (var i = 0; i < files.length; i++) { var file = files[i]; file.on.progress.push(function (current, total) { alert('Uploaded ' + current + ' bytes from ' + total + ' bytes.'); }); file.SentTo('upload.php'); } });Progress is reported only for AJAX uploads (FileAPI of Firefox/Chrome), not
xml<iframe>.15 December 2012
Vinum
thanks for your reply. I implemented it with progress tag.
8 December 2012
J04n.D03
Hello, how can i temporaly disable the Drop-zone? Is that possible?
8 December 2012
Proger_XP
There’s no built-in method to do this in one call but you can easily simulate this using events. Upload is initiated by fd.DropHandle class that’s inherited by FileDrop that you’re most likely using. FileDrop hooks that event and either performs the upload via
xml<iframe>or by FileAPI of Chrome/Firefox.So you can put your own handler in front of FileDrop’s that will stop event chain if drop zone is considered disabled in your application’s terms. Example:
var zone = new FileDrop(...); zone.on.upload.unshift(function () { if (thisZoneMustBeDisabled()) { // your func, obviously. return true; // stop remaining "on upload" handlers from being called. } }9 December 2012
Proger_XP
Come on, you’ve basically done the same thing. Look at this modified minimum.html and compare with that found in the download archive. You will notice that 2 things have changed:
If you try this example on your host you will see that toggling «Disable drop zone» checkbox will work accordingly to its name.
9 December 2012
J04n.D03
hello. that was too complicated for me... i am not an expert :)
i have this solution:
in filedrop.js
fd.FileDrop = function (zone, opt) { var self = this; self.disable = 0; // added this onemy script:
this.on.send.push(function (files) { if(this.disable){ return false; // break } this.disable = 1; for (var i = 0; i < files.length; i++) { files[i].SendTo('your-upload-script.php'); }now, after first upload this.disable is «1», and alway i want to upload it breaks in the if.
thanks
5 December 2012
MrMan
So, I have an incredibly simple example I’m trying to get to work…but I can not figure out what to return from my server. First off I can get my file and upload it fine. It’s triggering the <iframe> done event which I can’t seem to get.
var options = {iframe: {url: 'myurl', force: true}}; var zone = new FileDrop('uploader', options); zone.on.iframeDone.push(function (xhr) { debugger; alert('Done uploading via <iframe>, response:\n\n' + xhr.responseText); });<div id="uploader" style="display:inline-block;"> <button class="k-button" id="uploadDocumentButton"> </div>I’ve tried redirecting the response, sending a json string but my zone.on.iframeDone event never fires. What are you returning from the server in order to trigger this handler? One note is that if I am returning a JSON string I get prompted by the browser to download a file called «UploadDocument» which is simply the JSON string I am returning from the server. What am I missing? Also I must do this via the iframe method.
6 December 2012
MrMan
This is all I get out of the events:
FileDrop inputSetup event (1); args: LOG: { 0 : [object Object] } FileDrop upload event (2); args: LOG: [object MSEventObj] { 0 : [object MSEventObj] } FileDrop iframeSetup event (0); args: LOG: [object HTMLFormElement] { 0 : [object HTMLFormElement] }6 December 2012
Proger_XP
Glad you’re past this glitch now. As a side note you could probably return just
…but I prefer to keep things up to standard so I’m using all the wrapping HTML stuff.
6 December 2012
MrMan
Thanks! That worked great. As a note to .Net MVC developers trying to use this, Technobabble has a post detailing how to return a JSONP style response to the caller here: Nerdworks Blogorama – Enabling JSONP calls on ASP.NET MVC I only needed to modify it slightly to look for the fd-callback, set the return type to text/html, and html. Then passing in the response Proger_XP posted seemed to do the trick. For those wondering, my exact server response looked like this:
<!DOCTYPE html><html><head></head><body><script type='text/javascript'>try { window.top.fd_8118({}); } catch(e) {}</script></body></html>Obviously with the callback changing each time, and any data if you were returning it.
6 December 2012
Proger_XP
If you check demo’s upload.php you will see that
xml<iframe>needs not a normal JSON (or whatever JS’) response but JSONP like in old times. This means that your server-side script needs to include callback so that the client (FileDrop) gets notified when the script is loaded. Unless this is done iframeDone will never be called as there’s no code calling it as returned by the server.FileDrop passes fd-callback parameter that contains the name of function to call. upload.php uses it as follows (
PHP$callback = $_REQUEST['fd-callback'];):header('Content-Type: text/html'.$charset);
$output = addcslashes($output, "\\\"\0..\x1F");
echo '<!DOCTYPE html><html><head></head><body><script type="text/javascript">',
"try { window.top.$callback(\"$output\"); } catch (e) { }</script></body></html>";
In other words it’s as simple as building your normal JSON (or other) response and then wrapping it into CALLBACK(your_response).
5 December 2012
MrMan
If it helps any, when I try to redirect the response I get an error in the function:
self.FindInputRec = function (parent) { var resule; for (var i = 0; !resule && i < parent.childNodes.length; i++) { var node = parent.childNodes[i]; if (fd.IsTag(node, 'input') && node.getAttribute('type') == 'file' && fd.HasClass(node, self.opt.inputClass)) { resule = node; } else if (node.childNodes.length > 0) { resule = self.FindInputRec(node); } } return resule; }It blows up on parent because it’s null. The result isn’t something I particularly need, I just am looking for the trigger when the iframe is finished uploading.
19 November 2012
Tony
I couldn't get this working on IE9. Actually, I could get it working on IE9 in the hosted demo page (sort of) but I'm not sure whether any data was transfered. When I used Chrome it worked and showed me the file name. IE9 didn't. I copied and pasted the demo page straight into my index.html page, but the iframe wouldn't accept a file that I dragged onto the frame. Not sure what is wrong.
20 December 2012
Srdjan
I have same problem. Chrome doesn’t use iframe. When you drop file into <input type="file"> into Chrome or FF, control is filled as Browse did. I noticed that IE does not support this, and that is problem. If there is some way to «push» dragged file into file-input control, problem could be solved.
20 December 2012
Proger_XP
Looks serious enough. I’ll take a look and post a status update.
20 December 2012
MrMan
This is actually one of the same reasons I went about forcing iframe use. However I was able to get Chrome working with iframe
20 December 2012
Proger_XP
Previous versions of IE I’ve tested it on worked fine filling the input with the file name and triggering onchange. Maybe IE9 is different. I didn’t have time to look into this yet but I’ll try to do this during this or the next week.
9 November 2012
Jibi Abraham
I was looking for a pure JS implementation for a file uploader and yours is perfect. I'd just like to ask a quick question though. How would I go about adding additional data along with the files?
9 November 2012
Proger_XP
It depends on how you want to send it. If a GET query will suffice it's the ideal case – just hook File's sendXHR event and add your variables there.
If you want to include some large data in the POST body (along with uploading file data) it's only possible with Gecko and Chrome – Safari requires that we pass the entire File object to xhr.send() so we don't know/can't change the data we're sending.
If you don't support Safari then simply convert the File into a string and change it however you like.
9 November 2012
Proger_XP
Then just add the query to the URL you're passing to File.SendTo(url);. That's the simplest way.
9 November 2012
Jibi Abraham
Thanks for the quick reply. I guess I'll go with the usual GET method. Seems to be the easiest and the most commonly supported
9 November 2012
Proger_XP
Oh, and I forgot to mention that it's impossible to include additional POST data with iframe uploads (in Opera and IE). So my advice would be to try to fit all data into the query string (GET). It can't be too long though and it requires URL-encoding which makes it 3 times larger too. But it should be possible with several KiB's of binary data.
6 November 2012
Kevin Jones
I'm trying to use this library to do file uploads. Taking the simple example off this page it works. If I take that same example and embedded into another page then depending on where I put the 'zone' element the example fails. The page is a fairly complex three column affair. If I put the zone at the top of the page before any of the columns are rendered then it works, if I put the zone in one of the columns then it fails and if I put the zone after the columns then the code fails unless I have a div style="clear:both" in there as well.
Failure means different things for different browsers, in IE and Firefox I get no events fired, in Chrome I get the DragEnter event and nothing else.
This is obviously to do with positioning – is there a way of getting the drop zone to work inside a floating div?
Thanks
6 November 2012
Proger_XP
There should be although I haven't yet had an issue. It might be better if you use Firebug or similar tool of other browsers to tweak the CSS (if you believe it's styling error) spot-on and see what changes it.
In particular, I'd try zoom: 1 for IE and position: absolute/relative; z-index: 1000 for it and others. Take a note that
xml<input type="file">must be located above all other controls – it receives the events. But it should be invisible (hence opacity: 0).Let me know if you've found anything.
7 November 2012
Proger_XP
Try creating a minimum HTML page that will fail (you can use Bootstrap or other framework if you do in your project), upload it somewhere and send it to me. I'll take a look.
7 November 2012
Kevin Jones
Unfortunately none of that works – any other ideas?
25 October 2012
PHPCoder
This looks like a great bit of code. Unfortunately I'm unable to make the «minimum» example above work. I changed the backend to «upload.php» (using the php code from the demo). It does not appear to do anything after the file is selected. If the upload.php does not exist it does the same thing.
The demo does appear to work on my server but it's much too complicated for me to get started. Should the «minimum» code do something after a file is selected?
6 November 2012
Ali DHIBI
Hello every one and thanks for this Great work!
I'm trying to make the minimum example working on ie9 but i can't do it :( i have always empty value on file field, when trying to debug i get this answer: Array (
[name] ⇒
[type] ⇒
[tmp_name] ⇒
[error] ⇒ 4
[size] ⇒ 0) any one can help?
25 October 2012
Proger_XP
minimum.html indeed didn't do anything (had no on.done handler attached), it was by purpose. I realize it could be misleading so I have updated it (check it in the archive) to report back on a successful AJAX or
xml<iframe>upload.If you have more questions feel free to tell me.
24 October 2012
flam
Do you have any plans to port this to jquery?
24 October 2012
Proger_XP
What for? It's good on its own as well as with any library. And it's easier to maintain a single unit of code than a bunch of modifications. I don't see a solid reason.
12 October 2012
Herover
Hi, I made a image upload site for personal use using your code, which is great.
I just have one problem I would like to point out: memory. After uploading one gb. data, chrome started to act weird, and so did the rest of my computer — all the pictures where still stored in objects…
Right now, I just added
to line 421, since it cover my needs.
Is there a better way to do this? I couldn't find one, and simply deleting the pointer to the File object didn't work out for me…
12 October 2012
Proger_XP
Amazing, I had absolutely no idea you guys will be using FileDrop for 150 MiB or save 1 GiB files. About your problem – have you tested this with other browsers (Firefox if you're interested in pure AJAX upload)? Chrome/Webkit can have a memory leak, it's known to have some as well as other browsers (but each one differs).
17 October 2012
Proger_XP
I finally got some time to look into this in more detail.
You're right in your supposition that delete only removes the reference from the current variable so for example if you create an object, assign it to multiple variables (like var another = obj;) and delete obj the another var will be left intact while obj will become null.
So unless you don't free (delete) all the references the GC won't dispose the original object.
It would be great if you could test the following with your large file:
The above are all possible temporary fixes I could come up with; I can't tell if they will work at all beforehand. If you notice proper behaviour after applying them please remove them one-by-one to see what part of the code causes memory leak.
Also, if you have references to either fd.File or the data it passes in on.sendXHR event make sure to delete them as well.
Yet another note is that it might take some time before GC is triggered so it might not dispose the memory right away even if you have successfully deleted all references to it. I would try to leave it and the PC idle for 5-10 minutes to make sure.
Really hope something of this helps.
Never actually thought how they would implement this – my primary idea would be to use Flash but I really don't know if it's old-fashioned these days with the advance of HTML5 stuff.
13 October 2012
Herover
I just tested in firefox, and with same problem. I don't have a IE available for the time.
My test code is based on much of your example code, with the difference that I assign each file a id, which matches their number in the file list given in zone.on.send.push. Then either the file itself delete the object with its own id in the list, or another function loops all the files to check which one has been uploaded, and should be deleted. Neither worked for me.
After reading up on «delete», I've come to the theory (which could be wrong) that something is still pointing at the file, so it still exists. But nothing else is pointing at the reader object, so there is no problem when the file itself delete it after use. I did not test what happens if SendTo is fired again…
I might without internet a few days, so it will probably take some time before I can test more stuff, but it could be nice to see some kind of self-destruction function in the File object, I think :)
12 October 2012
CaptNemo
Yes, people need to move a lot of data around these days. My application is for a transcription business where customers need to upload hundreds of megs of audio for us to work on. These people are not «computer people» so it has to be idiot-proof, reliable, and cross-browser.
I see Dropbox, Google Drive, and YouTube doing big files without requiring special software so I figure there has to be a way. That's my real goal.
12 October 2012
Paul
var options = { iframe: { url: 'repraw.ashx?task=get_testupload&nId=1'} }; // Attach FileDrop to an area: var zone = new FileDrop('zone', options); var force = !fd.HasClass(btn, 'down'); zone.opt.iframe.force = force; fd.SetClass(btn, 'down', force); // Do something when a user chooses or drops a file: zone.on.send.push(function (files) { // if browser supports files[] will contain multiple items. for (var i = 0; i < files.length; i++) { var file = files[i]; file.SendTo('repraw.ashx?task=get_testupload&nId=1'); file.on.done.push(function (xhr) { alert('Test'); }); } });The event file.on.done.push(function(xhr){ }); on Firefox this is triggered but on IE it's not why?
Simply my alert('Test'); is not triggered when am using IE after a file is sent to the server side for processing…
Best Regards,
paul
12 October 2012
Proger_XP
File's done event only works for AJAX upload (Chrome/Safari/Firefox). For IE & Opera that use
xml<iframe>uploads you have to use FileDrop's iframeDone event.12 October 2012
Proger_XP
Just as you do with normal on.send – check the demo page's source code:
zone.on.iframeDone.push(function (resp) { fd.ByID('response').value = 'IFrame upload response: ' + resp.responseText; });12 October 2012
Paul
How do i initialize that? can you give me an example?
Thanks
9 October 2012
LordArach
This is awesome! I'm trying to store the file on the server to no avail though. I have the following on the php side that works in a standard upload form but not here. The script sees the file, creates the directory, and reports back your bits that the file CRC is good but the file doesn't save in the folder. I'm sure I'm doing something stupid. Any help in proving so would be greatly appreciated.
<?php
$charset = '; charset=utf-8';
$callback = &$_REQUEST['fd-callback'];
$FEIN = '12-3123123';
//$FEIN = $_POST['fein'];
$url = "http://www.somewhere.com";
$allowed = array('application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document');
if (!is_dir('../../'.$FEIN)){
mkdir('../../'.$FEIN);
}
if (isset($_FILES['fd-file'])){
$name = $_FILES['fd-file']['name'];
$data = $_FILES['fd-file']['tmp_name'];
$accept = &$_SERVER['HTTP_ACCEPT_CHARSET'];
$accept and $charset = '; charset='.strtok(strtok($accept, ';'), ',');
if (in_array($_FILES['fd-file']['type'], $allowed)){
if (move_uploaded_file($_FILES['fd-file']['tmp_name'], '../../'.$FEIN.'/'.$name)){
header("Location: $url");
}
}else{
echo 'Your file did not upload.';
}
}else{
$name = urldecode($_SERVER['HTTP_X_FILE_NAME']);
$data = file_get_contents("php://input");
}
$output = sprintf('%s; received %d bytes, CRC32 = %08X, MD5 = %s', $name, strlen($data), crc32($data), strtoupper(md5($data)));
if ($callback) {
header('Content-Type: text/html'.$charset);
$output = addcslashes($output, "\\\"\0..\x1F");
echo '<!DOCTYPE html><html><head></head><body><script type="text/javascript">', "try { window.top.$callback(\"$output\"); } catch (e) { }</script></body></html>";
}else{
header('Content-Type: text/plain'.$charset);
echo $output;
}
?>
9 October 2012
Proger_XP
Some things to try:
PHPerror_reporting(-1);to the beggining and check the logs.PHPmove_uploaded_file()? If so, try replacing this function withPHPfile_get_contents()– it's not secure but if it will work report here and I'll try to help.PHP$_FILES[]['type']– it's easy to bypass.18 October 2012
Proger_XP
Check the source code of the demo's index.html – it's File's on.done event that occurs once a file has been uploaded using AJAX. If you support
xml<iframe>uploads check FileDrop's (drop zone's) on.iframeDone event – also present in the demo.Hook on.done before calling file.sendTo() – it will receive the XHR object and its this will be set to the file sent so you can access its name, size and other properties.
18 October 2012
LordArach
I currently have it set up so that the user can request a client directory with an input field, the input AJAX's over to a php script to display all documents associated with that client, upload new files to that client's directory, and also call another AJAX event to delete documents. For this, I have an onkeyup on the input field that finds the client in the database to display the documents and then an onclick on the delete key next to the filename that triggers the delete portion. I'm having a bit of trouble finding where I can put in a section to automatically update the div with the filename when a new file is uploaded so it will display without having to refresh. I don't know where exactly in your script to attach a trigger to refresh the div. I hope that all makes sense. Any ideas?
12 October 2012
Proger_XP
Ah, I see. It's okay then.
Haha, that's amazing, thanks go for you though for using my code in your projects :)
12 October 2012
LordArach
Clarifying: I changed the last lines of the script in the HTML file, not the JS file so I should be able to keep up with changes you make in the future.
var inputValue = fd.ByID('inputValue').value var url = fd.HasClass('causeError', 'down') ? 'not-existing.php' : window.ZoneURL file.SendTo(url+'?inputValue='+inputValue)Then I added a GET to the upload file to use it there.
It's all working perfectly now. You did an awesome job on this piece and have the best support I've seen in a while!
12 October 2012
Proger_XP
You might have problems updating to the next version of FileDrop if you modify its script directly. Besides, there's no need to as it provides numerous event callbacks.
12 October 2012
LordArach
Thanks! I got that one pretty easily by var'ing out my field and attaching it to the end of the url string on the last line of the script.
11 October 2012
Proger_XP
Don't forget to tune in production nginx' (client_max_body_size) or other webserver's settings.
For the error fallback you can use file.on.error event – check the demo's code (index.html).
I'm happy you like FileDrop. Hopefully it will make your project a bit better :)
11 October 2012
CaptNemo
You're quite right. I had forgotten that the stuff I was mucking around with didn't come from your demo. haha. In any event (no pun intended) this problem seems solved. I've tested it now to 100 megs. Right now it fails at 150 megs, but that's because a 67 meg memory allocation request from PHP failed because of my PHP.INI settings. We'll see how far I get.
What I really want to do with file upload can't be done. I want to do my own code to send files from the browser to the server in sequenced chunks and re-assemble them on the server, provide progress indication, and continuation after an interruption, and no size limits--kind of a mini-FTP. This business of packing 600 megabytes into a POST and then hoping the browser successfully pushes it up to the server over the next two hours is ridiculous. But there's no other way to do it because the only way to access files on the client is through the POST mechanism.
Thank you very much for some very nice code, and thanks for your help. Phil
11 October 2012
Proger_XP
I assumed people implementing the PHP part would understand how the script works but perhaps I should describe it explicitly (this won't hurt at least).
And in fact it wasn't the problem in my demo's upload.php, it's just you have added the code into the wrong place :)
11 October 2012
CaptNemo
Well, well. Nicely done. It took a while for me to respond because I tested various cases on two completely different server environments and your fix works fine! Now that I see the problem, I think it was just an oversight on your part. I should have seen it myself but I'm not yet comfortable with the file upload process to question what I see. haha.
11 October 2012
Proger_XP
If you need to add it to the URL that's sent to the server just do this in your SendTo() call. For example, in the usage demo it's like this:
for (var i = 0; i < files.length; i++) { files[i].SendTo('your-upload-script.php?input=' + prompt('WTF?')); }11 October 2012
LordArach
I owe you a drink! It should help him as well. It sounded like the same issue. Now I just have to go through the js file to see where I can insert a variable to send an input box value with the file and I'll be done with this thing.
11 October 2012
Proger_XP
This was my mistake indeed, updated the code. Hope this helps CaptNemo as well.
11 October 2012
LordArach
Nevermind. This did the trick… file_put_contents('../../uploads/'.$name,$data);
Thanks! I really appreciate your help. I now have it creating the upload location, saving the file on the server, and writing the location to the database.
11 October 2012
LordArach
Cool! I have some progress and some «grr's». I had to modify the file_put_contents a bit because it wanted two parameters. I replaced it with is_dir('../../uploads') or mkdir('../../uploads'); file_put_contents('../../uploads/'.$name,'.pdf');
This is now creating the directory as it should and putting a file with the original name and format in that folder. The only issue now is that no matter what file I give it, all I get is a 1KB file back.
11 October 2012
Proger_XP
What I find really strange is that your execution (seems to?) goes by
PHPthenbranch. Let me explain:1. If file is being uploaded using regular form POSTing, i.e. if the browser doesn't support drag & drop upload,
PHPthenexecutes.2. If FileDrop uses file API to read/send the contents it does so by placing it into the POST body entirely, not as a regular form would send it. That's why we read file data from php://input (docs) which corresponds to raw POST input data.
So if you're using Firefox/Chrome/Safari you should have the
PHPelsebranch running. And, of course, you won't be able to justPHPmove_uploaded_file()there because it's not uploaded the way regular form does and PHP doesn't save it anywhere, create the record inPHP$_FILESand so on.What I suggest is:
if (!empty($_FILES['fd-file']) and is_uploaded_file($_FILES['fd-file']['tmp_name'])) {
$name = $_FILES['fd-file']['name'];
$data = file_get_contents($_FILES['fd-file']['tmp_name']);
} else {
$name = urldecode($_SERVER['HTTP_X_FILE_NAME']);
$data = file_get_contents("php://input");
}
// save the file somewhere by writting $data:
is_dir('uploads') or mkdir('uploads');
file_put_contents('uploads/'.time().'.dat', $data);
10 October 2012
CaptNemo
Interesting. I have PHP error reporting turned on and I know logging is working because there are errors from four days ago on another experiment in the log file, but no errors from this problem.
I have been testing this on a local Hiawatha server. To see if that's the problem, or maybe a timing problem, I just finished trying it on a remote server (1and1) running Apache, using a slow connection, and it does the same thing. That server is set up for 600 MB uploads
I really like this piece of code that Proger has developed. I'm sure the problem is something simple because the demo works on his server.
10 October 2012
LordArach
Mine looks almost identical at the moment after stripping out everything I didn't need. I put my move_uploaded_file() after the else statement though. It's still the same result. I put an or die() at the end of the first line and it catches it there. I'm thinking it has something to do with «fd-file» which is weird because it sees it to report back the name and status but not to actually move it.
10 October 2012
CaptNemo
Test code I'm running is below. It never reaches move_uploaded_file. It completes via file_get_contents after uploading all 800k of the file.
if (!empty($_FILES['fd-file']) and is_uploaded_file($_FILES['fd-file']['tmp_name'])) { $name = $_FILES['fd-file']['name']; $tmp_name = $_FILES["fd-file"]["tmp_name"]; $data = file_get_contents($tmp_name); $accept = &$_SERVER['HTTP_ACCEPT_CHARSET']; $accept and $charset = '; charset='.strtok(strtok($accept, ';'), ','); echo "before move uploaded\n"; die(); move_uploaded_file($tmp_name, "uploads/$name"); echo "after move uploaded\n"; die(); } else { $name = urldecode($_SERVER['HTTP_X_FILE_NAME']); $data = file_get_contents("php://input"); //echo "after file get contents\n"; //die(); }10 October 2012
CaptNemo
Same happens here so I'm watching this conversation. I'm not worried about safety right now either. I just want to make it work and I can add safety checks later.
10 October 2012
LordArach
move_uploaded_file() errors out on die() and doesn't move file. file_get_contents() completes the script and doesn't move file.
10 October 2012
LordArach
To be fair, this is for intranet only so I'm not as concerned with people uploading malicious files. I will definitely look into the magic numbers more though! It looks interesting.
It seems that the whole thing is dying on if (isset($_FILES['fd-file'])) for some reason. It is not liking «fd-file» at all. I've tried it in the top five browsers with the same outcome in each.
10 October 2012
Proger_XP
Come on, this is much more easy to fake than even the MIME – just rename badfile.exe to badfile.doc and it will retain the contents while bypassing your check. Find magic signature of doc/docx/pdf files and read it from the input – only then you can be (relatively) sure it's not something else.
Have you traced the execution? Is
PHPmove_uploaded_file()reached? Try insertingPHPdie()calls. In general it all looks fine.9 October 2012
LordArach
actually… substr($_FILES['fd-file']['name'], -4) == '.pdf'
9 October 2012
LordArach
I added error_reporting and the logs report zero errors. My standard upload form is moving right through it with move_uploaded_file and file_get_contents. The results in this script are unchanged. Thanks for the advice on $_FILES[]['type']! I switched it to substr($_FILES['name'], -3) == '.doc, .docx, .pdf'.
3 October 2012
Anonymous
I use Google Chrome and try to upload 30mb videofile. But Always brower busy. And Stop at FileDrop sendXHR event (1); args: . Does anyone have the same problem?
3 October 2012
Proger_XP
30 MiB might be too large. Are you sure the server supports that large uploads? Usual limit is about 5 MiB. If you're trying it in the official demo then this server definitely won't allow such a hassle.
Also, have you tried another browser? Especially Firefox.
5 September 2012
Andreas
Hi Proger,
Great script you made, but i have a serious problem with the «good» old Internet Explorer. I can drop an item to the FileDrop Box (iFrame) but the browser doesnt send data. i think this is not possible with ie. but could you perhaps disable the form submit on drag&drop for IE?
Greetings, Andreas
5 September 2012
Proger_XP
You're right, IE 6 was a pioneer in implementing file drag and drop but sort of in its own way so it doesn't work, at least today. I have disabled it for IE 6-, Normal
xml<iframe>uploads will work for it (by clicking on the drop zone).As a side note, IE 8 doesn't pretend to understand drag and drop.
You can already get the latest version with the fix. Thanks for notifying me.
3 September 2012
scratchresistor
Hi Proger,
Another strange problem – do you have any idea why Safari (and only Safari) would return the 'done' event immediately after the sendXHR event, with no upload performed?
3 September 2012
Proger_XP
Which version do you use? I have tested this on Safari 5.0.3 and it works:
3 September 2012
Proger_XP
The fix is there, grab the archive and test – it should work in any browser.
3 September 2012
Proger_XP
Thanks, I wrote it overnight and I'm glad you like it. Regarding the bug – I'm not sure why it works in my version of Safari; I'll check the newer version and see what's wrong. If it fails I'll only enable it for Chrome (although it doesn't mean that newer version of Chrome won't have the same bug as it's Webkit too).
Thanks for reporting anyway.
3 September 2012
scratchresistor
Looks like it's broken in the demo code too – the done event fires instantly after the sendXHR event. I've wrapped my fix in if (window.fd.isChrome) and it's all working well now.
Sorry I broke your code – awesome library by the way (in comparison to Plupload, which I was using before, and hate)!
3 September 2012
Proger_XP
Does it break in the demo page as well? Or only in your code?
3 September 2012
scratchresistor
Confirmed, the sendAsBinary fix breaks Safari – perhaps only apply it when Chrome is detected?
3 September 2012
Proger_XP
It's just with Safari? Try alert()'ing the data FileDrop is sending to the server – it's probably null or something:
self.SendXHR = function (xhr, data) { alert(data); if ... }If it's non-empty then check if the sendAsBinary() fix suggested earlier actually works. Also, maybe it has something to do with the kind of file you're uploading (binary, textual, etc.).
Have you changed the code sending the file? Since the demo works for you.
3 September 2012
scratchresistor
No, I'm getting content-length 0
3 September 2012
Proger_XP
Well, Safari transfers Content-Length for me. It doesn't for you?
3 September 2012
scratchresistor
I'm using 5.1.7, and your demo page work fine, I think it's likely a problem with my server code, so I was wondering if you knew of any differences between Safari and the other browsers in terms of how they do XHR that might affect what I need to do on my server. The only thing I can come up with is that Safari doesn't like sending the content-length header, so my server side code (python based, incidentally) might be reading zero bytes and returning a 200 straight away when using Safari.
2 September 2012
scratchresistor
Hi Proger,
I was having real trouble getting Chrome to work with binary files, but adding the following patch at the top of filedrop.js fixes it (from Portable sendAsBinary)
try { XMLHttpRequest.prototype.sendAsBinary = function(datastr) { function byteValue(x) { return x.charCodeAt(0) & 0xff; } var ords = Array.prototype.map.call(datastr, byteValue); var ui8a = new Uint8Array(ords); this.send(ui8a.buffer); } } catch (e) { // XHR not supported }2 September 2012
Proger_XP
Hey, thanks! I have updated the code, now it uses your fix (though it doesn't change XMLHttpRequest's prototype). You can get the fresh version here.
22 August 2012
resunny
i developed website with struts2. And i don't know how i attatch this javascript. Struts2 can't read a file when drag-n-drop a file.
16 August 2012
z3phir
very nice one little addon would be great image resize client side before upload
16 August 2012
Proger_XP
Can you clarify your idea?
17 August 2012
z3phir
something like plupload image resize
1 August 2012
Esa
Hi, excellent job! It works like a charm, but I'm stuck trying to show the image uploaded directly on the form (with a max-width css of course). Could you help me?
1 August 2012
Proger_XP
Hey Esa, thanks for your feedback! If you can provide more details or upload a sample I can give it a try.
8 August 2012
Proger_XP
You're welcome :)
8 August 2012
Esa
Hi, sorry for reading only now…
Really thx for that ^^
3 August 2012
Proger_XP
FileDrop provides cross-browser file name and size (see File properties). If you want MIME type or other details you can access browser's native file object by the nativeFile property. Example:
zone.on.send.push(function (files) { for (var i = 0; i < files.length; i++) { var file = files[i]; if (!file.name.match(/\.(gif|png|jpe?g)$/)) { alert('Wrong file extension.'); } else if (file.size > 3 * 1024 * 1024) { alert('File is too large.'); } else if (!file.nativeFile.type.match(/^image\//)) { alert('File must be an image.'); } else { // do the upload. } } }Of course you don't have to check for all the above details (and it hardly makes sense to check both MIME and extension).
3 August 2012
Esa
Hi again,
is there a way to force a choice among some extentions only and under a max size (x Mo) to prevent the uploading process.
I'm able to check these params on the upload.php script, but it's too late for me.
Cheers
2 August 2012
Esa
Lol, it seems we worte together^^
Anyway, thx a lot for your time.
2 August 2012
Esa
Well, I solved it.
In fact, the <img> url is cached then imgblobu.php?uid=11 is called once only. So I added a d param with a random value to force the recall of the image.
Here is the onDone I wrote:
var onDone = function (xhr) { var m = document.getElementById('imgres'); m.innerHTML = ""; var RandomID = function () { return 'img_' + (Math.random() * 10000).toFixed(); } do { var id = RandomID(); } while (document.getElementById(id)); m.innerHTML = "<img id='" + id + "' src='imgblobu.php?d=" + id + "&uid={$user.userid}'>"; };Cheers
2 August 2012
Proger_XP
No, it's fired either after successfully receiving the response or never – because there is also onError that is fired instead of onDone if something went wrong.
You can check if it's caching issue (likely it is) by doing alert(1) in your onDone handler. I can suggest three solutions:
2 August 2012
Esa
Hi again, I still have a trouble when I upload more than one image (one by one). It seems innerHtml works fine the first time but next still display the first image uploaded.
Pearhaps once the imgblobu.php has done one time, it still in cache (IE and FF) and is not call again?
Or the OnDone is sent before the complete end of the upload.php ? (the data in the DB is correct)
Did you see same problem from your side?
Cheers
2 August 2012
Esa
Yeah!!! You're the boss ;o)
Thx for this nice job.
2 August 2012
Proger_XP
Sorry, it was my mistake. Like I have said (and forgot when writing the code for you) iframeDone event belongs to the zone object (FileDrop), not File.
var options = {iframe: {url: 'upload.php'}}; var zone = new FileDrop('zone', options); var onDone = function (xhr) { var m = document.getElementById('imgres'); m.innerHTML = '<img src="imgblobu.php?uid=1">'; }; zone.on.iframeDone.push(onDone); zone.on.send.push(function (files) { for (var i = 0; i < files.length; i++) { files[i].on.done.push(onDone); files[i].SendTo('upload.php'); } });You can also force loading by
xml<iframe>to check if it works by setting iframe.force option like:var options = {iframe: {url: 'upload.php', force: true}}; // or after creating the zone: zone.opt.iframe.force = true;Don't worry about it, seeing that people like what I create makes me happy )
2 August 2012
Esa
Hi man with no name ^^
Well, it doesn't work because I did somethink wrong for sure, but what? :
<fieldset id="zone"> <legend></legend> <div id="imgres"><img src="tpl/images/imgres_msie.png"></div> </fieldset> <script type="text/javascript"> var options = {iframe: {url: 'upload.php'}}; var zone = new FileDrop('zone', options); var onDone = function (xhr) { var m = document.getElementById('imgres'); m.innerHTML = '<img src="imgblobu.php?uid=1">'; }; zone.on.send.push(function (files) { for (var i = 0; i < files.length; i++) { files[i].on.done.push(onDone); files[i].on.iframeDone.push(onDone); files[i].SendTo('upload.php'); } }); </script>I'm not proud to spam your comments with that… Could you hepl me more?
2 August 2012
Proger_XP
Haha, not sure why I'm Roy but anyway you're welcome. You don't have to put that code inside filedrop.js, it's a user-land code – just put it before you call file.SendTo().
2 August 2012
Esa
Hi Roy, 1/ thx for your quick replies^^ 2/ the ID is allready in the fieldset as hidden input, before the upload:
<fieldset id="zone"> <legend></legend> <input type="hidden" id="userid" value="{$user.userid}" /> <div id="imgres"><img src="img/imgres.png"></div> </fieldset>3/ where, in your filedrop.js, need I put this following code?
var onDone = function (xhr) { var id = fd.ByID('userid'); // the image ID var m = fd.ByID('imgres'); // the image div m.innerHTML = '<img src="imgblob.php?id="' + id.value + '>'; }; file.on.done.push(onDone); file.on.iframeDone.push(onDone);4/ really thx for your patience ;o)
2 August 2012
Proger_XP
Use this:
var onDone = function (xhr) { // if your script gives thumb ID in plain text: var id = xhr.responseText; // if it gives a JSON object string: try { var id = eval('return ' + xhr.responseText + ';').id; } catch (e) { } // now do what you need. }; file.on.done.push(onDone); file.on.iframeDone.push(onDone);p.s: code blocks are wrapped in double percents (%%).
2 August 2012
Esa
Thx for your reply. In the upload.php, I don't copy the file, I resize it and save it as Blob into the MySQL database. No need of the big source file, so the solution will be the second one.
I made a script (imgblob.php) to load and display the image from the DB.
Could you tell me in witch functions I've to place this code:
And of course, I need it with and without iFrame^^
Thx a lot
1 August 2012
Proger_XP
The solution depends on where you want to load the thumb from:
The first way can't be done using FileDrop alone – it involves browser-dependent File API. For example, in Firefox 4+ you can use this code:
if (files[i].nativeFile.type.match(/^image\//)) { var reader = new FileReader(); reader.onload = function (e) { var img = document.createElement("img"); img.src = e.target.result; fd.ByID('image').appendChild(img); }; reader.readAsDataURL(files[i].nativeFile); }It will add
xml<img />to #image element once the user selects an image for upload If you want to display that thumb only after the upload has succeeded use the done event:if (files[i].nativeFile.type.match(/^image\//)) { files[i].on.done.push(function () { ... reader.readAsDataURL(this.nativeFile); }); }The second way is simpler – you send the file normally listening for the done event; when it fires you receive the response object from which you can get thumbnail URL and do display it. This will work regardless of the browser used.
If you want to support
xml<iframe>fallback you need to listen for iframeDone event1 August 2012
Esa
I hope the html text will show up like it is:
<fieldset id="zone">
<legend>Drop a file inside…</legend> <div id="resimg">
<p>Or click here to <em>Browse</em>..</p> </div> </fieldset>
Well, I just put the <P> into a <Div> in order to replace the innerhtml by a <img> tag once the image is loaded, to show it. But I've no idea how and where I can do that. I think there are 2 places for that in the .js, due to the iframe or not, but I'm stuck… ;)
In fact, I would like to see the loaded image in the form immediatly after the loading is done.
Thx^^
23 June 2012
Roy
Your code looks nice. However, I wonder why multiple-files feature on your demo page is disabled if the browser is Firefox (13.0.1) ?
23 June 2012
Proger_XP
Looks like it wasn't disabled, it was a (new) Firefox glitch that caused the invisible file input to overlap the underlying buttons if the zone used
xml<fieldset>. Fixed in new version.24 June 2012
Proger_XP
I'm happy you find it useful! Hope others will find it as well. Thank you for using it, Roy.
24 June 2012
Roy
I see. I will try your uploader next week and then give you more feedback. So far your code is concise and easier to integrate than valums's ajax-upload. Thanks for sharing it!
24 June 2012
Proger_XP
You're welcome.
The problem was that I was using
xml<fieldset>on the demo page (and on some other pages too). That fieldset acts as an overflow protector. There's an invisible (opacity: 0)xml<input type="file">that uses font-size: 118px so that the user can click or drag a file anywhere inside the fieldset. Fieldset is styled with position: relative and overflow: hidden, however, Firefox has stopped to recognize the latter and thus the file input was overflowing its parent nodes thus overlaying the page under the fieldset.I added a fix to FileDrop.SetupInput() that checks if zone is of tag
xml<fieldset>and if it is it wraps the fieldset into axml<div>styling the latter with the same styles (position and overflow). Strange enough the file input continues to overflow but only on the left side of the div, not under – can't figure out how to fix this but at least it's not seriously troublesome. I would suggest using something else thanxml<fieldset>for zone container if it's a problem in some particular case.24 June 2012
Roy
Proger, that's quick. how did you fix it? thanks!
20 June 2012
Anonymous
Hi
Thank you for posting your code, great work! I have firefox 13.1 installed and the demo on your website does not work (you can see in the text box that no drag event is hooked); however using Chrome everything seems to work fine.
Do you have any idea of why this may happen?
Thanx
JT
20 June 2012
Proger_XP
Hm, I have just tested it:
Latest Firefox 13.0.1 / release.