PageRenderTime 60ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/public/flash/swf_upload/Flash/SWFUpload.as

https://github.com/kidakaka/canvas-lms
ActionScript | 1228 lines | 934 code | 188 blank | 106 comment | 193 complexity | 4a21e540a79b34a35a6a0d67b5cb3835 MD5 | raw file
  1. /* Todo:
  2. * Missing initial progress event
  3. * Improve resizing/encoding so it doesn't lock up browser.
  4. * */
  5. package {
  6. import flash.display.BlendMode;
  7. import flash.display.DisplayObjectContainer;
  8. import flash.display.Loader;
  9. import flash.display.Stage;
  10. import flash.display.Sprite;
  11. import flash.display.StageAlign;
  12. import flash.display.StageScaleMode;
  13. import flash.net.FileReferenceList;
  14. import flash.net.FileReference;
  15. import flash.net.FileFilter;
  16. import flash.net.URLRequest;
  17. import flash.net.URLRequestMethod;
  18. import flash.net.URLVariables;
  19. import flash.events.*;
  20. import flash.external.ExternalInterface;
  21. import flash.system.Security;
  22. import flash.text.AntiAliasType;
  23. import flash.text.GridFitType;
  24. import flash.text.StaticText;
  25. import flash.text.StyleSheet;
  26. import flash.text.TextDisplayMode;
  27. import flash.text.TextField;
  28. import flash.text.TextFieldType;
  29. import flash.text.TextFieldAutoSize;
  30. import flash.text.TextFormat;
  31. import flash.ui.Mouse;
  32. import flash.utils.ByteArray;
  33. import flash.utils.Timer;
  34. import FileItem;
  35. import ExternalCall;
  36. import ImageResizer;
  37. import ImageResizerEvent;
  38. import MultipartURLLoader;
  39. public class SWFUpload extends Sprite {
  40. // Cause SWFUpload to start as soon as the movie starts
  41. public static function main():void
  42. {
  43. var SWFUpload:SWFUpload = new SWFUpload();
  44. }
  45. private const build_number:String = "2.5.0 2010-02-17 Beta 3";
  46. // State tracking variables
  47. private var fileBrowserMany:FileReferenceList = new FileReferenceList();
  48. private var fileBrowserOne:FileReference = null; // This isn't set because it can't be reused like the FileReferenceList. It gets setup in the SelectFile method
  49. private var file_queue:Array = new Array(); // holds a list of all items that are to be uploaded.
  50. private var current_file_item:FileItem = null; // the item that is currently being uploaded.
  51. private var file_index:Array = new Array();
  52. private var successful_uploads:Number = 0; // Tracks the uploads that have been completed
  53. private var queue_errors:Number = 0; // Tracks files rejected during queueing
  54. private var upload_errors:Number = 0; // Tracks files that fail upload
  55. private var upload_cancelled:Number = 0; // Tracks number of cancelled files
  56. private var queued_uploads:Number = 0; // Tracks the FileItems that are waiting to be uploaded.
  57. private var valid_file_extensions:Array = new Array();// Holds the parsed valid extensions.
  58. private var serverDataTimer:Timer = null;
  59. private var assumeSuccessTimer:Timer = null;
  60. private var sizeTimer:Timer;
  61. private var hasCalledFlashReady:Boolean = false;
  62. // Callbacks
  63. private var flashReady_Callback:String;
  64. private var fileDialogStart_Callback:String;
  65. private var fileQueued_Callback:String;
  66. private var fileQueueError_Callback:String;
  67. private var fileDialogComplete_Callback:String;
  68. private var uploadResizeStart_Callback:String;
  69. private var uploadStart_Callback:String;
  70. private var uploadProgress_Callback:String;
  71. private var uploadError_Callback:String;
  72. private var uploadSuccess_Callback:String;
  73. private var uploadComplete_Callback:String;
  74. private var debug_Callback:String;
  75. private var mouseOut_Callback:String;
  76. private var mouseOver_Callback:String;
  77. private var mouseClick_Callback:String;
  78. // Values passed in from the HTML
  79. private var movieName:String;
  80. private var uploadURL:String;
  81. private var filePostName:String;
  82. private var uploadPostObject:Object;
  83. private var fileTypes:String;
  84. private var fileTypesDescription:String;
  85. private var fileSizeLimit:Number;
  86. private var fileUploadLimit:Number = 0;
  87. private var fileQueueLimit:Number = 0;
  88. private var useQueryString:Boolean = false;
  89. private var requeueOnError:Boolean = false;
  90. private var httpSuccess:Array = [];
  91. private var assumeSuccessTimeout:Number = 0;
  92. private var debugEnabled:Boolean;
  93. private var buttonLoader:Loader;
  94. private var buttonTextField:TextField;
  95. private var buttonCursorSprite:Sprite;
  96. private var buttonImageURL:String;
  97. //private var buttonWidth:Number;
  98. //private var buttonHeight:Number;
  99. private var buttonText:String;
  100. private var buttonTextStyle:String;
  101. private var buttonTextTopPadding:Number;
  102. private var buttonTextLeftPadding:Number;
  103. private var buttonAction:Number;
  104. private var buttonCursor:Number;
  105. private var buttonStateOver:Boolean;
  106. private var buttonStateMouseDown:Boolean;
  107. private var buttonStateDisabled:Boolean;
  108. // Error code "constants"
  109. // Size check constants
  110. private var SIZE_TOO_BIG:Number = 1;
  111. private var SIZE_ZERO_BYTE:Number = -1;
  112. private var SIZE_OK:Number = 0;
  113. // Queue errors
  114. private var ERROR_CODE_QUEUE_LIMIT_EXCEEDED:Number = -100;
  115. private var ERROR_CODE_FILE_EXCEEDS_SIZE_LIMIT:Number = -110;
  116. private var ERROR_CODE_ZERO_BYTE_FILE:Number = -120;
  117. private var ERROR_CODE_INVALID_FILETYPE:Number = -130;
  118. // Upload Errors
  119. private var ERROR_CODE_HTTP_ERROR:Number = -200;
  120. private var ERROR_CODE_MISSING_UPLOAD_URL:Number = -210;
  121. private var ERROR_CODE_IO_ERROR:Number = -220;
  122. private var ERROR_CODE_SECURITY_ERROR:Number = -230;
  123. private var ERROR_CODE_UPLOAD_LIMIT_EXCEEDED:Number = -240;
  124. private var ERROR_CODE_UPLOAD_FAILED:Number = -250;
  125. private var ERROR_CODE_SPECIFIED_FILE_ID_NOT_FOUND:Number = -260;
  126. private var ERROR_CODE_FILE_VALIDATION_FAILED:Number = -270;
  127. private var ERROR_CODE_FILE_CANCELLED:Number = -280;
  128. private var ERROR_CODE_UPLOAD_STOPPED:Number = -290;
  129. private var ERROR_CODE_RESIZE:Number = -300;
  130. // Button Actions
  131. private var BUTTON_ACTION_SELECT_FILE:Number = -100;
  132. private var BUTTON_ACTION_SELECT_FILES:Number = -110;
  133. private var BUTTON_ACTION_START_UPLOAD:Number = -120;
  134. private var BUTTON_ACTION_NONE:Number = -130;
  135. private var BUTTON_ACTION_JAVASCRIPT:Number = -130; // DEPRECATED
  136. private var BUTTON_CURSOR_ARROW:Number = -1;
  137. private var BUTTON_CURSOR_HAND:Number = -2;
  138. // Resize encoder
  139. private var ENCODER_JPEG:Number = -1;
  140. private var ENCODER_PNG:Number = -2;
  141. public function SWFUpload() {
  142. // Do the feature detection. Make sure this version of Flash supports the features we need. If not
  143. // abort initialization.
  144. if (!flash.net.FileReferenceList || !flash.net.FileReference || !flash.net.URLRequest || !flash.external.ExternalInterface || !flash.external.ExternalInterface.available || !DataEvent.UPLOAD_COMPLETE_DATA) {
  145. return;
  146. }
  147. var self:SWFUpload = this;
  148. Security.allowDomain("*"); // Allow uploading to any domain
  149. Security.allowInsecureDomain("*"); // Allow uploading from HTTP to HTTPS and HTTPS to HTTP
  150. // Keep Flash Player busy so it doesn't show the "flash script is running slowly" error
  151. var counter:Number = 0;
  152. root.addEventListener(Event.ENTER_FRAME, function ():void { if (++counter > 100) counter = 0; });
  153. // Setup file FileReferenceList events
  154. this.fileBrowserMany.addEventListener(Event.SELECT, this.Select_Many_Handler);
  155. this.fileBrowserMany.addEventListener(Event.CANCEL, this.DialogCancelled_Handler);
  156. this.stage.align = StageAlign.TOP_LEFT;
  157. this.stage.scaleMode = StageScaleMode.NO_SCALE;
  158. this.stage.addEventListener(Event.RESIZE, function (e:Event):void {
  159. self.HandleStageResize(e);
  160. });
  161. // Setup the button and text label
  162. this.buttonLoader = new Loader();
  163. var doNothing:Function = function ():void { };
  164. this.buttonLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, doNothing );
  165. this.buttonLoader.contentLoaderInfo.addEventListener(HTTPStatusEvent.HTTP_STATUS, doNothing );
  166. this.buttonLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, this.ButtonImageLoaded );
  167. this.stage.addChild(this.buttonLoader);
  168. this.stage.addEventListener(MouseEvent.CLICK, function (event:MouseEvent):void {
  169. self.UpdateButtonState();
  170. self.ButtonClickHandler(event);
  171. });
  172. this.stage.addEventListener(MouseEvent.MOUSE_DOWN, function (event:MouseEvent):void {
  173. self.buttonStateMouseDown = true;
  174. self.UpdateButtonState();
  175. });
  176. this.stage.addEventListener(MouseEvent.MOUSE_UP, function (event:MouseEvent):void {
  177. self.buttonStateMouseDown = false;
  178. self.UpdateButtonState();
  179. });
  180. this.stage.addEventListener(MouseEvent.MOUSE_OVER, function (event:MouseEvent):void {
  181. self.buttonStateMouseDown = event.buttonDown;
  182. self.buttonStateOver = true;
  183. self.UpdateButtonState();
  184. ExternalCall.Simple(self.mouseOver_Callback);
  185. });
  186. this.stage.addEventListener(MouseEvent.MOUSE_OUT, function (event:MouseEvent):void {
  187. self.buttonStateMouseDown = false;
  188. self.buttonStateOver = false;
  189. self.UpdateButtonState();
  190. });
  191. // Handle the mouse leaving the flash movie altogether
  192. this.stage.addEventListener(Event.MOUSE_LEAVE, function (event:Event):void {
  193. self.buttonStateMouseDown = false;
  194. self.buttonStateOver = false;
  195. self.UpdateButtonState();
  196. ExternalCall.Simple(self.mouseOut_Callback);
  197. });
  198. this.buttonTextField = new TextField();
  199. this.buttonTextField.type = TextFieldType.DYNAMIC;
  200. this.buttonTextField.antiAliasType = AntiAliasType.ADVANCED;
  201. this.buttonTextField.autoSize = TextFieldAutoSize.NONE;
  202. this.buttonTextField.cacheAsBitmap = true;
  203. this.buttonTextField.multiline = true;
  204. this.buttonTextField.wordWrap = false;
  205. this.buttonTextField.tabEnabled = false;
  206. this.buttonTextField.background = false;
  207. this.buttonTextField.border = false;
  208. this.buttonTextField.selectable = false;
  209. this.buttonTextField.condenseWhite = true;
  210. this.stage.addChild(this.buttonTextField);
  211. this.buttonCursorSprite = new Sprite();
  212. this.buttonCursorSprite.graphics.beginFill(0xFFFFFF, 0);
  213. this.buttonCursorSprite.graphics.drawRect(0, 0, 1, 1);
  214. this.buttonCursorSprite.graphics.endFill();
  215. this.buttonCursorSprite.buttonMode = true;
  216. this.buttonCursorSprite.x = 0;
  217. this.buttonCursorSprite.y = 0;
  218. this.buttonCursorSprite.addEventListener(MouseEvent.CLICK, doNothing);
  219. this.stage.addChild(this.buttonCursorSprite);
  220. this.sizeTimer = new Timer(10, 0);
  221. this.sizeTimer.addEventListener(TimerEvent.TIMER, function ():void {
  222. //self.Debug("Stage:" + self.stage.stageWidth + " by " + self.stage.stageHeight);
  223. if (self.stage.stageWidth > 0 || self.stage.stageHeight > 0) {
  224. self.HandleStageResize(null);
  225. self.sizeTimer.stop();
  226. self.sizeTimer.removeEventListener(TimerEvent.TIMER, arguments.callee);
  227. self.sizeTimer = null;
  228. }
  229. } );
  230. this.sizeTimer.start();
  231. // Get the movie name
  232. this.movieName = decodeURIComponent(root.loaderInfo.parameters.movieName);
  233. // **Configure the callbacks**
  234. // The JavaScript tracks all the instances of SWFUpload on a page. We can access the instance
  235. // associated with this SWF file using the movieName. Each callback is accessible by making
  236. // a call directly to it on our instance. There is no error handling for undefined callback functions.
  237. // A developer would have to deliberately remove the default functions,set the variable to null, or remove
  238. // it from the init function.
  239. this.flashReady_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].flashReady";
  240. this.fileDialogStart_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].fileDialogStart";
  241. this.fileQueued_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].fileQueued";
  242. this.fileQueueError_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].fileQueueError";
  243. this.fileDialogComplete_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].fileDialogComplete";
  244. this.uploadResizeStart_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].uploadResizeStart";
  245. this.uploadStart_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].uploadStart";
  246. this.uploadProgress_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].uploadProgress";
  247. this.uploadError_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].uploadError";
  248. this.uploadSuccess_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].uploadSuccess";
  249. this.uploadComplete_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].uploadComplete";
  250. this.debug_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].debug";
  251. this.mouseOut_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].mouseOut";
  252. this.mouseOver_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].mouseOver";
  253. this.mouseClick_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].mouseClick";
  254. // Get the Flash Vars
  255. this.uploadURL = decodeURIComponent(root.loaderInfo.parameters.uploadURL);
  256. this.filePostName = decodeURIComponent(root.loaderInfo.parameters.filePostName);
  257. this.fileTypes = decodeURIComponent(root.loaderInfo.parameters.fileTypes);
  258. this.fileTypesDescription = decodeURIComponent(root.loaderInfo.parameters.fileTypesDescription) + " (" + this.fileTypes + ")";
  259. this.loadPostParams(decodeURIComponent(root.loaderInfo.parameters.params));
  260. if (!this.filePostName) {
  261. this.filePostName = "Filedata";
  262. }
  263. if (!this.fileTypes) {
  264. this.fileTypes = "*.*";
  265. }
  266. if (!this.fileTypesDescription) {
  267. this.fileTypesDescription = "All Files";
  268. }
  269. this.LoadFileExensions(this.fileTypes);
  270. try {
  271. this.debugEnabled = decodeURIComponent(root.loaderInfo.parameters.debugEnabled) == "true" ? true : false;
  272. } catch (ex:Object) {
  273. this.debugEnabled = false;
  274. }
  275. try {
  276. this.SetFileSizeLimit(String(decodeURIComponent(root.loaderInfo.parameters.fileSizeLimit)));
  277. } catch (ex:Object) {
  278. this.fileSizeLimit = 0;
  279. }
  280. try {
  281. this.fileUploadLimit = Number(decodeURIComponent(root.loaderInfo.parameters.fileUploadLimit));
  282. if (this.fileUploadLimit < 0) this.fileUploadLimit = 0;
  283. } catch (ex:Object) {
  284. this.fileUploadLimit = 0;
  285. }
  286. try {
  287. this.fileQueueLimit = Number(decodeURIComponent(root.loaderInfo.parameters.fileQueueLimit));
  288. if (this.fileQueueLimit < 0) this.fileQueueLimit = 0;
  289. } catch (ex:Object) {
  290. this.fileQueueLimit = 0;
  291. }
  292. // Set the queue limit to match the upload limit when the queue limit is bigger than the upload limit
  293. if (this.fileQueueLimit > this.fileUploadLimit && this.fileUploadLimit != 0) this.fileQueueLimit = this.fileUploadLimit;
  294. // The the queue limit is unlimited and the upload limit is not then set the queue limit to the upload limit
  295. if (this.fileQueueLimit == 0 && this.fileUploadLimit != 0) this.fileQueueLimit = this.fileUploadLimit;
  296. try {
  297. this.useQueryString = decodeURIComponent(root.loaderInfo.parameters.useQueryString) == "true" ? true : false;
  298. } catch (ex:Object) {
  299. this.useQueryString = false;
  300. }
  301. try {
  302. this.requeueOnError = decodeURIComponent(root.loaderInfo.parameters.requeueOnError) == "true" ? true : false;
  303. } catch (ex:Object) {
  304. this.requeueOnError = false;
  305. }
  306. try {
  307. this.SetHTTPSuccess(String(decodeURIComponent(root.loaderInfo.parameters.httpSuccess)));
  308. } catch (ex:Object) {
  309. this.SetHTTPSuccess([]);
  310. }
  311. try {
  312. this.SetAssumeSuccessTimeout(Number(decodeURIComponent(root.loaderInfo.parameters.assumeSuccessTimeout)));
  313. } catch (ex:Object) {
  314. this.SetAssumeSuccessTimeout(0);
  315. }
  316. try {
  317. this.SetButtonImageURL(String(decodeURIComponent(root.loaderInfo.parameters.buttonImageURL)));
  318. } catch (ex:Object) {
  319. this.SetButtonImageURL("");
  320. }
  321. try {
  322. this.SetButtonText(String(decodeURIComponent(root.loaderInfo.parameters.buttonText)));
  323. } catch (ex:Object) {
  324. this.SetButtonText("");
  325. }
  326. try {
  327. this.SetButtonTextPadding(Number(decodeURIComponent(root.loaderInfo.parameters.buttonTextLeftPadding)), Number(decodeURIComponent(root.loaderInfo.parameters.buttonTextTopPadding)));
  328. } catch (ex:Object) {
  329. this.SetButtonTextPadding(0, 0);
  330. }
  331. try {
  332. this.SetButtonTextStyle(String(decodeURIComponent(root.loaderInfo.parameters.buttonTextStyle)));
  333. } catch (ex:Object) {
  334. this.SetButtonTextStyle("");
  335. }
  336. try {
  337. this.SetButtonAction(Number(decodeURIComponent(root.loaderInfo.parameters.buttonAction)));
  338. } catch (ex:Object) {
  339. this.SetButtonAction(this.BUTTON_ACTION_SELECT_FILES);
  340. }
  341. try {
  342. this.SetButtonDisabled(decodeURIComponent(root.loaderInfo.parameters.buttonDisabled) == "true" ? true : false);
  343. } catch (ex:Object) {
  344. this.SetButtonDisabled(Boolean(false));
  345. }
  346. try {
  347. this.SetButtonCursor(Number(decodeURIComponent(root.loaderInfo.parameters.buttonCursor)));
  348. } catch (ex:Object) {
  349. this.SetButtonCursor(this.BUTTON_CURSOR_ARROW);
  350. }
  351. this.SetupExternalInterface();
  352. this.Debug("SWFUpload Init Complete");
  353. this.PrintDebugInfo();
  354. ExternalCall.Simple(this.flashReady_Callback);
  355. this.hasCalledFlashReady = true;
  356. }
  357. private function HandleStageResize(e:Event):void {
  358. if (this.stage.stageWidth > 0 || this.stage.stageHeight > 0) {
  359. this.Debug("Stage Resize:" + this.stage.stageWidth + " by " + this.stage.stageHeight);
  360. // scale the button (if it's not loaded don't crash)
  361. try {
  362. var buttonHeight:Number = this.buttonLoader.contentLoaderInfo.height / 4;
  363. this.buttonLoader.height = this.stage.stageHeight * 4;
  364. this.buttonLoader.scaleX = this.buttonLoader.scaleY;
  365. } catch (ex:Error) { }
  366. // Scale the button cursor
  367. try {
  368. this.buttonCursorSprite.width = this.stage.stageWidth;
  369. this.buttonCursorSprite.height = this.stage.stageHeight;
  370. } catch (ex:Error) {}
  371. // scale the text area (it doesn't resize but it still needs to fit)
  372. try {
  373. this.buttonTextField.width = this.stage.stageWidth;
  374. this.buttonTextField.height = this.stage.stageHeight;
  375. } catch (ex:Error) {}
  376. }
  377. }
  378. private function SetupExternalInterface():void {
  379. try {
  380. ExternalInterface.addCallback("SelectFile", this.SelectFile);
  381. ExternalInterface.addCallback("SelectFiles", this.SelectFiles);
  382. ExternalInterface.addCallback("StartUpload", this.StartUpload);
  383. ExternalInterface.addCallback("ReturnUploadStart", this.ReturnUploadStart);
  384. ExternalInterface.addCallback("StopUpload", this.StopUpload);
  385. ExternalInterface.addCallback("CancelUpload", this.CancelUpload);
  386. ExternalInterface.addCallback("RequeueUpload", this.RequeueUpload);
  387. ExternalInterface.addCallback("GetStats", this.GetStats);
  388. ExternalInterface.addCallback("SetStats", this.SetStats);
  389. ExternalInterface.addCallback("GetFile", this.GetFile);
  390. ExternalInterface.addCallback("GetFileByIndex", this.GetFileByIndex);
  391. ExternalInterface.addCallback("GetFileByQueueIndex", this.GetFileByQueueIndex);
  392. ExternalInterface.addCallback("AddFileParam", this.AddFileParam);
  393. ExternalInterface.addCallback("RemoveFileParam", this.RemoveFileParam);
  394. ExternalInterface.addCallback("SetUploadURL", this.SetUploadURL);
  395. ExternalInterface.addCallback("SetPostParams", this.SetPostParams);
  396. ExternalInterface.addCallback("SetFileTypes", this.SetFileTypes);
  397. ExternalInterface.addCallback("SetFileSizeLimit", this.SetFileSizeLimit);
  398. ExternalInterface.addCallback("SetFileUploadLimit", this.SetFileUploadLimit);
  399. ExternalInterface.addCallback("SetFileQueueLimit", this.SetFileQueueLimit);
  400. ExternalInterface.addCallback("SetFilePostName", this.SetFilePostName);
  401. ExternalInterface.addCallback("SetUseQueryString", this.SetUseQueryString);
  402. ExternalInterface.addCallback("SetRequeueOnError", this.SetRequeueOnError);
  403. ExternalInterface.addCallback("SetHTTPSuccess", this.SetHTTPSuccess);
  404. ExternalInterface.addCallback("SetAssumeSuccessTimeout", this.SetAssumeSuccessTimeout);
  405. ExternalInterface.addCallback("SetDebugEnabled", this.SetDebugEnabled);
  406. ExternalInterface.addCallback("SetButtonImageURL", this.SetButtonImageURL);
  407. ExternalInterface.addCallback("SetButtonText", this.SetButtonText);
  408. ExternalInterface.addCallback("SetButtonTextPadding", this.SetButtonTextPadding);
  409. ExternalInterface.addCallback("SetButtonTextStyle", this.SetButtonTextStyle);
  410. ExternalInterface.addCallback("SetButtonAction", this.SetButtonAction);
  411. ExternalInterface.addCallback("SetButtonDisabled", this.SetButtonDisabled);
  412. ExternalInterface.addCallback("SetButtonCursor", this.SetButtonCursor);
  413. } catch (ex:Error) {
  414. this.Debug("Callbacks where not set: " + ex.message);
  415. return;
  416. }
  417. }
  418. /* *****************************************
  419. * FileReference Event Handlers
  420. * *************************************** */
  421. private function DialogCancelled_Handler(event:Event):void {
  422. this.Debug("Event: fileDialogComplete: File Dialog window cancelled.");
  423. ExternalCall.FileDialogComplete(this.fileDialogComplete_Callback, 0, 0, this.queued_uploads);
  424. }
  425. private function Open_Handler(event:Event):void {
  426. this.Debug("Event: uploadProgress (OPEN): File ID: " + this.current_file_item.id);
  427. this.current_file_item.finalUploadProgress = false;
  428. ExternalCall.UploadProgress(this.uploadProgress_Callback, this.current_file_item.ToJavaScriptObject(), 0, this.current_file_item.file_reference.size);
  429. }
  430. private function FileProgress_Handler(event:ProgressEvent):void {
  431. // On early than Mac OS X 10.3 bytesLoaded is always -1, convert this to zero. Do bytesTotal for good measure.
  432. // http://livedocs.adobe.com/flex/3/langref/flash/net/FileReference.html#event:progress
  433. var bytesLoaded:Number = event.bytesLoaded < 0 ? 0 : event.bytesLoaded;
  434. var bytesTotal:Number = event.bytesTotal < 0 ? 0 : event.bytesTotal;
  435. // Because Flash never fires a complete event if the server doesn't respond after 30 seconds or on Macs if there
  436. // is no content in the response we'll set a timer and assume that the upload is successful after the defined amount of
  437. // time. If the timeout is zero then we won't use the timer.
  438. if (bytesLoaded === bytesTotal) {
  439. this.current_file_item.finalUploadProgress = true;
  440. if (bytesTotal > 0 && this.assumeSuccessTimeout > 0) {
  441. if (this.assumeSuccessTimer !== null) {
  442. this.assumeSuccessTimer.stop();
  443. this.assumeSuccessTimer = null;
  444. }
  445. this.assumeSuccessTimer = new Timer(this.assumeSuccessTimeout * 1000, 1);
  446. this.assumeSuccessTimer.addEventListener(TimerEvent.TIMER_COMPLETE, AssumeSuccessTimer_Handler);
  447. this.assumeSuccessTimer.start();
  448. }
  449. }
  450. this.Debug("Event: uploadProgress: File ID: " + this.current_file_item.id + ". Bytes: " + bytesLoaded + ". Total: " + bytesTotal);
  451. ExternalCall.UploadProgress(this.uploadProgress_Callback, this.current_file_item.ToJavaScriptObject(), bytesLoaded, bytesTotal);
  452. }
  453. private function AssumeSuccessTimer_Handler(event:TimerEvent):void {
  454. this.Debug("Event: AssumeSuccess: " + this.assumeSuccessTimeout + " passed without server response");
  455. this.UploadSuccess(this.current_file_item, "", false);
  456. }
  457. private function Complete_Handler(event:Event):void {
  458. /* Because we can't do COMPLETE or DATA events (we have to do both) we can't
  459. * just call uploadSuccess from the complete handler, we have to wait for
  460. * the Data event which may never come. However, testing shows it always comes
  461. * within a couple milliseconds if it is going to come so the solution is:
  462. *
  463. * Set a timer in the COMPLETE event (which always fires) and if DATA is fired
  464. * it will stop the timer and call uploadComplete
  465. *
  466. * If the timer expires then DATA won't be fired and we call uploadComplete
  467. * */
  468. // Set the timer
  469. if (serverDataTimer != null) {
  470. this.serverDataTimer.stop();
  471. this.serverDataTimer = null;
  472. }
  473. this.serverDataTimer = new Timer(100, 1);
  474. //var self:SWFUpload = this;
  475. this.serverDataTimer.addEventListener(TimerEvent.TIMER, this.ServerDataTimer_Handler);
  476. this.serverDataTimer.start();
  477. }
  478. private function ServerDataTimer_Handler(event:TimerEvent):void {
  479. this.UploadSuccess(this.current_file_item, "");
  480. }
  481. private function ServerData_Handler(event:DataEvent):void {
  482. this.UploadSuccess(this.current_file_item, event.data);
  483. }
  484. private function UploadSuccess(file:FileItem, serverData:String, responseReceived:Boolean = true):void {
  485. if (this.serverDataTimer !== null) {
  486. this.serverDataTimer.stop();
  487. this.serverDataTimer = null;
  488. }
  489. if (this.assumeSuccessTimer !== null) {
  490. this.assumeSuccessTimer.stop();
  491. this.assumeSuccessTimer = null;
  492. }
  493. // If the 100% upload progress hasn't been called then call it now
  494. if (!file.finalUploadProgress) {
  495. file.finalUploadProgress = true;
  496. this.Debug("Event: uploadProgress (simulated 100%): File ID: " + file.id + ". Bytes: " + file.file_reference.size + ". Total: " + file.file_reference.size);
  497. ExternalCall.UploadProgress(this.uploadProgress_Callback, file.ToJavaScriptObject(), file.file_reference.size, file.file_reference.size);
  498. }
  499. this.successful_uploads++;
  500. file.file_status = FileItem.FILE_STATUS_SUCCESS;
  501. this.Debug("Event: uploadSuccess: File ID: " + file.id + " Response Received: " + responseReceived.toString() + " Data: " + serverData);
  502. ExternalCall.UploadSuccess(this.uploadSuccess_Callback, file.ToJavaScriptObject(), serverData, responseReceived);
  503. this.UploadComplete(false);
  504. }
  505. private function HTTPError_Handler(event:HTTPStatusEvent):void {
  506. var isSuccessStatus:Boolean = false;
  507. for (var i:Number = 0; i < this.httpSuccess.length; i++) {
  508. if (this.httpSuccess[i] === event.status) {
  509. isSuccessStatus = true;
  510. break;
  511. }
  512. }
  513. if (isSuccessStatus) {
  514. this.Debug("Event: httpError: Translating status code " + event.status + " to uploadSuccess");
  515. var serverDataEvent:DataEvent = new DataEvent(DataEvent.UPLOAD_COMPLETE_DATA, event.bubbles, event.cancelable, "");
  516. this.ServerData_Handler(serverDataEvent);
  517. } else {
  518. this.upload_errors++;
  519. this.current_file_item.file_status = FileItem.FILE_STATUS_ERROR;
  520. this.Debug("Event: uploadError: HTTP ERROR : File ID: " + this.current_file_item.id + ". HTTP Status: " + event.status + ".");
  521. ExternalCall.UploadError(this.uploadError_Callback, this.ERROR_CODE_HTTP_ERROR, this.current_file_item.ToJavaScriptObject(), event.status.toString());
  522. this.UploadComplete(true); // An IO Error is also called so we don't want to complete the upload yet.
  523. }
  524. }
  525. // Note: Flash Player does not support Uploads that require authentication. Attempting this will trigger an
  526. // IO Error or it will prompt for a username and password and may crash the browser (FireFox/Opera)
  527. private function IOError_Handler(event:IOErrorEvent):void {
  528. // Only trigger an IO Error event if we haven't already done an HTTP error
  529. if (this.current_file_item.file_status != FileItem.FILE_STATUS_ERROR) {
  530. this.upload_errors++;
  531. this.current_file_item.file_status = FileItem.FILE_STATUS_ERROR;
  532. this.Debug("Event: uploadError : IO Error : File ID: " + this.current_file_item.id + ". IO Error: " + event.text);
  533. ExternalCall.UploadError(this.uploadError_Callback, this.ERROR_CODE_IO_ERROR, this.current_file_item.ToJavaScriptObject(), event.text);
  534. }
  535. this.UploadComplete(true);
  536. }
  537. private function SecurityError_Handler(event:SecurityErrorEvent):void {
  538. this.upload_errors++;
  539. this.current_file_item.file_status = FileItem.FILE_STATUS_ERROR;
  540. this.Debug("Event: uploadError : Security Error : File Number: " + this.current_file_item.id + ". Error text: " + event.text);
  541. ExternalCall.UploadError(this.uploadError_Callback, this.ERROR_CODE_SECURITY_ERROR, this.current_file_item.ToJavaScriptObject(), event.text);
  542. this.UploadComplete(true);
  543. }
  544. private function Select_Many_Handler(event:Event):void {
  545. this.Select_Handler(this.fileBrowserMany.fileList);
  546. }
  547. private function Select_One_Handler(event:Event):void {
  548. var fileArray:Array = new Array(1);
  549. fileArray[0] = this.fileBrowserOne;
  550. this.Select_Handler(fileArray);
  551. }
  552. private function Select_Handler(file_reference_list:Array):void {
  553. this.Debug("Select Handler: Received the files selected from the dialog. Processing the file list...");
  554. var num_files_queued:Number = 0;
  555. // Determine how many queue slots are remaining (check the unlimited (0) settings, successful uploads and queued uploads)
  556. var queue_slots_remaining:Number = 0;
  557. if (this.fileUploadLimit == 0) {
  558. queue_slots_remaining = this.fileQueueLimit == 0 ? file_reference_list.length : (this.fileQueueLimit - this.queued_uploads); // If unlimited queue make the allowed size match however many files were selected.
  559. } else {
  560. var remaining_uploads:Number = this.fileUploadLimit - this.successful_uploads - this.queued_uploads;
  561. if (remaining_uploads < 0) remaining_uploads = 0;
  562. if (this.fileQueueLimit == 0 || this.fileQueueLimit >= remaining_uploads) {
  563. queue_slots_remaining = remaining_uploads;
  564. } else if (this.fileQueueLimit < remaining_uploads) {
  565. queue_slots_remaining = this.fileQueueLimit - this.queued_uploads;
  566. }
  567. }
  568. if (queue_slots_remaining < 0) queue_slots_remaining = 0;
  569. // Check if the number of files selected is greater than the number allowed to queue up.
  570. if (queue_slots_remaining < file_reference_list.length) {
  571. this.Debug("Event: fileQueueError : Selected Files (" + file_reference_list.length + ") exceeds remaining Queue size (" + queue_slots_remaining + ").");
  572. ExternalCall.FileQueueError(this.fileQueueError_Callback, this.ERROR_CODE_QUEUE_LIMIT_EXCEEDED, null, queue_slots_remaining.toString());
  573. } else {
  574. // Process each selected file
  575. for (var i:Number = 0; i < file_reference_list.length; i++) {
  576. var file_item:FileItem = new FileItem(file_reference_list[i], this.movieName, this.file_index.length);
  577. this.file_index[file_item.index] = file_item;
  578. // Verify that the file is accessible. Zero byte files and possibly other conditions can cause a file to be inaccessible.
  579. var jsFileObj:Object = file_item.ToJavaScriptObject();
  580. var is_valid_file_reference:Boolean = (jsFileObj.filestatus !== FileItem.FILE_STATUS_ERROR);
  581. if (is_valid_file_reference) {
  582. // Check the size, if it's within the limit add it to the upload list.
  583. var size_result:Number = this.CheckFileSize(file_item);
  584. var is_valid_filetype:Boolean = this.CheckFileType(file_item);
  585. if(size_result == this.SIZE_OK && is_valid_filetype) {
  586. file_item.file_status = FileItem.FILE_STATUS_QUEUED;
  587. this.file_queue.push(file_item);
  588. this.queued_uploads++;
  589. num_files_queued++;
  590. this.Debug("Event: fileQueued : File ID: " + file_item.id);
  591. ExternalCall.FileQueued(this.fileQueued_Callback, file_item.ToJavaScriptObject());
  592. }
  593. else if (!is_valid_filetype) {
  594. //file_item.file_reference = null; // Cleanup the object
  595. file_item.file_status = FileItem.FILE_STATUS_ERROR;
  596. this.queue_errors++;
  597. this.Debug("Event: fileQueueError : File not of a valid type.");
  598. ExternalCall.FileQueueError(this.fileQueueError_Callback, this.ERROR_CODE_INVALID_FILETYPE, file_item.ToJavaScriptObject(), "File is not an allowed file type.");
  599. }
  600. else if (size_result == this.SIZE_TOO_BIG) {
  601. //file_item.file_reference = null; // Cleanup the object
  602. file_item.file_status = FileItem.FILE_STATUS_ERROR;
  603. this.queue_errors++;
  604. this.Debug("Event: fileQueueError : File exceeds size limit.");
  605. ExternalCall.FileQueueError(this.fileQueueError_Callback, this.ERROR_CODE_FILE_EXCEEDS_SIZE_LIMIT, file_item.ToJavaScriptObject(), "File size exceeds allowed limit.");
  606. }
  607. else if (size_result == this.SIZE_ZERO_BYTE) {
  608. file_item.file_reference = null; // Cleanup the object
  609. file_item.file_status = FileItem.FILE_STATUS_ERROR;
  610. this.queue_errors++;
  611. this.Debug("Event: fileQueueError : File is zero bytes.");
  612. ExternalCall.FileQueueError(this.fileQueueError_Callback, this.ERROR_CODE_ZERO_BYTE_FILE, file_item.ToJavaScriptObject(), "File is zero bytes and cannot be uploaded.");
  613. }
  614. } else {
  615. file_item.file_reference = null; // Cleanup the object
  616. file_item.file_status = FileItem.FILE_STATUS_ERROR;
  617. this.queue_errors++;
  618. this.Debug("Event: fileQueueError : File is zero bytes or FileReference is invalid.");
  619. ExternalCall.FileQueueError(this.fileQueueError_Callback, this.ERROR_CODE_ZERO_BYTE_FILE, file_item.ToJavaScriptObject(), "File is zero bytes or cannot be accessed and cannot be uploaded.");
  620. }
  621. }
  622. }
  623. this.Debug("Event: fileDialogComplete : Finished processing selected files. Files selected: " + file_reference_list.length + ". Files Queued: " + num_files_queued);
  624. ExternalCall.FileDialogComplete(this.fileDialogComplete_Callback, file_reference_list.length, num_files_queued, this.queued_uploads);
  625. }
  626. /* ****************************************************************
  627. Externally exposed functions
  628. ****************************************************************** */
  629. // Opens a file browser dialog that allows one file to be selected.
  630. private function SelectFile():void {
  631. this.fileBrowserOne = new FileReference();
  632. this.fileBrowserOne.addEventListener(Event.SELECT, this.Select_One_Handler);
  633. this.fileBrowserOne.addEventListener(Event.CANCEL, this.DialogCancelled_Handler);
  634. // Default file type settings
  635. var allowed_file_types:String = "*.*";
  636. var allowed_file_types_description:String = "All Files";
  637. // Get the instance settings
  638. if (this.fileTypes.length > 0) allowed_file_types = this.fileTypes;
  639. if (this.fileTypesDescription.length > 0) allowed_file_types_description = this.fileTypesDescription;
  640. this.Debug("Event: fileDialogStart : Browsing files. Single Select. Allowed file types: " + allowed_file_types);
  641. ExternalCall.Simple(this.fileDialogStart_Callback);
  642. try {
  643. this.fileBrowserOne.browse([new FileFilter(allowed_file_types_description, allowed_file_types)]);
  644. } catch (ex:Error) {
  645. this.Debug("Exception: " + ex.toString());
  646. }
  647. }
  648. // Opens a file browser dialog that allows multiple files to be selected.
  649. private function SelectFiles():void {
  650. var allowed_file_types:String = "*.*";
  651. var allowed_file_types_description:String = "All Files";
  652. if (this.fileTypes.length > 0) allowed_file_types = this.fileTypes;
  653. if (this.fileTypesDescription.length > 0) allowed_file_types_description = this.fileTypesDescription;
  654. this.Debug("Event: fileDialogStart : Browsing files. Multi Select. Allowed file types: " + allowed_file_types);
  655. ExternalCall.Simple(this.fileDialogStart_Callback);
  656. try {
  657. this.fileBrowserMany.browse([new FileFilter(allowed_file_types_description, allowed_file_types)]);
  658. } catch (ex:Error) {
  659. this.Debug("Exception: " + ex.toString());
  660. }
  661. }
  662. // Cancel the current upload and stops. Doesn't advance the upload pointer. The current file is requeued at the beginning.
  663. private function StopUpload():void {
  664. if (this.current_file_item != null) {
  665. // Cancel the upload and re-queue the FileItem
  666. if (this.current_file_item.upload_type === FileItem.UPLOAD_TYPE_NORMAL) {
  667. this.current_file_item.file_reference.cancel();
  668. } else {
  669. if (this.current_file_item.resized_uploader != null) {
  670. this.current_file_item.resized_uploader.cancel();
  671. this.current_file_item.resized_uploader = null;
  672. }
  673. }
  674. // Remove the event handlers
  675. this.removeEventListeners(this.current_file_item);
  676. this.current_file_item.upload_type = FileItem.UPLOAD_TYPE_NORMAL;
  677. this.current_file_item.file_status = FileItem.FILE_STATUS_QUEUED;
  678. this.file_queue.unshift(this.current_file_item);
  679. var js_object:Object = this.current_file_item.ToJavaScriptObject();
  680. this.current_file_item = null;
  681. this.Debug("Event: uploadError: upload stopped. File ID: " + js_object.ID);
  682. ExternalCall.UploadError(this.uploadError_Callback, this.ERROR_CODE_UPLOAD_STOPPED, js_object, "Upload Stopped");
  683. this.Debug("Event: uploadComplete. File ID: " + js_object.ID);
  684. ExternalCall.UploadComplete(this.uploadComplete_Callback, js_object);
  685. this.Debug("StopUpload(): upload stopped.");
  686. } else {
  687. this.Debug("StopUpload(): No file is currently uploading. Nothing to do.");
  688. }
  689. }
  690. /* Cancels the upload specified by file_id
  691. * If the file is currently uploading it is cancelled and the uploadComplete
  692. * event gets called.
  693. * If the file is not currently uploading then only the uploadCancelled event is fired.
  694. *
  695. * The triggerComplete is used by the resize stuff to cancel the upload
  696. * */
  697. private function CancelUpload(file_id:String, triggerErrorEvent:Boolean = true):void {
  698. var file_item:FileItem = null;
  699. // Check the current file item
  700. if (this.current_file_item != null && (this.current_file_item.id == file_id || !file_id)) {
  701. if (this.current_file_item.upload_type === FileItem.UPLOAD_TYPE_NORMAL) {
  702. this.current_file_item.file_reference.cancel();
  703. } else {
  704. if (this.current_file_item.resized_uploader != null) {
  705. this.current_file_item.resized_uploader.cancel();
  706. this.current_file_item.resized_uploader = null;
  707. }
  708. }
  709. this.current_file_item.file_status = FileItem.FILE_STATUS_CANCELLED;
  710. this.current_file_item.upload_type = FileItem.UPLOAD_TYPE_NORMAL;
  711. this.upload_cancelled++;
  712. if (triggerErrorEvent) {
  713. this.Debug("Event: uploadError: File ID: " + this.current_file_item.id + ". Cancelled current upload");
  714. ExternalCall.UploadError(this.uploadError_Callback, this.ERROR_CODE_FILE_CANCELLED, this.current_file_item.ToJavaScriptObject(), "File Upload Cancelled.");
  715. } else {
  716. this.Debug("Event: cancelUpload: File ID: " + this.current_file_item.id + ". Cancelled current upload. Suppressed uploadError event.");
  717. }
  718. this.UploadComplete(false);
  719. } else if (file_id) {
  720. // Find the file in the queue
  721. var file_index:Number = this.FindIndexInFileQueue(file_id);
  722. if (file_index >= 0) {
  723. // Remove the file from the queue
  724. file_item = FileItem(this.file_queue[file_index]);
  725. file_item.file_status = FileItem.FILE_STATUS_CANCELLED;
  726. this.file_queue.splice(file_index, 1);
  727. this.queued_uploads--;
  728. this.upload_cancelled++;
  729. // Cancel the file (just for good measure) and make the callback
  730. if (file_item.upload_type === FileItem.UPLOAD_TYPE_NORMAL) {
  731. file_item.file_reference.cancel();
  732. } else {
  733. if (file_item.resized_uploader != null) {
  734. file_item.resized_uploader.cancel();
  735. file_item.resized_uploader = null;
  736. }
  737. }
  738. this.removeEventListeners(file_item);
  739. file_item.upload_type = FileItem.UPLOAD_TYPE_NORMAL;
  740. if (triggerErrorEvent) {
  741. this.Debug("Event: uploadError : " + file_item.id + ". Cancelled queued upload");
  742. ExternalCall.UploadError(this.uploadError_Callback, this.ERROR_CODE_FILE_CANCELLED, file_item.ToJavaScriptObject(), "File Cancelled");
  743. } else {
  744. this.Debug("Event: cancelUpload: File ID: " + file_item.id + ". Cancelled current upload. Suppressed uploadError event.");
  745. }
  746. // Get rid of the file object
  747. file_item = null;
  748. }
  749. } else {
  750. // Get the first file and cancel it
  751. while (this.file_queue.length > 0 && file_item == null) {
  752. // Check that File Reference is valid (if not make sure it's deleted and get the next one on the next loop)
  753. file_item = FileItem(this.file_queue.shift()); // Cast back to a FileItem
  754. if (typeof(file_item) == "undefined") {
  755. file_item = null;
  756. continue;
  757. }
  758. }
  759. if (file_item != null) {
  760. file_item.file_status = FileItem.FILE_STATUS_CANCELLED;
  761. this.queued_uploads--;
  762. this.upload_cancelled++;
  763. // Cancel the file (just for good measure) and make the callback
  764. if (file_item.upload_type === FileItem.UPLOAD_TYPE_NORMAL) {
  765. file_item.file_reference.cancel();
  766. } else {
  767. if (file_item.resized_uploader != null) {
  768. file_item.resized_uploader.cancel();
  769. file_item.resized_uploader = null;
  770. }
  771. }
  772. this.removeEventListeners(file_item);
  773. file_item.upload_type = FileItem.UPLOAD_TYPE_NORMAL;
  774. if (triggerErrorEvent) {
  775. this.Debug("Event: uploadError : " + file_item.id + ". Cancelled queued upload");
  776. ExternalCall.UploadError(this.uploadError_Callback, this.ERROR_CODE_FILE_CANCELLED, file_item.ToJavaScriptObject(), "File Cancelled");
  777. } else {
  778. this.Debug("Event: cancelUpload: File ID: " + file_item.id + ". Cancelled current upload. Suppressed uploadError event.");
  779. }
  780. // Get rid of the file object
  781. file_item = null;
  782. }
  783. }
  784. }
  785. /* Requeues the indicated file. Returns true if successful or if the file is
  786. * already in the queue. Otherwise returns false.
  787. * */
  788. private function RequeueUpload(fileIdentifier:*):Boolean {
  789. var file:FileItem = null;
  790. if (typeof(fileIdentifier) === "number") {
  791. var fileIndex:Number = Number(fileIdentifier);
  792. if (fileIndex >= 0 && fileIndex < this.file_index.length) {
  793. file = this.file_index[fileIndex];
  794. }
  795. } else if (typeof(fileIdentifier) === "string") {
  796. file = FindFileInFileIndex(String(fileIdentifier));
  797. } else {
  798. return false;
  799. }
  800. if (file !== null && file.file_reference !== null) {
  801. if (file.file_status === FileItem.FILE_STATUS_IN_PROGRESS || file.file_status === FileItem.FILE_STATUS_NEW) {
  802. return false;
  803. } else if (file.file_status !== FileItem.FILE_STATUS_QUEUED) {
  804. file.file_status = FileItem.FILE_STATUS_QUEUED;
  805. this.file_queue.unshift(file);
  806. this.queued_uploads++;
  807. }
  808. return true;
  809. } else {
  810. return false;
  811. }
  812. }
  813. private function GetStats():Object {
  814. return {
  815. in_progress : this.current_file_item == null ? 0 : 1,
  816. files_queued : this.queued_uploads,
  817. successful_uploads : this.successful_uploads,
  818. upload_errors : this.upload_errors,
  819. upload_cancelled : this.upload_cancelled,
  820. queue_errors : this.queue_errors
  821. };
  822. }
  823. private function SetStats(stats:Object):void {
  824. this.successful_uploads = typeof(stats["successful_uploads"]) === "number" ? stats["successful_uploads"] : this.successful_uploads;
  825. this.upload_errors = typeof(stats["upload_errors"]) === "number" ? stats["upload_errors"] : this.upload_errors;
  826. this.upload_cancelled = typeof(stats["upload_cancelled"]) === "number" ? stats["upload_cancelled"] : this.upload_cancelled;
  827. this.queue_errors = typeof(stats["queue_errors"]) === "number" ? stats["queue_errors"] : this.queue_errors;
  828. }
  829. private function GetFile(file_id:String):Object {
  830. var file_index:Number = this.FindIndexInFileQueue(file_id);
  831. if (file_index >= 0) {
  832. var file:FileItem = this.file_queue[file_index];
  833. } else {
  834. if (this.current_file_item != null) {
  835. file = this.current_file_item;
  836. } else {
  837. for (var i:Number = 0; i < this.file_queue.length; i++) {
  838. file = this.file_queue[i];
  839. if (file != null) break;
  840. }
  841. }
  842. }
  843. if (file == null) {
  844. return null;
  845. } else {
  846. return file.ToJavaScriptObject();
  847. }
  848. }
  849. private function GetFileByIndex(index:Number):Object {
  850. if (index < 0 || index > this.file_index.length - 1) {
  851. return null;
  852. } else {
  853. return this.file_index[index].ToJavaScriptObject();
  854. }
  855. }
  856. private function GetFileByQueueIndex(index:Number):Object {
  857. if (index < 0 || index > this.file_queue.length - 1) {
  858. return null;
  859. } else {
  860. return this.file_queue[index].ToJavaScriptObject();
  861. }
  862. }
  863. private function AddFileParam(file_id:String, name:String, value:String):Boolean {
  864. var item:FileItem = this.FindFileInFileIndex(file_id);
  865. if (item != null) {
  866. item.AddParam(name, value);
  867. return true;
  868. }
  869. else {
  870. return false;
  871. }
  872. }
  873. private function RemoveFileParam(file_id:String, name:String):Boolean {
  874. var item:FileItem = this.FindFileInFileIndex(file_id);
  875. if (item != null) {
  876. item.RemoveParam(name);
  877. return true;
  878. }
  879. else {
  880. return false;
  881. }
  882. }
  883. private function SetUploadURL(url:String):void {
  884. if (typeof(url) !== "undefined" && url !== "") {
  885. this.uploadURL = url;
  886. }
  887. }
  888. private function SetPostParams(post_object:Object):void {
  889. if (typeof(post_object) !== "undefined" && post_object !== null) {
  890. this.uploadPostObject = post_object;
  891. }
  892. }
  893. private function SetFileTypes(types:String, description:String):void {
  894. this.fileTypes = types;
  895. this.fileTypesDescription = description;
  896. this.LoadFileExensions(this.fileTypes);
  897. }
  898. // Sets the file size limit. Accepts size values with units: 100 b, 1KB, 23Mb, 4 Gb
  899. // Parsing is not robust. "100 200 MB KB B GB" parses as "100 MB"
  900. private function SetFileSizeLimit(size:String):void {
  901. var value:Number = 0;
  902. var unit:String = "kb";
  903. // Trim the string
  904. var trimPattern:RegExp = /^\s*|\s*$/;
  905. size = size.toLowerCase();
  906. size = size.replace(trimPattern, "");
  907. // Get the value part
  908. var values:Array = size.match(/^\d+/);
  909. if (values !== null && values.length > 0) {
  910. value = parseInt(values[0]);
  911. }
  912. if (isNaN(value) || value < 0) value = 0;
  913. // Get the units part
  914. var units:Array = size.match(/(b|kb|mb|gb)/);
  915. if (units != null && units.length > 0) {
  916. unit = units[0];
  917. }
  918. // Set the multiplier for converting the unit to bytes
  919. var multiplier:Number = 1024;
  920. if (unit === "b")
  921. multiplier = 1;
  922. else if (unit === "mb")
  923. multiplier = 1048576;
  924. else if (unit === "gb")
  925. multiplier = 1073741824;
  926. this.fileSizeLimit = value * multiplier;
  927. }
  928. private function SetFileUploadLimit(file_upload_limit:Number):void {
  929. if (file_upload_limit < 0) file_upload_limit = 0;
  930. this.fileUploadLimit = file_upload_limit;
  931. }
  932. private function SetFileQueueLimit(file_queue_limit:Number):void {
  933. if (file_queue_limit < 0) file_queue_limit = 0;
  934. this.fileQueueLimit = file_queue_limit;
  935. }
  936. private function SetFilePostName(file_post_name:String):void {
  937. if (file_post_name != "") {
  938. this.filePostName = file_post_name;
  939. }
  940. }
  941. private function SetUseQueryString(use_query_string:Boolean):void {
  942. this.useQueryString = use_query_string;
  943. }
  944. private function SetRequeueOnError(requeue_on_error:Boolean):void {
  945. this.requeueOnError = requeue_on_error;
  946. }
  947. private function SetHTTPSuccess(http_status_codes:*):void {
  948. this.httpSuccess = [];
  949. if (typeof http_status_codes === "string") {
  950. var status_code_strings:Array = http_status_codes.replace(" ", "").split(",");
  951. for each (var http_status_string:String in status_code_strings)
  952. {
  953. try {
  954. this.httpSuccess.push(Number(http_status_string));
  955. } catch (ex:Object) {
  956. // Ignore errors
  957. this.Debug("Could not add HTTP Success code: " + http_status_string);
  958. }
  959. }
  960. }
  961. else if (typeof http_status_codes === "object" && typeof http_status_codes.length === "number") {
  962. for each (var http_status:* in http_status_codes)
  963. {
  964. try {
  965. this.Debug("adding: " + http_status);
  966. this.httpSuccess.push(Number(http_status));
  967. } catch (ex:Object) {
  968. this.Debug("Could not add HTTP Success code: " + http_status);
  969. }
  970. }
  971. }
  972. }
  973. private function SetAssumeSuccessTimeout(timeout_seconds:Number):void {
  974. this.assumeSuccessTimeout = timeout_seconds < 0 ? 0 : timeout_seconds;
  975. }
  976. private function SetDebugEnabled(debug_enabled:Boolean):void {
  977. this.debugEnabled = debug_enabled;
  978. }
  979. /* *************************************************************
  980. Button Handling Functions
  981. *************************************************************** */
  982. private function SetButtonImageURL(button_image_url:String):void {
  983. this.buttonImageURL = button_image_url;
  984. try {
  985. if (this.buttonImageURL !== null && this.buttonImageURL !== "") {
  986. this.buttonLoader.load(new URLRequest(this.buttonImageURL));
  987. }
  988. } catch (ex:Object) {
  989. }
  990. }
  991. private function ButtonImageLoaded(e:Event):void {
  992. this.Debug("Button Image Loaded");
  993. this.HandleStageResize(null);
  994. }
  995. private function ButtonClickHandler(e:MouseEvent):void {
  996. if (!this.buttonStateDisabled) {
  997. if (this.buttonAction === this.BUTTON_ACTION_SELECT_FILE) {
  998. this.SelectFile();
  999. }
  1000. else if (this.buttonAction === this.BUTTON_ACTION_START_UPLOAD) {
  1001. this.StartUpload();
  1002. }
  1003. else if (this.buttonAction === this.BUTTON_ACTION_NONE) {
  1004. ExternalCall.Simple(this.mouseClick_Callback);
  1005. }
  1006. else {
  1007. this.SelectFiles();
  1008. }
  1009. } else {
  1010. ExternalCall.Simple(this.mouseClick_Callback);
  1011. }
  1012. }
  1013. private function UpdateButtonState():void {
  1014. var xOffset:Number = 0;
  1015. var yOffset:Number = 0;
  1016. this.buttonLoader.x = xOffset;
  1017. this.buttonLoader.y = yOffset;
  1018. if (this.buttonStateDisabled) {
  1019. this.buttonLoader.y = (this.buttonLoader.height / 4) * -3 + yOffset;
  1020. }
  1021. else if (this.buttonStateMouseDown) {
  1022. this.buttonLoader.y = (this.buttonLoader.height / 4) * -2 + yOffset;
  1023. }
  1024. else if (this.buttonStateOver) {
  1025. this.buttonLoader.y = (this.buttonLoader.height / 4) * -1 + yOffset;
  1026. }
  1027. else {
  1028. this.buttonLoader.y = -yOffset;
  1029. }
  1030. };
  1031. private function SetButtonText(button_text:String):void {
  1032. this.buttonText = button_text;
  1033. this.SetButtonTextStyle(this.buttonTextStyle);
  1034. }
  1035. private function SetButtonTextStyle(button_text_style:String):void {
  1036. this.buttonTextStyle = button_text_style;
  1037. var style:StyleSheet = new StyleSheet();
  1038. style.parseCSS(this.buttonTextStyle);
  1039. this.buttonTextField.styleSheet = style;
  1040. this.buttonTextField.htmlText = th