]> scripts.mit.edu Git - autoinstalls/wordpress.git/blob - wp-includes/js/swfupload/swfupload.js
Wordpress 2.7.1
[autoinstalls/wordpress.git] / wp-includes / js / swfupload / swfupload.js
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                 // Setup global control tracking
35                 SWFUpload.instances[this.movieName] = this;
36
37                 // Load the settings.  Load the Flash movie.
38                 this.initSettings();
39                 this.loadFlash();
40                 this.displayDebugInfo();
41         } catch (ex) {
42                 delete SWFUpload.instances[this.movieName];
43                 throw ex;
44         }
45 };
46
47 /* *************** */
48 /* Static Members  */
49 /* *************** */
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
58 };
59 SWFUpload.UPLOAD_ERROR = {
60         HTTP_ERROR                                              : -200,
61         MISSING_UPLOAD_URL                      : -210,
62         IO_ERROR                                                : -220,
63         SECURITY_ERROR                                  : -230,
64         UPLOAD_LIMIT_EXCEEDED                   : -240,
65         UPLOAD_FAILED                                   : -250,
66         SPECIFIED_FILE_ID_NOT_FOUND             : -260,
67         FILE_VALIDATION_FAILED                  : -270,
68         FILE_CANCELLED                                  : -280,
69         UPLOAD_STOPPED                                  : -290
70 };
71 SWFUpload.FILE_STATUS = {
72         QUEUED           : -1,
73         IN_PROGRESS      : -2,
74         ERROR            : -3,
75         COMPLETE         : -4,
76         CANCELLED        : -5
77 };
78 SWFUpload.BUTTON_ACTION = {
79         SELECT_FILE  : -100,
80         SELECT_FILES : -110,
81         START_UPLOAD : -120
82 };
83 SWFUpload.CURSOR = {
84         ARROW : -1,
85         HAND : -2
86 };
87 SWFUpload.WINDOW_MODE = {
88         WINDOW : "window",
89         TRANSPARENT : "transparent",
90         OPAQUE : "opaque"
91 };
92
93 /* ******************** */
94 /* Instance Members  */
95 /* ******************** */
96
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];
102         };
103         
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", []);
111         
112         // File Settings
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);
118
119         // Flash Settings
120         this.ensureDefault("flash_url", "swfupload.swf");
121         this.ensureDefault("prevent_swf_caching", true);
122         
123         // Button Settings
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);
136         
137         // Debug Settings
138         this.ensureDefault("debug", false);
139         this.settings.debug_enabled = this.settings.debug;      // Here to maintain v2 API
140         
141         // Event Handlers
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);
148         
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);
154         
155         this.ensureDefault("debug_handler", this.debugMessage);
156
157         this.ensureDefault("custom_settings", {});
158
159         // Other settings
160         this.customSettings = this.settings.custom_settings;
161         
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);
165         }
166         
167         delete this.ensureDefault;
168 };
169
170 SWFUpload.prototype.loadFlash = function () {
171         if (this.settings.button_placeholder_id !== "") {
172                 this.replaceWithFlash();
173         } else {
174                 this.appendFlash();
175         }
176 };
177
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;
182
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";
186         }
187
188         // Get the body tag where we will be adding the flash movie
189         targetElement = document.getElementsByTagName("body")[0];
190
191         if (targetElement == undefined) {
192                 throw "Could not find the 'body' element.";
193         }
194
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";
200
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)
203 };
204
205 // Private: replaceWithFlash replaces the button_placeholder element with the flash movie.
206 SWFUpload.prototype.replaceWithFlash = function () {
207         var targetElement, tempParent;
208
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";
212         }
213
214         // Get the element where we will be placing the flash movie
215         targetElement = document.getElementById(this.settings.button_placeholder_id);
216
217         if (targetElement == undefined) {
218                 throw "Could not find the placeholder element.";
219         }
220
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);
225
226 };
227
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("");
239 };
240
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(",");
247         
248         // Build the parameter string
249         return ["movieName=", encodeURIComponent(this.movieName),
250                         "&amp;uploadURL=", encodeURIComponent(this.settings.upload_url),
251                         "&amp;useQueryString=", encodeURIComponent(this.settings.use_query_string),
252                         "&amp;requeueOnError=", encodeURIComponent(this.settings.requeue_on_error),
253                         "&amp;httpSuccess=", encodeURIComponent(httpSuccessString),
254                         "&amp;params=", encodeURIComponent(paramString),
255                         "&amp;filePostName=", encodeURIComponent(this.settings.file_post_name),
256                         "&amp;fileTypes=", encodeURIComponent(this.settings.file_types),
257                         "&amp;fileTypesDescription=", encodeURIComponent(this.settings.file_types_description),
258                         "&amp;fileSizeLimit=", encodeURIComponent(this.settings.file_size_limit),
259                         "&amp;fileUploadLimit=", encodeURIComponent(this.settings.file_upload_limit),
260                         "&amp;fileQueueLimit=", encodeURIComponent(this.settings.file_queue_limit),
261                         "&amp;debugEnabled=", encodeURIComponent(this.settings.debug_enabled),
262                         "&amp;buttonImageURL=", encodeURIComponent(this.settings.button_image_url),
263                         "&amp;buttonWidth=", encodeURIComponent(this.settings.button_width),
264                         "&amp;buttonHeight=", encodeURIComponent(this.settings.button_height),
265                         "&amp;buttonText=", encodeURIComponent(this.settings.button_text),
266                         "&amp;buttonTextTopPadding=", encodeURIComponent(this.settings.button_text_top_padding),
267                         "&amp;buttonTextLeftPadding=", encodeURIComponent(this.settings.button_text_left_padding),
268                         "&amp;buttonTextStyle=", encodeURIComponent(this.settings.button_text_style),
269                         "&amp;buttonAction=", encodeURIComponent(this.settings.button_action),
270                         "&amp;buttonDisabled=", encodeURIComponent(this.settings.button_disabled),
271                         "&amp;buttonCursor=", encodeURIComponent(this.settings.button_cursor)
272                 ].join("");
273 };
274
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);
280         }
281
282         if (this.movieElement === null) {
283                 throw "Could not find Flash element";
284         }
285         
286         return this.movieElement;
287 };
288
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&amp;name=value"
291 SWFUpload.prototype.buildParamString = function () {
292         var postParams = this.settings.post_params; 
293         var paramStringPairs = [];
294
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()));
299                         }
300                 }
301         }
302
303         return paramStringPairs.join("&amp;");
304 };
305
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 () {
310         try {
311                 // Make sure Flash is done before we try to remove it
312                 this.stopUpload();
313                 
314                 // Remove the SWFUpload DOM nodes
315                 var movieElement = null;
316                 try {
317                         movieElement = this.getMovieElement();
318                 } catch (ex) {
319                 }
320                 
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);
327                                 }
328                         }
329                 }
330                 
331                 // Destroy references
332                 SWFUpload.instances[this.movieName] = null;
333                 delete SWFUpload.instances[this.movieName];
334
335                 delete this.movieElement;
336                 delete this.settings;
337                 delete this.customSettings;
338                 delete this.eventQueue;
339                 delete this.movieName;
340                 
341                 delete window[this.movieName];
342                 
343                 return true;
344         } catch (ex1) {
345                 return false;
346         }
347 };
348
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 () {
354         this.debug(
355                 [
356                         "---SWFUpload Instance Info---\n",
357                         "Version: ", SWFUpload.version, "\n",
358                         "Movie Name: ", this.movieName, "\n",
359                         "Settings:\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",
373
374                         "\t", "prevent_swf_caching:      ", this.settings.prevent_swf_caching.toString(), "\n",
375
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",
386
387                         "\t", "custom_settings:          ", this.settings.custom_settings.toString(), "\n",
388                         "Event Handlers:\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"
399                 ].join("")
400         );
401 };
402
403 /* Note: addSetting and getSetting are no longer used by SWFUpload but are included
404         the maintain v2 API compatibility
405 */
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);
410     } else {
411         return (this.settings[name] = value);
412         }
413 };
414
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];
419         }
420
421     return "";
422 };
423
424
425
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 || [];
431         
432         var movieElement = this.getMovieElement();
433         var returnValue;
434
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]);
445                 } else {
446                         throw "Too many arguments";
447                 }
448                 
449                 // Unescape file post param values
450                 if (returnValue != undefined && typeof returnValue.post === "object") {
451                         returnValue = this.unescapeFilePostParams(returnValue);
452                 }
453                 
454                 return returnValue;
455         } else {
456                 throw "Invalid function name: " + functionName;
457         }
458 };
459
460
461 /* *****************************
462         -- Flash control methods --
463         Your UI should use these
464         to operate SWFUpload
465    ***************************** */
466
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");
471 };
472
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");
480 };
481
482
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]);
487 };
488
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;
495         }
496         this.callFlash("CancelUpload", [fileID, triggerErrorEvent]);
497 };
498
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");
503 };
504
505 /* ************************
506  * Settings methods
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
510  *   effect.
511  * *********************** */
512
513 // Public: getStats gets the file statistics object.
514 SWFUpload.prototype.getStats = function () {
515         return this.callFlash("GetStats");
516 };
517
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]);
524 };
525
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]);
531         } else {
532                 return this.callFlash("GetFile", [fileID]);
533         }
534 };
535
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]);
541 };
542
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]);
547 };
548
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]);
553 };
554
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]);
559 };
560
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]);
565 };
566
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]);
571 };
572
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]);
578 };
579
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]);
584 };
585
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]);
590 };
591
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]);
596 };
597
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]);
602 };
603
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]);
608 };
609
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]);
614 };
615
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(",");
620         }
621         
622         this.settings.http_success = http_status_codes;
623         this.callFlash("SetHTTPSuccess", [http_status_codes]);
624 };
625
626
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]);
631 };
632
633 // Public: setButtonImageURL loads a button image sprite
634 SWFUpload.prototype.setButtonImageURL = function (buttonImageURL) {
635         if (buttonImageURL == undefined) {
636                 buttonImageURL = "";
637         }
638         
639         this.settings.button_image_url = buttonImageURL;
640         this.callFlash("SetButtonImageURL", [buttonImageURL]);
641 };
642
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;
647         
648         var movie = this.getMovieElement();
649         if (movie != undefined) {
650                 movie.style.width = width + "px";
651                 movie.style.height = height + "px";
652         }
653         
654         this.callFlash("SetButtonDimensions", [width, height]);
655 };
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]);
660 };
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]);
666 };
667
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]);
672 };
673 // Public: setButtonDisabled disables/enables the button
674 SWFUpload.prototype.setButtonDisabled = function (isDisabled) {
675         this.settings.button_disabled = isDisabled;
676         this.callFlash("SetButtonDisabled", [isDisabled]);
677 };
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]);
682 };
683
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]);
688 };
689
690 /* *******************************
691         Flash Event Interfaces
692         These functions are used by Flash to trigger the various
693         events.
694         
695         All these functions a Private.
696         
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 ******************************* */
702
703 SWFUpload.prototype.queueEvent = function (handlerName, argumentArray) {
704         // Warning: Don't call this.debug inside here or you'll create an infinite loop
705         
706         if (argumentArray == undefined) {
707                 argumentArray = [];
708         } else if (!(argumentArray instanceof Array)) {
709                 argumentArray = [argumentArray];
710         }
711         
712         var self = this;
713         if (typeof this.settings[handlerName] === "function") {
714                 // Queue the event
715                 this.eventQueue.push(function () {
716                         this.settings[handlerName].apply(this, argumentArray);
717                 });
718                 
719                 // Execute the next queued event
720                 setTimeout(function () {
721                         self.executeNextEvent();
722                 }, 0);
723                 
724         } else if (this.settings[handlerName] !== null) {
725                 throw "Event handler " + handlerName + " is unknown or is not a function";
726         }
727 };
728
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
733
734         var  f = this.eventQueue ? this.eventQueue.shift() : null;
735         if (typeof(f) === "function") {
736                 f.apply(this);
737         }
738 };
739
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 = {};
746         var uk;
747
748         if (file != undefined) {
749                 for (var k in file.post) {
750                         if (file.post.hasOwnProperty(k)) {
751                                 uk = k;
752                                 var match;
753                                 while ((match = reg.exec(uk)) !== null) {
754                                         uk = uk.replace(match[0], String.fromCharCode(parseInt("0x" + match[1], 16)));
755                                 }
756                                 unescapedPost[uk] = file.post[k];
757                         }
758                 }
759
760                 file.post = unescapedPost;
761         }
762
763         return file;
764 };
765
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.";
771         }
772
773         // Fix IE Flash/Form bug
774         if (window[this.movieName] == undefined) {
775                 window[this.movieName] = movieElement;
776         }
777         
778         this.queueEvent("swfupload_loaded_handler");
779 };
780
781
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");
785 };
786
787
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);
792 };
793
794
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]);
799 };
800
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]);
805 };
806
807 SWFUpload.prototype.uploadStart = function (file) {
808         file = this.unescapeFilePostParams(file);
809         this.queueEvent("return_upload_start_handler", file);
810 };
811
812 SWFUpload.prototype.returnUploadStart = function (file) {
813         var returnValue;
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";
819         }
820
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) {
824                 returnValue = true;
825         }
826         
827         returnValue = !!returnValue;
828         
829         this.callFlash("ReturnUploadStart", [returnValue]);
830 };
831
832
833
834 SWFUpload.prototype.uploadProgress = function (file, bytesComplete, bytesTotal) {
835         file = this.unescapeFilePostParams(file);
836         this.queueEvent("upload_progress_handler", [file, bytesComplete, bytesTotal]);
837 };
838
839 SWFUpload.prototype.uploadError = function (file, errorCode, message) {
840         file = this.unescapeFilePostParams(file);
841         this.queueEvent("upload_error_handler", [file, errorCode, message]);
842 };
843
844 SWFUpload.prototype.uploadSuccess = function (file, serverData) {
845         file = this.unescapeFilePostParams(file);
846         this.queueEvent("upload_success_handler", [file, serverData]);
847 };
848
849 SWFUpload.prototype.uploadComplete = function (file) {
850         file = this.unescapeFilePostParams(file);
851         this.queueEvent("upload_complete_handler", file);
852 };
853
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);
858 };
859
860
861 /* **********************************
862         Debug Console
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.
866
867         The console is automatically scrolled as messages appear.
868         
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
871         and complexity.
872 ********************************** */
873    
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 = [];
880
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]);
886                                 }
887                         }
888                         exceptionMessage = exceptionValues.join("\n") || "";
889                         exceptionValues = exceptionMessage.split("\n");
890                         exceptionMessage = "EXCEPTION: " + exceptionValues.join("\nEXCEPTION: ");
891                         SWFUpload.Console.writeLine(exceptionMessage);
892                 } else {
893                         SWFUpload.Console.writeLine(message);
894                 }
895         }
896 };
897
898 SWFUpload.Console = {};
899 SWFUpload.Console.writeLine = function (message) {
900         var console, documentForm;
901
902         try {
903                 console = document.getElementById("SWFUpload_Console");
904
905                 if (!console) {
906                         documentForm = document.createElement("form");
907                         document.getElementsByTagName("body")[0].appendChild(documentForm);
908
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);
919                 }
920
921                 console.value += message + "\n";
922
923                 console.scrollTop = console.scrollHeight - console.clientHeight;
924         } catch (ex) {
925                 alert("Exception: " + ex.name + " Message: " + ex.message);
926         }
927 };