3 * Copyright(c) 2006-2010 Ext JS, LLC
5 * http://www.extjs.com/license
8 * SWFUpload: http://www.swfupload.org, http://swfupload.googlecode.com
\r
10 * mmSWFUpload 1.0: Flash upload dialog - http://profandesign.se/swfupload/, http://www.vinterwebb.se/
\r
12 * SWFUpload is (c) 2006-2007 Lars Huring, Olov Nilz�n and Mammon Media and is released under the MIT License:
\r
13 * http://www.opensource.org/licenses/mit-license.php
\r
15 * SWFUpload 2 is (c) 2007-2008 Jake Roberts and is released under the MIT License:
\r
16 * http://www.opensource.org/licenses/mit-license.php
\r
21 /* ******************* */
\r
22 /* Constructor & Init */
\r
23 /* ******************* */
\r
26 if (SWFUpload == undefined) {
\r
27 SWFUpload = function (settings) {
\r
28 this.initSWFUpload(settings);
\r
32 SWFUpload.prototype.initSWFUpload = function (settings) {
\r
34 this.customSettings = {}; // A container where developers can place their own settings associated with this instance.
\r
35 this.settings = settings;
\r
36 this.eventQueue = [];
\r
37 this.movieName = "SWFUpload_" + SWFUpload.movieCount++;
\r
38 this.movieElement = null;
\r
41 // Setup global control tracking
\r
42 SWFUpload.instances[this.movieName] = this;
\r
44 // Load the settings. Load the Flash movie.
\r
45 this.initSettings();
\r
47 this.displayDebugInfo();
\r
49 delete SWFUpload.instances[this.movieName];
\r
54 /* *************** */
\r
55 /* Static Members */
\r
56 /* *************** */
\r
57 SWFUpload.instances = {};
\r
58 SWFUpload.movieCount = 0;
\r
59 SWFUpload.version = "2.2.0 2009-03-25";
\r
60 SWFUpload.QUEUE_ERROR = {
\r
61 QUEUE_LIMIT_EXCEEDED : -100,
\r
62 FILE_EXCEEDS_SIZE_LIMIT : -110,
\r
63 ZERO_BYTE_FILE : -120,
\r
64 INVALID_FILETYPE : -130
\r
66 SWFUpload.UPLOAD_ERROR = {
\r
68 MISSING_UPLOAD_URL : -210,
\r
70 SECURITY_ERROR : -230,
\r
71 UPLOAD_LIMIT_EXCEEDED : -240,
\r
72 UPLOAD_FAILED : -250,
\r
73 SPECIFIED_FILE_ID_NOT_FOUND : -260,
\r
74 FILE_VALIDATION_FAILED : -270,
\r
75 FILE_CANCELLED : -280,
\r
76 UPLOAD_STOPPED : -290
\r
78 SWFUpload.FILE_STATUS = {
\r
85 SWFUpload.BUTTON_ACTION = {
\r
87 SELECT_FILES : -110,
\r
90 SWFUpload.CURSOR = {
\r
94 SWFUpload.WINDOW_MODE = {
\r
96 TRANSPARENT : "transparent",
\r
100 // Private: takes a URL, determines if it is relative and converts to an absolute URL
\r
101 // using the current site. Only processes the URL if it can, otherwise returns the URL untouched
\r
102 SWFUpload.completeURL = function(url) {
\r
103 if (typeof(url) !== "string" || url.match(/^https?:\/\//i) || url.match(/^\//)) {
\r
107 var currentURL = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ":" + window.location.port : "");
\r
109 var indexSlash = window.location.pathname.lastIndexOf("/");
\r
110 if (indexSlash <= 0) {
\r
113 path = window.location.pathname.substr(0, indexSlash) + "/";
\r
116 return /*currentURL +*/ path + url;
\r
121 /* ******************** */
\r
122 /* Instance Members */
\r
123 /* ******************** */
\r
125 // Private: initSettings ensures that all the
\r
126 // settings are set, getting a default value if one was not assigned.
\r
127 SWFUpload.prototype.initSettings = function () {
\r
128 this.ensureDefault = function (settingName, defaultValue) {
\r
129 this.settings[settingName] = (this.settings[settingName] == undefined) ? defaultValue : this.settings[settingName];
\r
132 // Upload backend settings
\r
133 this.ensureDefault("upload_url", "");
\r
134 this.ensureDefault("preserve_relative_urls", false);
\r
135 this.ensureDefault("file_post_name", "Filedata");
\r
136 this.ensureDefault("post_params", {});
\r
137 this.ensureDefault("use_query_string", false);
\r
138 this.ensureDefault("requeue_on_error", false);
\r
139 this.ensureDefault("http_success", []);
\r
140 this.ensureDefault("assume_success_timeout", 0);
\r
143 this.ensureDefault("file_types", "*.*");
\r
144 this.ensureDefault("file_types_description", "All Files");
\r
145 this.ensureDefault("file_size_limit", 0); // Default zero means "unlimited"
\r
146 this.ensureDefault("file_upload_limit", 0);
\r
147 this.ensureDefault("file_queue_limit", 0);
\r
150 this.ensureDefault("flash_url", "swfupload.swf");
\r
151 this.ensureDefault("prevent_swf_caching", true);
\r
154 this.ensureDefault("button_image_url", "");
\r
155 this.ensureDefault("button_width", 1);
\r
156 this.ensureDefault("button_height", 1);
\r
157 this.ensureDefault("button_text", "");
\r
158 this.ensureDefault("button_text_style", "color: #000000; font-size: 16pt;");
\r
159 this.ensureDefault("button_text_top_padding", 0);
\r
160 this.ensureDefault("button_text_left_padding", 0);
\r
161 this.ensureDefault("button_action", SWFUpload.BUTTON_ACTION.SELECT_FILES);
\r
162 this.ensureDefault("button_disabled", false);
\r
163 this.ensureDefault("button_placeholder_id", "");
\r
164 this.ensureDefault("button_placeholder", null);
\r
165 this.ensureDefault("button_cursor", SWFUpload.CURSOR.ARROW);
\r
166 this.ensureDefault("button_window_mode", SWFUpload.WINDOW_MODE.WINDOW);
\r
169 this.ensureDefault("debug", false);
\r
170 this.settings.debug_enabled = this.settings.debug; // Here to maintain v2 API
\r
173 this.settings.return_upload_start_handler = this.returnUploadStart;
\r
174 this.ensureDefault("swfupload_loaded_handler", null);
\r
175 this.ensureDefault("file_dialog_start_handler", null);
\r
176 this.ensureDefault("file_queued_handler", null);
\r
177 this.ensureDefault("file_queue_error_handler", null);
\r
178 this.ensureDefault("file_dialog_complete_handler", null);
\r
180 this.ensureDefault("upload_start_handler", null);
\r
181 this.ensureDefault("upload_progress_handler", null);
\r
182 this.ensureDefault("upload_error_handler", null);
\r
183 this.ensureDefault("upload_success_handler", null);
\r
184 this.ensureDefault("upload_complete_handler", null);
\r
186 this.ensureDefault("debug_handler", this.debugMessage);
\r
188 this.ensureDefault("custom_settings", {});
\r
191 this.customSettings = this.settings.custom_settings;
\r
193 // Update the flash url if needed
\r
194 if (!!this.settings.prevent_swf_caching) {
\r
195 this.settings.flash_url = this.settings.flash_url + (this.settings.flash_url.indexOf("?") < 0 ? "?" : "&") + "preventswfcaching=" + new Date().getTime();
\r
198 if (!this.settings.preserve_relative_urls) {
\r
199 //this.settings.flash_url = SWFUpload.completeURL(this.settings.flash_url); // Don't need to do this one since flash doesn't look at it
\r
200 this.settings.upload_url = SWFUpload.completeURL(this.settings.upload_url);
\r
201 this.settings.button_image_url = SWFUpload.completeURL(this.settings.button_image_url);
\r
204 delete this.ensureDefault;
\r
207 // Private: loadFlash replaces the button_placeholder element with the flash movie.
\r
208 SWFUpload.prototype.loadFlash = function () {
\r
209 var targetElement, tempParent;
\r
211 // Make sure an element with the ID we are going to use doesn't already exist
\r
212 if (document.getElementById(this.movieName) !== null) {
\r
213 throw "ID " + this.movieName + " is already in use. The Flash Object could not be added";
\r
216 // Get the element where we will be placing the flash movie
\r
217 targetElement = document.getElementById(this.settings.button_placeholder_id) || this.settings.button_placeholder;
\r
219 if (targetElement == undefined) {
\r
220 throw "Could not find the placeholder element: " + this.settings.button_placeholder_id;
\r
223 // Append the container and load the flash
\r
224 tempParent = document.createElement("div");
\r
225 tempParent.innerHTML = this.getFlashHTML(); // Using innerHTML is non-standard but the only sensible way to dynamically add Flash in IE (and maybe other browsers)
\r
226 targetElement.parentNode.replaceChild(tempParent.firstChild, targetElement);
\r
228 // Fix IE Flash/Form bug
\r
229 if (window[this.movieName] == undefined) {
\r
230 window[this.movieName] = this.getMovieElement();
\r
235 // Private: getFlashHTML generates the object tag needed to embed the flash in to the document
\r
236 SWFUpload.prototype.getFlashHTML = function () {
\r
237 // Flash Satay object syntax: http://www.alistapart.com/articles/flashsatay
\r
238 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">',
\r
239 '<param name="wmode" value="', this.settings.button_window_mode, '" />',
\r
240 '<param name="movie" value="', this.settings.flash_url, '" />',
\r
241 '<param name="quality" value="high" />',
\r
242 '<param name="menu" value="false" />',
\r
243 '<param name="allowScriptAccess" value="always" />',
\r
244 '<param name="flashvars" value="' + this.getFlashVars() + '" />',
\r
245 '</object>'].join("");
\r
248 // Private: getFlashVars builds the parameter string that will be passed
\r
249 // to flash in the flashvars param.
\r
250 SWFUpload.prototype.getFlashVars = function () {
\r
251 // Build a string from the post param object
\r
252 var paramString = this.buildParamString();
\r
253 var httpSuccessString = this.settings.http_success.join(",");
\r
255 // Build the parameter string
\r
256 return ["movieName=", encodeURIComponent(this.movieName),
\r
257 "&uploadURL=", encodeURIComponent(this.settings.upload_url),
\r
258 "&useQueryString=", encodeURIComponent(this.settings.use_query_string),
\r
259 "&requeueOnError=", encodeURIComponent(this.settings.requeue_on_error),
\r
260 "&httpSuccess=", encodeURIComponent(httpSuccessString),
\r
261 "&assumeSuccessTimeout=", encodeURIComponent(this.settings.assume_success_timeout),
\r
262 "&params=", encodeURIComponent(paramString),
\r
263 "&filePostName=", encodeURIComponent(this.settings.file_post_name),
\r
264 "&fileTypes=", encodeURIComponent(this.settings.file_types),
\r
265 "&fileTypesDescription=", encodeURIComponent(this.settings.file_types_description),
\r
266 "&fileSizeLimit=", encodeURIComponent(this.settings.file_size_limit),
\r
267 "&fileUploadLimit=", encodeURIComponent(this.settings.file_upload_limit),
\r
268 "&fileQueueLimit=", encodeURIComponent(this.settings.file_queue_limit),
\r
269 "&debugEnabled=", encodeURIComponent(this.settings.debug_enabled),
\r
270 "&buttonImageURL=", encodeURIComponent(this.settings.button_image_url),
\r
271 "&buttonWidth=", encodeURIComponent(this.settings.button_width),
\r
272 "&buttonHeight=", encodeURIComponent(this.settings.button_height),
\r
273 "&buttonText=", encodeURIComponent(this.settings.button_text),
\r
274 "&buttonTextTopPadding=", encodeURIComponent(this.settings.button_text_top_padding),
\r
275 "&buttonTextLeftPadding=", encodeURIComponent(this.settings.button_text_left_padding),
\r
276 "&buttonTextStyle=", encodeURIComponent(this.settings.button_text_style),
\r
277 "&buttonAction=", encodeURIComponent(this.settings.button_action),
\r
278 "&buttonDisabled=", encodeURIComponent(this.settings.button_disabled),
\r
279 "&buttonCursor=", encodeURIComponent(this.settings.button_cursor)
\r
283 // Public: getMovieElement retrieves the DOM reference to the Flash element added by SWFUpload
\r
284 // The element is cached after the first lookup
\r
285 SWFUpload.prototype.getMovieElement = function () {
\r
286 if (this.movieElement == undefined) {
\r
287 this.movieElement = document.getElementById(this.movieName);
\r
290 if (this.movieElement === null) {
\r
291 throw "Could not find Flash element";
\r
294 return this.movieElement;
\r
297 // Private: buildParamString takes the name/value pairs in the post_params setting object
\r
298 // and joins them up in to a string formatted "name=value&name=value"
\r
299 SWFUpload.prototype.buildParamString = function () {
\r
300 var postParams = this.settings.post_params;
\r
301 var paramStringPairs = [];
\r
303 if (typeof(postParams) === "object") {
\r
304 for (var name in postParams) {
\r
305 if (postParams.hasOwnProperty(name)) {
\r
306 paramStringPairs.push(encodeURIComponent(name.toString()) + "=" + encodeURIComponent(postParams[name].toString()));
\r
311 return paramStringPairs.join("&");
\r
314 // Public: Used to remove a SWFUpload instance from the page. This method strives to remove
\r
315 // all references to the SWF, and other objects so memory is properly freed.
\r
316 // Returns true if everything was destroyed. Returns a false if a failure occurs leaving SWFUpload in an inconsistant state.
\r
317 // Credits: Major improvements provided by steffen
\r
318 SWFUpload.prototype.destroy = function () {
\r
320 // Make sure Flash is done before we try to remove it
\r
321 this.cancelUpload(null, false);
\r
324 // Remove the SWFUpload DOM nodes
\r
325 var movieElement = null;
\r
326 movieElement = this.getMovieElement();
\r
328 if (movieElement && typeof(movieElement.CallFunction) === "unknown") { // We only want to do this in IE
\r
329 // Loop through all the movie's properties and remove all function references (DOM/JS IE 6/7 memory leak workaround)
\r
330 for (var i in movieElement) {
\r
332 if (typeof(movieElement[i]) === "function") {
\r
333 movieElement[i] = null;
\r
338 // Remove the Movie Element from the page
\r
340 movieElement.parentNode.removeChild(movieElement);
\r
344 // Remove IE form fix reference
\r
345 window[this.movieName] = null;
\r
347 // Destroy other references
\r
348 SWFUpload.instances[this.movieName] = null;
\r
349 delete SWFUpload.instances[this.movieName];
\r
351 this.movieElement = null;
\r
352 this.settings = null;
\r
353 this.customSettings = null;
\r
354 this.eventQueue = null;
\r
355 this.movieName = null;
\r
365 // Public: displayDebugInfo prints out settings and configuration
\r
366 // information about this SWFUpload instance.
\r
367 // This function (and any references to it) can be deleted when placing
\r
368 // SWFUpload in production.
\r
369 SWFUpload.prototype.displayDebugInfo = function () {
\r
372 "---SWFUpload Instance Info---\n",
\r
373 "Version: ", SWFUpload.version, "\n",
\r
374 "Movie Name: ", this.movieName, "\n",
\r
376 "\t", "upload_url: ", this.settings.upload_url, "\n",
\r
377 "\t", "flash_url: ", this.settings.flash_url, "\n",
\r
378 "\t", "use_query_string: ", this.settings.use_query_string.toString(), "\n",
\r
379 "\t", "requeue_on_error: ", this.settings.requeue_on_error.toString(), "\n",
\r
380 "\t", "http_success: ", this.settings.http_success.join(", "), "\n",
\r
381 "\t", "assume_success_timeout: ", this.settings.assume_success_timeout, "\n",
\r
382 "\t", "file_post_name: ", this.settings.file_post_name, "\n",
\r
383 "\t", "post_params: ", this.settings.post_params.toString(), "\n",
\r
384 "\t", "file_types: ", this.settings.file_types, "\n",
\r
385 "\t", "file_types_description: ", this.settings.file_types_description, "\n",
\r
386 "\t", "file_size_limit: ", this.settings.file_size_limit, "\n",
\r
387 "\t", "file_upload_limit: ", this.settings.file_upload_limit, "\n",
\r
388 "\t", "file_queue_limit: ", this.settings.file_queue_limit, "\n",
\r
389 "\t", "debug: ", this.settings.debug.toString(), "\n",
\r
391 "\t", "prevent_swf_caching: ", this.settings.prevent_swf_caching.toString(), "\n",
\r
393 "\t", "button_placeholder_id: ", this.settings.button_placeholder_id.toString(), "\n",
\r
394 "\t", "button_placeholder: ", (this.settings.button_placeholder ? "Set" : "Not Set"), "\n",
\r
395 "\t", "button_image_url: ", this.settings.button_image_url.toString(), "\n",
\r
396 "\t", "button_width: ", this.settings.button_width.toString(), "\n",
\r
397 "\t", "button_height: ", this.settings.button_height.toString(), "\n",
\r
398 "\t", "button_text: ", this.settings.button_text.toString(), "\n",
\r
399 "\t", "button_text_style: ", this.settings.button_text_style.toString(), "\n",
\r
400 "\t", "button_text_top_padding: ", this.settings.button_text_top_padding.toString(), "\n",
\r
401 "\t", "button_text_left_padding: ", this.settings.button_text_left_padding.toString(), "\n",
\r
402 "\t", "button_action: ", this.settings.button_action.toString(), "\n",
\r
403 "\t", "button_disabled: ", this.settings.button_disabled.toString(), "\n",
\r
405 "\t", "custom_settings: ", this.settings.custom_settings.toString(), "\n",
\r
406 "Event Handlers:\n",
\r
407 "\t", "swfupload_loaded_handler assigned: ", (typeof this.settings.swfupload_loaded_handler === "function").toString(), "\n",
\r
408 "\t", "file_dialog_start_handler assigned: ", (typeof this.settings.file_dialog_start_handler === "function").toString(), "\n",
\r
409 "\t", "file_queued_handler assigned: ", (typeof this.settings.file_queued_handler === "function").toString(), "\n",
\r
410 "\t", "file_queue_error_handler assigned: ", (typeof this.settings.file_queue_error_handler === "function").toString(), "\n",
\r
411 "\t", "upload_start_handler assigned: ", (typeof this.settings.upload_start_handler === "function").toString(), "\n",
\r
412 "\t", "upload_progress_handler assigned: ", (typeof this.settings.upload_progress_handler === "function").toString(), "\n",
\r
413 "\t", "upload_error_handler assigned: ", (typeof this.settings.upload_error_handler === "function").toString(), "\n",
\r
414 "\t", "upload_success_handler assigned: ", (typeof this.settings.upload_success_handler === "function").toString(), "\n",
\r
415 "\t", "upload_complete_handler assigned: ", (typeof this.settings.upload_complete_handler === "function").toString(), "\n",
\r
416 "\t", "debug_handler assigned: ", (typeof this.settings.debug_handler === "function").toString(), "\n"
\r
421 /* Note: addSetting and getSetting are no longer used by SWFUpload but are included
\r
422 the maintain v2 API compatibility
\r
424 // Public: (Deprecated) addSetting adds a setting value. If the value given is undefined or null then the default_value is used.
\r
425 SWFUpload.prototype.addSetting = function (name, value, default_value) {
\r
426 if (value == undefined) {
\r
427 return (this.settings[name] = default_value);
\r
429 return (this.settings[name] = value);
\r
433 // Public: (Deprecated) getSetting gets a setting. Returns an empty string if the setting was not found.
\r
434 SWFUpload.prototype.getSetting = function (name) {
\r
435 if (this.settings[name] != undefined) {
\r
436 return this.settings[name];
\r
444 // Private: callFlash handles function calls made to the Flash element.
\r
445 // Calls are made with a setTimeout for some functions to work around
\r
446 // bugs in the ExternalInterface library.
\r
447 SWFUpload.prototype.callFlash = function (functionName, argumentArray) {
\r
448 argumentArray = argumentArray || [];
\r
450 var movieElement = this.getMovieElement();
\r
451 var returnValue, returnString;
\r
453 // Flash's method if calling ExternalInterface methods (code adapted from MooTools).
\r
455 returnString = movieElement.CallFunction('<invoke name="' + functionName + '" returntype="javascript">' + __flash__argumentsToXML(argumentArray, 0) + '</invoke>');
\r
456 returnValue = eval(returnString);
\r
458 throw "Call to " + functionName + " failed";
\r
461 // Unescape file post param values
\r
462 if (returnValue != undefined && typeof returnValue.post === "object") {
\r
463 returnValue = this.unescapeFilePostParams(returnValue);
\r
466 return returnValue;
\r
469 /* *****************************
\r
470 -- Flash control methods --
\r
471 Your UI should use these
\r
472 to operate SWFUpload
\r
473 ***************************** */
\r
475 // WARNING: this function does not work in Flash Player 10
\r
476 // Public: selectFile causes a File Selection Dialog window to appear. This
\r
477 // dialog only allows 1 file to be selected.
\r
478 SWFUpload.prototype.selectFile = function () {
\r
479 this.callFlash("SelectFile");
\r
482 // WARNING: this function does not work in Flash Player 10
\r
483 // Public: selectFiles causes a File Selection Dialog window to appear/ This
\r
484 // dialog allows the user to select any number of files
\r
485 // Flash Bug Warning: Flash limits the number of selectable files based on the combined length of the file names.
\r
486 // If the selection name length is too long the dialog will fail in an unpredictable manner. There is no work-around
\r
488 SWFUpload.prototype.selectFiles = function () {
\r
489 this.callFlash("SelectFiles");
\r
493 // Public: startUpload starts uploading the first file in the queue unless
\r
494 // the optional parameter 'fileID' specifies the ID
\r
495 SWFUpload.prototype.startUpload = function (fileID) {
\r
496 this.callFlash("StartUpload", [fileID]);
\r
499 // Public: cancelUpload cancels any queued file. The fileID parameter may be the file ID or index.
\r
500 // If you do not specify a fileID the current uploading file or first file in the queue is cancelled.
\r
501 // If you do not want the uploadError event to trigger you can specify false for the triggerErrorEvent parameter.
\r
502 SWFUpload.prototype.cancelUpload = function (fileID, triggerErrorEvent) {
\r
503 if (triggerErrorEvent !== false) {
\r
504 triggerErrorEvent = true;
\r
506 this.callFlash("CancelUpload", [fileID, triggerErrorEvent]);
\r
509 // Public: stopUpload stops the current upload and requeues the file at the beginning of the queue.
\r
510 // If nothing is currently uploading then nothing happens.
\r
511 SWFUpload.prototype.stopUpload = function () {
\r
512 this.callFlash("StopUpload");
\r
515 /* ************************
\r
517 * These methods change the SWFUpload settings.
\r
518 * SWFUpload settings should not be changed directly on the settings object
\r
519 * since many of the settings need to be passed to Flash in order to take
\r
521 * *********************** */
\r
523 // Public: getStats gets the file statistics object.
\r
524 SWFUpload.prototype.getStats = function () {
\r
525 return this.callFlash("GetStats");
\r
528 // Public: setStats changes the SWFUpload statistics. You shouldn't need to
\r
529 // change the statistics but you can. Changing the statistics does not
\r
530 // affect SWFUpload accept for the successful_uploads count which is used
\r
531 // by the upload_limit setting to determine how many files the user may upload.
\r
532 SWFUpload.prototype.setStats = function (statsObject) {
\r
533 this.callFlash("SetStats", [statsObject]);
\r
536 // Public: getFile retrieves a File object by ID or Index. If the file is
\r
537 // not found then 'null' is returned.
\r
538 SWFUpload.prototype.getFile = function (fileID) {
\r
539 if (typeof(fileID) === "number") {
\r
540 return this.callFlash("GetFileByIndex", [fileID]);
\r
542 return this.callFlash("GetFile", [fileID]);
\r
546 // Public: addFileParam sets a name/value pair that will be posted with the
\r
547 // file specified by the Files ID. If the name already exists then the
\r
548 // exiting value will be overwritten.
\r
549 SWFUpload.prototype.addFileParam = function (fileID, name, value) {
\r
550 return this.callFlash("AddFileParam", [fileID, name, value]);
\r
553 // Public: removeFileParam removes a previously set (by addFileParam) name/value
\r
554 // pair from the specified file.
\r
555 SWFUpload.prototype.removeFileParam = function (fileID, name) {
\r
556 this.callFlash("RemoveFileParam", [fileID, name]);
\r
559 // Public: setUploadUrl changes the upload_url setting.
\r
560 SWFUpload.prototype.setUploadURL = function (url) {
\r
561 this.settings.upload_url = url.toString();
\r
562 this.callFlash("SetUploadURL", [url]);
\r
565 // Public: setPostParams changes the post_params setting
\r
566 SWFUpload.prototype.setPostParams = function (paramsObject) {
\r
567 this.settings.post_params = paramsObject;
\r
568 this.callFlash("SetPostParams", [paramsObject]);
\r
571 // Public: addPostParam adds post name/value pair. Each name can have only one value.
\r
572 SWFUpload.prototype.addPostParam = function (name, value) {
\r
573 this.settings.post_params[name] = value;
\r
574 this.callFlash("SetPostParams", [this.settings.post_params]);
\r
577 // Public: removePostParam deletes post name/value pair.
\r
578 SWFUpload.prototype.removePostParam = function (name) {
\r
579 delete this.settings.post_params[name];
\r
580 this.callFlash("SetPostParams", [this.settings.post_params]);
\r
583 // Public: setFileTypes changes the file_types setting and the file_types_description setting
\r
584 SWFUpload.prototype.setFileTypes = function (types, description) {
\r
585 this.settings.file_types = types;
\r
586 this.settings.file_types_description = description;
\r
587 this.callFlash("SetFileTypes", [types, description]);
\r
590 // Public: setFileSizeLimit changes the file_size_limit setting
\r
591 SWFUpload.prototype.setFileSizeLimit = function (fileSizeLimit) {
\r
592 this.settings.file_size_limit = fileSizeLimit;
\r
593 this.callFlash("SetFileSizeLimit", [fileSizeLimit]);
\r
596 // Public: setFileUploadLimit changes the file_upload_limit setting
\r
597 SWFUpload.prototype.setFileUploadLimit = function (fileUploadLimit) {
\r
598 this.settings.file_upload_limit = fileUploadLimit;
\r
599 this.callFlash("SetFileUploadLimit", [fileUploadLimit]);
\r
602 // Public: setFileQueueLimit changes the file_queue_limit setting
\r
603 SWFUpload.prototype.setFileQueueLimit = function (fileQueueLimit) {
\r
604 this.settings.file_queue_limit = fileQueueLimit;
\r
605 this.callFlash("SetFileQueueLimit", [fileQueueLimit]);
\r
608 // Public: setFilePostName changes the file_post_name setting
\r
609 SWFUpload.prototype.setFilePostName = function (filePostName) {
\r
610 this.settings.file_post_name = filePostName;
\r
611 this.callFlash("SetFilePostName", [filePostName]);
\r
614 // Public: setUseQueryString changes the use_query_string setting
\r
615 SWFUpload.prototype.setUseQueryString = function (useQueryString) {
\r
616 this.settings.use_query_string = useQueryString;
\r
617 this.callFlash("SetUseQueryString", [useQueryString]);
\r
620 // Public: setRequeueOnError changes the requeue_on_error setting
\r
621 SWFUpload.prototype.setRequeueOnError = function (requeueOnError) {
\r
622 this.settings.requeue_on_error = requeueOnError;
\r
623 this.callFlash("SetRequeueOnError", [requeueOnError]);
\r
626 // Public: setHTTPSuccess changes the http_success setting
\r
627 SWFUpload.prototype.setHTTPSuccess = function (http_status_codes) {
\r
628 if (typeof http_status_codes === "string") {
\r
629 http_status_codes = http_status_codes.replace(" ", "").split(",");
\r
632 this.settings.http_success = http_status_codes;
\r
633 this.callFlash("SetHTTPSuccess", [http_status_codes]);
\r
636 // Public: setHTTPSuccess changes the http_success setting
\r
637 SWFUpload.prototype.setAssumeSuccessTimeout = function (timeout_seconds) {
\r
638 this.settings.assume_success_timeout = timeout_seconds;
\r
639 this.callFlash("SetAssumeSuccessTimeout", [timeout_seconds]);
\r
642 // Public: setDebugEnabled changes the debug_enabled setting
\r
643 SWFUpload.prototype.setDebugEnabled = function (debugEnabled) {
\r
644 this.settings.debug_enabled = debugEnabled;
\r
645 this.callFlash("SetDebugEnabled", [debugEnabled]);
\r
648 // Public: setButtonImageURL loads a button image sprite
\r
649 SWFUpload.prototype.setButtonImageURL = function (buttonImageURL) {
\r
650 if (buttonImageURL == undefined) {
\r
651 buttonImageURL = "";
\r
654 this.settings.button_image_url = buttonImageURL;
\r
655 this.callFlash("SetButtonImageURL", [buttonImageURL]);
\r
658 // Public: setButtonDimensions resizes the Flash Movie and button
\r
659 SWFUpload.prototype.setButtonDimensions = function (width, height) {
\r
660 this.settings.button_width = width;
\r
661 this.settings.button_height = height;
\r
663 var movie = this.getMovieElement();
\r
664 if (movie != undefined) {
\r
665 movie.style.width = width + "px";
\r
666 movie.style.height = height + "px";
\r
669 this.callFlash("SetButtonDimensions", [width, height]);
\r
671 // Public: setButtonText Changes the text overlaid on the button
\r
672 SWFUpload.prototype.setButtonText = function (html) {
\r
673 this.settings.button_text = html;
\r
674 this.callFlash("SetButtonText", [html]);
\r
676 // Public: setButtonTextPadding changes the top and left padding of the text overlay
\r
677 SWFUpload.prototype.setButtonTextPadding = function (left, top) {
\r
678 this.settings.button_text_top_padding = top;
\r
679 this.settings.button_text_left_padding = left;
\r
680 this.callFlash("SetButtonTextPadding", [left, top]);
\r
683 // Public: setButtonTextStyle changes the CSS used to style the HTML/Text overlaid on the button
\r
684 SWFUpload.prototype.setButtonTextStyle = function (css) {
\r
685 this.settings.button_text_style = css;
\r
686 this.callFlash("SetButtonTextStyle", [css]);
\r
688 // Public: setButtonDisabled disables/enables the button
\r
689 SWFUpload.prototype.setButtonDisabled = function (isDisabled) {
\r
690 this.settings.button_disabled = isDisabled;
\r
691 this.callFlash("SetButtonDisabled", [isDisabled]);
\r
693 // Public: setButtonAction sets the action that occurs when the button is clicked
\r
694 SWFUpload.prototype.setButtonAction = function (buttonAction) {
\r
695 this.settings.button_action = buttonAction;
\r
696 this.callFlash("SetButtonAction", [buttonAction]);
\r
699 // Public: setButtonCursor changes the mouse cursor displayed when hovering over the button
\r
700 SWFUpload.prototype.setButtonCursor = function (cursor) {
\r
701 this.settings.button_cursor = cursor;
\r
702 this.callFlash("SetButtonCursor", [cursor]);
\r
705 /* *******************************
\r
706 Flash Event Interfaces
\r
707 These functions are used by Flash to trigger the various
\r
710 All these functions a Private.
\r
712 Because the ExternalInterface library is buggy the event calls
\r
713 are added to a queue and the queue then executed by a setTimeout.
\r
714 This ensures that events are executed in a determinate order and that
\r
715 the ExternalInterface bugs are avoided.
\r
716 ******************************* */
\r
718 SWFUpload.prototype.queueEvent = function (handlerName, argumentArray) {
\r
719 // Warning: Don't call this.debug inside here or you'll create an infinite loop
\r
721 if (argumentArray == undefined) {
\r
722 argumentArray = [];
\r
723 } else if (!(argumentArray instanceof Array)) {
\r
724 argumentArray = [argumentArray];
\r
728 if (typeof this.settings[handlerName] === "function") {
\r
730 this.eventQueue.push(function () {
\r
731 this.settings[handlerName].apply(this, argumentArray);
\r
734 // Execute the next queued event
\r
735 setTimeout(function () {
\r
736 self.executeNextEvent();
\r
739 } else if (this.settings[handlerName] !== null) {
\r
740 throw "Event handler " + handlerName + " is unknown or is not a function";
\r
744 // Private: Causes the next event in the queue to be executed. Since events are queued using a setTimeout
\r
745 // we must queue them in order to garentee that they are executed in order.
\r
746 SWFUpload.prototype.executeNextEvent = function () {
\r
747 // Warning: Don't call this.debug inside here or you'll create an infinite loop
\r
749 var f = this.eventQueue ? this.eventQueue.shift() : null;
\r
750 if (typeof(f) === "function") {
\r
755 // Private: unescapeFileParams is part of a workaround for a flash bug where objects passed through ExternalInterface cannot have
\r
756 // properties that contain characters that are not valid for JavaScript identifiers. To work around this
\r
757 // the Flash Component escapes the parameter names and we must unescape again before passing them along.
\r
758 SWFUpload.prototype.unescapeFilePostParams = function (file) {
\r
759 var reg = /[$]([0-9a-f]{4})/i;
\r
760 var unescapedPost = {};
\r
763 if (file != undefined) {
\r
764 for (var k in file.post) {
\r
765 if (file.post.hasOwnProperty(k)) {
\r
768 while ((match = reg.exec(uk)) !== null) {
\r
769 uk = uk.replace(match[0], String.fromCharCode(parseInt("0x" + match[1], 16)));
\r
771 unescapedPost[uk] = file.post[k];
\r
775 file.post = unescapedPost;
\r
781 // Private: Called by Flash to see if JS can call in to Flash (test if External Interface is working)
\r
782 SWFUpload.prototype.testExternalInterface = function () {
\r
784 return this.callFlash("TestExternalInterface");
\r
790 // Private: This event is called by Flash when it has finished loading. Don't modify this.
\r
791 // Use the swfupload_loaded_handler event setting to execute custom code when SWFUpload has loaded.
\r
792 SWFUpload.prototype.flashReady = function () {
\r
793 // Check that the movie element is loaded correctly with its ExternalInterface methods defined
\r
794 var movieElement = this.getMovieElement();
\r
796 if (!movieElement) {
\r
797 this.debug("Flash called back ready but the flash movie can't be found.");
\r
801 this.cleanUp(movieElement);
\r
803 this.queueEvent("swfupload_loaded_handler");
\r
806 // Private: removes Flash added fuctions to the DOM node to prevent memory leaks in IE.
\r
807 // This function is called by Flash each time the ExternalInterface functions are created.
\r
808 SWFUpload.prototype.cleanUp = function (movieElement) {
\r
809 // Pro-actively unhook all the Flash functions
\r
811 if (this.movieElement && typeof(movieElement.CallFunction) === "unknown") { // We only want to do this in IE
\r
812 this.debug("Removing Flash functions hooks (this should only run in IE and should prevent memory leaks)");
\r
813 for (var key in movieElement) {
\r
815 if (typeof(movieElement[key]) === "function") {
\r
816 movieElement[key] = null;
\r
826 // Fix Flashes own cleanup code so if the SWFMovie was removed from the page
\r
827 // it doesn't display errors.
\r
828 window["__flash__removeCallback"] = function (instance, name) {
\r
831 instance[name] = null;
\r
833 } catch (flashEx) {
\r
841 /* This is a chance to do something before the browse window opens */
\r
842 SWFUpload.prototype.fileDialogStart = function () {
\r
843 this.queueEvent("file_dialog_start_handler");
\r
847 /* Called when a file is successfully added to the queue. */
\r
848 SWFUpload.prototype.fileQueued = function (file) {
\r
849 file = this.unescapeFilePostParams(file);
\r
850 this.queueEvent("file_queued_handler", file);
\r
854 /* Handle errors that occur when an attempt to queue a file fails. */
\r
855 SWFUpload.prototype.fileQueueError = function (file, errorCode, message) {
\r
856 file = this.unescapeFilePostParams(file);
\r
857 this.queueEvent("file_queue_error_handler", [file, errorCode, message]);
\r
860 /* Called after the file dialog has closed and the selected files have been queued.
\r
861 You could call startUpload here if you want the queued files to begin uploading immediately. */
\r
862 SWFUpload.prototype.fileDialogComplete = function (numFilesSelected, numFilesQueued, numFilesInQueue) {
\r
863 this.queueEvent("file_dialog_complete_handler", [numFilesSelected, numFilesQueued, numFilesInQueue]);
\r
866 SWFUpload.prototype.uploadStart = function (file) {
\r
867 file = this.unescapeFilePostParams(file);
\r
868 this.queueEvent("return_upload_start_handler", file);
\r
871 SWFUpload.prototype.returnUploadStart = function (file) {
\r
873 if (typeof this.settings.upload_start_handler === "function") {
\r
874 file = this.unescapeFilePostParams(file);
\r
875 returnValue = this.settings.upload_start_handler.call(this, file);
\r
876 } else if (this.settings.upload_start_handler != undefined) {
\r
877 throw "upload_start_handler must be a function";
\r
880 // Convert undefined to true so if nothing is returned from the upload_start_handler it is
\r
881 // interpretted as 'true'.
\r
882 if (returnValue === undefined) {
\r
883 returnValue = true;
\r
886 returnValue = !!returnValue;
\r
888 this.callFlash("ReturnUploadStart", [returnValue]);
\r
893 SWFUpload.prototype.uploadProgress = function (file, bytesComplete, bytesTotal) {
\r
894 file = this.unescapeFilePostParams(file);
\r
895 this.queueEvent("upload_progress_handler", [file, bytesComplete, bytesTotal]);
\r
898 SWFUpload.prototype.uploadError = function (file, errorCode, message) {
\r
899 file = this.unescapeFilePostParams(file);
\r
900 this.queueEvent("upload_error_handler", [file, errorCode, message]);
\r
903 SWFUpload.prototype.uploadSuccess = function (file, serverData, responseReceived) {
\r
904 file = this.unescapeFilePostParams(file);
\r
905 this.queueEvent("upload_success_handler", [file, serverData, responseReceived]);
\r
908 SWFUpload.prototype.uploadComplete = function (file) {
\r
909 file = this.unescapeFilePostParams(file);
\r
910 this.queueEvent("upload_complete_handler", file);
\r
913 /* Called by SWFUpload JavaScript and Flash functions when debug is enabled. By default it writes messages to the
\r
914 internal debug console. You can override this event and have messages written where you want. */
\r
915 SWFUpload.prototype.debug = function (message) {
\r
916 this.queueEvent("debug_handler", message);
\r
920 /* **********************************
\r
922 The debug console is a self contained, in page location
\r
923 for debug message to be sent. The Debug Console adds
\r
924 itself to the body if necessary.
\r
926 The console is automatically scrolled as messages appear.
\r
928 If you are using your own debug handler or when you deploy to production and
\r
929 have debug disabled you can remove these functions to reduce the file size
\r
931 ********************************** */
\r
933 // Private: debugMessage is the default debug_handler. If you want to print debug messages
\r
934 // call the debug() function. When overriding the function your own function should
\r
935 // check to see if the debug setting is true before outputting debug information.
\r
936 SWFUpload.prototype.debugMessage = function (message) {
\r
937 if (this.settings.debug) {
\r
938 var exceptionMessage, exceptionValues = [];
\r
940 // Check for an exception object and print it nicely
\r
941 if (typeof message === "object" && typeof message.name === "string" && typeof message.message === "string") {
\r
942 for (var key in message) {
\r
943 if (message.hasOwnProperty(key)) {
\r
944 exceptionValues.push(key + ": " + message[key]);
\r
947 exceptionMessage = exceptionValues.join("\n") || "";
\r
948 exceptionValues = exceptionMessage.split("\n");
\r
949 exceptionMessage = "EXCEPTION: " + exceptionValues.join("\nEXCEPTION: ");
\r
950 SWFUpload.Console.writeLine(exceptionMessage);
\r
952 SWFUpload.Console.writeLine(message);
\r
957 SWFUpload.Console = {};
\r
958 SWFUpload.Console.writeLine = function (message) {
\r
959 var console, documentForm;
\r
962 console = document.getElementById("SWFUpload_Console");
\r
965 documentForm = document.createElement("form");
\r
966 document.getElementsByTagName("body")[0].appendChild(documentForm);
\r
968 console = document.createElement("textarea");
\r
969 console.id = "SWFUpload_Console";
\r
970 console.style.fontFamily = "monospace";
\r
971 console.setAttribute("wrap", "off");
\r
972 console.wrap = "off";
\r
973 console.style.overflow = "auto";
\r
974 console.style.width = "700px";
\r
975 console.style.height = "350px";
\r
976 console.style.margin = "5px";
\r
977 documentForm.appendChild(console);
\r
980 console.value += message + "\n";
\r
982 console.scrollTop = console.scrollHeight - console.clientHeight;
\r
984 alert("Exception: " + ex.name + " Message: " + ex.message);
\r