Clean drag and drop upload in Safari
Somehow I often find myself arguing in defense of the web browser as a viable platform for developing rich applications. In many such discussions, the issue of interoperability with the desktop arises. Someone will astutely observe that they can’t even drag and drop from their OS file manager into their browser, and all hell will break loose.
Happily, this is changing! Since version 3, Safari on Mac OS X has had support for dragging and dropping files from the finder into file input boxes. In various kludgy ways, Firefox and IE are now following suite.
Unfortunately, even in Safari, the default look of the <input type=”file”> box is quite ugly and the element itself is difficult to style. In addition, clicking anywhere in the file input element causes the default open file dialog to appear. I wanted to provide drag-and-drop uploading without ugly boxes or browser dialogs. The solution I came up with involves hiding the file upload box entirely by setting its opacity to 0, and then preventing the default action on click via event.preventDefault(). Here’s a sample of what I mean, with the entire browser window converted into a drag area.
Note that the drag area must be the first DOM element to receive the drop event for this approach to work. Unfortunately I ran into a bug where the file dialog refuses to bubble click events to other elements below it. This is baffling to me, since event.preventDefault() should not stop event propagation, but only prevent the default browser handler from being called. You can see what I mean by trying to click the link in the sample HTML file. If this is not a bug, and someone has an answer, I would really appreciate it.
Note also that there are java applet-based drag and drop solutions, but they are reserved for developers who have nothing but disdain for their users.
4 comments:
Cool hack. The problem with web apps as rich applications is that there are a ton of little things like this that don’t quite work, that require hacks like this to work around. Even when developing desktop apps, there are all kinds of little things that you have to get right to really fit in with the system (eg to “feel like a Mac app”).
The model of a desktop app communicating with a server via some API seems to me to be an easier way to get the benefits of web apps along with the benefits of feeling like a native app.
Clearly some rich web apps can work, but I’m personally much more likely to pick a desktop app than a web app for something I use a lot.
Thanks Sean! I see where you’re coming from, but the convenience of being able to access your application from anywhere is still very appealing to me. For this reason I have a slight bias against desktop apps, as my mac isn’t always with me. On the other hand, native mobile apps don’t suffer from this, and I greatly prefer native iPhone wrappers around web services like twitter and facebook.
Writing an app that feels like a Mac app is a difficult task, but at least there is a target to aim for. I find that the problem with web app design is that it’s much harder to pin down exactly what a web app should feel like.
Awesome! Your code helps me a ton on a project I’m building. You wanted to know how a person could click on your link? What about adding this to your body tag?
This way, when you move your mouse inside Safari the container hides.
But, when you click on a file outside of Safari (to grab a file) the container shows up. Since you’re dragging a file over the Safari window it still won’t have notice a mouse move. When you let go to drop the file it’ll go to your container. As soon as Safari gets focus back the container goes away. I suppose onfocus may be better (but keep in mind you’d have to have an onload with the same code, since onfocus doesn’t seem to trigger on a refresh)? Anyway, just thought you’d like to know.
Thanks again for your code!
Opps… It didn’t do the code…
mousemove = “document.getElementById(‘container’).style.display = ‘none’;”
onblur = “document.getElementById(‘container’).style.display = ”;”