s3_swf_upload 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }