Tuesday, January 30, 2007

SWFUpload: The Saga Continues...

I've had a little feedback on SWFUpload. And you might want to thumb through the comments for a few hints (there aren't that many).

Macs (they always gotta be different)

It seems on Macs that if your 'upload_backend' does not return any data that the UploadComplete event will never be called. This seems to happen for any browser which indicates that is probably an issue in the Flash for Mac implementation. So, instead of just having a blank page for your 'upload_backend' just throw in some text like, Thank you. Upload Complete. That, reportedly, will solve the problem.

IOError (specifically, Firefox for Windows)

If you get an IOError then you may not be able to upload any more files. The report says the Open File dialog will no longer open. For me the Open File dialog does appear and the UploadStart event gets called but then I never get any UploadProgress callbacks.

Solution: Handle this some way in your error handler. You could alert the user to reload the page. Or use Javascript to remove the offending Flash movie and reload it then let the user know that she needs to try again.

Better Solution: Fix the upload.swf. I realized that the logic in my changes to the Flash file was not very good. When an error occurred upload.swf would just stop processing the queue. Then when you tried to add more files it just tried to upload the erred out file again. So, I've fixed that. There still seems to be occasions when upload.swf just stops responding and you can't get the Open File dialog to come up. You may still have to rely on the "reload the movie" solution discussed above. This still feels like a deeper flash issue that may be part of the immaturity of the file upload features of Flash itself.

Firefox, Cookies and Sessions

I've finally started implemented SWFUpload in one of my own projects. It's been quite the challenge. It turns out that in Firefox for Windows that when SWFUpload uploads the file it sends the Cookies from Internet Explorer. So that means the session set up by ASP.Net (the session_id is stored in a cookie) for Firefox is not re-established when SWFUpload makes the upload. This is a problem I can't fix. I have had to change the way I link the form that my user is filling out and the files she upload since they're submitted separately and I can't rely on any session values.

Another Feature

I also added an upload limit feature. You set the upload limit when instantiating the SWFUpload object and, even if the user queues up more files, the movie won't upload any more files than the limit. I added a new error code (-60) to report back on files rejected because the upload limit has been reached.

Isn't implementation grand!

Monday, January 29, 2007

What is up with Blogger anyhow?

I've not been using Blogger long. It seems to have some issues. When I visit http://linebyline.blogspot.com/ I get a page that is several days old. I got an email from someone saying it was several weeks old.

When I visit http://linebyline.blogspot.com/index.html I get a page that is...less old.

When I use some trickery and visit http://linebyline.blogspot.com/index.html?r=randomvalue then I finally get the most up-to-date page.

I ran a packet sniff and I can see that when my browser requests http://linebyline.blogspot.com that blogspot comes back with a 304 Not Modified response. Well, bull! I just made a new post. It sure has been modified.

Anyone know how to fix this?

Wednesday, January 24, 2007

SWFUpload R3 Update

I've finished my final additions to SWFUpload. The "delayed" upload works fine. It is a bit of extra work, especially if you try to carefully take care of errors.

I've updated the Demos and sent a copy back to the original authors. They like the features I've added. Maybe some of them will end up in the official release.

It's been fun. Now it's time to get back to work.


Tuesday, January 23, 2007

SWFUpload Revision 3 Demo

I've completed the major work on my third revision of SWFUpload. I've thoroughly taken the plunge and have made several modifications to the SWFUpload flash file. That, in turn, required several changes to the Javascript file.

I’ve added the following features:
  • SWFObject has been removed in favor of my Flash Feature Detection technique.
  • File Objects now include a unique ID. This is useful for working with the DOM.
  • It is now possible to cancel an upload-in-progress.
  • It is now possible to cancel all the files queued for upload (but not yet uploaded).

I have updated my demo to show off the new features. Again, I don't have a host. Contact me if you want a copy. It's based around asp.net but is easily adapted to any server technology:


Other ideas

I’d like to add a feature that allows you to remove queued files before the upload starts. Now that I have unique file IDs this should be pretty easy.


Trained the wrong way, but still trained

It occurred to me that SWFUpload does not quite fit in with the normal HTTP file upload format that we (and our users) are all used to. Usually we select our files and then probably have to fill in other parts of a form. Once completed we submit the entire form together. SWFUpload is breaking this up. Users might have a tendancy to click the Submit button before their uploads have finished.

I appreciate the benefit of starting uploads immediately. Users can finish the form while the upload is going and it'll all be more efficient. However, that’s not how users have been trained to use websites. They have been trained to complete a form (without looking at its labels). Then you pressing submit to back the message that says you did it all wrong. You trying again (and again) and finally getting it submitted.

With that in mind I think I am going to add one final feature. It will allow you to specify whether or not the queued-up files should be uploaded immediately or should wait until a command to upload is given. Now the user can queue up their files and fill out the form. The Submit button will kick off the SWFUpload file upload (the user still gets the great benefit of watching the file progress and getting feedback about the file size). The uploadQueueComplete event handler is called when the upload finishes and it submits the form. The page can watch for any SWFUpload errors and cancel the submit if necessary.

This is more in keeping with the expected user experience.

I'll keep ya'll posted. Yep, I mean both of you.

Flash Feature Detection

I've continued to work on my SWFUpload revision. I've tested the graceful degradation a bit more and it is slowly improving. I've tested it with Flash 2, 4, 6, and 8 in Internet Explorer 6. Of course, it only works in Flash Player 8 or above but it correctly degrades for early players.

Flash Player Feature Detection
I've also started on a Revision 3 which changes the entire method of Flash Version Detection. I have removed the SWFObject code (which performs the Flash version detection). I'm experimenting with a detection method similar to browser Object Detection. Instead of looking at the flash version number (as reported by the browser) I have the player check for key features, such as, Javascript calls to Flash, Flash calls to Javascript and the whole File Upload bit, which only work in since Flash Player 8.

I do this by having Javascript first add the flash movie to the page. It does not attempt any Flash version checking. If Flash is installed and working in the browser the movie will load. If a Flash Player older than version 8 is installed it will not be able to play the movie properly and the SWFUpload script stops.

However, if Flash Player 8 or above is installed the movie calls a Javascript function which alerts the SWFUpload script that it can continue loading. SWFUpload continues by loading the UI components so the user can begin uploading files.

New SWFUpload features

I didn't think I'd go so far in this project as to begin tweaking the Flash files. But now that I have I am going to begin looking in to adding Cancel Upload and Cancel Queue features.

It's been an interesting excursion so far but I think I've just about spent enough time on it. Hopefully I'll have what I want wrapped up pretty quick.

Thursday, January 18, 2007

SWFUpload Revision 2 Demo

Here I go again. After posting my changes to the SWFUpload script I decided I better throw the script up on a server and make sure it really works. Well, it didn't quite work. I've updated the post a bit so hopefully everything is peachy.

I built an ASP.Net demo that shows off my changes. Unfortunately, I don't have anywhere to host it or to post the files for download. So, if you want a copy of the demo files leave contact info in the comments.

SWFUpload Revisited and Revised

Some discussion about my SWFUpload FORM solution for ASP.Net rekindled my interest in the script. I also re-read my post about SWFUpload and realized that it was a bit incomplete in its explaination. So I've done some more work and I hope this is more helpful.

I also realize that I'm just posting code. You'll have to get the original SWFUpload and make sure all your file names and paths are correct/updated before this example code will work.

The Problem

SWFUpload does not provide a way for having more than one upload object per page. This is probably fine for most cases. However, if you want to upload an image and a word document (with different file size constraints or other settings) you need to have more than one upload object on the page.

So, I've revised the SWFUpload script. I had to restructure the design a bit (SWFUpload was built as a "Static" object, I needed it to work as an "Instance" object).

The new script operates almost like the original. However, these changes make it so you can't just throw a script tag in the body and instantiate the upload object. If you try that IE will have a fit. So you need to attach some code to the window.onload event (or any event that gets executed after the page is finished loading).

Operational Notes/Change log

My installation of Internet Explorer is broken. The SWFObject flash detection does not work for me. I've updated the SWFUpload script so you can set the "flash_version" setting to 0 (zero) bypassing the version detection. I'm not sure what will happen if Flash is not installed.

I've replaced the Debug output with a "Debug Console". The old debug doesn't work now that we have to wait until the page is loaded. The Debug Console looks for a FORM tag, adds a TextArea and puts the output there. If it can't find a FORM then it creates one and adds it to the body.

I've added a setting that allows you to tell SWFUpload where to add the Flash objects. ASP.Net requires that the Flash be added outside the FORM tags.

I've added a setting that indicates where to place the A tag (link) that causes the File Dialog to open.

I've updated the default Error Handler so it writes to the "Debug Console" instead of putting up alerts.

I de-obfuscated a bunch of the SWFObject code. So, now it's easier to read, but makes for a larger file.


The Script


/**
* mmSWFUpload 0.7.1 Revision 2 by Jacob Roberts, January 2007, linebyline.blogspot.com
*
* + Changed from a Static Class to an Instance (changed code/class structure)
* + Added "flash_version" setting. When set to zero the version check is skipped
* + Added Debug Console. The Instance class can't do document.write.
* = De-obfuscated SWFObject a bit
* - Removed standalone mode.
* + Added "ui_target" setting. When non-blank the link is added.
* + Added "flash_target" setting. When blank the flash is appended to the <body> tag
* = This fixes ASP.Net not allowing the flash to be added to the Form
* + Added error checking to the callSWF method
*
* mmSWFUpload 0.7: Flash upload dialog - http://profandesign.se/swfupload/
*
* SWFUpload is (c) 2006 Lars Huring and Mammon Media and is released under the MIT License:
* http://www.opensource.org/licenses/mit-license.php
*
* VERSION HISTORY
* 0.5 - First release
*
* 0.6 - 2006-11-24
* - Got rid of flash overlay
* - SWF size reduced to 840b
* - CSS-only styling of button
* - Add upload to links etc.
*
* 0.7 - 2006-11-27
* - Added filesize param and check in SWF
*
* 0.7.1 - 2006-12-01
* - Added link_mode param for standalone links
* if set to "standalone", createElement("a") won't run.
* - Added link_text param if css isn't needed.
* - Renamed cssClass to css_class for consistency
*
*/

/* Constructor */
function mmSWFUpload(settings) {
// Remove background flicker in IE
try {
document.execCommand('BackgroundImageCache', false, true);
} catch(e) {}

this.movieName = "mmSWFUpload_" + mmSWFUpload.movieCount++;

this.init(settings);
this.doDebug = this.getSetting("debug");

this.movieElement = this.loadFlash();
if (this.movieElement == null) {
if (this.doDebug) Console.Writeln("Could not load flash.");
return;
}

this.loadUI();

if (this.doDebug) {
this.debug();
}

}

/* Static thingies */
mmSWFUpload.movieCount = 0;

// Default error handling.
mmSWFUpload.handleErrors = function(errcode, file, msg) {

switch(errcode) {

case -10: // HTTP error
Console.Writeln("Error Code: HTTP Error, File name: " + file.name + ", Message: " + msg);
break;

case -20: // No backend file specified
Console.Writeln("Error Code: No backend file, File name: " + file.name + ", Message: " + msg);
break;

case -30: // IOError
Console.Writeln("Error Code: IO Error, File name: " + file.name + ", Message: " + msg);
break;

case -40: // Security error
Console.Writeln("Error Code: Security Error, File name: " + file.name + ", Message: " + msg);
break;

case -50: // Filesize too big
Console.Writeln("Error Code: File too big, File name: " + file.name + ", File size: " + file.size + ", Message: " + msg);
break;

}

};

