s3_swf_upload 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/.gitignore +6 -0
  2. data/CHANGELOG +26 -0
  3. data/Gemfile +4 -0
  4. data/MIT-LICENSE +20 -0
  5. data/Manifest +34 -0
  6. data/README.textile +223 -0
  7. data/Rakefile +14 -0
  8. data/flex_src/bin-release/flex-config.xml +361 -0
  9. data/flex_src/compile +2 -0
  10. data/flex_src/src/Globals.as +15 -0
  11. data/flex_src/src/S3Uploader.as +204 -0
  12. data/flex_src/src/com/adobe/net/MimeTypeMap.as +196 -0
  13. data/flex_src/src/com/elctech/S3UploadOptions.as +32 -0
  14. data/flex_src/src/com/elctech/S3UploadRequest.as +259 -0
  15. data/flex_src/src/com/nathancolgate/s3_swf_upload/BrowseButton.as +55 -0
  16. data/flex_src/src/com/nathancolgate/s3_swf_upload/S3Queue.as +117 -0
  17. data/flex_src/src/com/nathancolgate/s3_swf_upload/S3Signature.as +118 -0
  18. data/flex_src/src/com/nathancolgate/s3_swf_upload/S3Upload.as +111 -0
  19. data/lib/patch/integer.rb +12 -0
  20. data/lib/s3_swf_upload/railtie.rb +16 -0
  21. data/lib/s3_swf_upload/railties/generators/s3_swf_upload.rb +19 -0
  22. data/lib/s3_swf_upload/railties/generators/uploader/USAGE +10 -0
  23. data/lib/s3_swf_upload/railties/generators/uploader/templates/amazon_s3.yml +20 -0
  24. data/lib/s3_swf_upload/railties/generators/uploader/templates/s3_down_button.gif +0 -0
  25. data/lib/s3_swf_upload/railties/generators/uploader/templates/s3_over_button.gif +0 -0
  26. data/lib/s3_swf_upload/railties/generators/uploader/templates/s3_up_button.gif +0 -0
  27. data/lib/s3_swf_upload/railties/generators/uploader/templates/s3_upload.js +118 -0
  28. data/lib/s3_swf_upload/railties/generators/uploader/templates/s3_upload.swf +0 -0
  29. data/lib/s3_swf_upload/railties/generators/uploader/templates/s3_uploads_controller.rb +53 -0
  30. data/lib/s3_swf_upload/railties/generators/uploader/uploader_generator.rb +20 -0
  31. data/lib/s3_swf_upload/railties/tasks/crossdomain.xml +5 -0
  32. data/lib/s3_swf_upload/s3_config.rb +43 -0
  33. data/lib/s3_swf_upload/signature.rb +203 -0
  34. data/lib/s3_swf_upload/view_helpers.rb +171 -0
  35. data/lib/s3_swf_upload.rb +10 -0
  36. data/s3_swf_upload.gemspec +29 -0
  37. metadata +103 -0
