2 * SWFUpload: http://www.swfupload.org, http://swfupload.googlecode.com
4 * mmSWFUpload 1.0: Flash upload dialog - http://profandesign.se/swfupload/, http://www.vinterwebb.se/
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
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
15 /* ******************* */
16 /* Constructor & Init */
17 /* ******************* */
20 if (SWFUpload == undefined) {
21 SWFUpload = function (settings) {
22 this.initSWFUpload(settings);
26 SWFUpload.prototype.initSWFUpload = function (settings) {
28 this.customSettings = {}; // A container where developers can place their own settings associated with this instance.
29 this.settings = settings;
31 this.movieName = "SWFUpload_" + SWFUpload.movieCount++;
32 this.movieElement = null;
35 // Setup global control tracking
36 SWFUpload.instances[this.movieName] = this;
38 // Load the settings. Load the Flash movie.
41 this.displayDebugInfo();
43 delete SWFUpload.instances[this.movieName];
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
60 SWFUpload.UPLOAD_ERROR = {
62 MISSING_UPLOAD_URL : -210,
64 SECURITY_ERROR : -230,
65 UPLOAD_LIMIT_EXCEEDED : -240,
67 SPECIFIED_FILE_ID_NOT_FOUND : -260,
68 FILE_VALIDATION_FAILED : -270,
69 FILE_CANCELLED : -280,
72 SWFUpload.FILE_STATUS = {
79 SWFUpload.BUTTON_ACTION = {
88 SWFUpload.WINDOW_MODE = {
90 TRANSPARENT : "transparent",
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(/^\//)) {
101 var currentURL = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ":" + window.location.port : "");
103 var indexSlash = window.location.pathname.lastIndexOf("/");
104 if (indexSlash <= 0) {
107 path = window.location.pathname.substr(0, indexSlash) + "/";
110 return /*currentURL +*/ path + url;
115 /* ******************** */
116 /* Instance Members */
117 /* ******************** */
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];
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);
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);
144 this.ensureDefault("flash_url", "swfupload.swf");
145 this.ensureDefault("prevent_swf_caching", true);
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);
163 this.ensureDefault("debug", false);
164 this.settings.debug_enabled = this.settings.debug; // Here to maintain v2 API
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);
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);
180 this.ensureDefault("debug_handler", this.debugMessage);
182 this.ensureDefault("custom_settings", {});
185 this.customSettings = this.settings.custom_settings;
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();
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);
198 delete this.ensureDefault;
201 // Private: loadFlash replaces the button_placeholder element with the flash movie.
202 SWFUpload.prototype.loadFlash = function () {
203 var targetElement, tempParent;
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";
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;
213 if (targetElement == undefined) {
214 throw "Could not find the placeholder element: " + this.settings.button_placeholder_id;
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);
222 // Fix IE Flash/Form bug
223 if (window[this.movieName] == undefined) {
224 window[this.movieName] = this.getMovieElement();
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("");
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(",");
249 // Build the parameter string
250 return ["movieName=", encodeURIComponent(this.movieName),
251 "&uploadURL=", encodeURIComponent(this.settings.upload_url),
252 "&useQueryString=", encodeURIComponent(this.settings.use_query_string),
253 "&requeueOnError=", encodeURIComponent(this.settings.requeue_on_error),
254 "&httpSuccess=", encodeURIComponent(httpSuccessString),
255 "&assumeSuccessTimeout=", encodeURIComponent(this.settings.assume_success_timeout),
256 "&params=", encodeURIComponent(paramString),
257 "&filePostName=", encodeURIComponent(this.settings.file_post_name),
258 "&fileTypes=", encodeURIComponent(this.settings.file_types),
259 "&fileTypesDescription=", encodeURIComponent(this.settings.file_types_description),
260 "&fileSizeLimit=", encodeURIComponent(this.settings.file_size_limit),
261 "&fileUploadLimit=", encodeURIComponent(this.settings.file_upload_limit),
262 "&fileQueueLimit=", encodeURIComponent(this.settings.file_queue_limit),
263 "&debugEnabled=", encodeURIComponent(this.settings.debug_enabled),
264 "&buttonImageURL=", encodeURIComponent(this.settings.button_image_url),
265 "&buttonWidth=", encodeURIComponent(this.settings.button_width),
266 "&buttonHeight=", encodeURIComponent(this.settings.button_height),
267 "&buttonText=", encodeURIComponent(this.settings.button_text),
268 "&buttonTextTopPadding=", encodeURIComponent(this.settings.button_text_top_padding),
269 "&buttonTextLeftPadding=", encodeURIComponent(this.settings.button_text_left_padding),
270 "&buttonTextStyle=", encodeURIComponent(this.settings.button_text_style),
271 "&buttonAction=", encodeURIComponent(this.settings.button_action),
272 "&buttonDisabled=", encodeURIComponent(this.settings.button_disabled),
273 "&buttonCursor=", encodeURIComponent(this.settings.button_cursor)
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);
284 if (this.movieElement === null) {
285 throw "Could not find Flash element";
288 return this.movieElement;
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&name=value"
293 SWFUpload.prototype.buildParamString = function () {
294 var postParams = this.settings.post_params;
295 var paramStringPairs = [];
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()));
305 return paramStringPairs.join("&");
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 () {
314 // Make sure Flash is done before we try to remove it
315 this.cancelUpload(null, false);
318 // Remove the SWFUpload DOM nodes
319 var movieElement = null;
320 movieElement = this.getMovieElement();
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) {
326 if (typeof(movieElement[i]) === "function") {
327 movieElement[i] = null;
332 // Remove the Movie Element from the page
334 movieElement.parentNode.removeChild(movieElement);
338 // Remove IE form fix reference
339 window[this.movieName] = null;
341 // Destroy other references
342 SWFUpload.instances[this.movieName] = null;
343 delete SWFUpload.instances[this.movieName];
345 this.movieElement = null;
346 this.settings = null;
347 this.customSettings = null;
348 this.eventQueue = null;
349 this.movieName = null;
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 () {
366 "---SWFUpload Instance Info---\n",
367 "Version: ", SWFUpload.version, "\n",
368 "Movie Name: ", this.movieName, "\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",
385 "\t", "prevent_swf_caching: ", this.settings.prevent_swf_caching.toString(), "\n",
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",
399 "\t", "custom_settings: ", this.settings.custom_settings.toString(), "\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"
415 /* Note: addSetting and getSetting are no longer used by SWFUpload but are included
416 the maintain v2 API compatibility
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);
423 return (this.settings[name] = value);
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];
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 || [];
444 var movieElement = this.getMovieElement();
445 var returnValue, returnString;
447 // Flash's method if calling ExternalInterface methods (code adapted from MooTools).
449 returnString = movieElement.CallFunction('<invoke name="' + functionName + '" returntype="javascript">' + __flash__argumentsToXML(argumentArray, 0) + '</invoke>');
450 returnValue = eval(returnString);
452 throw "Call to " + functionName + " failed";
455 // Unescape file post param values
456 if (returnValue != undefined && typeof returnValue.post === "object") {
457 returnValue = this.unescapeFilePostParams(returnValue);
463 /* *****************************
464 -- Flash control methods --
465 Your UI should use these
467 ***************************** */
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");
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
482 SWFUpload.prototype.selectFiles = function () {
483 this.callFlash("SelectFiles");
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]);
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;
500 this.callFlash("CancelUpload", [fileID, triggerErrorEvent]);
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");
509 /* ************************
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
515 * *********************** */
517 // Public: getStats gets the file statistics object.
518 SWFUpload.prototype.getStats = function () {
519 return this.callFlash("GetStats");
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]);
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]);
536 return this.callFlash("GetFile", [fileID]);
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]);
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]);
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]);
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]);
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]);
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]);
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]);
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]);
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]);
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]);
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]);
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]);
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]);
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(",");
626 this.settings.http_success = http_status_codes;
627 this.callFlash("SetHTTPSuccess", [http_status_codes]);
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]);
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]);
642 // Public: setButtonImageURL loads a button image sprite
643 SWFUpload.prototype.setButtonImageURL = function (buttonImageURL) {
644 if (buttonImageURL == undefined) {
648 this.settings.button_image_url = buttonImageURL;
649 this.callFlash("SetButtonImageURL", [buttonImageURL]);
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;
657 var movie = this.getMovieElement();
658 if (movie != undefined) {
659 movie.style.width = width + "px";
660 movie.style.height = height + "px";
663 this.callFlash("SetButtonDimensions", [width, height]);
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]);
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]);
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]);
682 // Public: setButtonDisabled disables/enables the button
683 SWFUpload.prototype.setButtonDisabled = function (isDisabled) {
684 this.settings.button_disabled = isDisabled;
685 this.callFlash("SetButtonDisabled", [isDisabled]);
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]);
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]);
699 /* *******************************
700 Flash Event Interfaces
701 These functions are used by Flash to trigger the various
704 All these functions a Private.
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 ******************************* */
712 SWFUpload.prototype.queueEvent = function (handlerName, argumentArray) {
713 // Warning: Don't call this.debug inside here or you'll create an infinite loop
715 if (argumentArray == undefined) {
717 } else if (!(argumentArray instanceof Array)) {
718 argumentArray = [argumentArray];
722 if (typeof this.settings[handlerName] === "function") {
724 this.eventQueue.push(function () {
725 this.settings[handlerName].apply(this, argumentArray);
728 // Execute the next queued event
729 setTimeout(function () {
730 self.executeNextEvent();
733 } else if (this.settings[handlerName] !== null) {
734 throw "Event handler " + handlerName + " is unknown or is not a function";
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
743 var f = this.eventQueue ? this.eventQueue.shift() : null;
744 if (typeof(f) === "function") {
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 = {};
757 if (file != undefined) {
758 for (var k in file.post) {
759 if (file.post.hasOwnProperty(k)) {
762 while ((match = reg.exec(uk)) !== null) {
763 uk = uk.replace(match[0], String.fromCharCode(parseInt("0x" + match[1], 16)));
765 unescapedPost[uk] = file.post[k];
769 file.post = unescapedPost;
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 () {
778 return this.callFlash("TestExternalInterface");
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();
791 this.debug("Flash called back ready but the flash movie can't be found.");
795 this.cleanUp(movieElement);
797 this.queueEvent("swfupload_loaded_handler");
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
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) {
809 if (typeof(movieElement[key]) === "function") {
810 movieElement[key] = null;
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) {
825 instance[name] = null;
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");
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);
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]);
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]);
860 SWFUpload.prototype.uploadStart = function (file) {
861 file = this.unescapeFilePostParams(file);
862 this.queueEvent("return_upload_start_handler", file);
865 SWFUpload.prototype.returnUploadStart = function (file) {
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";
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) {
880 returnValue = !!returnValue;
882 this.callFlash("ReturnUploadStart", [returnValue]);
887 SWFUpload.prototype.uploadProgress = function (file, bytesComplete, bytesTotal) {
888 file = this.unescapeFilePostParams(file);
889 this.queueEvent("upload_progress_handler", [file, bytesComplete, bytesTotal]);
892 SWFUpload.prototype.uploadError = function (file, errorCode, message) {
893 file = this.unescapeFilePostParams(file);
894 this.queueEvent("upload_error_handler", [file, errorCode, message]);
897 SWFUpload.prototype.uploadSuccess = function (file, serverData, responseReceived) {
898 file = this.unescapeFilePostParams(file);
899 this.queueEvent("upload_success_handler", [file, serverData, responseReceived]);
902 SWFUpload.prototype.uploadComplete = function (file) {
903 file = this.unescapeFilePostParams(file);
904 this.queueEvent("upload_complete_handler", file);
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);
914 /* **********************************
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.
920 The console is automatically scrolled as messages appear.
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
925 ********************************** */
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 = [];
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]);
941 exceptionMessage = exceptionValues.join("\n") || "";
942 exceptionValues = exceptionMessage.split("\n");
943 exceptionMessage = "EXCEPTION: " + exceptionValues.join("\nEXCEPTION: ");
944 SWFUpload.Console.writeLine(exceptionMessage);
946 SWFUpload.Console.writeLine(message);
951 SWFUpload.Console = {};
952 SWFUpload.Console.writeLine = function (message) {
953 var console, documentForm;
956 console = document.getElementById("SWFUpload_Console");
959 documentForm = document.createElement("form");
960 document.getElementsByTagName("body")[0].appendChild(documentForm);
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);
974 console.value += message + "\n";
976 console.scrollTop = console.scrollHeight - console.clientHeight;
978 alert("Exception: " + ex.name + " Message: " + ex.message);