diff options
Diffstat (limited to 'lib/swfupload/swfupload.js')
-rw-r--r-- | lib/swfupload/swfupload.js | 202 |
1 files changed, 109 insertions, 93 deletions
diff --git a/lib/swfupload/swfupload.js b/lib/swfupload/swfupload.js index 849cf28e..7a6f6567 100644 --- a/lib/swfupload/swfupload.js +++ b/lib/swfupload/swfupload.js @@ -31,6 +31,7 @@ SWFUpload.prototype.initSWFUpload = function (settings) { this.movieName = "SWFUpload_" + SWFUpload.movieCount++; this.movieElement = null; + // Setup global control tracking SWFUpload.instances[this.movieName] = this; @@ -49,7 +50,7 @@ SWFUpload.prototype.initSWFUpload = function (settings) { /* *************** */ SWFUpload.instances = {}; SWFUpload.movieCount = 0; -SWFUpload.version = "2.2.0 Beta 2"; +SWFUpload.version = "2.2.0 Beta 5 2008-01-29"; SWFUpload.QUEUE_ERROR = { QUEUE_LIMIT_EXCEEDED : -100, FILE_EXCEEDS_SIZE_LIMIT : -110, @@ -130,7 +131,7 @@ SWFUpload.prototype.initSettings = function () { 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_cursor", SWFUpload.CURSOR.ARROW); this.ensureDefault("button_window_mode", SWFUpload.WINDOW_MODE.WINDOW); @@ -160,50 +161,15 @@ SWFUpload.prototype.initSettings = function () { 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(); } 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 @@ -215,7 +181,7 @@ SWFUpload.prototype.replaceWithFlash = function () { targetElement = document.getElementById(this.settings.button_placeholder_id); 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 @@ -223,13 +189,18 @@ SWFUpload.prototype.replaceWithFlash = function () { 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" />', @@ -306,46 +277,54 @@ SWFUpload.prototype.buildParamString = function () { // 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 @@ -430,31 +409,22 @@ SWFUpload.prototype.callFlash = function (functionName, argumentArray) { 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; }; @@ -464,17 +434,19 @@ SWFUpload.prototype.callFlash = function (functionName, argumentArray) { 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"); }; @@ -763,21 +735,65 @@ SWFUpload.prototype.unescapeFilePostParams = function (file) { 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 () { |