|
Straxus cat /dev/kbd | grep --random-lines > straxus.javadevelopersjournal.com | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Mailing List
Login Console
|
Creating a Mozilla/Firefox Drag and Drop file upload Script (Part 1)
There has been a lot of focus lately on web applications which have enhanced rich-client functionality, such as the oft-published AJAX approach adopted by Google Maps and GMail. One of the features which is present for desktop applications but which is difficult to accomplish with a web page is drag and drop of something that didn’t start off on the webpage (for example, dragging an image around a webpage is fairly easy to do, however dragging a file or shortcut from the desktop onto the webpage is much more difficult). In addition, although such functionality exists and is fairly easy to access with an ActiveX control for Internet Explorer, it is difficult to replicate inside of a Mozilla/Firefox browser due to the inherent complexities of cross-platform support as well as the stronger security model. However, difficult does not mean impossible, and this article will describe how to create a control which allows a user to drag a file onto a webpage and upload it (automatically if desired) to a given server. I will mention now that this first part of the discussion will create a file which functions correctly on the local machine – Part 2 will deal with the difficulties of packaging up this code in a Jar, signing that Jar, and deploying it on a remote server. Overview of what will be doneBefore we dive in, I will give you a quick run-down of what we will accomplish with this code example. The steps which need to be followed are:
Registering for the Drag and Drop eventThe first thing that we need to do is tell the Mozilla/Firefox window that we want to register for the drag-and-drop event. Now, the way it would normally work for an event is that we would do the following:window.addEventListener("dragdrop", dragDropHandler, true);This would register the method dragDropHandler with the dragdrop event for the window. However, just doing this will not work correctly. We need to first tell the browser window explicitly that we want drag and drop events, and then register for the event. Code for this looks like:window.captureEvents(Event.DRAGDROP);Finally, we’ll want to defer doing this until the page has loaded, to ensure that all the HTML and scripts are present before we try to use this. So, the final code for this will look like: function loadMethod() Requesting permission to access the XPConnect bridgeIn Mozilla, the main browser functionality is wrapped in a library called XPCOM. This library is what handles most of the lower-level interactions with the host operating system, and is designed with cross-platform considerations in mind. If you wish to access XPCOM functionality from within a web page of some kind, you must use the XPConnect bridge which handles interfacing between XPCOM and Javascript. For a much more in-depth explanation of how all of these components work together, please see the Mozilla XPConnect Page.Since XPConnect provides a lot of system access, permission to access it is only given after a security check. In order to request this security check, we must do the following: netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');This will ask the browser for the ability to communicate with the XPConnect bridge. If the page is not already a trusted page, this will cause a dialog to appear for the user asking them if they wish to grant permission for the page to "install and run software" (which I suppose is the primary use of the XPConnect bridge).A couple of things about the Mozilla permissions system need to be pointed out right now, as they will affect how this drag and drop example is built:
function dragDropHandler (evt) {Retrieve the Drag and Drop Event from MozillaNow we’re going to get into the interesting stuff – how to load classes from XPCOM which handle the drag and drop operation. To start with, we need to load in the Mozilla Drag Service. This is done with:var dragService =What this line does is load in the Mozilla drag service class from the table of classes, and then retrieve the nsIDragService class (API Reference for nsIDragService available here) from that loaded class and return it. This class handles the creation and destruction of drag and drop sessions, and we will use it to retrieve the current drag-and-drop session with: var dragSession = dragService.getCurrentSession();We now have the in-progress drag and drop session, which is an nsIDragSession (API Reference for nsIDragSession available here). In order to draw the data out of this session, we need to create a new nsITransferable (API Reference for nsITransferable available here) and choose the types of drag-and-drop data we want to receive. This is done with: var transferObject =Take note of the second line of code above – the nsITransferable needs to be explicitly created/casted using the QueryInterface call to ensure that all the properties and methods of nsITransferable are present on the Javascript object. Determining the Format of the Data being DroppedSo we’ve created an nsITransferable object, but we don’t yet know what types of data are present in the drag and drop session. In order to check if certain MIME types are supported by the session, we would call:var isSupported = dragSession.isDataFlavorSupported("application/x-moz-file");This will return a boolean (true or false) indicating whether the given MIME type is supported. For the sake of this example, I have foregone checking of the MIME type of the session data – this will result in an error if the thing dragged onto the Mozilla window is not a file.Based on the assumption that a file will be present, I have chosen to only request the application/x-moz-file data flavor from the drag-and-drop session – this is the MIME type of a file, and it is all I want to be dropped. However, you can choose any MIME type you want - a list of supported MIME types is available here. The code to set the requested MIME types is: transferObject.addDataFlavor("application/x-moz-file");This will cause only the application/x-moz-file data to be retrieved from the Drag Session which is in progress.Retrieving Filenames from the Drag sessionFinally, we get to what we’ve wanted to do all along – retrieve the names of the files being dropped onto the browser window. First, we’ll want to figure out how many files are being dropped, which is done with:var numItems = dragSession.numDropItems;This will allow us to loop through each dragged item and handle it individually. Next, we want to enter the loop and grab the actual items from the drag session. This is done with: for (var i = 0; i < numItems; i++)This will retrieve the given item from the Drag Session into the nsITransferable object which we created. At this point we have the dragged file in a Transfer object, but we still need to retrieve the specific data-type from the Transfer object. In order to do this, we need to call the transferObject.getTransferData method (Method API docs available here). However, you will note that this method has two parameters listed as OUT parameters – what that means is that return values for this method will be returned in those objects. In order to properly handle an XPCOM OUT parameter, we need to create new Object()s and pass those in as the OUT parameters, and then check the Object’s value property. An example of how to do all of this (and return the data object at the same time) is: // We need to pass in Javascript 'Object's to any XPConnect method whichAs we can see, we have created two new OUT parameters, called the getTransferData method to retrieve the dragged data, and displayed the value of the second OUT parameter in a dialog box using the Object.value property. Request File System Read PermissionsBefore we can set the value of a File input field, we must request local file read permissions. This is done with:netscape.security.PrivilegeManager.enablePrivilege('UniversalFileRead');Please note that if we don’t do this, we will get a security exception when we attempt to set the value of the file input field. Also remember the restrictions on enablePermissions which were described in the Request permission to access the Mozilla XPConnect bridge section – the same restrictions apply here.Save the Filename to the Form’s File Input FieldAt long last, we’ve reached the end. In order to save the filename of the dragged file into the form’s file input field, we need to take the value of the data object which we were returned from the getTransferData call and cast it as an nsIFile (API Reference for nsIFile available here). Then, we take the path from the nsIFile and save it in the file input field’s value property. This is done with:var droppedFile = dataObj.value.QueryInterface(Components.interfaces.nsIFile);Note the QueryInterface call to ensure that the nsIFile capabilities were applied. Also take note of the retrieval of the file input field – in this example, we will retrieve the same file input field every time through the loop and overwrite it’s value with the value of the next dragged file. If we wanted to do something more intelligent like add a new file input field for each file, we could use DOM to create a new file input node, e.g.: var newFileIn = document.createElement(“input”);It would also probably be advisable to set the form to be hidden, so the user isn’t seeing all of these file input fields appearing and such. This can be done by setting the form to have a style of ‘visibility: hidden’, e.g.: <formAlso take note of the encoding type of multipart/form-data – since we’re uploading a file, we will want to encode with this type to ensure the file isn’t mangled in transit (as the default form encoding of application/x-www-form-urlencoded will do). At this point, the file data is saved in the form. When the form is submitted, it will be uploaded to the server. Depending upon your application, you may wish for this to be an automatic process – in that case, you would simply call formObject.submit() at the end of your Javascript method, and the form would be uploaded. Marking the Event as handledNow that we’re done and we’ve handled the event, make sure to let Mozilla know! If you don’t mark the event as handled, then the default handler will also kick in and do unexpected and undesirable things (like open the document inside of the current window). This marking is done with:evt.stopPropagation();Where evt was the event that we were passed in to our drag and drop handler. Full code for this discussionThis code is the full code of the sample which I built. I have included several debugging output statements which were not discussed above, which show the state of the drag and drop operation at different points. It must also be noted that, in order to have a production-level set of usable code, you will want to implement error checking and exception catching (which I have left out as it contributes nothing but clutter to the demonstration of functionality). In particular, every permission check can throw an exception if the permission is not granted, so that should be handled in a more graceful manner.<HTML> As a final note, this article is Copyright (C) 2005, Codesta LLC. All Rights Reserved. All of the research that I did for this article was on company time, and Codesta agreed to let me publish it. The information in it is free for you to use, but don't go claiming it's yours - it's not. ironstorm made this comment,
comment added :: 29th June 2005, 09:35 GMT-05
Straxus made this comment,
comment added :: 29th June 2005, 09:46 GMT-05 :: http://straxus.javadevelopersjournal.com
Trevan made this comment,
comment added :: 18th July 2005, 15:20 GMT-05
Straxus made this comment,
comment added :: 23rd July 2005, 09:24 GMT-05 :: http://straxus.javadevelopersjournal.com
Priyu made this comment,
comment added :: 26th November 2005, 06:55 GMT-05
jj made this comment,
comment added :: 5th December 2005, 05:25 GMT-05
Straxus made this comment,
comment added :: 5th December 2005, 22:37 GMT-05 :: http://straxus.javadevelopersjournal.com
FreddytheFish made this comment,
comment added :: 13th December 2005, 19:11 GMT-05
Napolux made this comment,
comment added :: 17th February 2006, 07:05 GMT-05 :: http://www.napolux.com
Straxus made this comment,
comment added :: 17th February 2006, 12:00 GMT-05 :: http://straxus.javadevelopersjournal.com
ATLAS made this comment,
comment added :: 20th February 2006, 23:57 GMT-05
Straxus made this comment,
comment added :: 21st February 2006, 13:44 GMT-05 :: http://straxus.javadevelopersjournal.com
ATLAS made this comment,
comment added :: 21st February 2006, 14:24 GMT-05
Fish made this comment,
comment added :: 25th February 2006, 23:23 GMT-05
woktiny made this comment,
comment added :: 14th March 2006, 16:57 GMT-05
Mike made this comment,
comment added :: 9th May 2006, 15:27 GMT-05
dipesh made this comment,
comment added :: 7th June 2006, 11:51 GMT-05
Benjamin Hawkes-Lewis made this comment,
comment added :: 24th June 2006, 04:20 GMT-05
Matt made this comment,
comment added :: 9th August 2006, 15:51 GMT-05
dyrek made this comment,
comment added :: 1st November 2006, 16:36 GMT-05
dyrek made this comment,
comment added :: 1st November 2006, 16:37 GMT-05
Dave made this comment,
comment added :: 3rd January 2007, 10:59 GMT-05
Tref Gare made this comment,
comment added :: 6th March 2007, 20:34 GMT-05
rgtaylor made this comment,
comment added :: 11th April 2007, 22:58 GMT-05
tom made this comment,
comment added :: 8th June 2007, 03:53 GMT-05
Matze made this comment,
comment added :: 17th July 2007, 08:57 GMT-05
rgth made this comment,
comment added :: 3rd October 2007, 03:28 GMT-05
barry made this comment,
comment added :: 8th December 2007, 05:50 GMT-05
Rod made this comment,
comment added :: 11th March 2008, 13:00 GMT-05
ashutosh made this comment,
comment added :: 28th July 2008, 04:59 GMT-05
zedwood made this comment,
comment added :: 6th October 2008, 14:46 GMT-05 :: http://zedwood.com/article/104/Javascript_-_Drag_a
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||