/* Instance Thingies */
// Ensure that all the object settings are set or get a default value
mmSWFUpload.prototype.init = function(settings) {
this.settings = [];

this.addSetting("ui_target", settings["ui_target"], "");
this.addSetting("upload_backend", settings["upload_backend"], "");
this.addSetting("upload_start_callback", settings["upload_start_callback"], "");
this.addSetting("upload_complete_callback", settings["upload_complete_callback"], "");
this.addSetting("upload_progress_callback", settings["upload_progress_callback"], "");
this.addSetting("upload_cancel_callback", settings["upload_cancel_callback"], "");
this.addSetting("upload_error_callback", settings["upload_error_callback"], "mmSWFUpload.handleErrors");
this.addSetting("upload_queue_complete_callback", settings["upload_queue_complete_callback"], "");
this.addSetting("allowed_filetypes", settings["allowed_filetypes"], "*.gif;*.jpg;*.png");
this.addSetting("allowed_filesize", settings["allowed_filesize"], "1000");
this.addSetting("debug", settings["debug"], false);
this.addSetting("flash_path", settings["flash_path"], "upload.swf");

this.addSetting("flash_target", settings["flash_target"], "");
this.addSetting("flash_width", settings["flash_width"], "1px");
this.addSetting("flash_height", settings["flash_height"], "1px");
this.addSetting("flash_version", settings["flash_version"], "8")
this.addSetting("flash_color", settings["flash_color"], "#000000");

this.addSetting("link_css_class", settings["link_css_class"], "SWFUploadLink")
this.addSetting("link_text", settings["link_text"], "Upload File");

};

mmSWFUpload.prototype.loadFlash = function() {
var movieElement = null;

// Create SWFObject
var so = new SWFObject(this.getSetting("flash_path"), this.movieName, this.getSetting("flash_width"), this.getSetting("flash_height"), this.getSetting("flash_version"), this.getSetting("flash_color"));

// If we have the right version of flash load the flash
//if (deconcept.SWFObjectUtil.getPlayerVersion(so.getAttribute("version")).major >= this.getSetting("flash_version")) {

so.addParam("wmode", "transparent");
so.addParam("menu", "false");

// Add all settings to flash
so.addVariable("uploadBackend", this.getSetting("upload_backend"));
so.addVariable("uploadStartCallback", this.getSetting("upload_start_callback"));
so.addVariable("uploadProgressCallback", this.getSetting("upload_progress_callback"));
so.addVariable("uploadCompleteCallback", this.getSetting("upload_complete_callback"));
so.addVariable("uploadCancelCallback", this.getSetting("upload_cancel_callback"));
so.addVariable("uploadErrorCallback", this.getSetting("upload_error_callback"));
so.addVariable("allowedFiletypes", this.getSetting("allowed_filetypes"));
so.addVariable("allowedFilesize", this.getSetting("allowed_filesize"));
so.addVariable("uploadQueueCompleteCallback", this.getSetting("upload_queue_complete_callback"));

// Output the flash

so.write(this.getSetting("flash_target"));

movieElement = document.getElementById(this.movieName);

//}

return movieElement;
};

mmSWFUpload.prototype.loadUI = function() {
if(this.getSetting("target") != "") {
var self = this;

// Create link element
var link = document.createElement("a");
link.href = "#";
link.onclick = function () { self.callSWF(); return false; };
link.className = this.getSetting("link_css_class");
link.innerHTML = this.getSetting("link_text");


// Add the link to the target
var target = document.getElementById(this.getSetting("ui_target"))
if (typeof(target) != "undefined" && target && target.innerHTML) {
target.innerHTML = ""; // Clear all the children. This is the "bad way" but I really don't want to walk the childNodes array
target.appendChild(link);
}
}
};

// Make sure that we get a few default values
mmSWFUpload.prototype.addSetting = function(name, value, default_value) {
if (typeof(value) == "undefined" || value == null) {
this.settings[name] = default_value;
} else {
this.settings[name] = value;
}

return this.settings[name];
};

mmSWFUpload.prototype.getSetting = function(name) {
if (typeof(this.settings[name]) == "undefined") {
return null;
} else {
return this.settings[name];
}
};