@@ -0,0 +1,196 @@
1
+ /*
2
+ Copyright (c) 2008, Adobe Systems Incorporated
3
+ All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are
7
+ met:
8
+
9
+ * Redistributions of source code must retain the above copyright notice,
10
+ this list of conditions and the following disclaimer.
11
+
12
+ * Redistributions in binary form must reproduce the above copyright
13
+ notice, this list of conditions and the following disclaimer in the
14
+ documentation and/or other materials provided with the distribution.
15
+
16
+ * Neither the name of Adobe Systems Incorporated nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21
+ IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23
+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
+ */
32
+ package com.adobe.net
33
+ {
34
+ public class MimeTypeMap
35
+ {
36
+ private var types:Array =
37
+ [["application/andrew-inset","ez"],
38
+ ["application/atom+xml","atom"],
39
+ ["application/mac-binhex40","hqx"],
40
+ ["application/mac-compactpro","cpt"],
41
+ ["application/mathml+xml","mathml"],
42
+ ["application/msword","doc"],
43
+ ["application/octet-stream","bin","dms","lha","lzh","exe","class","so","dll","dmg"],
44
+ ["application/oda","oda"],
45
+ ["application/ogg","ogg"],
46
+ ["application/pdf","pdf"],
47
+ ["application/postscript","ai","eps","ps"],
48
+ ["application/rdf+xml","rdf"],
49
+ ["application/smil","smi","smil"],
50
+ ["application/srgs","gram"],
51
+ ["application/srgs+xml","grxml"],
52
+ ["application/vnd.adobe.apollo-application-installer-package+zip","air"],
53
+ ["application/vnd.mif","mif"],
54
+ ["application/vnd.mozilla.xul+xml","xul"],
55
+ ["application/vnd.ms-excel","xls"],
56
+ ["application/vnd.ms-powerpoint","ppt"],
57
+ ["application/vnd.rn-realmedia","rm"],
58
+ ["application/vnd.wap.wbxml","wbxml"],
59
+ ["application/vnd.wap.wmlc","wmlc"],
60
+ ["application/vnd.wap.wmlscriptc","wmlsc"],
61
+ ["application/voicexml+xml","vxml"],
62
+ ["application/x-bcpio","bcpio"],
63
+ ["application/x-cdlink","vcd"],
64
+ ["application/x-chess-pgn","pgn"],
65
+ ["application/x-cpio","cpio"],
66
+ ["application/x-csh","csh"],
67
+ ["application/x-director","dcr","dir","dxr"],
68
+ ["application/x-dvi","dvi"],
69
+ ["application/x-futuresplash","spl"],
70
+ ["application/x-gtar","gtar"],
71
+ ["application/x-hdf","hdf"],
72
+ ["application/x-javascript","js"],
73
+ ["application/x-koan","skp","skd","skt","skm"],
74
+ ["application/x-latex","latex"],
75
+ ["application/x-netcdf","nc","cdf"],
76
+ ["application/x-sh","sh"],
77
+ ["application/x-shar","shar"],
78
+ ["application/x-shockwave-flash","swf"],
79
+ ["application/x-stuffit","sit"],
80
+ ["application/x-sv4cpio","sv4cpio"],
81
+ ["application/x-sv4crc","sv4crc"],
82
+ ["application/x-tar","tar"],
83
+ ["application/x-tcl","tcl"],
84
+ ["application/x-tex","tex"],
85
+ ["application/x-texinfo","texinfo","texi"],
86
+ ["application/x-troff","t","tr","roff"],
87
+ ["application/x-troff-man","man"],
88
+ ["application/x-troff-me","me"],
89
+ ["application/x-troff-ms","ms"],
90
+ ["application/x-ustar","ustar"],
91
+ ["application/x-wais-source","src"],
92
+ ["application/xhtml+xml","xhtml","xht"],
93
+ ["application/xml","xml","xsl"],
94
+ ["application/xml-dtd","dtd"],
95
+ ["application/xslt+xml","xslt"],
96
+ ["application/zip","zip"],
97
+ ["audio/basic","au","snd"],
98
+ ["audio/midi","mid","midi","kar"],
99
+ ["audio/mpeg","mp3","mpga","mp2"],
100
+ ["audio/x-aiff","aif","aiff","aifc"],
101
+ ["audio/x-mpegurl","m3u"],
102
+ ["audio/x-pn-realaudio","ram","ra"],
103
+ ["audio/x-wav","wav"],
104
+ ["chemical/x-pdb","pdb"],
105
+ ["chemical/x-xyz","xyz"],
106
+ ["image/bmp","bmp"],
107
+ ["image/cgm","cgm"],
108
+ ["image/gif","gif"],
109
+ ["image/ief","ief"],
110
+ ["image/jpeg","jpg","jpeg","jpe"],
111
+ ["image/png","png"],
112
+ ["image/svg+xml","svg"],
113
+ ["image/tiff","tiff","tif"],
114
+ ["image/vnd.djvu","djvu","djv"],
115
+ ["image/vnd.wap.wbmp","wbmp"],
116
+ ["image/x-cmu-raster","ras"],
117
+ ["image/x-icon","ico"],
118
+ ["image/x-portable-anymap","pnm"],
119
+ ["image/x-portable-bitmap","pbm"],
120
+ ["image/x-portable-graymap","pgm"],
121
+ ["image/x-portable-pixmap","ppm"],
122
+ ["image/x-rgb","rgb"],
123
+ ["image/x-xbitmap","xbm"],
124
+ ["image/x-xpixmap","xpm"],
125
+ ["image/x-xwindowdump","xwd"],
126
+ ["model/iges","igs","iges"],
127
+ ["model/mesh","msh","mesh","silo"],
128
+ ["model/vrml","wrl","vrml"],
129
+ ["text/calendar","ics","ifb"],
130
+ ["text/css","css"],
131
+ ["text/html","html","htm"],
132
+ ["text/plain","txt","asc"],
133
+ ["text/richtext","rtx"],
134
+ ["text/rtf","rtf"],
135
+ ["text/sgml","sgml","sgm"],
136
+ ["text/tab-separated-values","tsv"],
137
+ ["text/vnd.wap.wml","wml"],
138
+ ["text/vnd.wap.wmlscript","wmls"],
139
+ ["text/x-setext","etx"],
140
+ ["video/mpeg","mpg","mpeg","mpe"],
141
+ ["video/quicktime","mov","qt"],
142
+ ["video/vnd.mpegurl","m4u","mxu"],
143
+ ["video/x-flv","flv"],
144
+ ["video/x-msvideo","avi"],
145
+ ["video/x-sgi-movie","movie"],
146
+ ["x-conference/x-cooltalk","ice"]];
147
+
148
+ /**
149
+ * Returns the mimetype for the given extension.
150
+ */
151
+ public function getMimeType(extension:String):String
152
+ {
153
+ extension = extension.toLocaleLowerCase();
154
+ for each (var a:Array in types)
155
+ {
156
+ for each (var b:String in a)
157
+ {
158
+ if (b == extension)
159
+ {
160
+ return a[0];
161
+ }
162
+ }
163
+ }
164
+ return null;
165
+ }
166
+
167
+ /**
168
+ * Returns the prefered extension for the given mimetype.
169
+ */
170
+ public function getExtension(mimetype:String):String
171
+ {
172
+ mimetype = mimetype.toLocaleLowerCase();
173
+ for each (var a:Array in types)
174
+ {
175
+ if (a[0] == mimetype)
176
+ {
177
+ return a[1];
178
+ }
179
+ }
180
+ return null;
181
+ }
182
+
183
+ /**
184
+ * Adds a mimetype to the map. The order of the extensions matters. The most preferred should come first.
185
+ */
186
+ public function addMimeType(mimetype:String, extensions:Array):void
187
+ {
188
+ var newType:Array = [mimetype];
189
+ for each (var a:String in extensions)
190
+ {
191
+ newType.push(a);
192
+ }
193
+ types.push(newType);
194
+ }
195
+ }
196
+ }
@@ -0,0 +1,32 @@
1
+ package com.elctech {
2
+ public class S3UploadOptions {
3
+ /**
4
+ * Options specified at:
5
+ * http://docs.amazonwebservices.com/AmazonS3/2006-03-01/HTTPPOSTForms.html
6
+ */
7
+ public var AWSAccessKeyId:String;
8
+ public var acl:String;
9
+ public var bucket:String;
10
+ public var CacheControl:String;
11
+ public var ContentType:String;
12
+ public var ContentDisposition:String;
13
+ public var ContentEncoding:String;
14
+ public var Expires:String;
15
+ public var key:String;
16
+ public var newKey:String;
17
+ public var policy:String;
18
+ public var successactionredirect:String;
19
+ public var redirect:String;
20
+ public var successactionstatus:String;
21
+ public var signature:String;
22
+ public var xamzsecuritytoken:String;
23
+ public var file:String;
24
+
25
+ /**
26
+ * Addition field
27
+ */
28
+ public var Secure:String; /* A flag indicating whether HTTPS should be used. */
29
+ public var FileName:String;
30
+ public var FileSize:String;
31
+ }
32
+ }
@@ -0,0 +1,259 @@
1
+ package com.elctech {
2
+
3
+ // import flash.events.*;
4
+ import flash.events.EventDispatcher;
5
+ import flash.events.ProgressEvent;
6
+ import flash.events.Event;
7
+ import flash.events.IOErrorEvent;
8
+ import flash.events.SecurityErrorEvent;
9
+ import flash.events.HTTPStatusEvent;
10
+ import flash.events.DataEvent;
11
+
12
+ // import flash.net.*;
13
+ import flash.net.FileReference;
14
+ import flash.net.URLVariables;
15
+ import flash.net.URLRequest;
16
+ import flash.net.URLRequestMethod;
17
+
18
+ import flash.system.Security;
19
+ import flash.xml.XMLDocument;
20
+ import flash.xml.XMLNode;
21
+ // import mx.controls.Alert;
22
+
23
+ /**
24
+ * This class encapsulates a POST request to S3.
25
+ *
26
+ * After you create an S3PostRequest, invoke S3PostRequest::upload(fileReference:FileReference).
27
+ *
28
+ */
29
+ public class S3UploadRequest extends EventDispatcher {
30
+
31
+ [Event(name="open", type="flash.events.Event.OPEN")]
32
+ [Event(name="uploadCompleteData", type="flash.events.DataEvent.UPLOAD_COMPLETE_DATA")]
33
+ [Event(name="ioError", type="flash.events.IOErrorEvent.IO_ERROR")]
34
+ [Event(name="securityError", type="flash.events.SecurityErrorEvent.SECURITY_ERROR")]
35
+ [Event(name="progress", type="flash.events.ProgressEvent.PROGRESS")]
36
+
37
+ private var _accessKeyId:String;
38
+ private var _bucket:String;
39
+ private var _key:String;
40
+ private var _options:S3UploadOptions;
41
+ private var _httpStatusErrorReceived:Boolean;
42
+ private var _uploadStarted:Boolean;
43
+ private var fileReference:FileReference;
44
+
45
+ private const ENDPOINT:String = "s3.amazonaws.com";
46
+ private const MIN_BUCKET_LENGTH:int = 3;
47
+ private const MAX_BUCKET_LENGTH:int = 63;
48
+
49
+
50
+ /**
51
+ * Creates and initializes a new S3PostRequest object.
52
+ * @param accessKeyId The AWS access key id to authenticate the request
53
+ * @param bucket The bucket to POST into
54
+ * @param key The key to create
55
+ * @param options Options for this request
56
+ */
57
+ public function S3UploadRequest(options:S3UploadOptions) {
58
+
59
+ _accessKeyId = options.AWSAccessKeyId;
60
+ _bucket = options.bucket;
61
+ _key = options.key;
62
+ _options = options;
63
+
64
+ if (options.newKey) { //NOTE that we stop caring about the specified prefix if we have a newkey.
65
+ _key = options.newKey;
66
+ options.key = options.newKey; //so we output the right value in callbacks, etc.
67
+ }
68
+ }
69
+
70
+ private function buildUrl():String {
71
+
72
+ var canUseVanityStyle:Boolean = canUseVanityStyle(_bucket);
73
+
74
+ if(_options.Secure!="false" && canUseVanityStyle && _bucket.match(/\./)) {
75
+ // We cannot use SSL for bucket names containing "."
76
+ // The certificate won't match "my.bucket.s3.amazonaws.com"
77
+ throw new SecurityError("Cannot use SSL with bucket name containing '.': " + _bucket);
78
+ }
79
+
80
+ var postUrl:String = "http" + ((_options.Secure == 'true') ? "s" : "") + "://";
81
+
82
+ if(canUseVanityStyle) {
83
+ postUrl += _bucket + "." + ENDPOINT;
84
+ } else {
85
+ postUrl += ENDPOINT + "/" + _bucket;
86
+ }
87
+
88
+ return postUrl;
89
+ }
90
+
91
+ private function canUseVanityStyle(bucket:String):Boolean {
92
+ if( bucket.length < MIN_BUCKET_LENGTH ||
93
+ bucket.length > MAX_BUCKET_LENGTH ||
94
+ bucket.match(/^\./) ||
95
+ bucket.match(/\.$/) ) {
96
+ return false;
97
+ }
98
+
99
+ // must be lower case
100
+ if(bucket.toLowerCase() != bucket) {
101
+ return false;
102
+ }
103
+
104
+ // Check not IPv4-like
105
+ if (bucket.match(/^[0-9]|+\.[0-9]|+\.[0-9]|+\.[0-9]|+$/)) {
106
+ return false;
107
+ }
108
+
109
+ // Check each label
110
+ if(bucket.match(/\./)) {
111
+ var labels:Array = bucket.split(/\./);
112
+ for (var i:int = 0;i < labels.length; i++) {
113
+ if(!labels[i].match(/^[a-z0-9]([a-z0-9\-]*[a-z0-9])?$/)) {
114
+ return false;
115
+ }
116
+ }
117
+ }
118
+
119
+ return true;
120
+ }
121
+
122
+ private function loadPolicyFile(postUrl:String):void {
123
+ /*
124
+ * Due to the restrictions imposed by the Adobe Flash security sandbox,
125
+ * the bucket being uploaded to must contain a public-readable crossdomain.xml
126
+ * file that allows access from the domain that served the SWF hosting this code.
127
+ *
128
+ * Read Adobe's documentation on the Flash security sandbox for more information.
129
+ *
130
+ */
131
+
132
+ Security.loadPolicyFile(postUrl + "/crossdomain.xml");
133
+ }
134
+
135
+
136
+ public function removeListeners():void {
137
+ trace('removeListeners');
138
+ fileReference.removeEventListener(Event.OPEN, onOpen);
139
+ fileReference.removeEventListener(ProgressEvent.PROGRESS, onProgress);
140
+ fileReference.removeEventListener(IOErrorEvent.IO_ERROR, onIOError);
141
+ fileReference.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
142
+ fileReference.removeEventListener(DataEvent.UPLOAD_COMPLETE_DATA, onUploadCompleteData);
143
+ fileReference.removeEventListener(HTTPStatusEvent.HTTP_STATUS, onHttpStatus);
144
+ }
145
+ /**
146
+ * Initiates a POST upload request to S3
147
+ * @param fileReference A FileReference object referencing the file to upload to S3.
148
+ */
149
+ public function upload(_fileReference:FileReference):void {
150
+
151
+ if(_uploadStarted) {
152
+ throw new Error("S3PostRequest object cannot be reused. Create another S3PostRequest object to send another request to Amazon S3.");
153
+ }
154
+ _uploadStarted = true;
155
+
156
+ // Save the FileReference object so that it doesn't get GCed.
157
+ // If this happens, we can lose events that should be dispatched.
158
+ fileReference = _fileReference;
159
+
160
+ var postUrl:String = buildUrl();
161
+ loadPolicyFile(postUrl);
162
+ var urlRequest:URLRequest = new URLRequest(postUrl);
163
+ urlRequest.method = URLRequestMethod.POST;
164
+ urlRequest.data = buildPostVariables();
165
+
166
+ // set up event handlers *****************************************************
167
+ fileReference.addEventListener(Event.OPEN, onOpen);
168
+ fileReference.addEventListener(ProgressEvent.PROGRESS, onProgress);
169
+ fileReference.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
170
+ fileReference.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
171
+ fileReference.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA, onUploadCompleteData);
172
+ fileReference.addEventListener(HTTPStatusEvent.HTTP_STATUS, onHttpStatus);
173
+ // *****************************************************************************
174
+
175
+ // send the request
176
+ fileReference.upload(urlRequest, "file", false);
177
+ }
178
+
179
+ private function buildPostVariables():URLVariables {
180
+
181
+ var postVariables:URLVariables = new URLVariables();
182
+
183
+ postVariables.key = _key;
184
+ postVariables.acl = _options.acl;
185
+ postVariables.AWSAccessKeyId = _accessKeyId;
186
+ postVariables.signature = _options.signature;
187
+ postVariables["Content-Type"] = _options.ContentType;
188
+ postVariables["Content-Disposition"] = "attachment";
189
+ postVariables.policy = _options.policy;
190
+
191
+ /**
192
+ * Certain combinations of Flash player version and platform don't handle
193
+ * HTTP responses with the header 'Content-Length: 0'. These clients do not
194
+ * dispatch completion or error events when such a response is received.
195
+ * Therefore it is impossible to tell when the upload has completed or failed.
196
+ *
197
+ * Flash clients should always set the success_action_status parameter to 201
198
+ * so that Amazon S3 returns a response with Content-Length being non-zero.
199
+ *
200
+ */
201
+ postVariables.success_action_status = "201";
202
+
203
+ return postVariables;
204
+ }
205
+
206
+ private function onOpen(event:Event):void {
207
+ trace('onOpen: '+this._key);
208
+ this.dispatchEvent(event);
209
+ }
210
+ private function onIOError(event:IOErrorEvent):void {
211
+ /*
212
+ * FileReference.upload likes to send cryptic IOErrors when it doesn't get a status code that it likes.
213
+ * If we already got an error HTTP status code, don't propagate this event since the HTTPStatusEvent
214
+ * event handler dispatches an IOErrorEvent.
215
+ */
216
+ if(!_httpStatusErrorReceived) {
217
+ this.dispatchEvent(event);
218
+ }
219
+ }
220
+ private function onSecurityError(event:SecurityErrorEvent):void {
221
+ this.dispatchEvent(event);
222
+ }
223
+ private function onProgress(event:ProgressEvent):void {
224
+ this.dispatchEvent(event);
225
+ }
226
+ private function onUploadCompleteData(event:DataEvent):void {
227
+ var data:String = event.data;
228
+ if(isError(data)) {
229
+ this.dispatchEvent(
230
+ new IOErrorEvent(IOErrorEvent.IO_ERROR, event.bubbles, event.cancelable, "Amazon S3 returned an error: " + data + ".")
231
+ );
232
+ } else {
233
+ this.dispatchEvent(new DataEvent(DataEvent.UPLOAD_COMPLETE_DATA, event.bubbles, event.cancelable, data));
234
+ }
235
+ }
236
+ private function onHttpStatus(event:HTTPStatusEvent):void {
237
+ _httpStatusErrorReceived = true;
238
+ if(Math.floor(event.status/100) == 2) {
239
+ this.dispatchEvent(new DataEvent(DataEvent.UPLOAD_COMPLETE_DATA, event.bubbles, event.cancelable, "Amazon S3 returned HTTP status " + event.status.toString() + "."));
240
+ } else {
241
+ this.dispatchEvent(new IOErrorEvent(IOErrorEvent.IO_ERROR, event.bubbles, event.cancelable, "Amazon S3 returned an error: HTTP status " + event.status.toString() + "."));
242
+ }
243
+ }
244
+
245
+ private function isError(responseText:String):Boolean {
246
+ var xml:XMLDocument = new XMLDocument();
247
+ xml.ignoreWhite = true;
248
+ xml.parseXML(responseText);
249
+ var root:XMLNode = xml.firstChild;
250
+ if( root == null || root.nodeName != "Error" )
251
+ {
252
+ return false;
253
+ }
254
+ return true;
255
+ }
256
+
257
+ }
258
+
259
+ }
@@ -0,0 +1,55 @@
1
+ package com.nathancolgate.s3_swf_upload {
2
+
3
+ import flash.display.*;
4
+ import flash.events.MouseEvent;
5
+ import flash.events.Event;
6
+ import flash.net.*;
7
+
8
+ public dynamic class BrowseButton extends Sprite {
9
+
10
+ private var _playButton:flash.display.SimpleButton;
11
+
12
+ public function BrowseButton(width:Number,
13
+ height:Number,
14
+ buttonUpUrl:String,
15
+ buttonDownUrl:String,
16
+ buttonOverUrl:String)
17
+ {
18
+ super();
19
+
20
+ _playButton = new flash.display.SimpleButton();
21
+ _playButton.useHandCursor = true;
22
+ addChild(_playButton);
23
+
24
+ // Hit Test
25
+ var hit_test:Shape = new flash.display.Shape();
26
+ hit_test.graphics.beginFill(0xFFCC00);
27
+ hit_test.graphics.drawRect(0, 0, width, height);
28
+ hit_test.graphics.endFill();
29
+ _playButton.hitTestState = hit_test;
30
+
31
+ // Up
32
+ var upLoader:Loader = new Loader();
33
+ upLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,function(e:Event):void{
34
+ _playButton.upState = new Bitmap(e.target.content.bitmapData);
35
+ });
36
+ upLoader.load(new URLRequest(buttonUpUrl));
37
+
38
+ // Down
39
+ var downLoader:Loader = new Loader();
40
+ downLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,function(e:Event):void{
41
+ _playButton.downState = new Bitmap(e.target.content.bitmapData);
42
+ });
43
+ downLoader.load(new URLRequest(buttonDownUrl));
44
+
45
+ // Over
46
+ var overLoader:Loader = new Loader();
47
+ overLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,function(e:Event):void{
48
+ _playButton.overState = new Bitmap(e.target.content.bitmapData);
49
+ });
50
+ overLoader.load(new URLRequest(buttonOverUrl));
51
+ }
52
+
53
+
54
+ }
55
+ }
@@ -0,0 +1,117 @@
1
+ package com.nathancolgate.s3_swf_upload {
2
+
3
+ import mx.collections.ArrayCollection;
4
+ import mx.events.CollectionEvent;
5
+ import flash.external.ExternalInterface;
6
+ import flash.net.FileReference;
7
+ import com.nathancolgate.s3_swf_upload.*;
8
+
9
+ public class S3Queue extends ArrayCollection {
10
+
11
+ // S3 Interaction Vars
12
+ private var _signatureUrl:String;
13
+ private var _prefixPath:String;
14
+
15
+ public var currentSignature:S3Signature;
16
+
17
+ public function S3Queue(signatureUrl:String,
18
+ prefixPath:String,
19
+ source:Array = null) {
20
+
21
+ _signatureUrl = signatureUrl;
22
+ _prefixPath = prefixPath;
23
+ super(source);
24
+
25
+ // Outgoing calls
26
+ this.addEventListener(CollectionEvent.COLLECTION_CHANGE, changeHandler);
27
+ // Incoming calls
28
+ ExternalInterface.addCallback("startUploading", startUploadingHandler);
29
+ ExternalInterface.addCallback("clearQueue", clearHandler);
30
+ ExternalInterface.addCallback("stopUploading", stopUploadingHandler);
31
+ }
32
+
33
+ public function uploadNextFile():void{
34
+ // ExternalInterface.call('s3_swf.jsLog','uploadNextFile');
35
+ // ExternalInterface.call('s3_swf.jsLog','Start uploadNextFile...');
36
+ var next_file:FileReference = FileReference(this.getItemAt(0));
37
+ currentSignature = new S3Signature(next_file,_signatureUrl,_prefixPath);
38
+ // ExternalInterface.call('s3_swf.jsLog','End uploadNextFile');
39
+ }
40
+
41
+ // whenever the queue changes this function is called
42
+ private function changeHandler(event:CollectionEvent):void{
43
+ // ExternalInterface.call('s3_swf.jsLog','changeHandler');
44
+ // ExternalInterface.call('s3_swf.jsLog','Calling onQueueChange...');
45
+ ExternalInterface.call(S3Uploader.s3_swf_obj+'.onQueueChange',this.toJavascript());
46
+ // ExternalInterface.call('s3_swf.jsLog','onQueueChange called');
47
+ }
48
+
49
+ // Remove all files from the upload queue;
50
+ private function clearHandler():void{
51
+ // ExternalInterface.call('s3_swf.jsLog','clearHandler');
52
+ // ExternalInterface.call('s3_swf.jsLog','Removing All...');
53
+ this.removeAll();
54
+ // ExternalInterface.call('s3_swf.jsLog','All removed');
55
+ // ExternalInterface.call('s3_swf.jsLog','Calling onQueueClear...');
56
+ ExternalInterface.call(S3Uploader.s3_swf_obj+'.onQueueClear',this.toJavascript());
57
+ // ExternalInterface.call('s3_swf.jsLog','onQueueClear called');
58
+ }
59
+
60
+ // Start uploading the files from the queue
61
+ private function startUploadingHandler():void{
62
+ // ExternalInterface.call('s3_swf.jsLog','startUploadingHandler');
63
+ if (this.length > 0){
64
+ // ExternalInterface.call('s3_swf.jsLog','Calling onUploadingStart...');
65
+ ExternalInterface.call(S3Uploader.s3_swf_obj+'.onUploadingStart');
66
+ // ExternalInterface.call('s3_swf.jsLog','onUploadingStart called');
67
+ // ExternalInterface.call('s3_swf.jsLog','Uploading next file...');
68
+ uploadNextFile();
69
+ // ExternalInterface.call('s3_swf.jsLog','Next file uploaded');
70
+ } else {
71
+ // ExternalInterface.call('s3_swf.jsLog','Calling onQueueEmpty...');
72
+ ExternalInterface.call(S3Uploader.s3_swf_obj+'.onQueueEmpty',this);
73
+ // ExternalInterface.call('s3_swf.jsLog','onQueueEmpty called');
74
+ }
75
+ }
76
+
77
+ // Cancel Current File Upload
78
+ // Which stops all future uploads as well
79
+ private function stopUploadingHandler():void{
80
+ // ExternalInterface.call('s3_swf.jsLog','stopUploadingHandler');
81
+ if (this.length > 0){
82
+ var current_file:FileReference = FileReference(this.getItemAt(0));
83
+ // ExternalInterface.call('s3_swf.jsLog','Cancelling current file...');
84
+ current_file.cancel();
85
+
86
+ currentSignature.s3upload.removeListeners();
87
+
88
+ // ExternalInterface.call('s3_swf.jsLog','Current file cancelled');
89
+ // ExternalInterface.call('s3_swf.jsLog','Calling onUploadingStop...');
90
+ ExternalInterface.call(S3Uploader.s3_swf_obj+'.onUploadingStop');
91
+ // ExternalInterface.call('s3_swf.jsLog','onUploadingStop called');
92
+ } else {
93
+ // ExternalInterface.call('s3_swf.jsLog','Calling onQueueEmpty...');
94
+ ExternalInterface.call(S3Uploader.s3_swf_obj+'.onQueueEmpty',this.toJavascript());
95
+ // ExternalInterface.call('s3_swf.jsLog','onQueueEmpty called');
96
+ }
97
+ }
98
+
99
+ // This is a rather silly function to need, especially since it worked at one point
100
+ // In flash player 10.1, you could no longer send files over external reference
101
+ // This is the hack to get around the problem. Essentially: turn all those
102
+ // Files into objects
103
+ // August 27, 2010 - NCC@BNB
104
+ public function toJavascript():Object {
105
+ var faux_queue:Object = new Object();
106
+ faux_queue.files = new Array();
107
+ for (var i:int = 0;i < source.length; i++) {
108
+ faux_queue.files[i] = new Object();
109
+ faux_queue.files[i].name = source[i].name;
110
+ faux_queue.files[i].size = source[i].size;
111
+ faux_queue.files[i].type = source[i].type;
112
+ }
113
+ return faux_queue;
114
+ }
115
+
116
+ }
117
+ }