PageRenderTime 28ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/src/uploader/as/Uploader.as

https://github.com/open-webos/yui3
ActionScript | 980 lines | 531 code | 216 blank | 233 comment | 62 complexity | 747ef5df2eb81e9f4d2689958886896a MD5 | raw file
  1. package
  2. {
  3. import com.yahoo.util.YUIBridge;
  4. import flash.display.Loader;
  5. import flash.display.Sprite;
  6. import flash.display.StageAlign;
  7. import flash.display.StageScaleMode;
  8. import flash.events.DataEvent;
  9. import flash.events.Event;
  10. import flash.events.FocusEvent;
  11. import flash.events.HTTPStatusEvent;
  12. import flash.events.IOErrorEvent;
  13. import flash.events.KeyboardEvent;
  14. import flash.events.MouseEvent;
  15. import flash.events.ProgressEvent;
  16. import flash.events.SecurityErrorEvent;
  17. import flash.external.ExternalInterface;
  18. import flash.net.FileFilter;
  19. import flash.net.FileReference;
  20. import flash.net.FileReferenceList;
  21. import flash.net.URLRequest;
  22. import flash.net.URLVariables;
  23. import flash.ui.Keyboard;
  24. import flash.utils.Dictionary;
  25. [SWF(backgroundColor=0xFFFFFF)]
  26. /**
  27. * The base Uploader class for YUI's Flash-based file uploader.
  28. *
  29. * @author Allen Rabinovich
  30. */
  31. public class Uploader extends Sprite {
  32. //--------------------------------------
  33. // Constructor
  34. //--------------------------------------
  35. public function Uploader()
  36. {
  37. super();
  38. yuiBridge = new YUIBridge(this.stage);
  39. logMessage("Initializing uploader...");
  40. initializeComponent();
  41. }
  42. //--------------------------------------------------------------------------
  43. //
  44. // Variables
  45. //
  46. //--------------------------------------------------------------------------
  47. private var allowMultiple:Boolean = false;
  48. private var allowLog:Boolean = false;
  49. private var filterArray:Array;
  50. private var fileDataList:Object;
  51. private var fileRefList:Object;
  52. private var fileIDList:Dictionary;
  53. private var fileIDCounter:Number;
  54. private var filesToUpload:Array;
  55. private var singleFile:FileReference;
  56. private var multipleFiles:FileReferenceList;
  57. public var yuiBridge:YUIBridge;
  58. /**
  59. * Determines how many files will be uploaded simultaneously
  60. *
  61. * @see setSimUploadLimit
  62. * @langversion 3.0
  63. * @playerversion Flash 9.0.28.0
  64. */
  65. public var simultaneousUploadLimit:Number = 2;
  66. // Track the number of current upload threads
  67. private var currentUploadThreads:Number = 0;
  68. // How the uploader is rendered, either "button" or "transparent"
  69. private var renderType:String;
  70. // The Sprite containing the rendered UI.
  71. private var buttonSprite:Sprite = new Sprite();
  72. // The skin for the button, if "button" renderType is used.
  73. private var buttonSkin:Loader = new Loader();
  74. // Height and width for the button
  75. private var buttonHeight:Number;
  76. private var buttonWidth:Number;
  77. //--------------------------------------
  78. // Public Methods
  79. //--------------------------------------
  80. /**
  81. * Sets the number of simultaneous file uploads possible.
  82. * The maximum is 5.
  83. * @param numberOfUploads Number of simultaneous uploads, no fewer than 1
  84. * and no larger than 5.
  85. */
  86. public function setSimUploadLimit (simUploadLimit:int) : void {
  87. if (simUploadLimit <= 1) {
  88. this.simultaneousUploadLimit = 1;
  89. logMessage("Simultaneous upload limit has been set to 1");
  90. }
  91. else if (simUploadLimit >= 5) {
  92. this.simultaneousUploadLimit = 5;
  93. logMessage("Simultaneous upload limit has been set to 5");
  94. }
  95. else {
  96. this.simultaneousUploadLimit = simUploadLimit;
  97. logMessage("Simultaneous upload limit has been set to " + simUploadLimit);
  98. }
  99. }
  100. /**
  101. * Sets a list of file type filters for the "Open File(s)" dialog.
  102. *
  103. * @param newFilterArray An array of sets of key-value pairs of the form
  104. * {extensions: extensionString, description: descriptionString, macType: macTypeString [optional]}
  105. * The extension string is a semicolon-delimited list of elements of the form "*.xxx",
  106. * e.g. "*.jpg;*.gif;*.png".
  107. */
  108. public function setFileFilters(newFilterArray:Array) : void {
  109. filterArray = processFileFilterObjects(newFilterArray);
  110. if (allowLog) {
  111. var logString:String = "File filters have been set to the following: \n";
  112. for each (var ff:FileFilter in filterArray) {
  113. logString += ff.extension + ": " + ff.description + "\n";
  114. }
  115. logMessage(logString);
  116. }
  117. }
  118. /**
  119. * Sets a flag allowing logging in Flash trace and Yahoo logger.
  120. *
  121. * @param allowLogging Whether to allow log messages.
  122. *
  123. */
  124. public function setAllowLogging(allowLogging:Boolean) : void {
  125. if (this.allowLog != allowLogging) {
  126. logMessage("Logging has been turned " + (allowLogging ? "on." : "off."));
  127. this.allowLog = allowLogging;
  128. }
  129. }
  130. /**
  131. * Sets a flag allowing multiple file selection in the "Browse" dialog.
  132. *
  133. * @param allowMultiple Whether to allow multiple file selection.
  134. *
  135. */
  136. public function setAllowMultipleFiles(allowMultipleFiles:Boolean) : void {
  137. this.allowMultiple = allowMultipleFiles;
  138. logMessage("Multiple file upload has been turned " + (allowMultiple ? "on." : "off."));
  139. }
  140. /**
  141. * Triggers a prompt for the user to browse their file system to select
  142. * files to be uploaded.
  143. *
  144. * @param allowMultiple Whether to allow the user to select more than
  145. * one file
  146. *
  147. * @param filterArray An array of filter objects, each with <code>
  148. * description</code>, and <code>extensions</code> properties which
  149. * determine which files the user is allowed to select
  150. */
  151. private function browse(allowMultiple:Boolean = false, filterArray:Array = null):void {
  152. if(!allowMultiple) {
  153. logMessage("Starting to browse for a single file...")
  154. singleFile = new FileReference();
  155. singleFile.addEventListener(Event.SELECT, singleFileSelected);
  156. if(filterArray) {
  157. singleFile.browse(filterArray);
  158. }
  159. else {
  160. singleFile.browse();
  161. }
  162. }
  163. else {
  164. logMessage("Starting to browse for multiple files...")
  165. multipleFiles = new FileReferenceList();
  166. multipleFiles.addEventListener(Event.SELECT, multipleFilesSelected);
  167. if(filterArray) {
  168. multipleFiles.browse(filterArray);
  169. }
  170. else {
  171. multipleFiles.browse();
  172. }
  173. }
  174. }
  175. /**
  176. * Removes the file from the set to be uploaded
  177. *
  178. * @param fileID The ID of the file to be removed
  179. */
  180. public function removeFile(fileID:String):Object {
  181. logMessage("Removing file " + fileID);
  182. delete fileDataList[fileID];
  183. delete fileRefList[fileID];
  184. logMessage("Returning new file list: " + fileDataList);
  185. return fileDataList;
  186. }
  187. public function enable () : void {
  188. if (renderType == "button") {
  189. this.addEventListener(MouseEvent.ROLL_OVER, buttonMouseOver);
  190. this.addEventListener(MouseEvent.ROLL_OUT, buttonMouseOut);
  191. this.addEventListener(MouseEvent.MOUSE_DOWN, buttonMouseDown);
  192. this.addEventListener(MouseEvent.MOUSE_UP, buttonMouseUp);
  193. this.addEventListener(MouseEvent.CLICK, handleMouseClick);
  194. buttonSkin.y = 0;
  195. }
  196. else {
  197. this.addEventListener(MouseEvent.CLICK, handleMouseClick);
  198. this.addEventListener(MouseEvent.CLICK, transparentClick);
  199. this.addEventListener(MouseEvent.MOUSE_DOWN, transparentDown);
  200. this.addEventListener(MouseEvent.MOUSE_UP, transparentUp);
  201. this.addEventListener(MouseEvent.ROLL_OVER, transparentRollOver);
  202. this.addEventListener(MouseEvent.ROLL_OUT, transparentRollOut);
  203. }
  204. logMessage("Uploader UI has been enabled.");
  205. }
  206. public function disable () : void {
  207. if (renderType == "button") {
  208. this.removeEventListener(MouseEvent.ROLL_OVER, buttonMouseOver);
  209. this.removeEventListener(MouseEvent.ROLL_OUT, buttonMouseOut);
  210. this.removeEventListener(MouseEvent.MOUSE_DOWN, buttonMouseDown);
  211. this.removeEventListener(MouseEvent.MOUSE_UP, buttonMouseUp);
  212. this.removeEventListener(MouseEvent.CLICK, handleMouseClick);
  213. buttonSkin.y = -3*buttonHeight;
  214. }
  215. else {
  216. this.removeEventListener(MouseEvent.CLICK, handleMouseClick);
  217. this.removeEventListener(MouseEvent.CLICK, transparentClick);
  218. this.removeEventListener(MouseEvent.MOUSE_DOWN, transparentDown);
  219. this.removeEventListener(MouseEvent.MOUSE_UP, transparentUp);
  220. this.removeEventListener(MouseEvent.ROLL_OVER, transparentRollOver);
  221. this.removeEventListener(MouseEvent.ROLL_OUT, transparentRollOut);
  222. }
  223. logMessage("Uploader UI has been disabled.");
  224. }
  225. /**
  226. * Clears the set of files that had been selected for upload
  227. */
  228. public function clearFileList():Boolean {
  229. filesToUpload = [];
  230. fileDataList = new Object();
  231. fileRefList = new Object();
  232. fileIDList = new Dictionary();
  233. fileIDCounter = 0;
  234. logMessage("The file list has been cleared.");
  235. return true;
  236. }
  237. /**
  238. * Uploads a file corresponding to a specified ID to a specified path where a script handles writing to the server.
  239. *
  240. * @param fileID The ID of the file to be uploaded
  241. * @param url The path to the serverside script
  242. * @param method The HTTP submission method. Possible values are "GET" and "POST"
  243. * @param vars An object containing variables to be sent along with the request
  244. * @param fieldName The field name that precedes the file data in the upload POST operation.
  245. * The uploadDataFieldName value must be non-null and a non-empty String.
  246. * @param headers An object containing variables that should be set as headers in the POST request. The following header names
  247. * cannot be used:
  248. * <code>
  249. * Accept-Charset, Accept-Encoding, Accept-Ranges, Age, Allow, Allowed, Authorization, Charge-To, Connect, Connection,
  250. * Content-Length, Content-Location, Content-Range, Cookie, Date, Delete, ETag, Expect, Get, Head, Host, Keep-Alive,
  251. * Last-Modified, Location, Max-Forwards, Options, Post, Proxy-Authenticate, Proxy-Authorization, Proxy-Connection,
  252. * Public, Put, Range, Referer, Request-Range, Retry-After, Server, TE, Trace, Trailer, Transfer-Encoding, Upgrade,
  253. * URI, User-Agent, Vary, Via, Warning, WWW-Authenticate, x-flash-version.
  254. * </code>
  255. */
  256. public function upload(fileID:String, url:String, method:String = "GET", vars:Object = null, fieldName:String = "Filedata"):void {
  257. // null checking in the params is not working correctly
  258. filesToUpload = [];
  259. if(isEmptyString(method)) {
  260. method = "GET";
  261. }
  262. if(isEmptyString(fieldName)) {
  263. fieldName = "Filedata";
  264. }
  265. var request:URLRequest = formURLRequest(url, method, vars);
  266. var fr:FileReference = fileRefList[fileID];
  267. this.currentUploadThreads++;
  268. fr.upload(request,fieldName);
  269. logMessage("Starting the upload of file " + fileID);
  270. }
  271. /**
  272. * Uploads the specified files to a specified path where a script handles writing to the server.
  273. *
  274. * @param fileIDs The IDs of the files to be uploaded
  275. * @param url The path to the serverside script
  276. * @param method The HTTP submission method. Possible values are "GET" and "POST"
  277. * @param vars An object containing data to be sent along with the request
  278. * @param fieldName The field name that precedes the file data in the upload POST operation. The uploadDataFieldName value must be non-null and a non-empty String.
  279. */
  280. public function uploadThese(fileIDs:Array, url:String, method:String = "GET", vars:Object = null, fieldName:String = "Filedata"):void {
  281. if(isEmptyString(method)) {
  282. method = "GET";
  283. }
  284. if(isEmptyString(fieldName)) {
  285. fieldName = "Filedata";
  286. }
  287. var request:URLRequest = formURLRequest(url, method, vars);
  288. for each(var fileID:String in fileIDs) {
  289. queueForUpload(fileRefList[fileID], request, fieldName);
  290. }
  291. processQueue();
  292. }
  293. /**
  294. * Uploads all files to a specified path where a script handles writing to the server.
  295. *
  296. * @param fileID The ID of the file to be uploaded
  297. * @param url The path to the serverside script
  298. * @param method The HTTP submission method. Possible values are "GET" and "POST"
  299. * @param vars An object containing data to be sent along with the request
  300. * @param fieldName The field name that precedes the file data in the upload POST operation. The uploadDataFieldName value must be non-null and a non-empty String.
  301. * @param headers An object containing variables that should be set as headers in the POST request. The following header names
  302. * cannot be used:
  303. * <code>
  304. * Accept-Charset, Accept-Encoding, Accept-Ranges, Age, Allow, Allowed, Authorization, Charge-To, Connect, Connection,
  305. * Content-Length, Content-Location, Content-Range, Cookie, Date, Delete, ETag, Expect, Get, Head, Host, Keep-Alive,
  306. * Last-Modified, Location, Max-Forwards, Options, Post, Proxy-Authenticate, Proxy-Authorization, Proxy-Connection,
  307. * Public, Put, Range, Referer, Request-Range, Retry-After, Server, TE, Trace, Trailer, Transfer-Encoding, Upgrade,
  308. * URI, User-Agent, Vary, Via, Warning, WWW-Authenticate, x-flash-version.
  309. * </code>
  310. */
  311. public function uploadAll(url:String, method:String = "GET", vars:Object = null, fieldName:String = "Filedata", headers:Object = null):void {
  312. if(isEmptyString(method)) {
  313. method = "GET";
  314. }
  315. if(isEmptyString(fieldName)) {
  316. fieldName = "Filedata";
  317. }
  318. var request:URLRequest = formURLRequest(url, method, vars);
  319. filesToUpload = [];
  320. // sort files in the order that they were given to us
  321. var fileIds:Array = [];
  322. for (var fileId:String in fileRefList) {
  323. fileIds.push(parseInt(fileId.substr(4)));
  324. }
  325. fileIds.sort(Array.NUMERIC);
  326. for each(var fileId2:int in fileIds) {
  327. queueForUpload(fileRefList["file"+fileId2], request, fieldName);
  328. }
  329. processQueue();
  330. }
  331. /**
  332. * Cancels either an upload of the file corresponding to a given fileID, or in the absence of the specified fileID, all active files being uploaded.
  333. *
  334. * @param fileID The ID of the file to be uploaded
  335. */
  336. public function cancel(fileID:String = null):void {
  337. logMessage("Canceling upload of " + fileID?fileID:"all files.");
  338. if (fileID == null) { // cancel all files
  339. for each (var item:FileReference in fileRefList) {
  340. item.cancel();
  341. }
  342. this.currentUploadThreads = 0;
  343. filesToUpload = [];
  344. }
  345. else { // cancel specified file
  346. var fr:FileReference = fileRefList[fileID];
  347. if (this.currentUploadThreads > 0)
  348. this.currentUploadThreads--;
  349. fr.cancel();
  350. }
  351. }
  352. /*
  353. Events
  354. -------------------------------
  355. mouseDown - fires when the mouse button is pressed over uploader
  356. mouseUp - fires when the mouse button is released over uploader
  357. rollOver - fires when the mouse rolls over the uploader
  358. rollOut - fires when the mouse rolls out of the uploader
  359. click - fires when the uploader is clicked
  360. fileSelect - fires when the user selects one or more files (after browse is called). Passes the array of currently selected files (if prior browse calls were made and clearFileList hasn't been called, all files the user has ever selected will be returned), along with all information available about them (name, size, type, creationDate, modificationDate, creator).
  361. uploadStart - fires when a file starts uploading. Passes a file id for identifying the file.
  362. uploadProgress - fires when a file upload reports progress. Passes the file id, as well as bytesUploaded and bytesTotal for the given file.
  363. uploadComplete - fires when a file upload is completed successfully and passes the corresponding file id.
  364. uploadCompleteData - fires when data is received from the server after upload and passes the corresponding file id and the said data.
  365. uploadError - fires when an error occurs during download. Passes the id of the file that was being uploaded and an error type.
  366. */
  367. private function transparentDown (event:MouseEvent) : void {
  368. logMessage("Dispatching mousedown event.");
  369. var newEvent:Object = new Object();
  370. newEvent.type = "mousedown";
  371. yuiBridge.sendEvent(newEvent);
  372. }
  373. private function transparentUp (event:MouseEvent) : void {
  374. logMessage("Dispatching mouseup event.");
  375. var newEvent:Object = new Object();
  376. newEvent.type = "mouseup";
  377. yuiBridge.sendEvent(newEvent);
  378. }
  379. private function transparentRollOver (event:MouseEvent) : void {
  380. logMessage("Dispatching mouseenter event.");
  381. var newEvent:Object = new Object();
  382. newEvent.type = "mouseenter";
  383. yuiBridge.sendEvent(newEvent);
  384. }
  385. private function transparentRollOut (event:MouseEvent) : void {
  386. logMessage("Dispatching mouseleave event.");
  387. var newEvent:Object = new Object();
  388. newEvent.type = "mouseleave";
  389. yuiBridge.sendEvent(newEvent);
  390. }
  391. private function transparentClick (event:MouseEvent) : void {
  392. logMessage("Dispatching click event.");
  393. var newEvent:Object = new Object();
  394. newEvent.type = "click";
  395. yuiBridge.sendEvent(newEvent);
  396. }
  397. private function uploadStart (event:Event) : void {
  398. logMessage("Dispatching uploadstart event for " + fileIDList[event.target]);
  399. var newEvent:Object = new Object();
  400. newEvent.id = fileIDList[event.target];
  401. newEvent.type = "uploadstart";
  402. yuiBridge.sendEvent(newEvent);
  403. }
  404. private function uploadProgress (event:ProgressEvent) : void {
  405. logMessage("Dispatching uploadprogress event for " + fileIDList[event.target] + ": " + event.bytesLoaded.toString() + " / " + event.bytesTotal.toString());
  406. var newEvent:Object = new Object();
  407. newEvent.id = fileIDList[event.target];
  408. newEvent.bytesLoaded = event.bytesLoaded;
  409. newEvent.bytesTotal = event.bytesTotal;
  410. newEvent.type = "uploadprogress"
  411. yuiBridge.sendEvent(newEvent);
  412. }
  413. private function uploadComplete (event:Event) : void {
  414. logMessage("Dispatching uploadcomplete event for " + fileIDList[event.target]);
  415. var newEvent:Object = new Object();
  416. newEvent.id = fileIDList[event.target];
  417. newEvent.type = "uploadcomplete"
  418. yuiBridge.sendEvent(newEvent);
  419. this.currentUploadThreads--;
  420. // get next off of queue:
  421. processQueue();
  422. }
  423. private function uploadCompleteData (event:DataEvent) : void {
  424. logMessage("Dispatching uploadcompletedata event for " + fileIDList[event.target] + ": ");
  425. logMessage("Received the following data: " + event.data);
  426. var newEvent:Object = new Object();
  427. newEvent.id = fileIDList[event.target];
  428. newEvent.data = event.data;
  429. newEvent.type = "uploadcompletedata"
  430. yuiBridge.sendEvent(newEvent);
  431. }
  432. private function uploadCancel (event:Event) : void {
  433. logMessage("Dispatching uploadcancel event for " + fileIDList[event.target]);
  434. var newEvent:Object = new Object();
  435. newEvent.id = fileIDList[event.target];
  436. newEvent.type = "uploadcancel";
  437. yuiBridge.sendEvent(newEvent);
  438. }
  439. private function uploadError (event:Event) : void {
  440. var newEvent:Object = {};
  441. if (event is HTTPStatusEvent) {
  442. var myev:HTTPStatusEvent = event as HTTPStatusEvent;
  443. newEvent.status = myev.status;
  444. logMessage("HTTP status error for " + fileIDList[event.target] + ": " + myev.status);
  445. }
  446. else if (event is IOErrorEvent) {
  447. newEvent.status = event.toString();
  448. logMessage("IO error for " + fileIDList[event.target] + ". Likely causes are problems with Internet connection or server misconfiguration.");
  449. }
  450. else if (event is SecurityErrorEvent) {
  451. newEvent.status = event.toString();
  452. logMessage("Security error for " + fileIDList[event.target]);
  453. }
  454. logMessage ("Dispatching error event for " + fileIDList[event.target]);
  455. newEvent.type = "uploaderror";
  456. newEvent.id = fileIDList[event.target];
  457. yuiBridge.sendEvent(newEvent);
  458. // get next off of queue:
  459. processQueue();
  460. }
  461. // Fired when the user selects a single file
  462. private function singleFileSelected(event:Event):void {
  463. this.clearFileList();
  464. addFile(event.target as FileReference);
  465. processSelection();
  466. }
  467. // Fired when the user selects multiple files
  468. private function multipleFilesSelected(event:Event):void {
  469. var currentFRL:FileReferenceList = multipleFiles;
  470. for each (var currentFR:FileReference in currentFRL.fileList) {
  471. addFile(currentFR);
  472. }
  473. processSelection();
  474. }
  475. private function renderAsButton (buttonSkinSprite:String) : void {
  476. logMessage("Rendering uploader as button...");
  477. buttonSkin.load(new URLRequest(buttonSkinSprite));
  478. var _this:Uploader = this;
  479. var initLoader:Function = function (event:Event) : void {
  480. buttonSprite.addChild(buttonSkin);
  481. buttonHeight = buttonSkin.height/4;
  482. buttonWidth = buttonSkin.width;
  483. var buttonMask:Sprite = new Sprite();
  484. buttonMask.graphics.beginFill(0x000000,1);
  485. buttonMask.graphics.drawRect(0,0,buttonWidth,buttonHeight);
  486. buttonMask.graphics.endFill();
  487. _this.addChild(buttonMask);
  488. buttonSprite.mask = buttonMask;
  489. var buttonStageResize:Function = function (evt:Event = null) : void {
  490. buttonSprite.width = _this.stage.stageWidth;
  491. buttonSprite.height = _this.stage.stageHeight*4;
  492. buttonMask.width = _this.stage.stageWidth;
  493. buttonMask.height = _this.stage.stageHeight;
  494. };
  495. buttonStageResize();
  496. _this.stage.scaleMode = StageScaleMode.NO_SCALE;
  497. _this.stage.align = StageAlign.TOP_LEFT;
  498. _this.stage.tabChildren = false;
  499. _this.stage.addEventListener(Event.RESIZE, buttonStageResize);
  500. _this.addEventListener(MouseEvent.ROLL_OVER, buttonMouseOver);
  501. _this.addEventListener(MouseEvent.ROLL_OUT, buttonMouseOut);
  502. _this.addEventListener(MouseEvent.MOUSE_DOWN, buttonMouseDown);
  503. _this.addEventListener(MouseEvent.MOUSE_UP, buttonMouseUp);
  504. _this.addEventListener(MouseEvent.CLICK, handleMouseClick);
  505. _this.stage.addEventListener(KeyboardEvent.KEY_DOWN, handleKeyDown);
  506. _this.stage.addEventListener(KeyboardEvent.KEY_UP, handleKeyUp);
  507. _this.addChild(buttonSprite);
  508. }
  509. var errorLoader:Function = function (event:IOErrorEvent) : void {
  510. renderAsTransparent();
  511. }
  512. buttonSkin.contentLoaderInfo.addEventListener(Event.COMPLETE, initLoader);
  513. buttonSkin.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, errorLoader);
  514. }
  515. private function buttonMouseOver (event:MouseEvent) : void {
  516. buttonSkin.y = -1*buttonHeight;
  517. }
  518. private function buttonMouseOut (event:MouseEvent) : void {
  519. buttonSkin.y = 0;
  520. }
  521. private function buttonMouseDown (event:MouseEvent) : void {
  522. buttonSkin.y = -2*buttonHeight;
  523. }
  524. private function buttonMouseUp (event:MouseEvent) : void {
  525. buttonSkin.y = 0;
  526. }
  527. private function renderAsTransparent () : void {
  528. logMessage("Rendering uploader as transparent overlay.");
  529. function transparentStageResize (evt:Event) : void {
  530. buttonSprite.width = buttonSprite.stage.stageWidth;
  531. buttonSprite.height = buttonSprite.stage.stageHeight;
  532. }
  533. buttonSprite.graphics.beginFill(0xffffff, 0);
  534. buttonSprite.graphics.drawRect(0,0,5,5);
  535. buttonSprite.width = this.stage.stageWidth;
  536. buttonSprite.height = this.stage.stageHeight;
  537. buttonSprite.graphics.endFill();
  538. this.stage.scaleMode = StageScaleMode.NO_SCALE;
  539. this.stage.align = StageAlign.TOP_LEFT;
  540. this.stage.tabChildren = false;
  541. this.stage.addEventListener(Event.RESIZE, transparentStageResize);
  542. this.addEventListener(MouseEvent.CLICK, handleMouseClick);
  543. this.addEventListener(MouseEvent.CLICK, transparentClick);
  544. this.addEventListener(MouseEvent.MOUSE_DOWN, transparentDown);
  545. this.addEventListener(MouseEvent.MOUSE_UP, transparentUp);
  546. this.addEventListener(MouseEvent.ROLL_OVER, transparentRollOver);
  547. this.addEventListener(MouseEvent.ROLL_OUT, transparentRollOut);
  548. this.buttonMode = true;
  549. this.useHandCursor = true;
  550. this.addChild(buttonSprite);
  551. }
  552. private function handleKeyDown (evt:KeyboardEvent) : void {
  553. if (evt.keyCode == Keyboard.ENTER || evt.keyCode == Keyboard.SPACE) {
  554. logMessage("Keyboard 'Enter' or 'Space' down.");
  555. buttonSkin.y = -2*buttonHeight;
  556. }
  557. }
  558. private function handleKeyUp (evt:KeyboardEvent) : void {
  559. if (evt.keyCode == Keyboard.ENTER || evt.keyCode == Keyboard.SPACE) {
  560. buttonSkin.y = 0;
  561. logMessage("Keyboard 'Enter' or 'Space' up.");
  562. logMessage("Keyboard 'Enter' or 'Space' detected, launching 'Open File' dialog.");
  563. this.browse(this.allowMultiple, this.filterArray);
  564. }
  565. }
  566. private function handleFocusIn (evt:FocusEvent) : void {
  567. logMessage("Focus is on the Uploader.");
  568. }
  569. private function handleFocusOut (evt:FocusEvent) : void {
  570. logMessage("Focus is out on the Uploader.");
  571. }
  572. private function handleMouseClick (evt:MouseEvent) : void {
  573. logMessage("Mouse click detected, launching 'Open File' dialog.");
  574. this.browse(this.allowMultiple, this.filterArray);
  575. }
  576. //--------------------------------------------------------------------------
  577. //
  578. // Overridden Properties
  579. //
  580. //--------------------------------------------------------------------------
  581. /**
  582. * @private
  583. * Initializes the component and enables communication with JavaScript
  584. *
  585. * @param parent A container that the PopUpManager uses to place the Menu
  586. * control in. The Menu control may not actually be parented by this object.
  587. *
  588. * @param xmlDataProvider The data provider for the Menu control.
  589. * @see #dataProvider
  590. *
  591. * @return An instance of the Menu class.
  592. *
  593. * @see #popUpMenu()
  594. * @see com.yahoo.astra.fl.data.XMLDataProvider
  595. */
  596. protected function initializeComponent():void {
  597. logMessage("Initializing uploader...");
  598. var btnSkinURL:String;
  599. btnSkinURL = yuiBridge.flashvars["buttonSkin"];
  600. logMessage("Button skin: " + btnSkinURL);
  601. if (btnSkinURL != null) {
  602. logMessage("Starting to render as button...");
  603. this.renderType = "button";
  604. this.renderAsButton(btnSkinURL);
  605. }
  606. else {
  607. this.renderType = "transparent";
  608. this.renderAsTransparent();
  609. }
  610. yuiBridge.addCallbacks ({removeFile:removeFile, clearFileList:clearFileList, upload:upload,uploadThese:uploadThese,uploadAll:uploadAll,cancel:cancel,setAllowLogging:setAllowLogging,setAllowMultipleFiles:setAllowMultipleFiles,setSimUploadLimit:setSimUploadLimit,setFileFilters:setFileFilters,enable:enable, disable:disable});
  611. // removeFile (fileID:String = null)
  612. // Removes one or all files from the upload queue
  613. // ExternalInterface.addCallback("removeFile", removeFile);
  614. // clearFileList (): Boolean
  615. // Clears the list of files to be uploaded.
  616. // ExternalInterface.addCallback("clearFileList", clearFileList);
  617. // upload(fileID:String, url:String, method:String = "GET", vars:Object = null, fieldName:String = "Filedata")
  618. // Uploads the specified file in a specified POST variable, attaching other variables using the specified method
  619. // ExternalInterface.addCallback("upload", upload);
  620. //ExternalInterface.addCallback("uploadThese", uploadThese);
  621. // uploadAll(url:String, method:String = "GET", vars:Object = null, fieldName:String = "Filedata")
  622. // Uploads all files in the queue, using simultaneousUploads.
  623. //ExternalInterface.addCallback("uploadAll", uploadAll);
  624. // cancel (fileID:String = null)
  625. // Cancels the specified file upload; or all, if no id is specified
  626. //ExternalInterface.addCallback("cancel", cancel);
  627. // setAllowLoging (allowLogging:Boolean = false)
  628. // Allows log outputs to be produced.
  629. //ExternalInterface.addCallback("setAllowLogging", setAllowLogging);
  630. // setAllowMultipleFiles (allowMultiple:Boolean = false)
  631. // Allows multiple file selection
  632. //ExternalInterface.addCallback("setAllowMultipleFiles", this.setAllowMultipleFiles);
  633. // setSimUploadLimit(simUpload:int = [2,5])
  634. // Sets the number of simultaneous uploads allowed when automatically managing queue.
  635. //ExternalInterface.addCallback("setSimUploadLimit", this.setSimUploadLimit);
  636. // setFileFilters(fileFilters:Array)
  637. // Sets file filters for file selection.
  638. //ExternalInterface.addCallback("setFileFilters", this.setFileFilters);
  639. // enable()
  640. // Enables Uploader UI
  641. //ExternalInterface.addCallback("enable", enable);
  642. // disable()
  643. // Disables Uploader UI
  644. //ExternalInterface.addCallback("disable", disable);
  645. // Initialize properties.
  646. fileDataList = new Object();
  647. fileRefList = new Object();
  648. fileIDList = new Dictionary();
  649. singleFile = new FileReference();
  650. multipleFiles = new FileReferenceList();
  651. fileIDCounter = 0;
  652. filesToUpload = [];
  653. }
  654. //--------------------------------------
  655. // Private Methods
  656. //--------------------------------------
  657. /**
  658. * @private
  659. * Formats objects containing extensions of files to be filtered into formal FileFilter objects
  660. */
  661. private function processFileFilterObjects(filtersArray:Array) : Array {
  662. // TODO: Should we have an 'allowedExtensions' property that the JS user accesses directly? Potential here for typos ('extension' instead of 'extensions') as well as a misunderstanding of the nature of the expected array
  663. // TODO: Description not showing (testing on OS X PPC player)
  664. for (var i:int = 0; i < filtersArray.length; i++) {
  665. filtersArray[i] = new FileFilter(filtersArray[i].description, filtersArray[i].extensions, filtersArray[i].macType);
  666. }
  667. return filtersArray;
  668. }
  669. /**
  670. * @private
  671. * Outputs the files selected to an output panel and triggers a 'fileSelect' event.
  672. */
  673. private function processSelection():void {
  674. var dstring:String = "";
  675. dstring += "Files Selected: \n";
  676. for each (var item:Object in fileDataList) {
  677. dstring += item.name + "\n ";
  678. }
  679. logMessage(dstring);
  680. var newEvent:Object = new Object();
  681. newEvent.fileList = fileDataList;
  682. newEvent.type = "fileselect"
  683. yuiBridge.sendEvent(newEvent);
  684. }
  685. /**
  686. * @private
  687. * Adds a file reference object to the internal queue and assigns listeners to its events
  688. */
  689. private function addFile(fr:FileReference):void {
  690. var fileID:String = "file" + fileIDCounter;
  691. var fileName:String = fr.name;
  692. var fileCDate:Date = fr.creationDate;
  693. var fileMDate:Date = fr.modificationDate;
  694. var fileSize:Number = fr.size;
  695. fileIDCounter++;
  696. fileDataList[fileID] = {id: fileID, name: fileName, cDate: fileCDate, mDate: fileMDate, size: fileSize};//, type: fileType, creator: fileCreator};
  697. fr.addEventListener(Event.OPEN, uploadStart);
  698. fr.addEventListener(ProgressEvent.PROGRESS, uploadProgress);
  699. fr.addEventListener(Event.COMPLETE, uploadComplete);
  700. fr.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA, uploadCompleteData);
  701. fr.addEventListener(HTTPStatusEvent.HTTP_STATUS, uploadError);
  702. fr.addEventListener(IOErrorEvent.IO_ERROR, uploadError);
  703. fr.addEventListener(SecurityErrorEvent.SECURITY_ERROR, uploadError);
  704. fr.addEventListener(Event.CANCEL,uploadCancel);
  705. fileRefList[fileID] = fr;
  706. fileIDList[fr] = fileID;
  707. }
  708. /**
  709. * @private
  710. * Queues a file for upload
  711. */
  712. private function queueForUpload(fr:FileReference, request:URLRequest, fieldName:String):void {
  713. filesToUpload.push( {fr:fr, request:request, fieldName:fieldName });
  714. }
  715. /**
  716. * @private
  717. * Uploads the next file in the upload queue.
  718. */
  719. private function processQueue():void {
  720. while (this.currentUploadThreads < this.simultaneousUploadLimit && filesToUpload.length > 0) {
  721. var objToUpload:Object = filesToUpload.shift();
  722. var fr:FileReference = objToUpload.fr;
  723. var request:URLRequest = objToUpload.request;
  724. var fieldName:String = objToUpload.fieldName;
  725. logMessage("Starting upload for " + objToUpload.id);
  726. fr.upload(request,fieldName);
  727. this.currentUploadThreads++;
  728. }
  729. }
  730. /**
  731. * @private
  732. * Creates a URLRequest object from a url, and optionally includes an HTTP request method and additional variables to be sent
  733. */
  734. private function formURLRequest(url:String, method:String = "GET", vars:Object = null):URLRequest {
  735. var request:URLRequest = new URLRequest();
  736. request.url = url;
  737. request.method = method;
  738. request.data = new URLVariables();
  739. for (var itemName:String in vars) {
  740. request.data[itemName] = vars[itemName];
  741. }
  742. return request;
  743. }
  744. /**
  745. * @private
  746. * Determines whether an object is equivalent to an empty string
  747. */
  748. private function isEmptyString(toCheck:*):Boolean {
  749. if( toCheck == "null" ||
  750. toCheck == "" ||
  751. toCheck == null ) {
  752. return true;
  753. }
  754. else {
  755. return false;
  756. }
  757. }
  758. private function logMessage (message:String) : void {
  759. if (this.allowLog) {
  760. trace(message);
  761. }
  762. }
  763. }
  764. }