mmSWFUpload.prototype.callSWF = function() {
if (this.movieElement != null) {
try {
this.movieElement.uploadImage();
}
catch (e) {
if (this.doDebug) {
Console.Writeln("Could not call uploadImage");
}
}
} else {
if (this.doDebug) {
Console.Writeln("Could not find Flash element");
}
}
};

mmSWFUpload.prototype.debug = function() {
var debug_message = "----- DEBUG OUTPUT ----\n";

debug_message += "ID: " + this.movieElement.id + "\n";

// It's bad to use the for..in with an associative array, but oh well
for (var key in this.settings) {
debug_message += key + ": " + this.settings[key] + "\n";
}
/*debug_message += "Flash Target: " + this.getSetting("flash_target") + "\n";
debug_message += "UI Target: " + this.getSetting("ui_target") + "\n";
debug_message += "Upload start callback: " + this.getSetting("upload_start_callback") + "\n";
debug_message += "Upload progress callback: " + this.getSetting("upload_progress_callback") + "\n";
debug_message += "Upload complete callback: " + this.getSetting("upload_complete_callback") + "\n";
debug_message += "Upload filetypes: " + this.getSetting("allowed_filetypes") + "\n";
debug_message += "Max filesize: " + this.getSetting("allowed_filesize") + "kb \n";
debug_message += "Link text: " + this.getSetting("link_text") + "\n";
debug_message += "CSS class: " + this.getSetting("link_css_class") + "\n";
debug_message += "Upload backend file: " + this.getSetting("upload_backend") + "\n";
debug_message += "Upload error callback: " + this.getSetting("upload_error_callback") + "\n";
debug_message += "Upload cancel callback: " + this.getSetting("upload_cancel_callback") + "\n";
debug_message += "Upload queue complete callback: " + this.getSetting("upload_queue_complete_callback") + "\n";*/
debug_message += "----- DEBUG OUTPUT END ----\n";
debug_message += "\n";

Console.Writeln(debug_message);
};

if (typeof Console == "undefined") {
var Console = new Object();
}

Console.Writeln = function(value) {
var console = document.getElementById("mmSWFUpload_Console");

if (!console) {
var documentForm = document.getElementsByTagName("form")[0];

if (!documentForm) {
documentForm = document.createElement("form");
document.getElementsByTagName("body")[0].appendChild(documentForm);
}

console = document.createElement("textarea");
console.id = "mmSWFUpload_Console";
console.style.width = "500px";
console.style.height = "350px";
documentForm.appendChild(console);
}

console.value += value + "\n";

console.scrollTop = console.scrollHeight - console.clientHeight;
}



/**
* SWFObject v1.4: Flash Player detection and embed - http://blog.deconcept.com/swfobject/
*
* SWFObject is (c) 2006 Geoff Stearns and is released under the MIT License:
* http://www.opensource.org/licenses/mit-license.php
*
* **SWFObject is the SWF embed script formerly known as FlashObject. The name was changed for
* legal reasons.
*/
if (typeof deconcept == "undefined") {
var deconcept = new Object();
}
if (typeof deconcept.util == "undefined") {
deconcept.util = new Object();
}
if (typeof deconcept.SWFObjectUtil == "undefined") {
deconcept.SWFObjectUtil=new Object();
}

deconcept.SWFObject = function(flash_path, id, width, height, minimum_major_version, background_color, _7, default_quality, _9, _a, _b) {
if (!document.createElement || !document.getElementById) {
return;
}

this.DETECT_KEY = _b ? _b : "detectflash";

this.skipDetect = deconcept.util.getRequestParameter(this.DETECT_KEY) == "0" ? true : false;

this.params = new Object();
this.variables = new Object();
this.attributes = new Array();

if (flash_path) {
this.setAttribute("swf", flash_path);
}

if (id) {
this.setAttribute("id", id);
}

if (width) {
this.setAttribute("width", width);
}

if (height) {
this.setAttribute("height", height);
}

if (minimum_major_version) {
this.setAttribute("version", new deconcept.PlayerVersion(minimum_major_version.toString().split(".")));
} else {
this.setAttribute("version", new deconcept.PlayerVersion([0,0,0]));
}

this.installedVer = deconcept.SWFObjectUtil.getPlayerVersion(this.getAttribute("version"), _7);

if (background_color) {
this.addParam("bgcolor", background_color);
}

var quality = default_quality ? default_quality : "high";

this.addParam("quality", quality);
this.setAttribute("useExpressInstall", _7);
this.setAttribute("doExpressInstall", false);
var _d = (_9) ? _9 : window.location;
this.setAttribute("xiRedirectUrl", _d);
this.setAttribute("redirectUrl", "");

if (_a) {
this.setAttribute("redirectUrl", _a);
}
};

