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;
34 // Setup global control tracking
35 SWFUpload.instances[this.movieName] = this;
37 // Load the settings. Load the Flash movie.
40 this.displayDebugInfo();
42 delete SWFUpload.instances[this.movieName];
50 SWFUpload.instances = {};
51 SWFUpload.movieCount = 0;
52 SWFUpload.version = "2.2.0 Beta 2";
53 SWFUpload.QUEUE_ERROR = {
54 QUEUE_LIMIT_EXCEEDED : -100,
55 FILE_EXCEEDS_SIZE_LIMIT : -110,
56 ZERO_BYTE_FILE : -120,
57 INVALID_FILETYPE : -130
59 SWFUpload.UPLOAD_ERROR = {
61 MISSING_UPLOAD_URL : -210,
63 SECURITY_ERROR : -230,
64 UPLOAD_LIMIT_EXCEEDED : -240,
66 SPECIFIED_FILE_ID_NOT_FOUND : -260,
67 FILE_VALIDATION_FAILED : -270,
68 FILE_CANCELLED : -280,
71 SWFUpload.FILE_STATUS = {
78 SWFUpload.BUTTON_ACTION = {
87 SWFUpload.WINDOW_MODE = {
89 TRANSPARENT : "transparent",
93 /* ******************** */
94 /* Instance Members */
95 /* ******************** */
97 // Private: initSettings ensures that all the
98 // settings are set, getting a default value if one was not assigned.
99 SWFUpload.prototype.initSettings = function () {
100 this.ensureDefault = function (settingName, defaultValue) {
101 this.settings[settingName] = (this.settings[settingName] == undefined) ? defaultValue : this.settings[settingName];
104 // Upload backend settings
105 this.ensureDefault("upload_url", "");
106 this.ensureDefault("file_post_name", "Filedata");
107 this.ensureDefault("post_params", {});
108 this.ensureDefault("use_query_string", false);
109 this.ensureDefault("requeue_on_error", false);
110 this.ensureDefault("http_success", []);
113 this.ensureDefault("file_types", "*.*");
114 this.ensureDefault("file_types_description", "All Files");
115 this.ensureDefault("file_size_limit", 0); // Default zero means "unlimited"
116 this.ensureDefault("file_upload_limit", 0);
117 this.ensureDefault("file_queue_limit", 0);
120 this.ensureDefault("flash_url", "swfupload.swf");
121 this.ensureDefault("prevent_swf_caching", true);
124 this.ensureDefault("button_image_url", "");
125 this.ensureDefault("button_width", 1);
126 this.ensureDefault("button_height", 1);
127 this.ensureDefault("button_text", "");
128 this.ensureDefault("button_text_style", "color: #000000; font-size: 16pt;");
129 this.ensureDefault("button_text_top_padding", 0);
130 this.ensureDefault("button_text_left_padding", 0);
131 this.ensureDefault("button_action", SWFUpload.BUTTON_ACTION.SELECT_FILES);
132 this.ensureDefault("button_disabled", false);
133 this.ensureDefault("button_placeholder_id", null);
134 this.ensureDefault("button_cursor", SWFUpload.CURSOR.ARROW);
135 this.ensureDefault("button_window_mode", SWFUpload.WINDOW_MODE.WINDOW);
138 this.ensureDefault("debug", false);
139 this.settings.debug_enabled = this.settings.debug; // Here to maintain v2 API
142 this.settings.return_upload_start_handler = this.returnUploadStart;
143 this.ensureDefault("swfupload_loaded_handler", null);
144 this.ensureDefault("file_dialog_start_handler", null);
145 this.ensureDefault("file_queued_handler", null);
146 this.ensureDefault("file_queue_error_handler", null);
147 this.ensureDefault("file_dialog_complete_handler", null);
149 this.ensureDefault("upload_start_handler", null);
150 this.ensureDefault("upload_progress_handler", null);
151 this.ensureDefault("upload_error_handler", null);
152 this.ensureDefault("upload_success_handler", null);
153 this.ensureDefault("upload_complete_handler", null);
155 this.ensureDefault("debug_handler", this.debugMessage);
157 this.ensureDefault("custom_settings", {});
160 this.customSettings = this.settings.custom_settings;
162 // Update the flash url if needed
163 if (this.settings.prevent_swf_caching) {
164 this.settings.flash_url = this.settings.flash_url + "?swfuploadrnd=" + Math.floor(Math.random() * 999999999);
167 delete this.ensureDefault;
170 SWFUpload.prototype.loadFlash = function () {
171 if (this.settings.button_placeholder_id !== "") {
172 this.replaceWithFlash();
178 // Private: appendFlash gets the HTML tag for the Flash
179 // It then appends the flash to the body
180 SWFUpload.prototype.appendFlash = function () {
181 var targetElement, container;
183 // Make sure an element with the ID we are going to use doesn't already exist
184 if (document.getElementById(this.movieName) !== null) {
185 throw "ID " + this.movieName + " is already in use. The Flash Object could not be added";
188 // Get the body tag where we will be adding the flash movie
189 targetElement = document.getElementsByTagName("body")[0];
191 if (targetElement == undefined) {
192 throw "Could not find the 'body' element.";
195 // Append the container and load the flash
196 container = document.createElement("div");
197 container.style.width = "1px";
198 container.style.height = "1px";
199 container.style.overflow = "hidden";
201 targetElement.appendChild(container);
202 container.innerHTML = this.getFlashHTML(); // Using innerHTML is non-standard but the only sensible way to dynamically add Flash in IE (and maybe other browsers)
205 // Private: replaceWithFlash replaces the button_placeholder element with the flash movie.
206 SWFUpload.prototype.replaceWithFlash = function () {
207 var targetElement, tempParent;
209 // Make sure an element with the ID we are going to use doesn't already exist
210 if (document.getElementById(this.movieName) !== null) {
211 throw "ID " + this.movieName + " is already in use. The Flash Object could not be added";
214 // Get the element where we will be placing the flash movie
215 targetElement = document.getElementById(this.settings.button_placeholder_id);
217 if (targetElement == undefined) {
218 throw "Could not find the placeholder element.";
221 // Append the container and load the flash
222 tempParent = document.createElement("div");
223 tempParent.innerHTML = this.getFlashHTML(); // Using innerHTML is non-standard but the only sensible way to dynamically add Flash in IE (and maybe other browsers)
224 targetElement.parentNode.replaceChild(tempParent.firstChild, targetElement);
228 // Private: getFlashHTML generates the object tag needed to embed the flash in to the document
229 SWFUpload.prototype.getFlashHTML = function () {
230 // Flash Satay object syntax: http://www.alistapart.com/articles/flashsatay
231 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">',
232 '<param name="wmode" value="', this.settings.button_window_mode , '" />',
233 '<param name="movie" value="', this.settings.flash_url, '" />',
234 '<param name="quality" value="high" />',
235 '<param name="menu" value="false" />',
236 '<param name="allowScriptAccess" value="always" />',
237 '<param name="flashvars" value="' + this.getFlashVars() + '" />',
238 '</object>'].join("");
241 // Private: getFlashVars builds the parameter string that will be passed
242 // to flash in the flashvars param.
243 SWFUpload.prototype.getFlashVars = function () {
244 // Build a string from the post param object
245 var paramString = this.buildParamString();
246 var httpSuccessString = this.settings.http_success.join(",");
248 // Build the parameter string
249 return ["movieName=", encodeURIComponent(this.movieName),
250 "&uploadURL=", encodeURIComponent(this.settings.upload_url),
251 "&useQueryString=", encodeURIComponent(this.settings.use_query_string),
252 "&requeueOnError=", encodeURIComponent(this.settings.requeue_on_error),
253 "&httpSuccess=", encodeURIComponent(httpSuccessString),
254 "&params=", encodeURIComponent(paramString),
255 "&filePostName=", encodeURIComponent(this.settings.file_post_name),
256 "&fileTypes=", encodeURIComponent(this.settings.file_types),
257 "&fileTypesDescription=", encodeURIComponent(this.settings.file_types_description),
258 "&fileSizeLimit=", encodeURIComponent(this.settings.file_size_limit),
259 "&fileUploadLimit=", encodeURIComponent(this.settings.file_upload_limit),
260 "&fileQueueLimit=", encodeURIComponent(this.settings.file_queue_limit),
261 "&debugEnabled=", encodeURIComponent(this.settings.debug_enabled),
262 "&buttonImageURL=", encodeURIComponent(this.settings.button_image_url),
263 "&buttonWidth=", encodeURIComponent(this.settings.button_width),
264 "&buttonHeight=", encodeURIComponent(this.settings.button_height),
265 "&buttonText=", encodeURIComponent(this.settings.button_text),
266 "&buttonTextTopPadding=", encodeURIComponent(this.settings.button_text_top_padding),
267 "&buttonTextLeftPadding=", encodeURIComponent(this.settings.button_text_left_padding),
268 "&buttonTextStyle=", encodeURIComponent(this.settings.button_text_style),
269 "&buttonAction=", encodeURIComponent(this.settings.button_action),
270 "&buttonDisabled=", encodeURIComponent(this.settings.button_disabled),
271 "&buttonCursor=", encodeURIComponent(this.settings.button_cursor)
275 // Public: getMovieElement retrieves the DOM reference to the Flash element added by SWFUpload
276 // The element is cached after the first lookup
277 SWFUpload.prototype.getMovieElement = function () {
278 if (this.movieElement == undefined) {
279 this.movieElement = document.getElementById(this.movieName);
282 if (this.movieElement === null) {
283 throw "Could not find Flash element";
286 return this.movieElement;
289 // Private: buildParamString takes the name/value pairs in the post_params setting object
290 // and joins them up in to a string formatted "name=value&name=value"
291 SWFUpload.prototype.buildParamString = function () {
292 var postParams = this.settings.post_params;
293 var paramStringPairs = [];
295 if (typeof(postParams) === "object") {
296 for (var name in postParams) {
297 if (postParams.hasOwnProperty(name)) {
298 paramStringPairs.push(encodeURIComponent(name.toString()) + "=" + encodeURIComponent(postParams[name].toString()));
303 return paramStringPairs.join("&");
306 // Public: Used to remove a SWFUpload instance from the page. This method strives to remove
307 // all references to the SWF, and other objects so memory is properly freed.
308 // Returns true if everything was destroyed. Returns a false if a failure occurs leaving SWFUpload in an inconsistant state.
309 SWFUpload.prototype.destroy = function () {
311 // Make sure Flash is done before we try to remove it
314 // Remove the SWFUpload DOM nodes
315 var movieElement = null;
317 movieElement = this.getMovieElement();
321 if (movieElement != undefined && movieElement.parentNode != undefined && typeof movieElement.parentNode.removeChild === "function") {
322 var container = movieElement.parentNode;
323 if (container != undefined) {
324 container.removeChild(movieElement);
325 if (container.parentNode != undefined && typeof container.parentNode.removeChild === "function") {
326 container.parentNode.removeChild(container);
331 // Destroy references
332 SWFUpload.instances[this.movieName] = null;
333 delete SWFUpload.instances[this.movieName];
335 delete this.movieElement;
336 delete this.settings;
337 delete this.customSettings;
338 delete this.eventQueue;
339 delete this.movieName;
341 delete window[this.movieName];
349 // Public: displayDebugInfo prints out settings and configuration
350 // information about this SWFUpload instance.
351 // This function (and any references to it) can be deleted when placing
352 // SWFUpload in production.
353 SWFUpload.prototype.displayDebugInfo = function () {
356 "---SWFUpload Instance Info---\n",
357 "Version: ", SWFUpload.version, "\n",
358 "Movie Name: ", this.movieName, "\n",
360 "\t", "upload_url: ", this.settings.upload_url, "\n",
361 "\t", "flash_url: ", this.settings.flash_url, "\n",
362 "\t", "use_query_string: ", this.settings.use_query_string.toString(), "\n",
363 "\t", "requeue_on_error: ", this.settings.requeue_on_error.toString(), "\n",
364 "\t", "http_success: ", this.settings.http_success.join(", "), "\n",
365 "\t", "file_post_name: ", this.settings.file_post_name, "\n",
366 "\t", "post_params: ", this.settings.post_params.toString(), "\n",
367 "\t", "file_types: ", this.settings.file_types, "\n",
368 "\t", "file_types_description: ", this.settings.file_types_description, "\n",
369 "\t", "file_size_limit: ", this.settings.file_size_limit, "\n",
370 "\t", "file_upload_limit: ", this.settings.file_upload_limit, "\n",
371 "\t", "file_queue_limit: ", this.settings.file_queue_limit, "\n",
372 "\t", "debug: ", this.settings.debug.toString(), "\n",
374 "\t", "prevent_swf_caching: ", this.settings.prevent_swf_caching.toString(), "\n",
376 "\t", "button_placeholder_id: ", this.settings.button_placeholder_id.toString(), "\n",
377 "\t", "button_image_url: ", this.settings.button_image_url.toString(), "\n",
378 "\t", "button_width: ", this.settings.button_width.toString(), "\n",
379 "\t", "button_height: ", this.settings.button_height.toString(), "\n",
380 "\t", "button_text: ", this.settings.button_text.toString(), "\n",
381 "\t", "button_text_style: ", this.settings.button_text_style.toString(), "\n",
382 "\t", "button_text_top_padding: ", this.settings.button_text_top_padding.toString(), "\n",
383 "\t", "button_text_left_padding: ", this.settings.button_text_left_padding.toString(), "\n",
384 "\t", "button_action: ", this.settings.button_action.toString(), "\n",
385 "\t", "button_disabled: ", this.settings.button_disabled.toString(), "\n",
387 "\t", "custom_settings: ", this.settings.custom_settings.toString(), "\n",
389 "\t", "swfupload_loaded_handler assigned: ", (typeof this.settings.swfupload_loaded_handler === "function").toString(), "\n",
390 "\t", "file_dialog_start_handler assigned: ", (typeof this.settings.file_dialog_start_handler === "function").toString(), "\n",
391 "\t", "file_queued_handler assigned: ", (typeof this.settings.file_queued_handler === "function").toString(), "\n",
392 "\t", "file_queue_error_handler assigned: ", (typeof this.settings.file_queue_error_handler === "function").toString(), "\n",
393 "\t", "upload_start_handler assigned: ", (typeof this.settings.upload_start_handler === "function").toString(), "\n",
394 "\t", "upload_progress_handler assigned: ", (typeof this.settings.upload_progress_handler === "function").toString(), "\n",
395 "\t", "upload_error_handler assigned: ", (typeof this.settings.upload_error_handler === "function").toString(), "\n",
396 "\t", "upload_success_handler assigned: ", (typeof this.settings.upload_success_handler === "function").toString(), "\n",
397 "\t", "upload_complete_handler assigned: ", (typeof this.settings.upload_complete_handler === "function").toString(), "\n",
398 "\t", "debug_handler assigned: ", (typeof this.settings.debug_handler === "function").toString(), "\n"
403 /* Note: addSetting and getSetting are no longer used by SWFUpload but are included
404 the maintain v2 API compatibility
406 // Public: (Deprecated) addSetting adds a setting value. If the value given is undefined or null then the default_value is used.
407 SWFUpload.prototype.addSetting = function (name, value, default_value) {
408 if (value == undefined) {
409 return (this.settings[name] = default_value);
411 return (this.settings[name] = value);
415 // Public: (Deprecated) getSetting gets a setting. Returns an empty string if the setting was not found.
416 SWFUpload.prototype.getSetting = function (name) {
417 if (this.settings[name] != undefined) {
418 return this.settings[name];
426 // Private: callFlash handles function calls made to the Flash element.
427 // Calls are made with a setTimeout for some functions to work around
428 // bugs in the ExternalInterface library.
429 SWFUpload.prototype.callFlash = function (functionName, argumentArray) {
430 argumentArray = argumentArray || [];
432 var movieElement = this.getMovieElement();
435 if (typeof movieElement[functionName] === "function") {
436 // 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.
437 if (argumentArray.length === 0) {
438 returnValue = movieElement[functionName]();
439 } else if (argumentArray.length === 1) {
440 returnValue = movieElement[functionName](argumentArray[0]);
441 } else if (argumentArray.length === 2) {
442 returnValue = movieElement[functionName](argumentArray[0], argumentArray[1]);
443 } else if (argumentArray.length === 3) {
444 returnValue = movieElement[functionName](argumentArray[0], argumentArray[1], argumentArray[2]);
446 throw "Too many arguments";
449 // Unescape file post param values
450 if (returnValue != undefined && typeof returnValue.post === "object") {
451 returnValue = this.unescapeFilePostParams(returnValue);
456 throw "Invalid function name: " + functionName;
461 /* *****************************
462 -- Flash control methods --
463 Your UI should use these
465 ***************************** */
467 // Public: selectFile causes a File Selection Dialog window to appear. This
468 // dialog only allows 1 file to be selected. WARNING: this function does not work in Flash Player 10
469 SWFUpload.prototype.selectFile = function () {
470 this.callFlash("SelectFile");
473 // Public: selectFiles causes a File Selection Dialog window to appear/ This
474 // dialog allows the user to select any number of files
475 // Flash Bug Warning: Flash limits the number of selectable files based on the combined length of the file names.
476 // If the selection name length is too long the dialog will fail in an unpredictable manner. There is no work-around
477 // for this bug. WARNING: this function does not work in Flash Player 10
478 SWFUpload.prototype.selectFiles = function () {
479 this.callFlash("SelectFiles");
483 // Public: startUpload starts uploading the first file in the queue unless
484 // the optional parameter 'fileID' specifies the ID
485 SWFUpload.prototype.startUpload = function (fileID) {
486 this.callFlash("StartUpload", [fileID]);
489 // Public: cancelUpload cancels any queued file. The fileID parameter may be the file ID or index.
490 // If you do not specify a fileID the current uploading file or first file in the queue is cancelled.
491 // If you do not want the uploadError event to trigger you can specify false for the triggerErrorEvent parameter.
492 SWFUpload.prototype.cancelUpload = function (fileID, triggerErrorEvent) {
493 if (triggerErrorEvent !== false) {
494 triggerErrorEvent = true;
496 this.callFlash("CancelUpload", [fileID, triggerErrorEvent]);
499 // Public: stopUpload stops the current upload and requeues the file at the beginning of the queue.
500 // If nothing is currently uploading then nothing happens.
501 SWFUpload.prototype.stopUpload = function () {
502 this.callFlash("StopUpload");
505 /* ************************
507 * These methods change the SWFUpload settings.
508 * SWFUpload settings should not be changed directly on the settings object
509 * since many of the settings need to be passed to Flash in order to take
511 * *********************** */
513 // Public: getStats gets the file statistics object.
514 SWFUpload.prototype.getStats = function () {
515 return this.callFlash("GetStats");
518 // Public: setStats changes the SWFUpload statistics. You shouldn't need to
519 // change the statistics but you can. Changing the statistics does not
520 // affect SWFUpload accept for the successful_uploads count which is used
521 // by the upload_limit setting to determine how many files the user may upload.
522 SWFUpload.prototype.setStats = function (statsObject) {
523 this.callFlash("SetStats", [statsObject]);
526 // Public: getFile retrieves a File object by ID or Index. If the file is
527 // not found then 'null' is returned.
528 SWFUpload.prototype.getFile = function (fileID) {
529 if (typeof(fileID) === "number") {
530 return this.callFlash("GetFileByIndex", [fileID]);
532 return this.callFlash("GetFile", [fileID]);
536 // Public: addFileParam sets a name/value pair that will be posted with the
537 // file specified by the Files ID. If the name already exists then the
538 // exiting value will be overwritten.
539 SWFUpload.prototype.addFileParam = function (fileID, name, value) {
540 return this.callFlash("AddFileParam", [fileID, name, value]);
543 // Public: removeFileParam removes a previously set (by addFileParam) name/value
544 // pair from the specified file.
545 SWFUpload.prototype.removeFileParam = function (fileID, name) {
546 this.callFlash("RemoveFileParam", [fileID, name]);
549 // Public: setUploadUrl changes the upload_url setting.
550 SWFUpload.prototype.setUploadURL = function (url) {
551 this.settings.upload_url = url.toString();
552 this.callFlash("SetUploadURL", [url]);
555 // Public: setPostParams changes the post_params setting
556 SWFUpload.prototype.setPostParams = function (paramsObject) {
557 this.settings.post_params = paramsObject;
558 this.callFlash("SetPostParams", [paramsObject]);
561 // Public: addPostParam adds post name/value pair. Each name can have only one value.
562 SWFUpload.prototype.addPostParam = function (name, value) {
563 this.settings.post_params[name] = value;
564 this.callFlash("SetPostParams", [this.settings.post_params]);
567 // Public: removePostParam deletes post name/value pair.
568 SWFUpload.prototype.removePostParam = function (name) {
569 delete this.settings.post_params[name];
570 this.callFlash("SetPostParams", [this.settings.post_params]);
573 // Public: setFileTypes changes the file_types setting and the file_types_description setting
574 SWFUpload.prototype.setFileTypes = function (types, description) {
575 this.settings.file_types = types;
576 this.settings.file_types_description = description;
577 this.callFlash("SetFileTypes", [types, description]);
580 // Public: setFileSizeLimit changes the file_size_limit setting
581 SWFUpload.prototype.setFileSizeLimit = function (fileSizeLimit) {
582 this.settings.file_size_limit = fileSizeLimit;
583 this.callFlash("SetFileSizeLimit", [fileSizeLimit]);
586 // Public: setFileUploadLimit changes the file_upload_limit setting
587 SWFUpload.prototype.setFileUploadLimit = function (fileUploadLimit) {
588 this.settings.file_upload_limit = fileUploadLimit;
589 this.callFlash("SetFileUploadLimit", [fileUploadLimit]);
592 // Public: setFileQueueLimit changes the file_queue_limit setting
593 SWFUpload.prototype.setFileQueueLimit = function (fileQueueLimit) {
594 this.settings.file_queue_limit = fileQueueLimit;
595 this.callFlash("SetFileQueueLimit", [fileQueueLimit]);
598 // Public: setFilePostName changes the file_post_name setting
599 SWFUpload.prototype.setFilePostName = function (filePostName) {
600 this.settings.file_post_name = filePostName;
601 this.callFlash("SetFilePostName", [filePostName]);
604 // Public: setUseQueryString changes the use_query_string setting
605 SWFUpload.prototype.setUseQueryString = function (useQueryString) {
606 this.settings.use_query_string = useQueryString;
607 this.callFlash("SetUseQueryString", [useQueryString]);
610 // Public: setRequeueOnError changes the requeue_on_error setting
611 SWFUpload.prototype.setRequeueOnError = function (requeueOnError) {
612 this.settings.requeue_on_error = requeueOnError;
613 this.callFlash("SetRequeueOnError", [requeueOnError]);
616 // Public: setHTTPSuccess changes the http_success setting
617 SWFUpload.prototype.setHTTPSuccess = function (http_status_codes) {
618 if (typeof http_status_codes === "string") {
619 http_status_codes = http_status_codes.replace(" ", "").split(",");
622 this.settings.http_success = http_status_codes;
623 this.callFlash("SetHTTPSuccess", [http_status_codes]);
627 // Public: setDebugEnabled changes the debug_enabled setting
628 SWFUpload.prototype.setDebugEnabled = function (debugEnabled) {
629 this.settings.debug_enabled = debugEnabled;
630 this.callFlash("SetDebugEnabled", [debugEnabled]);
633 // Public: setButtonImageURL loads a button image sprite
634 SWFUpload.prototype.setButtonImageURL = function (buttonImageURL) {
635 if (buttonImageURL == undefined) {
639 this.settings.button_image_url = buttonImageURL;
640 this.callFlash("SetButtonImageURL", [buttonImageURL]);
643 // Public: setButtonDimensions resizes the Flash Movie and button
644 SWFUpload.prototype.setButtonDimensions = function (width, height) {
645 this.settings.button_width = width;
646 this.settings.button_height = height;
648 var movie = this.getMovieElement();
649 if (movie != undefined) {
650 movie.style.width = width + "px";
651 movie.style.height = height + "px";
654 this.callFlash("SetButtonDimensions", [width, height]);
656 // Public: setButtonText Changes the text overlaid on the button
657 SWFUpload.prototype.setButtonText = function (html) {
658 this.settings.button_text = html;
659 this.callFlash("SetButtonText", [html]);
661 // Public: setButtonTextPadding changes the top and left padding of the text overlay
662 SWFUpload.prototype.setButtonTextPadding = function (left, top) {
663 this.settings.button_text_top_padding = top;
664 this.settings.button_text_left_padding = left;
665 this.callFlash("SetButtonTextPadding", [left, top]);
668 // Public: setButtonTextStyle changes the CSS used to style the HTML/Text overlaid on the button
669 SWFUpload.prototype.setButtonTextStyle = function (css) {
670 this.settings.button_text_style = css;
671 this.callFlash("SetButtonTextStyle", [css]);
673 // Public: setButtonDisabled disables/enables the button
674 SWFUpload.prototype.setButtonDisabled = function (isDisabled) {
675 this.settings.button_disabled = isDisabled;
676 this.callFlash("SetButtonDisabled", [isDisabled]);
678 // Public: setButtonAction sets the action that occurs when the button is clicked
679 SWFUpload.prototype.setButtonAction = function (buttonAction) {
680 this.settings.button_action = buttonAction;
681 this.callFlash("SetButtonAction", [buttonAction]);
684 // Public: setButtonCursor changes the mouse cursor displayed when hovering over the button
685 SWFUpload.prototype.setButtonCursor = function (cursor) {
686 this.settings.button_cursor = cursor;
687 this.callFlash("SetButtonCursor", [cursor]);
690 /* *******************************
691 Flash Event Interfaces
692 These functions are used by Flash to trigger the various
695 All these functions a Private.
697 Because the ExternalInterface library is buggy the event calls
698 are added to a queue and the queue then executed by a setTimeout.
699 This ensures that events are executed in a determinate order and that
700 the ExternalInterface bugs are avoided.
701 ******************************* */
703 SWFUpload.prototype.queueEvent = function (handlerName, argumentArray) {
704 // Warning: Don't call this.debug inside here or you'll create an infinite loop
706 if (argumentArray == undefined) {
708 } else if (!(argumentArray instanceof Array)) {
709 argumentArray = [argumentArray];
713 if (typeof this.settings[handlerName] === "function") {
715 this.eventQueue.push(function () {
716 this.settings[handlerName].apply(this, argumentArray);
719 // Execute the next queued event
720 setTimeout(function () {
721 self.executeNextEvent();
724 } else if (this.settings[handlerName] !== null) {
725 throw "Event handler " + handlerName + " is unknown or is not a function";
729 // Private: Causes the next event in the queue to be executed. Since events are queued using a setTimeout
730 // we must queue them in order to garentee that they are executed in order.
731 SWFUpload.prototype.executeNextEvent = function () {
732 // Warning: Don't call this.debug inside here or you'll create an infinite loop
734 var f = this.eventQueue ? this.eventQueue.shift() : null;
735 if (typeof(f) === "function") {
740 // Private: unescapeFileParams is part of a workaround for a flash bug where objects passed through ExternalInterface cannot have
741 // properties that contain characters that are not valid for JavaScript identifiers. To work around this
742 // the Flash Component escapes the parameter names and we must unescape again before passing them along.
743 SWFUpload.prototype.unescapeFilePostParams = function (file) {
744 var reg = /[$]([0-9a-f]{4})/i;
745 var unescapedPost = {};
748 if (file != undefined) {
749 for (var k in file.post) {
750 if (file.post.hasOwnProperty(k)) {
753 while ((match = reg.exec(uk)) !== null) {
754 uk = uk.replace(match[0], String.fromCharCode(parseInt("0x" + match[1], 16)));
756 unescapedPost[uk] = file.post[k];
760 file.post = unescapedPost;
766 SWFUpload.prototype.flashReady = function () {
767 // Check that the movie element is loaded correctly with its ExternalInterface methods defined
768 var movieElement = this.getMovieElement();
769 if (typeof movieElement.StartUpload !== "function") {
770 throw "ExternalInterface methods failed to initialize.";
773 // Fix IE Flash/Form bug
774 if (window[this.movieName] == undefined) {
775 window[this.movieName] = movieElement;
778 this.queueEvent("swfupload_loaded_handler");
782 /* This is a chance to do something before the browse window opens */
783 SWFUpload.prototype.fileDialogStart = function () {
784 this.queueEvent("file_dialog_start_handler");
788 /* Called when a file is successfully added to the queue. */
789 SWFUpload.prototype.fileQueued = function (file) {
790 file = this.unescapeFilePostParams(file);
791 this.queueEvent("file_queued_handler", file);
795 /* Handle errors that occur when an attempt to queue a file fails. */
796 SWFUpload.prototype.fileQueueError = function (file, errorCode, message) {
797 file = this.unescapeFilePostParams(file);
798 this.queueEvent("file_queue_error_handler", [file, errorCode, message]);
801 /* Called after the file dialog has closed and the selected files have been queued.
802 You could call startUpload here if you want the queued files to begin uploading immediately. */
803 SWFUpload.prototype.fileDialogComplete = function (numFilesSelected, numFilesQueued) {
804 this.queueEvent("file_dialog_complete_handler", [numFilesSelected, numFilesQueued]);
807 SWFUpload.prototype.uploadStart = function (file) {
808 file = this.unescapeFilePostParams(file);
809 this.queueEvent("return_upload_start_handler", file);
812 SWFUpload.prototype.returnUploadStart = function (file) {
814 if (typeof this.settings.upload_start_handler === "function") {
815 file = this.unescapeFilePostParams(file);
816 returnValue = this.settings.upload_start_handler.call(this, file);
817 } else if (this.settings.upload_start_handler != undefined) {
818 throw "upload_start_handler must be a function";
821 // Convert undefined to true so if nothing is returned from the upload_start_handler it is
822 // interpretted as 'true'.
823 if (returnValue === undefined) {
827 returnValue = !!returnValue;
829 this.callFlash("ReturnUploadStart", [returnValue]);
834 SWFUpload.prototype.uploadProgress = function (file, bytesComplete, bytesTotal) {
835 file = this.unescapeFilePostParams(file);
836 this.queueEvent("upload_progress_handler", [file, bytesComplete, bytesTotal]);
839 SWFUpload.prototype.uploadError = function (file, errorCode, message) {
840 file = this.unescapeFilePostParams(file);
841 this.queueEvent("upload_error_handler", [file, errorCode, message]);
844 SWFUpload.prototype.uploadSuccess = function (file, serverData) {
845 file = this.unescapeFilePostParams(file);
846 this.queueEvent("upload_success_handler", [file, serverData]);
849 SWFUpload.prototype.uploadComplete = function (file) {
850 file = this.unescapeFilePostParams(file);
851 this.queueEvent("upload_complete_handler", file);
854 /* Called by SWFUpload JavaScript and Flash functions when debug is enabled. By default it writes messages to the
855 internal debug console. You can override this event and have messages written where you want. */
856 SWFUpload.prototype.debug = function (message) {
857 this.queueEvent("debug_handler", message);
861 /* **********************************
863 The debug console is a self contained, in page location
864 for debug message to be sent. The Debug Console adds
865 itself to the body if necessary.
867 The console is automatically scrolled as messages appear.
869 If you are using your own debug handler or when you deploy to production and
870 have debug disabled you can remove these functions to reduce the file size
872 ********************************** */
874 // Private: debugMessage is the default debug_handler. If you want to print debug messages
875 // call the debug() function. When overriding the function your own function should
876 // check to see if the debug setting is true before outputting debug information.
877 SWFUpload.prototype.debugMessage = function (message) {
878 if (this.settings.debug) {
879 var exceptionMessage, exceptionValues = [];
881 // Check for an exception object and print it nicely
882 if (typeof message === "object" && typeof message.name === "string" && typeof message.message === "string") {
883 for (var key in message) {
884 if (message.hasOwnProperty(key)) {
885 exceptionValues.push(key + ": " + message[key]);
888 exceptionMessage = exceptionValues.join("\n") || "";
889 exceptionValues = exceptionMessage.split("\n");
890 exceptionMessage = "EXCEPTION: " + exceptionValues.join("\nEXCEPTION: ");
891 SWFUpload.Console.writeLine(exceptionMessage);
893 SWFUpload.Console.writeLine(message);
898 SWFUpload.Console = {};
899 SWFUpload.Console.writeLine = function (message) {
900 var console, documentForm;
903 console = document.getElementById("SWFUpload_Console");
906 documentForm = document.createElement("form");
907 document.getElementsByTagName("body")[0].appendChild(documentForm);
909 console = document.createElement("textarea");
910 console.id = "SWFUpload_Console";
911 console.style.fontFamily = "monospace";
912 console.setAttribute("wrap", "off");
913 console.wrap = "off";
914 console.style.overflow = "auto";
915 console.style.width = "700px";
916 console.style.height = "350px";
917 console.style.margin = "5px";
918 documentForm.appendChild(console);
921 console.value += message + "\n";
923 console.scrollTop = console.scrollHeight - console.clientHeight;
925 alert("Exception: " + ex.name + " Message: " + ex.message);