web/wp-includes/js/swfupload/swfupload.js
branchwordpress
changeset 109 03b0d1493584
child 132 4d4862461b8d
equal deleted inserted replaced
-1:000000000000 109:03b0d1493584
       
     1 /**
       
     2  * SWFUpload: http://www.swfupload.org, http://swfupload.googlecode.com
       
     3  *
       
     4  * mmSWFUpload 1.0: Flash upload dialog - http://profandesign.se/swfupload/,  http://www.vinterwebb.se/
       
     5  *
       
     6  * SWFUpload is (c) 2006-2007 Lars Huring, Olov Nilzén and Mammon Media and is released under the MIT License:
       
     7  * http://www.opensource.org/licenses/mit-license.php
       
     8  *
       
     9  * SWFUpload 2 is (c) 2007-2008 Jake Roberts and is released under the MIT License:
       
    10  * http://www.opensource.org/licenses/mit-license.php
       
    11  *
       
    12  */
       
    13 
       
    14 
       
    15 /* ******************* */
       
    16 /* Constructor & Init  */
       
    17 /* ******************* */
       
    18 var SWFUpload;
       
    19 
       
    20 if (SWFUpload == undefined) {
       
    21 	SWFUpload = function (settings) {
       
    22 		this.initSWFUpload(settings);
       
    23 	};
       
    24 }
       
    25 
       
    26 SWFUpload.prototype.initSWFUpload = function (settings) {
       
    27 	try {
       
    28 		this.customSettings = {};	// A container where developers can place their own settings associated with this instance.
       
    29 		this.settings = settings;
       
    30 		this.eventQueue = [];
       
    31 		this.movieName = "SWFUpload_" + SWFUpload.movieCount++;
       
    32 		this.movieElement = null;
       
    33 
       
    34 
       
    35 		// Setup global control tracking
       
    36 		SWFUpload.instances[this.movieName] = this;
       
    37 
       
    38 		// Load the settings.  Load the Flash movie.
       
    39 		this.initSettings();
       
    40 		this.loadFlash();
       
    41 		this.displayDebugInfo();
       
    42 	} catch (ex) {
       
    43 		delete SWFUpload.instances[this.movieName];
       
    44 		throw ex;
       
    45 	}
       
    46 };
       
    47 
       
    48 /* *************** */
       
    49 /* Static Members  */
       
    50 /* *************** */
       
    51 SWFUpload.instances = {};
       
    52 SWFUpload.movieCount = 0;
       
    53 SWFUpload.version = "2.2.0 2009-03-25";
       
    54 SWFUpload.QUEUE_ERROR = {
       
    55 	QUEUE_LIMIT_EXCEEDED	  		: -100,
       
    56 	FILE_EXCEEDS_SIZE_LIMIT  		: -110,
       
    57 	ZERO_BYTE_FILE			  		: -120,
       
    58 	INVALID_FILETYPE		  		: -130
       
    59 };
       
    60 SWFUpload.UPLOAD_ERROR = {
       
    61 	HTTP_ERROR				  		: -200,
       
    62 	MISSING_UPLOAD_URL	      		: -210,
       
    63 	IO_ERROR				  		: -220,
       
    64 	SECURITY_ERROR			  		: -230,
       
    65 	UPLOAD_LIMIT_EXCEEDED	  		: -240,
       
    66 	UPLOAD_FAILED			  		: -250,
       
    67 	SPECIFIED_FILE_ID_NOT_FOUND		: -260,
       
    68 	FILE_VALIDATION_FAILED	  		: -270,
       
    69 	FILE_CANCELLED			  		: -280,
       
    70 	UPLOAD_STOPPED					: -290
       
    71 };
       
    72 SWFUpload.FILE_STATUS = {
       
    73 	QUEUED		 : -1,
       
    74 	IN_PROGRESS	 : -2,
       
    75 	ERROR		 : -3,
       
    76 	COMPLETE	 : -4,
       
    77 	CANCELLED	 : -5
       
    78 };
       
    79 SWFUpload.BUTTON_ACTION = {
       
    80 	SELECT_FILE  : -100,
       
    81 	SELECT_FILES : -110,
       
    82 	START_UPLOAD : -120
       
    83 };
       
    84 SWFUpload.CURSOR = {
       
    85 	ARROW : -1,
       
    86 	HAND : -2
       
    87 };
       
    88 SWFUpload.WINDOW_MODE = {
       
    89 	WINDOW : "window",
       
    90 	TRANSPARENT : "transparent",
       
    91 	OPAQUE : "opaque"
       
    92 };
       
    93 
       
    94 // Private: takes a URL, determines if it is relative and converts to an absolute URL
       
    95 // using the current site. Only processes the URL if it can, otherwise returns the URL untouched
       
    96 SWFUpload.completeURL = function(url) {
       
    97 	if (typeof(url) !== "string" || url.match(/^https?:\/\//i) || url.match(/^\//)) {
       
    98 		return url;
       
    99 	}
       
   100 	
       
   101 	var currentURL = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ":" + window.location.port : "");
       
   102 	
       
   103 	var indexSlash = window.location.pathname.lastIndexOf("/");
       
   104 	if (indexSlash <= 0) {
       
   105 		path = "/";
       
   106 	} else {
       
   107 		path = window.location.pathname.substr(0, indexSlash) + "/";
       
   108 	}
       
   109 	
       
   110 	return /*currentURL +*/ path + url;
       
   111 	
       
   112 };
       
   113 
       
   114 
       
   115 /* ******************** */
       
   116 /* Instance Members  */
       
   117 /* ******************** */
       
   118 
       
   119 // Private: initSettings ensures that all the
       
   120 // settings are set, getting a default value if one was not assigned.
       
   121 SWFUpload.prototype.initSettings = function () {
       
   122 	this.ensureDefault = function (settingName, defaultValue) {
       
   123 		this.settings[settingName] = (this.settings[settingName] == undefined) ? defaultValue : this.settings[settingName];
       
   124 	};
       
   125 	
       
   126 	// Upload backend settings
       
   127 	this.ensureDefault("upload_url", "");
       
   128 	this.ensureDefault("preserve_relative_urls", false);
       
   129 	this.ensureDefault("file_post_name", "Filedata");
       
   130 	this.ensureDefault("post_params", {});
       
   131 	this.ensureDefault("use_query_string", false);
       
   132 	this.ensureDefault("requeue_on_error", false);
       
   133 	this.ensureDefault("http_success", []);
       
   134 	this.ensureDefault("assume_success_timeout", 0);
       
   135 	
       
   136 	// File Settings
       
   137 	this.ensureDefault("file_types", "*.*");
       
   138 	this.ensureDefault("file_types_description", "All Files");
       
   139 	this.ensureDefault("file_size_limit", 0);	// Default zero means "unlimited"
       
   140 	this.ensureDefault("file_upload_limit", 0);
       
   141 	this.ensureDefault("file_queue_limit", 0);
       
   142 
       
   143 	// Flash Settings
       
   144 	this.ensureDefault("flash_url", "swfupload.swf");
       
   145 	this.ensureDefault("prevent_swf_caching", true);
       
   146 	
       
   147 	// Button Settings
       
   148 	this.ensureDefault("button_image_url", "");
       
   149 	this.ensureDefault("button_width", 1);
       
   150 	this.ensureDefault("button_height", 1);
       
   151 	this.ensureDefault("button_text", "");
       
   152 	this.ensureDefault("button_text_style", "color: #000000; font-size: 16pt;");
       
   153 	this.ensureDefault("button_text_top_padding", 0);
       
   154 	this.ensureDefault("button_text_left_padding", 0);
       
   155 	this.ensureDefault("button_action", SWFUpload.BUTTON_ACTION.SELECT_FILES);
       
   156 	this.ensureDefault("button_disabled", false);
       
   157 	this.ensureDefault("button_placeholder_id", "");
       
   158 	this.ensureDefault("button_placeholder", null);
       
   159 	this.ensureDefault("button_cursor", SWFUpload.CURSOR.ARROW);
       
   160 	this.ensureDefault("button_window_mode", SWFUpload.WINDOW_MODE.WINDOW);
       
   161 	
       
   162 	// Debug Settings
       
   163 	this.ensureDefault("debug", false);
       
   164 	this.settings.debug_enabled = this.settings.debug;	// Here to maintain v2 API
       
   165 	
       
   166 	// Event Handlers
       
   167 	this.settings.return_upload_start_handler = this.returnUploadStart;
       
   168 	this.ensureDefault("swfupload_loaded_handler", null);
       
   169 	this.ensureDefault("file_dialog_start_handler", null);
       
   170 	this.ensureDefault("file_queued_handler", null);
       
   171 	this.ensureDefault("file_queue_error_handler", null);
       
   172 	this.ensureDefault("file_dialog_complete_handler", null);
       
   173 	
       
   174 	this.ensureDefault("upload_start_handler", null);
       
   175 	this.ensureDefault("upload_progress_handler", null);
       
   176 	this.ensureDefault("upload_error_handler", null);
       
   177 	this.ensureDefault("upload_success_handler", null);
       
   178 	this.ensureDefault("upload_complete_handler", null);
       
   179 	
       
   180 	this.ensureDefault("debug_handler", this.debugMessage);
       
   181 
       
   182 	this.ensureDefault("custom_settings", {});
       
   183 
       
   184 	// Other settings
       
   185 	this.customSettings = this.settings.custom_settings;
       
   186 	
       
   187 	// Update the flash url if needed
       
   188 	if (!!this.settings.prevent_swf_caching) {
       
   189 		this.settings.flash_url = this.settings.flash_url + (this.settings.flash_url.indexOf("?") < 0 ? "?" : "&") + "preventswfcaching=" + new Date().getTime();
       
   190 	}
       
   191 	
       
   192 	if (!this.settings.preserve_relative_urls) {
       
   193 		//this.settings.flash_url = SWFUpload.completeURL(this.settings.flash_url);	// Don't need to do this one since flash doesn't look at it
       
   194 		this.settings.upload_url = SWFUpload.completeURL(this.settings.upload_url);
       
   195 		this.settings.button_image_url = SWFUpload.completeURL(this.settings.button_image_url);
       
   196 	}
       
   197 	
       
   198 	delete this.ensureDefault;
       
   199 };
       
   200 
       
   201 // Private: loadFlash replaces the button_placeholder element with the flash movie.
       
   202 SWFUpload.prototype.loadFlash = function () {
       
   203 	var targetElement, tempParent;
       
   204 
       
   205 	// Make sure an element with the ID we are going to use doesn't already exist
       
   206 	if (document.getElementById(this.movieName) !== null) {
       
   207 		throw "ID " + this.movieName + " is already in use. The Flash Object could not be added";
       
   208 	}
       
   209 
       
   210 	// Get the element where we will be placing the flash movie
       
   211 	targetElement = document.getElementById(this.settings.button_placeholder_id) || this.settings.button_placeholder;
       
   212 
       
   213 	if (targetElement == undefined) {
       
   214 		throw "Could not find the placeholder element: " + this.settings.button_placeholder_id;
       
   215 	}
       
   216 
       
   217 	// Append the container and load the flash
       
   218 	tempParent = document.createElement("div");
       
   219 	tempParent.innerHTML = this.getFlashHTML();	// Using innerHTML is non-standard but the only sensible way to dynamically add Flash in IE (and maybe other browsers)
       
   220 	targetElement.parentNode.replaceChild(tempParent.firstChild, targetElement);
       
   221 
       
   222 	// Fix IE Flash/Form bug
       
   223 	if (window[this.movieName] == undefined) {
       
   224 		window[this.movieName] = this.getMovieElement();
       
   225 	}
       
   226 	
       
   227 };
       
   228 
       
   229 // Private: getFlashHTML generates the object tag needed to embed the flash in to the document
       
   230 SWFUpload.prototype.getFlashHTML = function () {
       
   231 	// Flash Satay object syntax: http://www.alistapart.com/articles/flashsatay
       
   232 	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">',
       
   233 				'<param name="wmode" value="', this.settings.button_window_mode, '" />',
       
   234 				'<param name="movie" value="', this.settings.flash_url, '" />',
       
   235 				'<param name="quality" value="high" />',
       
   236 				'<param name="menu" value="false" />',
       
   237 				'<param name="allowScriptAccess" value="always" />',
       
   238 				'<param name="flashvars" value="' + this.getFlashVars() + '" />',
       
   239 				'</object>'].join("");
       
   240 };
       
   241 
       
   242 // Private: getFlashVars builds the parameter string that will be passed
       
   243 // to flash in the flashvars param.
       
   244 SWFUpload.prototype.getFlashVars = function () {
       
   245 	// Build a string from the post param object
       
   246 	var paramString = this.buildParamString();
       
   247 	var httpSuccessString = this.settings.http_success.join(",");
       
   248 	
       
   249 	// Build the parameter string
       
   250 	return ["movieName=", encodeURIComponent(this.movieName),
       
   251 			"&amp;uploadURL=", encodeURIComponent(this.settings.upload_url),
       
   252 			"&amp;useQueryString=", encodeURIComponent(this.settings.use_query_string),
       
   253 			"&amp;requeueOnError=", encodeURIComponent(this.settings.requeue_on_error),
       
   254 			"&amp;httpSuccess=", encodeURIComponent(httpSuccessString),
       
   255 			"&amp;assumeSuccessTimeout=", encodeURIComponent(this.settings.assume_success_timeout),
       
   256 			"&amp;params=", encodeURIComponent(paramString),
       
   257 			"&amp;filePostName=", encodeURIComponent(this.settings.file_post_name),
       
   258 			"&amp;fileTypes=", encodeURIComponent(this.settings.file_types),
       
   259 			"&amp;fileTypesDescription=", encodeURIComponent(this.settings.file_types_description),
       
   260 			"&amp;fileSizeLimit=", encodeURIComponent(this.settings.file_size_limit),
       
   261 			"&amp;fileUploadLimit=", encodeURIComponent(this.settings.file_upload_limit),
       
   262 			"&amp;fileQueueLimit=", encodeURIComponent(this.settings.file_queue_limit),
       
   263 			"&amp;debugEnabled=", encodeURIComponent(this.settings.debug_enabled),
       
   264 			"&amp;buttonImageURL=", encodeURIComponent(this.settings.button_image_url),
       
   265 			"&amp;buttonWidth=", encodeURIComponent(this.settings.button_width),
       
   266 			"&amp;buttonHeight=", encodeURIComponent(this.settings.button_height),
       
   267 			"&amp;buttonText=", encodeURIComponent(this.settings.button_text),
       
   268 			"&amp;buttonTextTopPadding=", encodeURIComponent(this.settings.button_text_top_padding),
       
   269 			"&amp;buttonTextLeftPadding=", encodeURIComponent(this.settings.button_text_left_padding),
       
   270 			"&amp;buttonTextStyle=", encodeURIComponent(this.settings.button_text_style),
       
   271 			"&amp;buttonAction=", encodeURIComponent(this.settings.button_action),
       
   272 			"&amp;buttonDisabled=", encodeURIComponent(this.settings.button_disabled),
       
   273 			"&amp;buttonCursor=", encodeURIComponent(this.settings.button_cursor)
       
   274 		].join("");
       
   275 };
       
   276 
       
   277 // Public: getMovieElement retrieves the DOM reference to the Flash element added by SWFUpload
       
   278 // The element is cached after the first lookup
       
   279 SWFUpload.prototype.getMovieElement = function () {
       
   280 	if (this.movieElement == undefined) {
       
   281 		this.movieElement = document.getElementById(this.movieName);
       
   282 	}
       
   283 
       
   284 	if (this.movieElement === null) {
       
   285 		throw "Could not find Flash element";
       
   286 	}
       
   287 	
       
   288 	return this.movieElement;
       
   289 };
       
   290 
       
   291 // Private: buildParamString takes the name/value pairs in the post_params setting object
       
   292 // and joins them up in to a string formatted "name=value&amp;name=value"
       
   293 SWFUpload.prototype.buildParamString = function () {
       
   294 	var postParams = this.settings.post_params; 
       
   295 	var paramStringPairs = [];
       
   296 
       
   297 	if (typeof(postParams) === "object") {
       
   298 		for (var name in postParams) {
       
   299 			if (postParams.hasOwnProperty(name)) {
       
   300 				paramStringPairs.push(encodeURIComponent(name.toString()) + "=" + encodeURIComponent(postParams[name].toString()));
       
   301 			}
       
   302 		}
       
   303 	}
       
   304 
       
   305 	return paramStringPairs.join("&amp;");
       
   306 };
       
   307 
       
   308 // Public: Used to remove a SWFUpload instance from the page. This method strives to remove
       
   309 // all references to the SWF, and other objects so memory is properly freed.
       
   310 // Returns true if everything was destroyed. Returns a false if a failure occurs leaving SWFUpload in an inconsistant state.
       
   311 // Credits: Major improvements provided by steffen
       
   312 SWFUpload.prototype.destroy = function () {
       
   313 	try {
       
   314 		// Make sure Flash is done before we try to remove it
       
   315 		this.cancelUpload(null, false);
       
   316 		
       
   317 
       
   318 		// Remove the SWFUpload DOM nodes
       
   319 		var movieElement = null;
       
   320 		movieElement = this.getMovieElement();
       
   321 		
       
   322 		if (movieElement && typeof(movieElement.CallFunction) === "unknown") { // We only want to do this in IE
       
   323 			// Loop through all the movie's properties and remove all function references (DOM/JS IE 6/7 memory leak workaround)
       
   324 			for (var i in movieElement) {
       
   325 				try {
       
   326 					if (typeof(movieElement[i]) === "function") {
       
   327 						movieElement[i] = null;
       
   328 					}
       
   329 				} catch (ex1) {}
       
   330 			}
       
   331 
       
   332 			// Remove the Movie Element from the page
       
   333 			try {
       
   334 				movieElement.parentNode.removeChild(movieElement);
       
   335 			} catch (ex) {}
       
   336 		}
       
   337 		
       
   338 		// Remove IE form fix reference
       
   339 		window[this.movieName] = null;
       
   340 
       
   341 		// Destroy other references
       
   342 		SWFUpload.instances[this.movieName] = null;
       
   343 		delete SWFUpload.instances[this.movieName];
       
   344 
       
   345 		this.movieElement = null;
       
   346 		this.settings = null;
       
   347 		this.customSettings = null;
       
   348 		this.eventQueue = null;
       
   349 		this.movieName = null;
       
   350 		
       
   351 		
       
   352 		return true;
       
   353 	} catch (ex2) {
       
   354 		return false;
       
   355 	}
       
   356 };
       
   357 
       
   358 
       
   359 // Public: displayDebugInfo prints out settings and configuration
       
   360 // information about this SWFUpload instance.
       
   361 // This function (and any references to it) can be deleted when placing
       
   362 // SWFUpload in production.
       
   363 SWFUpload.prototype.displayDebugInfo = function () {
       
   364 	this.debug(
       
   365 		[
       
   366 			"---SWFUpload Instance Info---\n",
       
   367 			"Version: ", SWFUpload.version, "\n",
       
   368 			"Movie Name: ", this.movieName, "\n",
       
   369 			"Settings:\n",
       
   370 			"\t", "upload_url:               ", this.settings.upload_url, "\n",
       
   371 			"\t", "flash_url:                ", this.settings.flash_url, "\n",
       
   372 			"\t", "use_query_string:         ", this.settings.use_query_string.toString(), "\n",
       
   373 			"\t", "requeue_on_error:         ", this.settings.requeue_on_error.toString(), "\n",
       
   374 			"\t", "http_success:             ", this.settings.http_success.join(", "), "\n",
       
   375 			"\t", "assume_success_timeout:   ", this.settings.assume_success_timeout, "\n",
       
   376 			"\t", "file_post_name:           ", this.settings.file_post_name, "\n",
       
   377 			"\t", "post_params:              ", this.settings.post_params.toString(), "\n",
       
   378 			"\t", "file_types:               ", this.settings.file_types, "\n",
       
   379 			"\t", "file_types_description:   ", this.settings.file_types_description, "\n",
       
   380 			"\t", "file_size_limit:          ", this.settings.file_size_limit, "\n",
       
   381 			"\t", "file_upload_limit:        ", this.settings.file_upload_limit, "\n",
       
   382 			"\t", "file_queue_limit:         ", this.settings.file_queue_limit, "\n",
       
   383 			"\t", "debug:                    ", this.settings.debug.toString(), "\n",
       
   384 
       
   385 			"\t", "prevent_swf_caching:      ", this.settings.prevent_swf_caching.toString(), "\n",
       
   386 
       
   387 			"\t", "button_placeholder_id:    ", this.settings.button_placeholder_id.toString(), "\n",
       
   388 			"\t", "button_placeholder:       ", (this.settings.button_placeholder ? "Set" : "Not Set"), "\n",
       
   389 			"\t", "button_image_url:         ", this.settings.button_image_url.toString(), "\n",
       
   390 			"\t", "button_width:             ", this.settings.button_width.toString(), "\n",
       
   391 			"\t", "button_height:            ", this.settings.button_height.toString(), "\n",
       
   392 			"\t", "button_text:              ", this.settings.button_text.toString(), "\n",
       
   393 			"\t", "button_text_style:        ", this.settings.button_text_style.toString(), "\n",
       
   394 			"\t", "button_text_top_padding:  ", this.settings.button_text_top_padding.toString(), "\n",
       
   395 			"\t", "button_text_left_padding: ", this.settings.button_text_left_padding.toString(), "\n",
       
   396 			"\t", "button_action:            ", this.settings.button_action.toString(), "\n",
       
   397 			"\t", "button_disabled:          ", this.settings.button_disabled.toString(), "\n",
       
   398 
       
   399 			"\t", "custom_settings:          ", this.settings.custom_settings.toString(), "\n",
       
   400 			"Event Handlers:\n",
       
   401 			"\t", "swfupload_loaded_handler assigned:  ", (typeof this.settings.swfupload_loaded_handler === "function").toString(), "\n",
       
   402 			"\t", "file_dialog_start_handler assigned: ", (typeof this.settings.file_dialog_start_handler === "function").toString(), "\n",
       
   403 			"\t", "file_queued_handler assigned:       ", (typeof this.settings.file_queued_handler === "function").toString(), "\n",
       
   404 			"\t", "file_queue_error_handler assigned:  ", (typeof this.settings.file_queue_error_handler === "function").toString(), "\n",
       
   405 			"\t", "upload_start_handler assigned:      ", (typeof this.settings.upload_start_handler === "function").toString(), "\n",
       
   406 			"\t", "upload_progress_handler assigned:   ", (typeof this.settings.upload_progress_handler === "function").toString(), "\n",
       
   407 			"\t", "upload_error_handler assigned:      ", (typeof this.settings.upload_error_handler === "function").toString(), "\n",
       
   408 			"\t", "upload_success_handler assigned:    ", (typeof this.settings.upload_success_handler === "function").toString(), "\n",
       
   409 			"\t", "upload_complete_handler assigned:   ", (typeof this.settings.upload_complete_handler === "function").toString(), "\n",
       
   410 			"\t", "debug_handler assigned:             ", (typeof this.settings.debug_handler === "function").toString(), "\n"
       
   411 		].join("")
       
   412 	);
       
   413 };
       
   414 
       
   415 /* Note: addSetting and getSetting are no longer used by SWFUpload but are included
       
   416 	the maintain v2 API compatibility
       
   417 */
       
   418 // Public: (Deprecated) addSetting adds a setting value. If the value given is undefined or null then the default_value is used.
       
   419 SWFUpload.prototype.addSetting = function (name, value, default_value) {
       
   420     if (value == undefined) {
       
   421         return (this.settings[name] = default_value);
       
   422     } else {
       
   423         return (this.settings[name] = value);
       
   424 	}
       
   425 };
       
   426 
       
   427 // Public: (Deprecated) getSetting gets a setting. Returns an empty string if the setting was not found.
       
   428 SWFUpload.prototype.getSetting = function (name) {
       
   429     if (this.settings[name] != undefined) {
       
   430         return this.settings[name];
       
   431 	}
       
   432 
       
   433     return "";
       
   434 };
       
   435 
       
   436 
       
   437 
       
   438 // Private: callFlash handles function calls made to the Flash element.
       
   439 // Calls are made with a setTimeout for some functions to work around
       
   440 // bugs in the ExternalInterface library.
       
   441 SWFUpload.prototype.callFlash = function (functionName, argumentArray) {
       
   442 	argumentArray = argumentArray || [];
       
   443 	
       
   444 	var movieElement = this.getMovieElement();
       
   445 	var returnValue, returnString;
       
   446 
       
   447 	// Flash's method if calling ExternalInterface methods (code adapted from MooTools).
       
   448 	try {
       
   449 		returnString = movieElement.CallFunction('<invoke name="' + functionName + '" returntype="javascript">' + __flash__argumentsToXML(argumentArray, 0) + '</invoke>');
       
   450 		returnValue = eval(returnString);
       
   451 	} catch (ex) {
       
   452 		throw "Call to " + functionName + " failed";
       
   453 	}
       
   454 	
       
   455 	// Unescape file post param values
       
   456 	if (returnValue != undefined && typeof returnValue.post === "object") {
       
   457 		returnValue = this.unescapeFilePostParams(returnValue);
       
   458 	}
       
   459 
       
   460 	return returnValue;
       
   461 };
       
   462 
       
   463 /* *****************************
       
   464 	-- Flash control methods --
       
   465 	Your UI should use these
       
   466 	to operate SWFUpload
       
   467    ***************************** */
       
   468 
       
   469 // WARNING: this function does not work in Flash Player 10
       
   470 // Public: selectFile causes a File Selection Dialog window to appear.  This
       
   471 // dialog only allows 1 file to be selected.
       
   472 SWFUpload.prototype.selectFile = function () {
       
   473 	this.callFlash("SelectFile");
       
   474 };
       
   475 
       
   476 // WARNING: this function does not work in Flash Player 10
       
   477 // Public: selectFiles causes a File Selection Dialog window to appear/ This
       
   478 // dialog allows the user to select any number of files
       
   479 // Flash Bug Warning: Flash limits the number of selectable files based on the combined length of the file names.
       
   480 // If the selection name length is too long the dialog will fail in an unpredictable manner.  There is no work-around
       
   481 // for this bug.
       
   482 SWFUpload.prototype.selectFiles = function () {
       
   483 	this.callFlash("SelectFiles");
       
   484 };
       
   485 
       
   486 
       
   487 // Public: startUpload starts uploading the first file in the queue unless
       
   488 // the optional parameter 'fileID' specifies the ID 
       
   489 SWFUpload.prototype.startUpload = function (fileID) {
       
   490 	this.callFlash("StartUpload", [fileID]);
       
   491 };
       
   492 
       
   493 // Public: cancelUpload cancels any queued file.  The fileID parameter may be the file ID or index.
       
   494 // If you do not specify a fileID the current uploading file or first file in the queue is cancelled.
       
   495 // If you do not want the uploadError event to trigger you can specify false for the triggerErrorEvent parameter.
       
   496 SWFUpload.prototype.cancelUpload = function (fileID, triggerErrorEvent) {
       
   497 	if (triggerErrorEvent !== false) {
       
   498 		triggerErrorEvent = true;
       
   499 	}
       
   500 	this.callFlash("CancelUpload", [fileID, triggerErrorEvent]);
       
   501 };
       
   502 
       
   503 // Public: stopUpload stops the current upload and requeues the file at the beginning of the queue.
       
   504 // If nothing is currently uploading then nothing happens.
       
   505 SWFUpload.prototype.stopUpload = function () {
       
   506 	this.callFlash("StopUpload");
       
   507 };
       
   508 
       
   509 /* ************************
       
   510  * Settings methods
       
   511  *   These methods change the SWFUpload settings.
       
   512  *   SWFUpload settings should not be changed directly on the settings object
       
   513  *   since many of the settings need to be passed to Flash in order to take
       
   514  *   effect.
       
   515  * *********************** */
       
   516 
       
   517 // Public: getStats gets the file statistics object.
       
   518 SWFUpload.prototype.getStats = function () {
       
   519 	return this.callFlash("GetStats");
       
   520 };
       
   521 
       
   522 // Public: setStats changes the SWFUpload statistics.  You shouldn't need to 
       
   523 // change the statistics but you can.  Changing the statistics does not
       
   524 // affect SWFUpload accept for the successful_uploads count which is used
       
   525 // by the upload_limit setting to determine how many files the user may upload.
       
   526 SWFUpload.prototype.setStats = function (statsObject) {
       
   527 	this.callFlash("SetStats", [statsObject]);
       
   528 };
       
   529 
       
   530 // Public: getFile retrieves a File object by ID or Index.  If the file is
       
   531 // not found then 'null' is returned.
       
   532 SWFUpload.prototype.getFile = function (fileID) {
       
   533 	if (typeof(fileID) === "number") {
       
   534 		return this.callFlash("GetFileByIndex", [fileID]);
       
   535 	} else {
       
   536 		return this.callFlash("GetFile", [fileID]);
       
   537 	}
       
   538 };
       
   539 
       
   540 // Public: addFileParam sets a name/value pair that will be posted with the
       
   541 // file specified by the Files ID.  If the name already exists then the
       
   542 // exiting value will be overwritten.
       
   543 SWFUpload.prototype.addFileParam = function (fileID, name, value) {
       
   544 	return this.callFlash("AddFileParam", [fileID, name, value]);
       
   545 };
       
   546 
       
   547 // Public: removeFileParam removes a previously set (by addFileParam) name/value
       
   548 // pair from the specified file.
       
   549 SWFUpload.prototype.removeFileParam = function (fileID, name) {
       
   550 	this.callFlash("RemoveFileParam", [fileID, name]);
       
   551 };
       
   552 
       
   553 // Public: setUploadUrl changes the upload_url setting.
       
   554 SWFUpload.prototype.setUploadURL = function (url) {
       
   555 	this.settings.upload_url = url.toString();
       
   556 	this.callFlash("SetUploadURL", [url]);
       
   557 };
       
   558 
       
   559 // Public: setPostParams changes the post_params setting
       
   560 SWFUpload.prototype.setPostParams = function (paramsObject) {
       
   561 	this.settings.post_params = paramsObject;
       
   562 	this.callFlash("SetPostParams", [paramsObject]);
       
   563 };
       
   564 
       
   565 // Public: addPostParam adds post name/value pair.  Each name can have only one value.
       
   566 SWFUpload.prototype.addPostParam = function (name, value) {
       
   567 	this.settings.post_params[name] = value;
       
   568 	this.callFlash("SetPostParams", [this.settings.post_params]);
       
   569 };
       
   570 
       
   571 // Public: removePostParam deletes post name/value pair.
       
   572 SWFUpload.prototype.removePostParam = function (name) {
       
   573 	delete this.settings.post_params[name];
       
   574 	this.callFlash("SetPostParams", [this.settings.post_params]);
       
   575 };
       
   576 
       
   577 // Public: setFileTypes changes the file_types setting and the file_types_description setting
       
   578 SWFUpload.prototype.setFileTypes = function (types, description) {
       
   579 	this.settings.file_types = types;
       
   580 	this.settings.file_types_description = description;
       
   581 	this.callFlash("SetFileTypes", [types, description]);
       
   582 };
       
   583 
       
   584 // Public: setFileSizeLimit changes the file_size_limit setting
       
   585 SWFUpload.prototype.setFileSizeLimit = function (fileSizeLimit) {
       
   586 	this.settings.file_size_limit = fileSizeLimit;
       
   587 	this.callFlash("SetFileSizeLimit", [fileSizeLimit]);
       
   588 };
       
   589 
       
   590 // Public: setFileUploadLimit changes the file_upload_limit setting
       
   591 SWFUpload.prototype.setFileUploadLimit = function (fileUploadLimit) {
       
   592 	this.settings.file_upload_limit = fileUploadLimit;
       
   593 	this.callFlash("SetFileUploadLimit", [fileUploadLimit]);
       
   594 };
       
   595 
       
   596 // Public: setFileQueueLimit changes the file_queue_limit setting
       
   597 SWFUpload.prototype.setFileQueueLimit = function (fileQueueLimit) {
       
   598 	this.settings.file_queue_limit = fileQueueLimit;
       
   599 	this.callFlash("SetFileQueueLimit", [fileQueueLimit]);
       
   600 };
       
   601 
       
   602 // Public: setFilePostName changes the file_post_name setting
       
   603 SWFUpload.prototype.setFilePostName = function (filePostName) {
       
   604 	this.settings.file_post_name = filePostName;
       
   605 	this.callFlash("SetFilePostName", [filePostName]);
       
   606 };
       
   607 
       
   608 // Public: setUseQueryString changes the use_query_string setting
       
   609 SWFUpload.prototype.setUseQueryString = function (useQueryString) {
       
   610 	this.settings.use_query_string = useQueryString;
       
   611 	this.callFlash("SetUseQueryString", [useQueryString]);
       
   612 };
       
   613 
       
   614 // Public: setRequeueOnError changes the requeue_on_error setting
       
   615 SWFUpload.prototype.setRequeueOnError = function (requeueOnError) {
       
   616 	this.settings.requeue_on_error = requeueOnError;
       
   617 	this.callFlash("SetRequeueOnError", [requeueOnError]);
       
   618 };
       
   619 
       
   620 // Public: setHTTPSuccess changes the http_success setting
       
   621 SWFUpload.prototype.setHTTPSuccess = function (http_status_codes) {
       
   622 	if (typeof http_status_codes === "string") {
       
   623 		http_status_codes = http_status_codes.replace(" ", "").split(",");
       
   624 	}
       
   625 	
       
   626 	this.settings.http_success = http_status_codes;
       
   627 	this.callFlash("SetHTTPSuccess", [http_status_codes]);
       
   628 };
       
   629 
       
   630 // Public: setHTTPSuccess changes the http_success setting
       
   631 SWFUpload.prototype.setAssumeSuccessTimeout = function (timeout_seconds) {
       
   632 	this.settings.assume_success_timeout = timeout_seconds;
       
   633 	this.callFlash("SetAssumeSuccessTimeout", [timeout_seconds]);
       
   634 };
       
   635 
       
   636 // Public: setDebugEnabled changes the debug_enabled setting
       
   637 SWFUpload.prototype.setDebugEnabled = function (debugEnabled) {
       
   638 	this.settings.debug_enabled = debugEnabled;
       
   639 	this.callFlash("SetDebugEnabled", [debugEnabled]);
       
   640 };
       
   641 
       
   642 // Public: setButtonImageURL loads a button image sprite
       
   643 SWFUpload.prototype.setButtonImageURL = function (buttonImageURL) {
       
   644 	if (buttonImageURL == undefined) {
       
   645 		buttonImageURL = "";
       
   646 	}
       
   647 	
       
   648 	this.settings.button_image_url = buttonImageURL;
       
   649 	this.callFlash("SetButtonImageURL", [buttonImageURL]);
       
   650 };
       
   651 
       
   652 // Public: setButtonDimensions resizes the Flash Movie and button
       
   653 SWFUpload.prototype.setButtonDimensions = function (width, height) {
       
   654 	this.settings.button_width = width;
       
   655 	this.settings.button_height = height;
       
   656 	
       
   657 	var movie = this.getMovieElement();
       
   658 	if (movie != undefined) {
       
   659 		movie.style.width = width + "px";
       
   660 		movie.style.height = height + "px";
       
   661 	}
       
   662 	
       
   663 	this.callFlash("SetButtonDimensions", [width, height]);
       
   664 };
       
   665 // Public: setButtonText Changes the text overlaid on the button
       
   666 SWFUpload.prototype.setButtonText = function (html) {
       
   667 	this.settings.button_text = html;
       
   668 	this.callFlash("SetButtonText", [html]);
       
   669 };
       
   670 // Public: setButtonTextPadding changes the top and left padding of the text overlay
       
   671 SWFUpload.prototype.setButtonTextPadding = function (left, top) {
       
   672 	this.settings.button_text_top_padding = top;
       
   673 	this.settings.button_text_left_padding = left;
       
   674 	this.callFlash("SetButtonTextPadding", [left, top]);
       
   675 };
       
   676 
       
   677 // Public: setButtonTextStyle changes the CSS used to style the HTML/Text overlaid on the button
       
   678 SWFUpload.prototype.setButtonTextStyle = function (css) {
       
   679 	this.settings.button_text_style = css;
       
   680 	this.callFlash("SetButtonTextStyle", [css]);
       
   681 };
       
   682 // Public: setButtonDisabled disables/enables the button
       
   683 SWFUpload.prototype.setButtonDisabled = function (isDisabled) {
       
   684 	this.settings.button_disabled = isDisabled;
       
   685 	this.callFlash("SetButtonDisabled", [isDisabled]);
       
   686 };
       
   687 // Public: setButtonAction sets the action that occurs when the button is clicked
       
   688 SWFUpload.prototype.setButtonAction = function (buttonAction) {
       
   689 	this.settings.button_action = buttonAction;
       
   690 	this.callFlash("SetButtonAction", [buttonAction]);
       
   691 };
       
   692 
       
   693 // Public: setButtonCursor changes the mouse cursor displayed when hovering over the button
       
   694 SWFUpload.prototype.setButtonCursor = function (cursor) {
       
   695 	this.settings.button_cursor = cursor;
       
   696 	this.callFlash("SetButtonCursor", [cursor]);
       
   697 };
       
   698 
       
   699 /* *******************************
       
   700 	Flash Event Interfaces
       
   701 	These functions are used by Flash to trigger the various
       
   702 	events.
       
   703 	
       
   704 	All these functions a Private.
       
   705 	
       
   706 	Because the ExternalInterface library is buggy the event calls
       
   707 	are added to a queue and the queue then executed by a setTimeout.
       
   708 	This ensures that events are executed in a determinate order and that
       
   709 	the ExternalInterface bugs are avoided.
       
   710 ******************************* */
       
   711 
       
   712 SWFUpload.prototype.queueEvent = function (handlerName, argumentArray) {
       
   713 	// Warning: Don't call this.debug inside here or you'll create an infinite loop
       
   714 	
       
   715 	if (argumentArray == undefined) {
       
   716 		argumentArray = [];
       
   717 	} else if (!(argumentArray instanceof Array)) {
       
   718 		argumentArray = [argumentArray];
       
   719 	}
       
   720 	
       
   721 	var self = this;
       
   722 	if (typeof this.settings[handlerName] === "function") {
       
   723 		// Queue the event
       
   724 		this.eventQueue.push(function () {
       
   725 			this.settings[handlerName].apply(this, argumentArray);
       
   726 		});
       
   727 		
       
   728 		// Execute the next queued event
       
   729 		setTimeout(function () {
       
   730 			self.executeNextEvent();
       
   731 		}, 0);
       
   732 		
       
   733 	} else if (this.settings[handlerName] !== null) {
       
   734 		throw "Event handler " + handlerName + " is unknown or is not a function";
       
   735 	}
       
   736 };
       
   737 
       
   738 // Private: Causes the next event in the queue to be executed.  Since events are queued using a setTimeout
       
   739 // we must queue them in order to garentee that they are executed in order.
       
   740 SWFUpload.prototype.executeNextEvent = function () {
       
   741 	// Warning: Don't call this.debug inside here or you'll create an infinite loop
       
   742 
       
   743 	var  f = this.eventQueue ? this.eventQueue.shift() : null;
       
   744 	if (typeof(f) === "function") {
       
   745 		f.apply(this);
       
   746 	}
       
   747 };
       
   748 
       
   749 // Private: unescapeFileParams is part of a workaround for a flash bug where objects passed through ExternalInterface cannot have
       
   750 // properties that contain characters that are not valid for JavaScript identifiers. To work around this
       
   751 // the Flash Component escapes the parameter names and we must unescape again before passing them along.
       
   752 SWFUpload.prototype.unescapeFilePostParams = function (file) {
       
   753 	var reg = /[$]([0-9a-f]{4})/i;
       
   754 	var unescapedPost = {};
       
   755 	var uk;
       
   756 
       
   757 	if (file != undefined) {
       
   758 		for (var k in file.post) {
       
   759 			if (file.post.hasOwnProperty(k)) {
       
   760 				uk = k;
       
   761 				var match;
       
   762 				while ((match = reg.exec(uk)) !== null) {
       
   763 					uk = uk.replace(match[0], String.fromCharCode(parseInt("0x" + match[1], 16)));
       
   764 				}
       
   765 				unescapedPost[uk] = file.post[k];
       
   766 			}
       
   767 		}
       
   768 
       
   769 		file.post = unescapedPost;
       
   770 	}
       
   771 
       
   772 	return file;
       
   773 };
       
   774 
       
   775 // Private: Called by Flash to see if JS can call in to Flash (test if External Interface is working)
       
   776 SWFUpload.prototype.testExternalInterface = function () {
       
   777 	try {
       
   778 		return this.callFlash("TestExternalInterface");
       
   779 	} catch (ex) {
       
   780 		return false;
       
   781 	}
       
   782 };
       
   783 
       
   784 // Private: This event is called by Flash when it has finished loading. Don't modify this.
       
   785 // Use the swfupload_loaded_handler event setting to execute custom code when SWFUpload has loaded.
       
   786 SWFUpload.prototype.flashReady = function () {
       
   787 	// Check that the movie element is loaded correctly with its ExternalInterface methods defined
       
   788 	var movieElement = this.getMovieElement();
       
   789 
       
   790 	if (!movieElement) {
       
   791 		this.debug("Flash called back ready but the flash movie can't be found.");
       
   792 		return;
       
   793 	}
       
   794 
       
   795 	this.cleanUp(movieElement);
       
   796 	
       
   797 	this.queueEvent("swfupload_loaded_handler");
       
   798 };
       
   799 
       
   800 // Private: removes Flash added fuctions to the DOM node to prevent memory leaks in IE.
       
   801 // This function is called by Flash each time the ExternalInterface functions are created.
       
   802 SWFUpload.prototype.cleanUp = function (movieElement) {
       
   803 	// Pro-actively unhook all the Flash functions
       
   804 	try {
       
   805 		if (this.movieElement && typeof(movieElement.CallFunction) === "unknown") { // We only want to do this in IE
       
   806 			this.debug("Removing Flash functions hooks (this should only run in IE and should prevent memory leaks)");
       
   807 			for (var key in movieElement) {
       
   808 				try {
       
   809 					if (typeof(movieElement[key]) === "function") {
       
   810 						movieElement[key] = null;
       
   811 					}
       
   812 				} catch (ex) {
       
   813 				}
       
   814 			}
       
   815 		}
       
   816 	} catch (ex1) {
       
   817 	
       
   818 	}
       
   819 
       
   820 	// Fix Flashes own cleanup code so if the SWFMovie was removed from the page
       
   821 	// it doesn't display errors.
       
   822 	window["__flash__removeCallback"] = function (instance, name) {
       
   823 		try {
       
   824 			if (instance) {
       
   825 				instance[name] = null;
       
   826 			}
       
   827 		} catch (flashEx) {
       
   828 		
       
   829 		}
       
   830 	};
       
   831 
       
   832 };
       
   833 
       
   834 
       
   835 /* This is a chance to do something before the browse window opens */
       
   836 SWFUpload.prototype.fileDialogStart = function () {
       
   837 	this.queueEvent("file_dialog_start_handler");
       
   838 };
       
   839 
       
   840 
       
   841 /* Called when a file is successfully added to the queue. */
       
   842 SWFUpload.prototype.fileQueued = function (file) {
       
   843 	file = this.unescapeFilePostParams(file);
       
   844 	this.queueEvent("file_queued_handler", file);
       
   845 };
       
   846 
       
   847 
       
   848 /* Handle errors that occur when an attempt to queue a file fails. */
       
   849 SWFUpload.prototype.fileQueueError = function (file, errorCode, message) {
       
   850 	file = this.unescapeFilePostParams(file);
       
   851 	this.queueEvent("file_queue_error_handler", [file, errorCode, message]);
       
   852 };
       
   853 
       
   854 /* Called after the file dialog has closed and the selected files have been queued.
       
   855 	You could call startUpload here if you want the queued files to begin uploading immediately. */
       
   856 SWFUpload.prototype.fileDialogComplete = function (numFilesSelected, numFilesQueued, numFilesInQueue) {
       
   857 	this.queueEvent("file_dialog_complete_handler", [numFilesSelected, numFilesQueued, numFilesInQueue]);
       
   858 };
       
   859 
       
   860 SWFUpload.prototype.uploadStart = function (file) {
       
   861 	file = this.unescapeFilePostParams(file);
       
   862 	this.queueEvent("return_upload_start_handler", file);
       
   863 };
       
   864 
       
   865 SWFUpload.prototype.returnUploadStart = function (file) {
       
   866 	var returnValue;
       
   867 	if (typeof this.settings.upload_start_handler === "function") {
       
   868 		file = this.unescapeFilePostParams(file);
       
   869 		returnValue = this.settings.upload_start_handler.call(this, file);
       
   870 	} else if (this.settings.upload_start_handler != undefined) {
       
   871 		throw "upload_start_handler must be a function";
       
   872 	}
       
   873 
       
   874 	// Convert undefined to true so if nothing is returned from the upload_start_handler it is
       
   875 	// interpretted as 'true'.
       
   876 	if (returnValue === undefined) {
       
   877 		returnValue = true;
       
   878 	}
       
   879 	
       
   880 	returnValue = !!returnValue;
       
   881 	
       
   882 	this.callFlash("ReturnUploadStart", [returnValue]);
       
   883 };
       
   884 
       
   885 
       
   886 
       
   887 SWFUpload.prototype.uploadProgress = function (file, bytesComplete, bytesTotal) {
       
   888 	file = this.unescapeFilePostParams(file);
       
   889 	this.queueEvent("upload_progress_handler", [file, bytesComplete, bytesTotal]);
       
   890 };
       
   891 
       
   892 SWFUpload.prototype.uploadError = function (file, errorCode, message) {
       
   893 	file = this.unescapeFilePostParams(file);
       
   894 	this.queueEvent("upload_error_handler", [file, errorCode, message]);
       
   895 };
       
   896 
       
   897 SWFUpload.prototype.uploadSuccess = function (file, serverData, responseReceived) {
       
   898 	file = this.unescapeFilePostParams(file);
       
   899 	this.queueEvent("upload_success_handler", [file, serverData, responseReceived]);
       
   900 };
       
   901 
       
   902 SWFUpload.prototype.uploadComplete = function (file) {
       
   903 	file = this.unescapeFilePostParams(file);
       
   904 	this.queueEvent("upload_complete_handler", file);
       
   905 };
       
   906 
       
   907 /* Called by SWFUpload JavaScript and Flash functions when debug is enabled. By default it writes messages to the
       
   908    internal debug console.  You can override this event and have messages written where you want. */
       
   909 SWFUpload.prototype.debug = function (message) {
       
   910 	this.queueEvent("debug_handler", message);
       
   911 };
       
   912 
       
   913 
       
   914 /* **********************************
       
   915 	Debug Console
       
   916 	The debug console is a self contained, in page location
       
   917 	for debug message to be sent.  The Debug Console adds
       
   918 	itself to the body if necessary.
       
   919 
       
   920 	The console is automatically scrolled as messages appear.
       
   921 	
       
   922 	If you are using your own debug handler or when you deploy to production and
       
   923 	have debug disabled you can remove these functions to reduce the file size
       
   924 	and complexity.
       
   925 ********************************** */
       
   926    
       
   927 // Private: debugMessage is the default debug_handler.  If you want to print debug messages
       
   928 // call the debug() function.  When overriding the function your own function should
       
   929 // check to see if the debug setting is true before outputting debug information.
       
   930 SWFUpload.prototype.debugMessage = function (message) {
       
   931 	if (this.settings.debug) {
       
   932 		var exceptionMessage, exceptionValues = [];
       
   933 
       
   934 		// Check for an exception object and print it nicely
       
   935 		if (typeof message === "object" && typeof message.name === "string" && typeof message.message === "string") {
       
   936 			for (var key in message) {
       
   937 				if (message.hasOwnProperty(key)) {
       
   938 					exceptionValues.push(key + ": " + message[key]);
       
   939 				}
       
   940 			}
       
   941 			exceptionMessage = exceptionValues.join("\n") || "";
       
   942 			exceptionValues = exceptionMessage.split("\n");
       
   943 			exceptionMessage = "EXCEPTION: " + exceptionValues.join("\nEXCEPTION: ");
       
   944 			SWFUpload.Console.writeLine(exceptionMessage);
       
   945 		} else {
       
   946 			SWFUpload.Console.writeLine(message);
       
   947 		}
       
   948 	}
       
   949 };
       
   950 
       
   951 SWFUpload.Console = {};
       
   952 SWFUpload.Console.writeLine = function (message) {
       
   953 	var console, documentForm;
       
   954 
       
   955 	try {
       
   956 		console = document.getElementById("SWFUpload_Console");
       
   957 
       
   958 		if (!console) {
       
   959 			documentForm = document.createElement("form");
       
   960 			document.getElementsByTagName("body")[0].appendChild(documentForm);
       
   961 
       
   962 			console = document.createElement("textarea");
       
   963 			console.id = "SWFUpload_Console";
       
   964 			console.style.fontFamily = "monospace";
       
   965 			console.setAttribute("wrap", "off");
       
   966 			console.wrap = "off";
       
   967 			console.style.overflow = "auto";
       
   968 			console.style.width = "700px";
       
   969 			console.style.height = "350px";
       
   970 			console.style.margin = "5px";
       
   971 			documentForm.appendChild(console);
       
   972 		}
       
   973 
       
   974 		console.value += message + "\n";
       
   975 
       
   976 		console.scrollTop = console.scrollHeight - console.clientHeight;
       
   977 	} catch (ex) {
       
   978 		alert("Exception: " + ex.name + " Message: " + ex.message);
       
   979 	}
       
   980 };