deconcept.SWFObject.prototype = {
setAttribute : function(attribute_name, value) {
this.attributes[attribute_name] = value;
},

getAttribute : function(attribute_name) {
return this.attributes[attribute_name];
},

addParam: function(name, value){
this.params[name] = value;
},

getParams: function() {
return this.params;
},

addVariable: function(name, value) {
this.variables[name] = value;
},

getVariable: function(name) {
return this.variables[name];
},

getVariables: function(){
return this.variables;
},

getVariablePairs: function() {
var name_value_pairs = new Array();
var variables = this.getVariables();

for (var key in variables) {
name_value_pairs.push(key + "=" + variables[key]);
}

return name_value_pairs;
},

getSWFHTML : function() {
var html = "";

// Create Mozilla Embed HTML
if (navigator.plugins && navigator.mimeTypes &amp;& navigator.mimeTypes.length) {
if (this.getAttribute("doExpressInstall")) {
this.addVariable("MMplayerType","PlugIn");
}

// Build the basic embed html
html = '<embed type="application/x-shockwave-flash" src="' + this.getAttribute("swf") + '" width="' + this.getAttribute("width") + '" height="' + this.getAttribute("height") + '"';
html += ' id="' + this.getAttribute("id") + '" name="' + this.getAttribute("id") + '" ';

// Add all our parameters
var params = this.getParams();
for (var key in params) {
html += [key] + '="' + params[key] + '" ';
}

// Add the flash variables, this is passed as a query string (e.g. name=value&name=value) via the "flashvars" attribute
var variable_pairs = this.getVariablePairs().join("&amp;");
if (variable_pairs.length > 0) {
html += 'flashvars="' + variable_pairs + '"';
}

html += "/>";

// Create IE Object HTML
} else {

if (this.getAttribute("doExpressInstall")) {
this.addVariable("MMplayerType","ActiveX");
}

// Build the basic Object tag
html = '<object id="' + this.getAttribute("id") + '" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="' + this.getAttribute("width") + '" height="' + this.getAttribute("height") + '">';
html += '<param name="movie" value="' + this.getAttribute("swf") + '" />';

// Add our parameters
var params = this.getParams();
for(var key in params) {
html += '<param name="' + key + '" value="' + params[key] + '" />';
}

// Add the flash variables. This is passed as a query string (e.g. name=value&name=value) via the "flashvars" param
var variable_pairs = this.getVariablePairs().join("&amp;");
if (variable_pairs.length > 0) {
html += '<param name="flashvars" value="' + variable_pairs + '" />';
}

html += "</object>";
}

return html;
},

write : function(flash_target) {

if (this.getAttribute("useExpressInstall")) {

var min_version_for_express_install = new deconcept.PlayerVersion([6,0,65]);

if (this.installedVer.versionIsValid(min_version_for_express_install) && !this.installedVer.versionIsValid(this.getAttribute("version"))) {
this.setAttribute("doExpressInstall", true);
this.addVariable("MMredirectURL", escape(this.getAttribute("xiRedirectUrl")));
document.title = document.title.slice(0,47) + " - Flash Player Installation";
this.addVariable("MMdoctitle", document.title);
}
}

if (this.skipDetect || this.getAttribute("doExpressInstall") || this.installedVer.versionIsValid(this.getAttribute("version"))) {
// Attempt to load the flash appended to the body

// NOTE: this part will cause IE to throw an error if not called after the page is finished loading
var container = document.createElement("div");
container.style.width = "0px";
container.style.height = "0px";
container.style.position = "absolute";
container.style.top = "0px";
container.style.left = "0px";

var target_element;
if (flash_target != "") {
target_element = document.getElementById(flash_target);
}
if (typeof(target_element) == "undefined") {
target_element = document.getElementsByTagName("body")[0];
}
if (typeof(target_element) == "undefined") {
return false;
}

target_element.appendChild(container);

container.innerHTML = this.getSWFHTML();

return true;
} else {
if (this.getAttribute("redirectUrl") != "") {
document.location.replace(this.getAttribute("redirectUrl"));
}
}

return false;
}
};

