*
* mmSWFUpload 1.0: Flash upload dialog - http://profandesign.se/swfupload/, http://www.vinterwebb.se/
*
- * SWFUpload is (c) 2006-2007 Lars Huring, Olov Nilzén and Mammon Media and is released under the MIT License:
+ * SWFUpload is (c) 2006-2007 Lars Huring, Olov Nilzén and Mammon Media and is released under the MIT License:
* http://www.opensource.org/licenses/mit-license.php
*
* SWFUpload 2 is (c) 2007-2008 Jake Roberts and is released under the MIT License:
this.movieName = "SWFUpload_" + SWFUpload.movieCount++;
this.movieElement = null;
+
// Setup global control tracking
SWFUpload.instances[this.movieName] = this;
/* *************** */
SWFUpload.instances = {};
SWFUpload.movieCount = 0;
-SWFUpload.version = "2.2.0 Beta 2";
+SWFUpload.version = "2.2.0 2009-03-25";
SWFUpload.QUEUE_ERROR = {
QUEUE_LIMIT_EXCEEDED : -100,
FILE_EXCEEDS_SIZE_LIMIT : -110,
OPAQUE : "opaque"
};
+// Private: takes a URL, determines if it is relative and converts to an absolute URL
+// using the current site. Only processes the URL if it can, otherwise returns the URL untouched
+SWFUpload.completeURL = function(url) {
+ if (typeof(url) !== "string" || url.match(/^https?:\/\//i) || url.match(/^\//)) {
+ return url;
+ }
+
+ var currentURL = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ":" + window.location.port : "");
+
+ var indexSlash = window.location.pathname.lastIndexOf("/");
+ if (indexSlash <= 0) {
+ path = "/";
+ } else {
+ path = window.location.pathname.substr(0, indexSlash) + "/";
+ }
+
+ return /*currentURL +*/ path + url;
+
+};
+
+
/* ******************** */
/* Instance Members */
/* ******************** */
// Upload backend settings
this.ensureDefault("upload_url", "");
+ this.ensureDefault("preserve_relative_urls", false);
this.ensureDefault("file_post_name", "Filedata");
this.ensureDefault("post_params", {});
this.ensureDefault("use_query_string", false);
this.ensureDefault("requeue_on_error", false);
this.ensureDefault("http_success", []);
+ this.ensureDefault("assume_success_timeout", 0);
// File Settings
this.ensureDefault("file_types", "*.*");
this.ensureDefault("button_text_left_padding", 0);
this.ensureDefault("button_action", SWFUpload.BUTTON_ACTION.SELECT_FILES);
this.ensureDefault("button_disabled", false);
- this.ensureDefault("button_placeholder_id", null);
+ this.ensureDefault("button_placeholder_id", "");
+ this.ensureDefault("button_placeholder", null);
this.ensureDefault("button_cursor", SWFUpload.CURSOR.ARROW);
this.ensureDefault("button_window_mode", SWFUpload.WINDOW_MODE.WINDOW);
this.customSettings = this.settings.custom_settings;
// Update the flash url if needed
- if (this.settings.prevent_swf_caching) {
- this.settings.flash_url = this.settings.flash_url + "?swfuploadrnd=" + Math.floor(Math.random() * 999999999);
+ if (!!this.settings.prevent_swf_caching) {
+ this.settings.flash_url = this.settings.flash_url + (this.settings.flash_url.indexOf("?") < 0 ? "?" : "&") + "preventswfcaching=" + new Date().getTime();
+ }
+
+ if (!this.settings.preserve_relative_urls) {
+ //this.settings.flash_url = SWFUpload.completeURL(this.settings.flash_url); // Don't need to do this one since flash doesn't look at it
+ this.settings.upload_url = SWFUpload.completeURL(this.settings.upload_url);
+ this.settings.button_image_url = SWFUpload.completeURL(this.settings.button_image_url);
}
delete this.ensureDefault;
};
+// Private: loadFlash replaces the button_placeholder element with the flash movie.
SWFUpload.prototype.loadFlash = function () {
- if (this.settings.button_placeholder_id !== "") {
- this.replaceWithFlash();
- } else {
- this.appendFlash();
- }
-};
-
-// Private: appendFlash gets the HTML tag for the Flash
-// It then appends the flash to the body
-SWFUpload.prototype.appendFlash = function () {
- var targetElement, container;
-
- // Make sure an element with the ID we are going to use doesn't already exist
- if (document.getElementById(this.movieName) !== null) {
- throw "ID " + this.movieName + " is already in use. The Flash Object could not be added";
- }
-
- // Get the body tag where we will be adding the flash movie
- targetElement = document.getElementsByTagName("body")[0];
-
- if (targetElement == undefined) {
- throw "Could not find the 'body' element.";
- }
-
- // Append the container and load the flash
- container = document.createElement("div");
- container.style.width = "1px";
- container.style.height = "1px";
- container.style.overflow = "hidden";
-
- targetElement.appendChild(container);
- container.innerHTML = this.getFlashHTML(); // Using innerHTML is non-standard but the only sensible way to dynamically add Flash in IE (and maybe other browsers)
-};
-
-// Private: replaceWithFlash replaces the button_placeholder element with the flash movie.
-SWFUpload.prototype.replaceWithFlash = function () {
var targetElement, tempParent;
// Make sure an element with the ID we are going to use doesn't already exist
}
// Get the element where we will be placing the flash movie
- targetElement = document.getElementById(this.settings.button_placeholder_id);
+ targetElement = document.getElementById(this.settings.button_placeholder_id) || this.settings.button_placeholder;
if (targetElement == undefined) {
- throw "Could not find the placeholder element.";
+ throw "Could not find the placeholder element: " + this.settings.button_placeholder_id;
}
// Append the container and load the flash
tempParent.innerHTML = this.getFlashHTML(); // Using innerHTML is non-standard but the only sensible way to dynamically add Flash in IE (and maybe other browsers)
targetElement.parentNode.replaceChild(tempParent.firstChild, targetElement);
+ // Fix IE Flash/Form bug
+ if (window[this.movieName] == undefined) {
+ window[this.movieName] = this.getMovieElement();
+ }
+
};
// Private: getFlashHTML generates the object tag needed to embed the flash in to the document
SWFUpload.prototype.getFlashHTML = function () {
// Flash Satay object syntax: http://www.alistapart.com/articles/flashsatay
return ['<object id="', this.movieName, '" type="application/x-shockwave-flash" data="', this.settings.flash_url, '" width="', this.settings.button_width, '" height="', this.settings.button_height, '" class="swfupload">',
- '<param name="wmode" value="', this.settings.button_window_mode , '" />',
+ '<param name="wmode" value="', this.settings.button_window_mode, '" />',
'<param name="movie" value="', this.settings.flash_url, '" />',
'<param name="quality" value="high" />',
'<param name="menu" value="false" />',
"&useQueryString=", encodeURIComponent(this.settings.use_query_string),
"&requeueOnError=", encodeURIComponent(this.settings.requeue_on_error),
"&httpSuccess=", encodeURIComponent(httpSuccessString),
+ "&assumeSuccessTimeout=", encodeURIComponent(this.settings.assume_success_timeout),
"&params=", encodeURIComponent(paramString),
"&filePostName=", encodeURIComponent(this.settings.file_post_name),
"&fileTypes=", encodeURIComponent(this.settings.file_types),
// Public: Used to remove a SWFUpload instance from the page. This method strives to remove
// all references to the SWF, and other objects so memory is properly freed.
// Returns true if everything was destroyed. Returns a false if a failure occurs leaving SWFUpload in an inconsistant state.
+// Credits: Major improvements provided by steffen
SWFUpload.prototype.destroy = function () {
try {
// Make sure Flash is done before we try to remove it
- this.stopUpload();
+ this.cancelUpload(null, false);
+
// Remove the SWFUpload DOM nodes
var movieElement = null;
- try {
- movieElement = this.getMovieElement();
- } catch (ex) {
- }
+ movieElement = this.getMovieElement();
- if (movieElement != undefined && movieElement.parentNode != undefined && typeof movieElement.parentNode.removeChild === "function") {
- var container = movieElement.parentNode;
- if (container != undefined) {
- container.removeChild(movieElement);
- if (container.parentNode != undefined && typeof container.parentNode.removeChild === "function") {
- container.parentNode.removeChild(container);
- }
+ if (movieElement && typeof(movieElement.CallFunction) === "unknown") { // We only want to do this in IE
+ // Loop through all the movie's properties and remove all function references (DOM/JS IE 6/7 memory leak workaround)
+ for (var i in movieElement) {
+ try {
+ if (typeof(movieElement[i]) === "function") {
+ movieElement[i] = null;
+ }
+ } catch (ex1) {}
}
+
+ // Remove the Movie Element from the page
+ try {
+ movieElement.parentNode.removeChild(movieElement);
+ } catch (ex) {}
}
- // Destroy references
+ // Remove IE form fix reference
+ window[this.movieName] = null;
+
+ // Destroy other references
SWFUpload.instances[this.movieName] = null;
delete SWFUpload.instances[this.movieName];
- delete this.movieElement;
- delete this.settings;
- delete this.customSettings;
- delete this.eventQueue;
- delete this.movieName;
+ this.movieElement = null;
+ this.settings = null;
+ this.customSettings = null;
+ this.eventQueue = null;
+ this.movieName = null;
- delete window[this.movieName];
return true;
- } catch (ex1) {
+ } catch (ex2) {
return false;
}
};
+
// Public: displayDebugInfo prints out settings and configuration
// information about this SWFUpload instance.
// This function (and any references to it) can be deleted when placing
"\t", "use_query_string: ", this.settings.use_query_string.toString(), "\n",
"\t", "requeue_on_error: ", this.settings.requeue_on_error.toString(), "\n",
"\t", "http_success: ", this.settings.http_success.join(", "), "\n",
+ "\t", "assume_success_timeout: ", this.settings.assume_success_timeout, "\n",
"\t", "file_post_name: ", this.settings.file_post_name, "\n",
"\t", "post_params: ", this.settings.post_params.toString(), "\n",
"\t", "file_types: ", this.settings.file_types, "\n",
"\t", "prevent_swf_caching: ", this.settings.prevent_swf_caching.toString(), "\n",
"\t", "button_placeholder_id: ", this.settings.button_placeholder_id.toString(), "\n",
+ "\t", "button_placeholder: ", (this.settings.button_placeholder ? "Set" : "Not Set"), "\n",
"\t", "button_image_url: ", this.settings.button_image_url.toString(), "\n",
"\t", "button_width: ", this.settings.button_width.toString(), "\n",
"\t", "button_height: ", this.settings.button_height.toString(), "\n",
argumentArray = argumentArray || [];
var movieElement = this.getMovieElement();
- var returnValue;
+ var returnValue, returnString;
- if (typeof movieElement[functionName] === "function") {
- // We have to go through all this if/else stuff because the Flash functions don't have apply() and only accept the exact number of arguments.
- if (argumentArray.length === 0) {
- returnValue = movieElement[functionName]();
- } else if (argumentArray.length === 1) {
- returnValue = movieElement[functionName](argumentArray[0]);
- } else if (argumentArray.length === 2) {
- returnValue = movieElement[functionName](argumentArray[0], argumentArray[1]);
- } else if (argumentArray.length === 3) {
- returnValue = movieElement[functionName](argumentArray[0], argumentArray[1], argumentArray[2]);
- } else {
- throw "Too many arguments";
- }
-
- // Unescape file post param values
- if (returnValue != undefined && typeof returnValue.post === "object") {
- returnValue = this.unescapeFilePostParams(returnValue);
- }
-
- return returnValue;
- } else {
- throw "Invalid function name: " + functionName;
+ // Flash's method if calling ExternalInterface methods (code adapted from MooTools).
+ try {
+ returnString = movieElement.CallFunction('<invoke name="' + functionName + '" returntype="javascript">' + __flash__argumentsToXML(argumentArray, 0) + '</invoke>');
+ returnValue = eval(returnString);
+ } catch (ex) {
+ throw "Call to " + functionName + " failed";
+ }
+
+ // Unescape file post param values
+ if (returnValue != undefined && typeof returnValue.post === "object") {
+ returnValue = this.unescapeFilePostParams(returnValue);
}
-};
+ return returnValue;
+};
/* *****************************
-- Flash control methods --
to operate SWFUpload
***************************** */
+// WARNING: this function does not work in Flash Player 10
// Public: selectFile causes a File Selection Dialog window to appear. This
-// dialog only allows 1 file to be selected. WARNING: this function does not work in Flash Player 10
+// dialog only allows 1 file to be selected.
SWFUpload.prototype.selectFile = function () {
this.callFlash("SelectFile");
};
+// WARNING: this function does not work in Flash Player 10
// Public: selectFiles causes a File Selection Dialog window to appear/ This
// dialog allows the user to select any number of files
// Flash Bug Warning: Flash limits the number of selectable files based on the combined length of the file names.
// If the selection name length is too long the dialog will fail in an unpredictable manner. There is no work-around
-// for this bug. WARNING: this function does not work in Flash Player 10
+// for this bug.
SWFUpload.prototype.selectFiles = function () {
this.callFlash("SelectFiles");
};
this.callFlash("SetHTTPSuccess", [http_status_codes]);
};
+// Public: setHTTPSuccess changes the http_success setting
+SWFUpload.prototype.setAssumeSuccessTimeout = function (timeout_seconds) {
+ this.settings.assume_success_timeout = timeout_seconds;
+ this.callFlash("SetAssumeSuccessTimeout", [timeout_seconds]);
+};
// Public: setDebugEnabled changes the debug_enabled setting
SWFUpload.prototype.setDebugEnabled = function (debugEnabled) {
return file;
};
+// Private: Called by Flash to see if JS can call in to Flash (test if External Interface is working)
+SWFUpload.prototype.testExternalInterface = function () {
+ try {
+ return this.callFlash("TestExternalInterface");
+ } catch (ex) {
+ return false;
+ }
+};
+
+// Private: This event is called by Flash when it has finished loading. Don't modify this.
+// Use the swfupload_loaded_handler event setting to execute custom code when SWFUpload has loaded.
SWFUpload.prototype.flashReady = function () {
// Check that the movie element is loaded correctly with its ExternalInterface methods defined
var movieElement = this.getMovieElement();
- if (typeof movieElement.StartUpload !== "function") {
- throw "ExternalInterface methods failed to initialize.";
- }
- // Fix IE Flash/Form bug
- if (window[this.movieName] == undefined) {
- window[this.movieName] = movieElement;
+ if (!movieElement) {
+ this.debug("Flash called back ready but the flash movie can't be found.");
+ return;
}
+
+ this.cleanUp(movieElement);
this.queueEvent("swfupload_loaded_handler");
};
+// Private: removes Flash added fuctions to the DOM node to prevent memory leaks in IE.
+// This function is called by Flash each time the ExternalInterface functions are created.
+SWFUpload.prototype.cleanUp = function (movieElement) {
+ // Pro-actively unhook all the Flash functions
+ try {
+ if (this.movieElement && typeof(movieElement.CallFunction) === "unknown") { // We only want to do this in IE
+ this.debug("Removing Flash functions hooks (this should only run in IE and should prevent memory leaks)");
+ for (var key in movieElement) {
+ try {
+ if (typeof(movieElement[key]) === "function") {
+ movieElement[key] = null;
+ }
+ } catch (ex) {
+ }
+ }
+ }
+ } catch (ex1) {
+
+ }
+
+ // Fix Flashes own cleanup code so if the SWFMovie was removed from the page
+ // it doesn't display errors.
+ window["__flash__removeCallback"] = function (instance, name) {
+ try {
+ if (instance) {
+ instance[name] = null;
+ }
+ } catch (flashEx) {
+
+ }
+ };
+
+};
+
/* This is a chance to do something before the browse window opens */
SWFUpload.prototype.fileDialogStart = function () {
/* Called after the file dialog has closed and the selected files have been queued.
You could call startUpload here if you want the queued files to begin uploading immediately. */
-SWFUpload.prototype.fileDialogComplete = function (numFilesSelected, numFilesQueued) {
- this.queueEvent("file_dialog_complete_handler", [numFilesSelected, numFilesQueued]);
+SWFUpload.prototype.fileDialogComplete = function (numFilesSelected, numFilesQueued, numFilesInQueue) {
+ this.queueEvent("file_dialog_complete_handler", [numFilesSelected, numFilesQueued, numFilesInQueue]);
};
SWFUpload.prototype.uploadStart = function (file) {
this.queueEvent("upload_error_handler", [file, errorCode, message]);
};
-SWFUpload.prototype.uploadSuccess = function (file, serverData) {
+SWFUpload.prototype.uploadSuccess = function (file, serverData, responseReceived) {
file = this.unescapeFilePostParams(file);
- this.queueEvent("upload_success_handler", [file, serverData]);
+ this.queueEvent("upload_success_handler", [file, serverData, responseReceived]);
};
SWFUpload.prototype.uploadComplete = function (file) {