Multiple File Upload Application with Flash CS4 and Actionscript 3.0
- Cory Reid
- |
- Actionscript 3.0, Flash Development
- |
- December 14th
I have been trying to create an upload application that can upload more than one image at a time for a very long time now; over a period of several weeks, I casually Googled around for information on creating such an application within Flash. After compiling a fairly decent sized resource of links to articles and tutorials, sets of video tutorials, and sketches on paper of what I was aiming for – I was finally able to piece all the parts together to create an application to do that very thing – upload multiple files at once. This post will go over the code that makes it work.
In this post I will include all the code that I used to make this Flash file upload application work and I want you to keep in mind that I am an amateur Flash developer with zero experience in Flash, and that the code is essentially a compilation of solutions to various problems that I found via Google.
First, I began by importing some classes for Flash that I used within the code. This probably isn’t all that I needed to import, but this is what I imported that worked.
import flash.net.FileReferenceList; import flash.net.FileReference; import fl.containers.ScrollPane;
After the import, I created my list of variables, and pre-assigned some with their values.
var fileList:FileReferenceList = new FileReferenceList(); var filefilters:Array; var i:Number = 0; var uploaderStatus:Boolean = false; var uploadQueue:Number = 0; var selectedFileArray:Array = new Array(); var uploadURL:URLRequest = new URLRequest(); var variables:URLVariables = new URLVariables(); uploadURL.url = (stage.loaderInfo.parameters.f)? stage.loaderInfo.parameters.f : 'process.php'; uploadURL.method = URLRequestMethod.POST; var scrollContent:MovieClip = new MovieClip(); this.addChild(scrollContent); //add the scrollContent to the stage uploader_mc.scrollPane.source = scrollContent; var theItemList:Object = Object(uploader_mc.scrollPane.content); var theAlbumList:Object = Object(uploader_mc.albumSelect); var theMessageBox:Object = Object(uploader_mc.messageText); var albumString:URLRequest = new URLRequest(); albumString.url = (stage.loaderInfo.parameters.f)? stage.loaderInfo.parameters.o : 'albums.php'; var albumLoader:URLLoader = new URLLoader(albumString); albumLoader.addEventListener(Event.COMPLETE, populateAlbumsList);
Now I want to delve into the meat of the Actionscript. One-by-one I will list the functions as they appear in my Actionscript 3.0 file and explain what they’re all about.
function setup(fileList:FileReferenceList) {
fileList.addEventListener(Event.SELECT, selectHandler);
uploader_mc.upload_btn.enabled = false;
}
setup(fileList);
setup() is passed the fileList variable and adds the needed event listeners to begin the application. Here is where you’d pass the even listeners for when the user begins browsing for files or for other things such as error handling (IO errors), when the entire upload completes (if you’re uploading through the FileReferenceList class directly), etc. I did not include any of that here as this is a BETA application and is not yet complete. To continue, this function also disables the upload button as we don’t want the user to be able to fire the upload event if no files have been selected.
-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
uploader_mc.select_btn.addEventListener(MouseEvent.CLICK, browseFiles);
function browseFiles(e:MouseEvent):void {
theMessageBox.text = "";
filefilters = [ new FileFilter('Images *.jpg; *.jpeg; *.gif; *.png', '*.jpg;*.jpeg;*.gif;*.png') ];
fileList.browse(filefilters);
}
In the above code snippet, we are adding an event listener to the select button and then immediately defining the function for the event listener – browseFiles(). This function is passed a MouseEvent and makes sure the message box (theMessageBox) is empty, adds the file filters to the fileFilters array and then launches the browse dialogue box for fileList. The user at this point would be browsing for the images they’d like to upload.
-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
uploader_mc.upload_btn.addEventListener(MouseEvent.CLICK, uploadFiles);
function uploadFiles(e:MouseEvent):void {
uploadSingleFile(uploadQueue);
}
Above we’re adding an event listener to the upload button and then immediately defining the function for the event listener – uploadFiles(). This function simply calls the uploadSingleFile function and to that, passes the value of the variable uploadQueue.
-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
uploader_mc.cancel_btn.addEventListener(MouseEvent.CLICK, cancelUpload);
function cancelUpload(e:MouseEvent):void {
var file:FileReference = FileReference(selectedFileArray[uploadQueue]);
file.cancel();
reset();
}
Here we are setting the event listener for the cancel button and defining the corresponding function – cancelUpload(). This function is passed a MouseEvent and gets the current file upload in progress and sets the variable file to that, then cancels that upload. After the cancel, it calls the reset function which prepares the upload application to re-browse for files and begin a new upload.
-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
function itemComplete(e:Event):void {
var file:FileReference = FileReference(e.target);
file.removeEventListener(Event.COMPLETE, itemComplete);
file.removeEventListener(IOErrorEvent.IO_ERROR, ioError);
theItemList.removeChildAt(0);
uploadQueue++;
for(x = uploadQueue; x < selectedFileArray.length; x++) {
theItemList.getChildByName("listItem"+x).y -= 85;
uploader_mc.scrollPane.update();
}
uploadSingleFile(uploadQueue);
}
itemComplete() is called every time a queued file has completed uploading. It begins by getting the FileReference information from the object that called the function, and setting it to the variable file. It then removes the event listeners which were on the object and removes the object from the list of files to download. It then increases uploadQueue by one and then iterates through all items still in the list to be uploaded and alters their position in the list (moves them up to fill the space of the removed item) and updates the list to make sure the scrollbar is current. After which, it calls uploadSingleFile, passing the new value of uploadQueue to begin uploading the next file in queue.
-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
function uploadSingleFile(index:Number):void {
theMessageBox.text = "";
try {
variables.album = uploader_mc.albumSelect.selectedItem.data;
if(index < selectedFileArray.length){
var file:FileReference = FileReference(selectedFileArray[index]);
file.addEventListener(Event.COMPLETE, itemComplete);
try {
uploaderStatus = true;
uploadURL.data = variables;
file.upload(uploadURL);
updateButtons();
} catch (error:Error) {
theMessageBox.text = "Problems uploading file: " + file.name;
}
} else {
reset();
}
} catch(Error:TypeError) {
theMessageBox.text = "Please select an album first!";
}
}
uploadSingleFile() is the function in which most of the magic happens – where the files are uploaded. It is passed a number to begin, and makes sure that the message box has no data displayed. It then tries to set an album value of the selected album in the drop-down list to the variables variable. If the user has not selected an album from the drop-down list, this fails and the catch sets the message box to display an error message informing the user to select an album first. Assuming the user has selected an album, and the first line within the try statement succeeds, it proceeds to see if the number passed to the uploadSingleFile function is not larger than the length of selectedFileArray – which if it is there are no more files to be uploaded, and the else section of the if/else block resets the uploader so the user may upload more files. If the index is smaller than the length of selectedFileArray then that file needs to be uploaded. It grabs the corresponding FileReference from the selectedFileArray and sets it to the file variable. Then it adds complete and IO error event listeners. It then attempts to set the uploaderStatus and uploadURL.data variables, upload the file to uploadURL, and last updates the buttons to reflect the file upload status. If any of that fails it sets the message box to display an error informing the user of which file had a problem.
-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
function selectHandler(e:Event):void {
for each(var file:FileReference in fileList.fileList) {
selectedFileArray.push(file);
createListItem(file);
uploader_mc.upload_btn.enabled = true;
}
}
selectHandler() is passed an event and the function iterates through all files selected through the dialogue box lanched by clicking the select button and for each one adds it to the selectedFileArray, adds the file to the list of files to be downloaded (the list the user sees), and sets the upload button to be clickable.
-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
function createListItem(file:FileReference):void {
var itemMC:listItem = new listItem();
itemMC.name = "listItem" + i;
itemMC.y += itemMC.height*i + 1;
itemMC.x = 8;
itemMC.fileName.text = file.name;
itemMC.fileSize.text = sizeAsText(file.size);
itemMC.progressBar.source = file;
theItemList.addChild(itemMC);
i++;
uploader_mc.scrollPane.update();
}
createListItem() receives a FileReference object, and is used to add the visual representations of the files queued for upload to the upload list that the use sees.
-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
function sizeAsText(num):String {
num = num / 1024;
if(num < 1024) {
num = String(Math.floor(num)) + " KBs";
} else {
if(num / 1024 < 1024) {
num = String(Math.floor(num / 1024)) + " MBs";
} else if (num / 1024 / 1024 < 1024) {
num = String(Math.floor(num / 1024 / 1024)) + " GBs";
}
}
return num;
}
function reset() {
//Set the uploading status
uploaderStatus = false;
//Reset counters
i = 0;
uploadQueue = 0;
//Reset filelist
selectedFileArray.length = 0;
//Remove any remaining items in list
while(theItemList.numChildren > 0) {
theItemList.removeChildAt(0);
}
//Make sure the scrollPane's scrollbar reflects current state
uploader_mc.scrollPane.update();
//Update the buttons
uploader_mc.albumSelect.selectedIndex = -1;
updateButtons();
}
function updateButtons() {
if(uploaderStatus) {
//Select Button
uploader_mc.select_btn.enabled = false;
//Upload Button
uploader_mc.upload_btn.enabled = false;
uploader_mc.upload_btn.visible = false;
//Cancel Button
uploader_mc.cancel_btn.enabled = true;
uploader_mc.cancel_btn.visible = true;
//Album List
theAlbumList.enabled = false;
} else {
//Select Button
uploader_mc.select_btn.enabled = true;
//Upload Button
uploader_mc.upload_btn.enabled = false;
uploader_mc.upload_btn.visible = true;
//Cancel Button
uploader_mc.cancel_btn.enabled = false;
uploader_mc.cancel_btn.visible = false;
//Album List
theAlbumList.enabled = true;
}
}
function populateAlbumsList(event:Event):void{
var xDoc:XMLDocument = new XMLDocument();
xDoc.ignoreWhite = true;
var albumsXML:XML = XML(albumLoader.data);
xDoc.parseXML(albumsXML.toXMLString());
var albums = xDoc.childNodes[0].childNodes;
for(var a=0; a<albums.length; a++) {
uploader_mc.albumSelect.addItem( {label:albums[a].attributes.label, data:albums[a].attributes.data} );
}
albumLoader.removeEventListener(Event.COMPLETE, populateAlbumsList);
}
The above four functions I feel need little explanation, so I’ve grouped them together.
sizeAsText() receives a number, the number should represent the size of a file in bytes it then formats that number as a “human-readable size” and returns that value.
reset() resets the player so that it’s ready to upload more files.
updateButtons() updates the buttons based on the status of the upload application.
populateAlbumsList() pulls in an XML file formatted in a specific way that contains the albums in which a user may upload their photos, and adds them to a drop-down list as options to choose from.
Now this post was not meant to include a whole lot of explanation as to how I came about all this, and how each piece interacts with another. This post assumes you have enough general scripting knowledge to figure out what is doing what – the code is listed in the same order it appears within the Actionscript file. If you have questions feel free to post them in the comments and I’ll do my best to help answer your questions!