deconcept.SWFObjectUtil.getPlayerVersion = function(_23,_24) {
var player_version = new deconcept.PlayerVersion([0,0,0]);

// Mozilla Detect
if (navigator.plugins && navigator.mimeTypes.length) {
var swf_plugin = navigator.plugins["Shockwave Flash"];
if (swf_plugin && swf_plugin.description) {
player_version = new deconcept.PlayerVersion(swf_plugin.description.replace(/([a-z]|[A-Z]|\s)+/,"").replace(/(\s+r|\s+b[0-9]+)/,".").split("."));
}

// IE Detect
} else {
try {
var axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
for(var i=3; axo != null; i++) {
axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash." + i);
player_version = new deconcept.PlayerVersion([i,0,0]);}
} catch (e){ }

if (_23 && player_version.major > _23.major) { return player_version; }

if (!_23 || ((_23.minor != 0 || _23.rev != 0) && player_version.major == _23.major) || player_version.major != 6 || _24) {
try{
player_version = new deconcept.PlayerVersion(axo.GetVariable("$version").split(" ")[1].split(","));
}
catch (e) { }
}
}

return player_version;
};

deconcept.PlayerVersion = function(version_array) {
this.major = parseInt(version_array[0]) != null ? parseInt(version_array[0]) : 0;
this.minor = parseInt(version_array[1]) || 0;
this.rev = parseInt(version_array[2]) || 0;
};

deconcept.PlayerVersion.prototype.versionIsValid = function(fv) {
if (this.major < fv.major) { return false; }
if (this.major > fv.major) { return true; }
if (this.minor < fv.minor) { return false; }
if (this.minor > fv.minor) { return true; }
if (this.rev < fv.rev) {return false; }

return true;
};

deconcept.util = {
getRequestParameter : function(parameter_name) {
var query_string = document.location.search || document.location.hash;
if (query_string) {
var parameter_pair = query_string.indexOf(parameter_name + "=");
var parameter_value_end_index = (query_string.indexOf("&", parameter_pair) > -1) ? query_string.indexOf("&", parameter_pair) : query_string.length;
if (query_string.length > 1 && parameter_pair > -1) {
return query_string.substring(query_string.indexOf("=", parameter_pair) + 1, parameter_value_end_index);
}
}

return "";
}
};

if (Array.prototype.push == null) {
Array.prototype.push = function(_2f) {
this[this.length] = _2f;
return this.length;
};
}
var getQueryParamValue = deconcept.util.getRequestParameter;
var FlashObject = deconcept.SWFObject; // for backwards compatibility
var SWFObject = deconcept.SWFObject;




Example HTML



<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>SWFUpload ASP.Net Revision</title>
<script type="text/javascript" src="jscripts/SWFUpload/mmSWFUploadR2.js"></script>
<script type="text/javascript">
uploadStart = function(fileObj) {
try {
Console.Writeln("Upload started");
} catch (e) { Console.Writeln("Error displaying file upload start information"); }

}

uploadProgress = function(fileObj, bytesLoaded) {

try {
var percent = Math.ceil((bytesLoaded / fileObj.size) * 100)
Console.Writeln("Upload Progress: " + fileObj.name + " " + percent);
} catch (e) { Console.Writeln("Error displaying file progress"); }
}

uploadComplete = function(fileObj) {
try {
Console.Writeln("Upload Complete: " + fileObj.name);
} catch (e) { Console.Writeln("Error displaying file upload complete information"); }
}

uploadQueueComplete = function(fileObj) {
try {
Console.Writeln("Queue Done");
} catch (e) { Console.Writeln("Error displaying queue complete information"); }
}

uploadCancel = function() {
try {
Console.Writeln("Pressed Cancel");
} catch (e) { Console.Writeln("Error displaying file cancel information"); }
}
</script>

<style type="text/css">

a.SWFUploadLink {
font-weight: bold;
color: blue;
text-decoration: none;
}

a.SWFUploadLink:hover {
text-decoration: underline;
}

</style>



</head>
<body>
<div id="flashTarget"></div>
<form action="" onsubmit="return false;">

<div id="wrapper">

<div id="SWFUpload">
Upload a PNG: <input type="file" name="upload" />
</div>

<div id="SWFUpload2">
Upload a GIF: <input type="file" name="upload" />
</div>


<input type="submit" value="Upload" onclick="javascript:alert('disabled...'); return false;" />



<script type="text/javascript">
var upload1;
var upload2;
var da_onload = window.onload;
window.onload = function() {
if (typeof(da_onload) == "function") {
da_onload();
}

upload1 = new mmSWFUpload({
debug : true,
flash_version: 8,
upload_backend : "../../upload.aspx",
ui_target : "SWFUpload",
flash_target : "flashTarget",
link_text : "Select File",
//link_css_class : "myCustomClass",
allowed_filesize : "400",
allowed_filetypes : "*.png",
upload_start_callback : 'uploadStart',
upload_progress_callback : 'uploadProgress',
upload_complete_callback : 'uploadComplete',
// upload_error_callback : 'uploadError',
upload_cancel_callback : 'uploadCancel',
upload_queue_complete_callback : 'uploadQueueComplete'
});

upload2 = new mmSWFUpload({
debug : true,
flash_version: 8,
upload_backend : "../../upload.aspx",
ui_target : "SWFUpload2",
flash_target : "flashTarget",
link_text : "Select File",
//link_css_class : "myCustomClass",
allowed_filesize : "400",
allowed_filetypes : "*.png",
upload_start_callback : 'uploadStart',
upload_progress_callback : 'uploadProgress',
upload_complete_callback : 'uploadComplete',
// upload_error_callback : 'uploadError',
upload_cancel_callback : 'uploadCancel',
upload_queue_complete_callback : 'uploadQueueComplete'
});
}


</script>


</div>
</form>

</body>
</html>



Usage Tips

Here are some tips on using this thing:
  • Refer to the script's init method to see all the settings and their defaults
  • Any settings you don't include will automatically get the default value
  • Any callbacks you don't specify won't be called
  • Setting flash_version to 0 (zero) disables the flash version detection
  • You can use the Debug Console for your own output, if you want
  • The upload_backend setting should have a comlpete URL or be relative to the SWF file (not the Javascript or the HTML file)
  • If you don't specifiy a ui_target setting (or the target is not found) then the Upload link is not added.
  • You can call up the File Dialog yourself using the callSWF() method on your SWFUpload instance objects.
  • If you don't specify a flash_target setting the script adds the flash to the body (which will be outside any FORMs).
  • In your events the this object won't be your SWFUpload instance object.
  • You can't attach the callbacks like you do Javascript events. The callback string has to be the full string you would use if you were calling the callback from Javascript. P.S. Callbacks are just Javascript functions you've declared somewhere. See the example callbacks to see what values are passed in when they are called.
  • SWFUpload doesn't seem to work if you are viewing the page as a local file (file://). You need to put it on a web server (http://)
  • SWFUpload will probably return an error if your upload_backend is not a script file (if you submit to an html/htm file IIS will return a HTTP 405 error. Submit to a script file (php, aspx, etc).
  • Make sure you upload_backend file is working normally before using it with SWFUpload. You will get IOErrors or HTTP errors.
  • For ASP.Net developers you'll want to make sure your maxRequestLength and executionTimeout are large enough.

So, there you go. Again, Good Luck!