37 |
38 | If you are using Rails 3.1, you will need to move the generated s3_upload.js from the public/javascripts directory to the app/assets/javascripts directory.
39 |
40 | 4. Configure your amazon parameters via the generated config/amazon_s3.yml file.
41 | (key and secret can optionally be removed from that file and configured via ENV['AWS_ACCESS_KEY_ID'] and ENV['AWS_SECRET_ACCESS_KEY'])
42 |
43 | 5. Make the bucket
44 |
45 | There used to be a rake task for this, but it was removed so that there would be no dependency of aws/s3.
46 |
47 | 6. Upload the "crossdomain.xml file":https://github.com/nathancolgate/s3-swf-upload-plugin/blob/master/lib/s3_swf_upload/railties/tasks/crossdomain.xml to the root of your S3 Bucket.
48 |
49 | There used to be a rake task for this, but it was removed so that there would be no dependency of aws/s3.
50 |
51 | Make sure the file is in the root of your bucket and is publicly readable.
52 |
53 | 7. Note: you no longer need to edit app/controller/s3_uploads_controller.rb
54 |
55 | In my tests in Rails 3, the application was able to correctly handle the requests from the flash object.
56 |
57 | This means that your authentication systems can still be used to protect the signature generation.
58 |
59 | 8. Initialize the SWF object in your view using this handy helper:
60 |
61 |
<%=raw s3_swf_upload_tag %>
62 |
63 |
64 | 9. To achieve basic functionality, the only other thing you need is something to call the startUploading function. For example:
65 |
66 |
67 |
68 |
69 | However, you will have no feedback or interface to let you know that anything is actually happening.
70 |
71 | 10. If you want to customise its behavior, "here's a more complex example":http://gist.github.com/382979
72 |
73 | And the "CSS":http://gist.github.com/383118 to go along.
74 |
75 | h2. File Renaming
76 |
77 | In my applications I upload all files to _tmp_ folder and then have rails manipulate the file (renaming, resizing, etc). Here's a starting point to give you an idea of what that looks like using Paperclip:
78 |
79 | "How to integrate with Paperclip":http://gist.github.com/575842
80 |
81 | I prefer this solution because it allows the application to keep tabs on the files. However, if you are looking for a pure javascript solution, check out some of the forks of this project.
82 |
83 | h2. General Parameters
84 |
85 | h3. :buttonWidth _(integer = 100)_
86 |
87 | h3. :buttonHeight _(integer = 30)_
88 |
89 | h3. :flashVersion _(string = '9.0.0')_
90 |
91 | h3. :queueSizeLimit _(integer = 100)_
92 |
93 | Maximum number of files that can be added to the queue.
94 |
95 | h3. :fileSizeLimit _(integer = 524288000)_
96 |
97 | Individual file size limit in bytes (default is 512 MB)
98 |
99 | h3. :fileTypes _(string = '*.*')_
100 |
101 | Something like this also works: '*.jpg;*.gif;*.png;'
102 |
103 | h3. :fileTypeDescs _(string = 'All Files')_
104 |
105 | Something like this also works: 'Image files.'
106 |
107 | h3. :selectMultipleFiles _(boolean = true)_
108 |
109 | Set this to false if you only want to allow users to pick one file at a time.
110 |
111 | h3. :keyPrefix _(string = '')_
112 |
113 | String to be prepended to the uploaded file name to make the Amazon S3 key (location in bucket).
114 |
115 | h3. :signaturePath _(string = '/s3_uploads.xml')_
116 |
117 | Fully qualified path to the controller and action that will serve up the Amazon S3 signature
118 |
119 | h3. :swfFilePath _(string = '/flash/s3_upload.swf')_
120 |
121 | Fully qualified path to the SWF file (this is the one that does all the work).
122 |
123 | h3. :buttonUpPath _(string = '/flash/s3_up_button.gif')_
124 |
125 | Fully qualified path to an image to be used as the Browse Button (in the up state). Image should have same dimensions as the buttonWidth and buttonHeight parameters.
126 |
127 | h3. :buttonOverPath _(string = '/flash/s3_over_button.gif')_
128 |
129 | Fully qualified path to an image to be used as the Browse Button (in the over state). Image should have same dimensions as the buttonWidth and buttonHeight parameters.
130 |
131 | h3. :buttonDownPath _(string = '/flash/s3_down_button.gif')_
132 |
133 | Fully qualified path to an image to be used as the Browse Button (in the down state). Image should have same dimensions as the buttonWidth and buttonHeight parameters.
134 |
135 | h2. Callback Parameters
136 |
137 | The real power of this refactoring is that the flex application makes all of the following calls to JavaScript. What you do with the calls is totally up to you:
138 |
139 | * :onFileAdd _(file)_
140 | * :onFileRemove _(file)_
141 | * :onFileSizeLimitReached _(file)_
142 | * :onFileNotInQueue _(file)_
143 | * :onQueueChange _(queue)_
144 | * :onQueueSizeLimitReached _(queue)_
145 | * :onQueueEmpty _(queue)_
146 | * :onQueueClear _(queue)_
147 | * :onUploadingStart _()_
148 | * :onUploadingStop _()_
149 | * :onUploadingFinish _()_
150 | * :onSignatureOpen _(file,event)_
151 | * :onSignatureProgress _(file,progress_event)_
152 | * :onSignatureSecurityError _(file,security_error_event)_
153 | * :onSignatureComplete _(file,event)_
154 | * :onSignatureIOError _(file,io_error_event)_
155 | * :onSignatureHttpStatus _(file,http_status_event)_
156 | * :onSignatureXMLError _(file,error_message)_
157 | * :onUploadError _(upload_options,error)_
158 | * :onUploadOpen _(upload_options,event)_
159 | * :onUploadProgress _(upload_options,progress_event)_
160 | * :onUploadIOError _(upload_options,io_error_event)_
161 | * :onUploadHttpStatus _(upload_options,http_status_event)_
162 | * :onUploadSecurityError _(upload_options,security_error_event)_
163 | * :onUploadComplete _(upload_options,event)_
164 |
165 | h2. JavaScript Functions
166 |
167 | The following functions can be called on the generated object. Normally the call looks something like this:
168 |
169 |
s3_swf_1_object.startUploading();
170 |
171 |
172 | h3. startUploading
173 |
174 | Starts the uploading process
175 |
176 | h3. stopUploading
177 |
178 | Stops the uploading process. Note: Stopping and restarting the uploading process is buggy. I'd avoid it.
179 |
180 | h3. clearQueue
181 |
182 | Clears all files out of the queue.
183 |
184 | h3. removeFileFromQueue(integer)
185 |
186 | Removes a specific file from the queue.
187 |
188 | h2. Will it work with < Rails 3?
189 |
190 | You bet. The Rails 3 specific gem only makes installation and setup easier. Here are some tips for getting this to work with < Rails 3:
191 |
192 | * install it as a plugin script/plugin install git://github.com/nathancolgate/s3-swf-upload-plugin.git
193 | * copy the "template files":http://github.com/nathancolgate/s3-swf-upload-plugin/tree/master/lib/s3_swf_upload/railties/generators/uploader/templates/ into your application (use the "generator":http://github.com/nathancolgate/s3-swf-upload-plugin/blob/master/lib/s3_swf_upload/railties/generators/uploader/uploader_generator.rb as a road map)
194 | * copy the "view helpers":http://github.com/nathancolgate/s3-swf-upload-plugin/blob/master/lib/s3_swf_upload/view_helpers.rb into your applications /lib directory.
195 | * add the view helper and integer monkey patch to an initialization file:
196 |
197 | require 'view_helpers'
198 | require 'patch/integer'
199 |
200 | * load the config file by adding this to the bottom of your environment.rb file: S3SwfUpload::S3Config.load_config
201 | * replace references to Rails.root or Rails.env in the /vendor/plugins/s3-swf-upload-plugin/lib/s3_swf_upload/s3_config.rb file.
202 | * comment out the require railties inside /vendor/plugins/s3-swf-upload-plugin/lib/s3_swf_upload.rb
203 | * you may need to require 's3_swf_upload' and 'aws/s3' in your environment.rb file
204 | * your route will be map.resources instead of resources.
205 |
206 | h2. Known Issues
207 |
208 | 1. As much as I would like the interface to be 100% HTML, a (legitimate) security feature in Flash does not allow it:
209 |
210 | bq. "With Adobe Flash Player 10, the FileReference.browse and FileReference.download operations may be initiated only through ActionScript that originates from user interaction." - "Adobe TechNote":http://kb2.adobe.com/cps/405/kb405546.html
211 |
212 | The next best thing I could come up with was to pass images in as buttons.
213 |
214 | -If the startUploading call is made after calling stopUploading, only the first file in the queue is successfully uploaded.-
215 |
216 | h2. Kudos
217 |
218 | Original plugin is Copyright (c) 2008 elctech, released under the MIT license
219 |
220 | Updates to plugin for multiple file uploader are Copyright (c) 2010 PRX, released under the MIT license
221 |
222 | Conversion of plugin to gem for rails 3 is Copyright (c) 2010 Nathan Colgate Clark, released under the MIT license
223 |
224 | Stripping the flex application of UI and adding callbacks Copyright (c) 2010 Nathan Colgate Clark, released under the MIT license
225 |
226 | Thanks to yickster (Nick Merwin) for fixing the stopUploading issue
227 |
228 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 |
3 | require 'rubygems'
4 | require 'bundler'
5 | begin
6 | Bundler.setup(:default, :development)
7 | rescue Bundler::BundlerError => e
8 | $stderr.puts e.message
9 | $stderr.puts "Run `bundle install` to install missing gems"
10 | exit e.status_code
11 | end
12 | require 'rake'
13 |
14 | require 'jeweler'
15 | Jeweler::Tasks.new do |gem|
16 | # gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
17 | gem.name = "s3_swf_upload"
18 | gem.homepage = "http://github.com/nathancolgate/s3-swf-upload-plugin"
19 | gem.license = "MIT"
20 | gem.summary = %Q{Rails 3 gem that allows you to upload files directly to S3 from your application using flex for file management, css for presentation, and javascript for behavior.}
21 | gem.description = %Q{Rails 3 gem that allows you to upload files directly to S3 from your application using flex for file management, css for presentation, and javascript for behavior.}
22 | gem.email = "nathan@brandnewbox.com"
23 | gem.authors = ["Nathan Colgate"]
24 | # dependencies defined in Gemfile
25 | end
26 | Jeweler::RubygemsDotOrgTasks.new
27 |
28 | require 'rake/testtask'
29 | Rake::TestTask.new(:test) do |test|
30 | test.libs << 'lib' << 'test'
31 | test.pattern = 'test/**/test_*.rb'
32 | test.verbose = true
33 | end
34 |
35 | desc "Code coverage detail"
36 | task :simplecov do
37 | ENV['COVERAGE'] = "true"
38 | Rake::Task['test'].execute
39 | end
40 |
41 | task :default => :test
42 |
43 | require 'rdoc/task'
44 | Rake::RDocTask.new do |rdoc|
45 | version = File.exist?('VERSION') ? File.read('VERSION') : ""
46 |
47 | rdoc.rdoc_dir = 'rdoc'
48 | rdoc.title = "s3_swf_upload #{version}"
49 | rdoc.rdoc_files.include('README*')
50 | rdoc.rdoc_files.include('lib/**/*.rb')
51 | end
52 |
--------------------------------------------------------------------------------
/VERSION:
--------------------------------------------------------------------------------
1 | 0.3.3
--------------------------------------------------------------------------------
/flex_src/bin-release/flex-config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
14 |
15 |
16 |
17 | 9.0.124
18 |
19 |
20 |
21 |
22 | false
23 |
24 |
25 |
26 | en_US
27 |
28 |
29 |
30 |
31 | ../src
32 |
33 |
34 |
35 | false
36 |
37 |
38 |
39 | true
40 |
41 |
42 |
43 |
46 |
47 |
48 |
49 |
50 |
51 | ${flexlib}/libs/player/11.1/playerglobal.swc
52 |
53 |
54 |
55 |
56 |
57 |
58 | false
59 |
60 |
61 |
66 |
67 |
68 |
69 | ${flexlib}/libs
70 |
71 | ${flexlib}/libs/player
72 |
73 | ${flexlib}/libs/player/11.1
74 |
75 |
76 | ${flexlib}/locale/{locale}
77 |
78 |
79 |
80 |
81 |
82 |
83 | http://www.adobe.com/2006/mxml
84 | ${flexlib}/mxml-manifest.xml
85 |
86 |
87 |
88 |
89 | true
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
108 |
109 |
110 |
111 | true
112 |
113 |
114 | true
115 |
116 |
117 | true
118 |
119 |
120 |
121 |
122 | true
123 |
124 |
125 |
126 |
127 |
128 | false
129 |
130 |
131 |
132 |
138 |
139 |
140 | false
141 |
142 |
143 |
144 |
147 |
148 |
149 |
150 |
151 |
152 |
153 | true
154 |
155 |
156 | 20
157 |
158 |
159 | 1000
160 |
161 |
162 |
163 |
164 |
172 |
173 |
174 |
175 | flash.fonts.JREFontManager
176 | flash.fonts.AFEFontManager
177 | flash.fonts.BatikFontManager
178 |
179 |
180 |
187 |
188 |
189 |
190 |
191 | false
192 |
193 |
194 | true
195 |
196 |
197 | true
198 |
199 |
200 | true
201 |
202 |
203 | true
204 |
205 |
206 | true
207 |
208 |
209 | true
210 |
211 |
212 | true
213 |
214 |
215 | true
216 |
217 |
218 | true
219 |
220 |
221 | true
222 |
223 |
224 | false
225 |
226 |
227 | false
228 |
229 |
230 | true
231 |
232 |
233 | true
234 |
235 |
236 |
237 | false
238 |
239 |
240 | false
241 |
242 |
243 | true
244 |
245 |
246 | true
247 |
248 |
249 | true
250 |
251 |
252 | true
253 |
254 |
255 | false
256 |
257 |
258 | true
259 |
260 |
261 | true
262 |
263 |
264 | true
265 |
266 |
267 | true
268 |
269 |
270 | true
271 |
272 |
273 | true
274 |
275 |
276 | false
277 |
278 |
279 | false
280 |
281 |
282 | true
283 |
284 |
285 |
286 | false
287 |
288 |
289 |
290 |
291 |
292 | false
293 |
294 |
295 | true
296 |
297 |
298 | true
299 |
300 |
301 | false
302 |
303 |
304 |
305 |
307 |
310 |
311 |
312 |
313 |
319 |
320 |
321 |
322 | libs/framework.swc
323 | framework_3.4.0.9271.swz
324 |
325 | framework_3.4.0.9271.swf
326 |
327 |
328 |
329 | true
330 |
331 |
334 |
337 |
338 |
339 | true
340 |
341 |
342 |
343 | Adobe Flex 3 Application
344 | http://www.adobe.com/products/flex
345 | unknown
346 | unknown
347 | EN
348 |
349 |
350 |
351 |
352 |
360 |
361 |
362 |
--------------------------------------------------------------------------------
/flex_src/compile:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | mxmlc -load-config ./bin-release/flex-config.xml ./src/S3Uploader.as -output ../lib/s3_swf_upload/railties/generators/uploader/templates/s3_upload.swf
--------------------------------------------------------------------------------
/flex_src/src/Globals.as:
--------------------------------------------------------------------------------
1 | package {
2 |
3 | import com.nathancolgate.s3_swf_upload.S3Queue;
4 |
5 | public dynamic class Globals extends Object{
6 |
7 | public static var queue:S3Queue;
8 |
9 | public function Globals(){
10 | super();
11 | return;
12 | }
13 |
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/flex_src/src/S3Uploader.as:
--------------------------------------------------------------------------------
1 | package {
2 |
3 | import flash.events.*;
4 | import flash.external.*;
5 | import flash.net.*;
6 | import flash.display.*;
7 | import flash.system.Security;
8 | import com.nathancolgate.s3_swf_upload.*;
9 |
10 | public class S3Uploader extends Sprite {
11 |
12 | //File Reference Vars
13 | public var queue:S3Queue;
14 | public var file:FileReference;
15 |
16 | private var _multipleFileDialogBox:FileReferenceList;
17 | private var _singleFileDialogBox:FileReference;
18 | private var _fileFilter:FileFilter;
19 |
20 | //config vars
21 | private var _fileSizeLimit:Number; //bytes
22 | private var _queueSizeLimit:Number;
23 | private var _selectMultipleFiles:Boolean;
24 |
25 | private var cssLoader:URLLoader;
26 | public static var s3_swf_obj:String;
27 |
28 | public function S3Uploader() {
29 | super();
30 | S3Uploader.s3_swf_obj = LoaderInfo(root.loaderInfo).parameters.s3_swf_obj;
31 | registerCallbacks();
32 | }
33 |
34 | private function registerCallbacks():void {
35 | if (ExternalInterface.available) {
36 | ExternalInterface.addCallback("init", init);
37 | ExternalInterface.call(S3Uploader.s3_swf_obj+'.init');
38 | }
39 | }
40 |
41 | private function init(signatureUrl:String,
42 | prefixPath:String,
43 | fileSizeLimit:Number,
44 | queueSizeLimit:Number,
45 | fileTypes:String,
46 | fileTypeDescs:String,
47 | selectMultipleFiles:Boolean,
48 | buttonWidth:Number,
49 | buttonHeight:Number,
50 | buttonUpUrl:String,
51 | buttonDownUrl:String,
52 | buttonOverUrl:String
53 | ):void {
54 | // ExternalInterface.call('s3_swf.jsLog','Initializing...');
55 |
56 | flash.system.Security.allowDomain("*");
57 |
58 | // UI
59 | var browseButton:BrowseButton = new BrowseButton(buttonWidth,buttonHeight,buttonUpUrl,buttonDownUrl,buttonOverUrl);
60 | addChild(browseButton);
61 |
62 |
63 | stage.showDefaultContextMenu = false;
64 | stage.scaleMode = flash.display.StageScaleMode.NO_SCALE;
65 | stage.align = flash.display.StageAlign.TOP_LEFT;
66 |
67 | this.addEventListener(MouseEvent.CLICK, clickHandler);
68 |
69 | // file dialog boxes
70 | // We do two, so that we have the option to pick one or many
71 | _fileSizeLimit = fileSizeLimit;
72 | _fileFilter = new FileFilter(fileTypeDescs, fileTypes);
73 | _queueSizeLimit = queueSizeLimit;
74 | _selectMultipleFiles = selectMultipleFiles;
75 | _multipleFileDialogBox = new FileReferenceList;
76 | _singleFileDialogBox = new FileReference;
77 | _multipleFileDialogBox.addEventListener(Event.SELECT, selectFileHandler);
78 | _singleFileDialogBox.addEventListener(Event.SELECT, selectFileHandler);
79 |
80 |
81 |
82 | // Setup Queue, File
83 | this.queue = new S3Queue(signatureUrl,prefixPath);
84 | Globals.queue = this.queue;
85 |
86 | ExternalInterface.addCallback("removeFileFromQueue", removeFileHandler);
87 | // ExternalInterface.call('s3_swf.jsLog','Initialized');
88 |
89 | }
90 |
91 | // called when the browse button is clicked
92 | // Browse for files
93 | private function clickHandler(event:Event):void{
94 | // ExternalInterface.call('s3_swf.jsLog','clickHandler');
95 | if(_selectMultipleFiles == true){
96 | // ExternalInterface.call('s3_swf.jsLog','Opening Multiple File Dialog box...');
97 | _multipleFileDialogBox.browse([_fileFilter]);
98 | // ExternalInterface.call('s3_swf.jsLog','Multiple File Dialog box Opened');
99 | } else {
100 | // ExternalInterface.call('s3_swf.jsLog','Opening Single File Dialog box...');
101 | _singleFileDialogBox.browse([_fileFilter]);
102 | // ExternalInterface.call('s3_swf.jsLog','Single File Dialog box Opened');
103 | }
104 | }
105 |
106 | // called after user selected files form the browse dialouge box.
107 | private function selectFileHandler(event:Event):void {
108 | // ExternalInterface.call('s3_swf.jsLog','selectFileHandler');
109 | var remainingSpots:int = _queueSizeLimit - this.queue.length;
110 | var tooMany:Boolean = false;
111 |
112 | if(_selectMultipleFiles == true){
113 | // Adding multiple files to the queue array
114 | // ExternalInterface.call('s3_swf.jsLog','Adding multiple files to the queue array...');
115 | if(event.currentTarget.fileList.length > remainingSpots) { tooMany = true; }
116 | var i:int;
117 | for (i=0;i < remainingSpots; i ++){
118 | // ExternalInterface.call('s3_swf.jsLog','Adding '+(i+1)+' of '+(remainingSpots)+' files to the queue array...');
119 | addFile(event.currentTarget.fileList[i]);
120 | // ExternalInterface.call('s3_swf.jsLog',(i+1)+' of '+(remainingSpots)+' files added to the queue array');
121 | }
122 | // ExternalInterface.call('s3_swf.jsLog','Multiple files added to the queue array');
123 | } else {
124 | // Adding one single file to the queue array
125 | // ExternalInterface.call('s3_swf.jsLog','Adding single file to the queue array...');
126 | if(remainingSpots > 0) {
127 | addFile(FileReference(event.target));
128 | } else {
129 | tooMany = true;
130 | }
131 | // ExternalInterface.call('s3_swf.jsLog','Single file added to the queue array');
132 | }
133 |
134 | if(tooMany == true) {
135 | // ExternalInterface.call('s3_swf.jsLog','Calling onQueueSizeLimitReached...');
136 | ExternalInterface.call(S3Uploader.s3_swf_obj+'.onQueueSizeLimitReached',this.queue.toJavascript());
137 | // ExternalInterface.call('s3_swf.jsLog','onQueueSizeLimitReached called');
138 | }
139 |
140 | }
141 |
142 | // Add Selected File to Queue from file browser dialog box
143 | private function addFile(file:FileReference):void{
144 | // ExternalInterface.call('s3_swf.jsLog','addFile');
145 | if(!file) return;
146 | if (checkFileSize(file.size)){
147 | // ExternalInterface.call('s3_swf.jsLog','Adding file to queue...');
148 | this.queue.addItem(file);
149 | // ExternalInterface.call('s3_swf.jsLog','File added to queue');
150 | // ExternalInterface.call('s3_swf.jsLog','Calling onFileAdd...');
151 | ExternalInterface.call(S3Uploader.s3_swf_obj+'.onFileAdd',toJavascript(file));
152 | // ExternalInterface.call('s3_swf.jsLog','onFileAdd called');
153 | } else {
154 | // ExternalInterface.call('s3_swf.jsLog','Calling onFileSizeLimitReached...');
155 | ExternalInterface.call(S3Uploader.s3_swf_obj+'.onFileSizeLimitReached',toJavascript(file));
156 | // ExternalInterface.call('s3_swf.jsLog','onFileSizeLimitReached called');
157 | }
158 | }
159 |
160 |
161 | // Remove File From Queue by index number
162 | private function removeFileHandler(index:Number):void{
163 | try {
164 | var del_file:FileReference = FileReference(this.queue.getItemAt(index));
165 | this.queue.removeItemAt(index);
166 | // ExternalInterface.call('s3_swf.jsLog','Calling onFileRemove...');
167 | ExternalInterface.call(S3Uploader.s3_swf_obj+'.onFileRemove',del_file);
168 | // ExternalInterface.call('s3_swf.jsLog','onFileRemove called');
169 | } catch(e:Error) {
170 | // ExternalInterface.call('s3_swf.jsLog','Calling onFileNotInQueue...');
171 | ExternalInterface.call(S3Uploader.s3_swf_obj+'.onFileNotInQueue');
172 | // ExternalInterface.call('s3_swf.jsLog','onFileNotInQueue called');
173 | }
174 | }
175 |
176 |
177 | /* MISC */
178 |
179 | // Checks the files do not exceed maxFileSize | if maxFileSize == 0 No File Limit Set
180 | private function checkFileSize(filesize:Number):Boolean{
181 | var r:Boolean = false;
182 | //if filesize greater then maxFileSize
183 | if (filesize > _fileSizeLimit){
184 | r = false;
185 | } else if (filesize <= _fileSizeLimit){
186 | r = true;
187 | }
188 | if (_fileSizeLimit == 0){
189 | r = true;
190 | }
191 | return r;
192 | }
193 |
194 | // Turns a FileReference into an Object so that ExternalInterface doesn't choke
195 | private function toJavascript(file:FileReference):Object{
196 | var javascriptable_file:Object = new Object();
197 | javascriptable_file.name = file.name;
198 | javascriptable_file.size = file.size;
199 | javascriptable_file.type = file.type;
200 | return javascriptable_file;
201 | }
202 |
203 | }
204 | }
--------------------------------------------------------------------------------
/flex_src/src/com/adobe/net/MimeTypeMap.as:
--------------------------------------------------------------------------------
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 | }
--------------------------------------------------------------------------------
/flex_src/src/com/elctech/S3UploadOptions.as:
--------------------------------------------------------------------------------
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 | }
33 |
--------------------------------------------------------------------------------
/flex_src/src/com/elctech/S3UploadRequest.as:
--------------------------------------------------------------------------------
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"] = _options.ContentDisposition;
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 | }
--------------------------------------------------------------------------------
/flex_src/src/com/nathancolgate/s3_swf_upload/BrowseButton.as:
--------------------------------------------------------------------------------
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 | }
56 |
--------------------------------------------------------------------------------
/flex_src/src/com/nathancolgate/s3_swf_upload/S3Queue.as:
--------------------------------------------------------------------------------
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 | }
118 |
--------------------------------------------------------------------------------
/flex_src/src/com/nathancolgate/s3_swf_upload/S3Signature.as:
--------------------------------------------------------------------------------
1 | package com.nathancolgate.s3_swf_upload {
2 |
3 | import com.elctech.S3UploadOptions;
4 | import com.nathancolgate.s3_swf_upload.*;
5 | import flash.external.ExternalInterface;
6 | import com.adobe.net.MimeTypeMap;
7 |
8 | import flash.net.*
9 | import flash.events.*
10 |
11 | public class S3Signature {
12 |
13 | private var upload_options:S3UploadOptions;
14 | private var _file:FileReference;
15 | //private var _prefixPath:String
16 |
17 | public var s3upload:S3Upload;
18 |
19 | public function S3Signature(file:FileReference,
20 | signatureUrl:String,
21 | prefixPath:String) {
22 | _file = file;
23 | // _prefixPath = prefixPath
24 | // Create options list for file s3 upload metadata
25 | upload_options = new S3UploadOptions;
26 | upload_options.FileSize = _file.size.toString();
27 | upload_options.FileName = getFileName(_file);
28 | upload_options.ContentType = getContentType(upload_options.FileName);
29 | upload_options.key = prefixPath + upload_options.FileName;
30 |
31 | var variables:URLVariables = new URLVariables();
32 | variables.key = upload_options.key
33 | variables.content_type = upload_options.ContentType;
34 |
35 | var request:URLRequest = new URLRequest(signatureUrl);
36 | request.method = URLRequestMethod.GET;
37 | request.data = variables;
38 |
39 | var signature:URLLoader = new URLLoader();
40 | signature.dataFormat = URLLoaderDataFormat.TEXT;
41 | signature.addEventListener(Event.OPEN, openHandler);
42 | signature.addEventListener(ProgressEvent.PROGRESS, progressHandler);
43 | signature.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
44 | signature.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
45 | signature.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
46 | signature.addEventListener(Event.COMPLETE, completeHandler);
47 | signature.load(request);
48 | }
49 |
50 | private function openHandler(event:Event):void {
51 | ExternalInterface.call(S3Uploader.s3_swf_obj+'.onSignatureOpen',toJavascript(_file),event);
52 | }
53 |
54 | private function progressHandler(progress_event:ProgressEvent):void {
55 | ExternalInterface.call(S3Uploader.s3_swf_obj+'.onSignatureProgress',toJavascript(_file),progress_event);
56 | }
57 |
58 | private function securityErrorHandler(security_error_event:SecurityErrorEvent):void {
59 | ExternalInterface.call(S3Uploader.s3_swf_obj+'.onSignatureSecurityError',toJavascript(_file),security_error_event);
60 | }
61 |
62 | private function httpStatusHandler(http_status_event:HTTPStatusEvent):void {
63 | ExternalInterface.call(S3Uploader.s3_swf_obj+'.onSignatureHttpStatus',toJavascript(_file),http_status_event);
64 | }
65 |
66 | private function ioErrorHandler(io_error_event:IOErrorEvent):void {
67 | ExternalInterface.call(S3Uploader.s3_swf_obj+'.onSignatureIOError',toJavascript(_file),io_error_event);
68 | }
69 |
70 | private function completeHandler(event:Event):void {
71 | ExternalInterface.call(S3Uploader.s3_swf_obj+'.onSignatureComplete',toJavascript(_file),event);
72 | var loader:URLLoader = URLLoader(event.target);
73 | var xml:XML = new XML(loader.data);
74 |
75 | // create the s3 options object
76 | upload_options.policy = xml.policy;
77 | upload_options.signature = xml.signature;
78 | upload_options.bucket = xml.bucket;
79 | upload_options.AWSAccessKeyId = xml.accesskeyid;
80 | upload_options.acl = xml.acl;
81 | upload_options.Expires = xml.expirationdate;
82 | upload_options.Secure = xml.https;
83 | upload_options.ContentDisposition = xml.contentDisposition;
84 | upload_options.newKey = xml.newKey; //NOTE that we stop caring about the specified prefix if we have a newkey.
85 |
86 | if (xml.errorMessage != "") {
87 | ExternalInterface.call(S3Uploader.s3_swf_obj+'.onSignatureXMLError',toJavascript(_file),xml.errorMessage);
88 | return;
89 | }
90 |
91 | s3upload = new S3Upload(upload_options);
92 | }
93 |
94 | /* MISC */
95 |
96 | private function getContentType(fileName:String):String {
97 | var fileNameArray:Array = fileName.split(/\./);
98 | var fileExtension:String = fileNameArray[fileNameArray.length - 1];
99 | var mimeMap:MimeTypeMap = new MimeTypeMap;
100 | var contentType:String = mimeMap.getMimeType(fileExtension);
101 | return contentType;
102 | }
103 |
104 | private function getFileName(file:FileReference):String {
105 | var fileName:String = file.name.replace(/^.*(\\|\/)/gi, '').replace(/[^A-Za-z0-9\.\-]/gi, '_');
106 | return fileName;
107 | }
108 |
109 | // Turns a FileReference into an Object so that ExternalInterface doesn't choke
110 | private function toJavascript(file:FileReference):Object{
111 | var javascriptable_file:Object = new Object();
112 | javascriptable_file.name = file.name;
113 | javascriptable_file.size = file.size;
114 | javascriptable_file.type = file.type;
115 | return javascriptable_file;
116 | }
117 |
118 | }
119 | }
--------------------------------------------------------------------------------
/flex_src/src/com/nathancolgate/s3_swf_upload/S3Upload.as:
--------------------------------------------------------------------------------
1 | package com.nathancolgate.s3_swf_upload {
2 |
3 | import com.elctech.S3UploadOptions;
4 | import com.elctech.S3UploadRequest;
5 | import flash.external.ExternalInterface;
6 | import com.nathancolgate.s3_swf_upload.*;
7 | import flash.net.*;
8 | import flash.events.*;
9 |
10 | public class S3Upload extends S3UploadRequest {
11 |
12 | private var _upload_options:S3UploadOptions;
13 |
14 | public function S3Upload(s3_upload_options:S3UploadOptions) {
15 | super(s3_upload_options);
16 |
17 | _upload_options = s3_upload_options;
18 |
19 | addEventListener(Event.OPEN, openHandler);
20 | addEventListener(ProgressEvent.PROGRESS, progressHandler);
21 | addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
22 | addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
23 | addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
24 | addEventListener(DataEvent.UPLOAD_COMPLETE_DATA, completeHandler);
25 |
26 | try {
27 | var next_file:FileReference = FileReference(Globals.queue.getItemAt(0));
28 | this.upload(next_file);
29 | } catch(error:Error) {
30 | ExternalInterface.call(S3Uploader.s3_swf_obj+'.onUploadError',_upload_options,error);
31 | }
32 | }
33 |
34 | // called after the file is opened before _upload_options
35 | private function openHandler(event:Event):void{
36 | // This should only happen once per file
37 | // But sometimes, after stopping and restarting the queeue
38 | // It gets called multiple times
39 | // BUG BUG BUG!
40 | // ExternalInterface.call('s3_swf.jsLog','openHandler');
41 | // ExternalInterface.call('s3_swf.jsLog','Calling onUploadOpen...');
42 | ExternalInterface.call(S3Uploader.s3_swf_obj+'.onUploadOpen',_upload_options,event);
43 | // ExternalInterface.call('s3_swf.jsLog','onUploadOpen called');
44 | }
45 |
46 | // called during the file _upload_options of each file being _upload_optionsed
47 | // we use this to feed the progress bar its data
48 | private function progressHandler(progress_event:ProgressEvent):void {
49 | // ExternalInterface.call('s3_swf.jsLog','progressHandler');
50 | // ExternalInterface.call('s3_swf.jsLog','Calling onUploadProgress...');
51 | ExternalInterface.call(S3Uploader.s3_swf_obj+'.onUploadProgress',_upload_options,progress_event);
52 | // ExternalInterface.call('s3_swf.jsLog','onUploadProgress called');
53 | }
54 |
55 | // only called if there is an error detected by flash player browsing or _upload_optionsing a file
56 | private function ioErrorHandler(io_error_event:IOErrorEvent):void{
57 | // ExternalInterface.call('s3_swf.jsLog','ioErrorHandler');
58 | // ExternalInterface.call('s3_swf.jsLog','Calling onUploadIOError...');
59 | ExternalInterface.call(S3Uploader.s3_swf_obj+'.onUploadIOError',_upload_options,io_error_event);
60 | // ExternalInterface.call('s3_swf.jsLog','onUploadIOError called');
61 | }
62 |
63 | private function httpStatusHandler(http_status_event:HTTPStatusEvent):void {
64 | // ExternalInterface.call('s3_swf.jsLog','httpStatusHandler');
65 | // ExternalInterface.call('s3_swf.jsLog','Calling onUploadHttpStatus...');
66 | ExternalInterface.call(S3Uploader.s3_swf_obj+'.onUploadHttpStatus',_upload_options,http_status_event);
67 | // ExternalInterface.call('s3_swf.jsLog','onUploadHttpStatus called');
68 | }
69 |
70 | // only called if a security error detected by flash player such as a sandbox violation
71 | private function securityErrorHandler(security_error_event:SecurityErrorEvent):void{
72 | // ExternalInterface.call('s3_swf.jsLog','securityErrorHandler');
73 | // ExternalInterface.call('s3_swf.jsLog','Calling onUploadSecurityError...');
74 | ExternalInterface.call(S3Uploader.s3_swf_obj+'.onUploadSecurityError',_upload_options,security_error_event);
75 | // ExternalInterface.call('s3_swf.jsLog','onUploadSecurityError called');
76 | }
77 |
78 | private function completeHandler(event:Event):void{
79 | // prepare to destroy
80 | removeListeners();
81 | removeEventListener(Event.OPEN, openHandler);
82 | removeEventListener(ProgressEvent.PROGRESS, progressHandler);
83 | removeEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
84 | removeEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
85 | removeEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
86 | removeEventListener(DataEvent.UPLOAD_COMPLETE_DATA, completeHandler);
87 |
88 | // callback
89 | // ExternalInterface.call('s3_swf.jsLog','completeHandler');
90 | // ExternalInterface.call('s3_swf.jsLog','Calling onUploadComplete...');
91 | ExternalInterface.call(S3Uploader.s3_swf_obj+'.onUploadComplete',_upload_options,event);
92 | // ExternalInterface.call('s3_swf.jsLog','onUploadComplete called');
93 | // ExternalInterface.call('s3_swf.jsLog','Removing item from global queue...');
94 |
95 | // destroy
96 | Globals.queue.removeItemAt(0);
97 |
98 | // ExternalInterface.call('s3_swf.jsLog','Item removed from global queue');
99 | if (Globals.queue.length > 0){
100 | // ExternalInterface.call('s3_swf.jsLog','Uploading next item in global queue...');
101 | Globals.queue.uploadNextFile();
102 | // ExternalInterface.call('s3_swf.jsLog','Next ttem in global queue uploaded');
103 | } else {
104 | // ExternalInterface.call('s3_swf.jsLog','Calling onUploadingFinish...');
105 | ExternalInterface.call(S3Uploader.s3_swf_obj+'.onUploadingFinish');
106 | // ExternalInterface.call('s3_swf.jsLog','onUploadingFinish called');
107 | }
108 | }
109 |
110 | }
111 | }
--------------------------------------------------------------------------------
/lib/patch/integer.rb:
--------------------------------------------------------------------------------
1 | class Integer
2 | # 32-bit left shift
3 | def js_shl(count)
4 | v = (self << count) & 0xffffffff
5 | v > 2**31 ? v - 2**32 : v
6 | end
7 |
8 | # 32-bit zero-fill right shift (>>>)
9 | def js_shr_zf(count)
10 | self >> count & (2**(32-count)-1)
11 | end
12 | end
--------------------------------------------------------------------------------
/lib/s3_swf_upload.rb:
--------------------------------------------------------------------------------
1 | require 'patch/integer'
2 | require 's3_swf_upload/signature'
3 | require 's3_swf_upload/s3_config'
4 | require 's3_swf_upload/view_helpers'
5 |
6 | module S3SwfUpload
7 | # Rails 3 Railties!
8 | # https://gist.github.com/af7e572c2dc973add221
9 | require 's3_swf_upload/railtie' if defined?(Rails)
10 | end
11 |
--------------------------------------------------------------------------------
/lib/s3_swf_upload/railtie.rb:
--------------------------------------------------------------------------------
1 | require 's3_swf_upload'
2 | require 'rails'
3 |
4 | module S3SwfUpload
5 | class Railtie < Rails::Railtie
6 |
7 | initializer "s3_swf_upload.load_s3_swf_upload_config" do
8 | S3SwfUpload::S3Config.load_config
9 | end
10 |
11 | generators do
12 | require "s3_swf_upload/railties/generators/uploader/uploader_generator"
13 | end
14 |
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/lib/s3_swf_upload/railties/generators/s3_swf_upload.rb:
--------------------------------------------------------------------------------
1 | require 'rails/generators/base'
2 |
3 | module S3SwfUpload
4 | module Generators
5 | class Base < Rails::Generators::Base #:nodoc:
6 |
7 | def self.source_root
8 | # puts '****'
9 | # puts File.expand_path(File.join(File.dirname(__FILE__), generator_name, 'templates'))
10 | File.expand_path(File.join(File.dirname(__FILE__),generator_name, 'templates'))
11 | end
12 |
13 | def self.banner
14 | "#{$0} generate s3_swf_upload:#{generator_name} #{self.arguments.map{ |a| a.usage }.join(' ')}"
15 | end
16 |
17 | end
18 | end
19 | end
--------------------------------------------------------------------------------
/lib/s3_swf_upload/railties/generators/uploader/USAGE:
--------------------------------------------------------------------------------
1 | Description:
2 | Adds the following files to your application:
3 |
4 | * amazon_s3.yml config file
5 | * s3_uploads_controller.rb
6 | * s3_upload.js
7 | * s3_upload.swf
8 |
9 | And then, as if that were not enough, it adds a route for you, too!
10 |
11 |
--------------------------------------------------------------------------------
/lib/s3_swf_upload/railties/generators/uploader/templates/amazon_s3.yml:
--------------------------------------------------------------------------------
1 | development:
2 | bucket:
3 | access_key_id:
4 | secret_access_key:
5 | max_file_size: 10485760
6 | acl: public-read
7 |
8 | test:
9 | bucket:
10 | access_key_id:
11 | secret_access_key:
12 | max_file_size: 10485760
13 | acl: public-read
14 |
15 | production:
16 | bucket:
17 | access_key_id:
18 | secret_access_key:
19 | max_file_size: 10485760
20 | acl: public-read
21 |
--------------------------------------------------------------------------------
/lib/s3_swf_upload/railties/generators/uploader/templates/s3_down_button.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nathancolgate/s3-swf-upload-plugin/7c0ffa717ef9b6212d2ecef9ed7eb6b224a499d2/lib/s3_swf_upload/railties/generators/uploader/templates/s3_down_button.gif
--------------------------------------------------------------------------------
/lib/s3_swf_upload/railties/generators/uploader/templates/s3_over_button.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nathancolgate/s3-swf-upload-plugin/7c0ffa717ef9b6212d2ecef9ed7eb6b224a499d2/lib/s3_swf_upload/railties/generators/uploader/templates/s3_over_button.gif
--------------------------------------------------------------------------------
/lib/s3_swf_upload/railties/generators/uploader/templates/s3_up_button.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nathancolgate/s3-swf-upload-plugin/7c0ffa717ef9b6212d2ecef9ed7eb6b224a499d2/lib/s3_swf_upload/railties/generators/uploader/templates/s3_up_button.gif
--------------------------------------------------------------------------------
/lib/s3_swf_upload/railties/generators/uploader/templates/s3_upload.js:
--------------------------------------------------------------------------------
1 | /* SWFObject v2.2
2 | is released under the MIT License
3 | */
4 | var s3_upload_swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else{if(typeof O.ActiveXObject!=D){try{var ad=new ActiveXObject(W);if(ad){ab=ad.GetVariable("$version");if(ab){X=true;ab=ab.split(" ")[1].split(",");ag=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}}catch(Z){}}}return{w3:aa,pv:ag,wk:af,ie:X,win:ae,mac:ac}}(),k=function(){if(!M.w3){return}if((typeof j.readyState!=D&&j.readyState=="complete")||(typeof j.readyState==D&&(j.getElementsByTagName("body")[0]||j.body))){f()}if(!J){if(typeof j.addEventListener!=D){j.addEventListener("DOMContentLoaded",f,false)}if(M.ie&&M.win){j.attachEvent(x,function(){if(j.readyState=="complete"){j.detachEvent(x,arguments.callee);f()}});if(O==top){(function(){if(J){return}try{j.documentElement.doScroll("left")}catch(X){setTimeout(arguments.callee,0);return}f()})()}}if(M.wk){(function(){if(J){return}if(!/loaded|complete/.test(j.readyState)){setTimeout(arguments.callee,0);return}f()})()}s(f)}}();function f(){if(J){return}try{var Z=j.getElementsByTagName("body")[0].appendChild(C("span"));Z.parentNode.removeChild(Z)}catch(aa){return}J=true;var X=U.length;for(var Y=0;Y0){for(var af=0;af0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute("width")||"0";ai.height=ae.getAttribute("height")||"0";if(ae.getAttribute("class")){ai.styleclass=ae.getAttribute("class")}if(ae.getAttribute("align")){ai.align=ae.getAttribute("align")}var ah={};var X=ae.getElementsByTagName("param");var ac=X.length;for(var ad=0;ad'}}aa.outerHTML='";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute("type",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()=="styleclass"){Z.setAttribute("class",ai[ac])}else{if(ac.toLowerCase()!="classid"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!="movie"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C("param");aa.setAttribute("name",X);aa.setAttribute("value",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName=="OBJECT"){if(M.ie&&M.win){X.style.display="none";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]=="function"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(".");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName("head")[0];if(!aa){return}var X=(ad&&typeof ad=="string")?ad:"screen";if(ab){n=null;G=null}if(!n||G!=X){var Z=C("style");Z.setAttribute("type","text/css");Z.setAttribute("media",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+" {"+Y+"}"))}}}function w(Z,X){if(!m){return}var Y=X?"visible":"hidden";if(J&&c(Z)){c(Z).style.visibility=Y}else{v("#"+Z,"visibility:"+Y)}}function L(Y){var Z=/[\\\"<>\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent("onunload",function(){var ac=I.length;for(var ab=0;ab
9 | */
10 | /* S3_Upload V0.2
11 | Copyright (c) 2010 Nathan Colgate,
12 | This software is released under the MIT License
13 | */
14 | var s3_swf;
15 | function s3_swf_init(id, options)
16 | {
17 | var buttonWidth = (options.buttonWidth != undefined) ? options.buttonWidth : 50;
18 | var buttonHeight = (options.buttonHeight != undefined) ? options.buttonHeight : 50;
19 | var flashVersion = (options.flashVersion != undefined) ? options.flashVersion : '9.0.0';
20 | var queueSizeLimit = (options.queueSizeLimit != undefined) ? options.queueSizeLimit : 10;
21 | var fileSizeLimit = (options.fileSizeLimit != undefined) ? options.fileSizeLimit : 524288000;
22 | var fileTypes = (options.fileTypes != undefined) ? options.fileTypes : "*.*";
23 | var fileTypeDescs = (options.fileTypeDescs != undefined) ? options.fileTypeDescs : "All Files";
24 | var selectMultipleFiles = (options.selectMultipleFiles != undefined) ? options.selectMultipleFiles : true;
25 | var keyPrefix = (options.keyPrefix != undefined) ? options.keyPrefix : "";
26 | var signaturePath = (options.signaturePath != undefined) ? options.signaturePath : "s3_uploads.xml";
27 | var swfFilePath = (options.swfFilePath != undefined) ? options.swfFilePath : "/flash/s3_upload.swf";
28 | var buttonUpPath = (options.buttonUpPath != undefined) ? options.buttonUpPath : "";
29 | var buttonOverPath = (options.buttonOverPath != undefined) ? options.buttonOverPath : "";
30 | var buttonDownPath = (options.buttonDownPath != undefined) ? options.buttonDownPath : "";
31 |
32 | var onFileAdd = (options.onFileAdd != undefined) ? options.onFileAdd : function(file){};
33 | var onFileRemove = (options.onFileRemove != undefined) ? options.onFileRemove : function(file){};
34 | var onFileSizeLimitReached = (options.onFileSizeLimitReached != undefined) ? options.onFileSizeLimitReached : function(file){};
35 | var onFileNotInQueue = (options.onFileNotInQueue != undefined) ? options.onFileNotInQueue : function(file){};
36 |
37 | var onQueueChange = (options.onQueueChange != undefined) ? options.onQueueChange : function(queue){};
38 | var onQueueClear = (options.onQueueClear != undefined) ? options.onQueueClear : function(queue){};
39 | var onQueueSizeLimitReached = (options.onQueueSizeLimitReached != undefined) ? options.onQueueSizeLimitReached : function(queue){};
40 | var onQueueEmpty = (options.onQueueEmpty != undefined) ? options.onQueueEmpty : function(queue){};
41 |
42 | var onUploadingStop = (options.onUploadingStop != undefined) ? options.onUploadingStop : function(){};
43 | var onUploadingStart = (options.onUploadingStart != undefined) ? options.onUploadingStart : function(){};
44 | var onUploadingFinish = (options.onUploadingFinish != undefined) ? options.onUploadingFinish : function(){};
45 |
46 | var onSignatureOpen = (options.onSignatureOpen != undefined) ? options.onSignatureOpen : function(file,event){};
47 | var onSignatureProgress = (options.onSignatureProgress != undefined) ? options.onSignatureProgress : function(file,progress_event){};
48 | var onSignatureHttpStatus = (options.onSignatureHttpStatus != undefined) ? options.onSignatureHttpStatus : function(file,http_status_event){};
49 | var onSignatureComplete = (options.onSignatureComplete != undefined) ? options.onSignatureComplete : function(file,event){};
50 | var onSignatureSecurityError = (options.onSignatureSecurityError != undefined) ? options.onSignatureSecurityError : function(file,security_error_event){};
51 | var onSignatureIOError = (options.onSignatureIOError != undefined) ? options.onSignatureIOError : function(file,io_error_event){};
52 | var onSignatureXMLError = (options.onSignatureXMLError != undefined) ? options.onSignatureXMLError : function(file,error_message){};
53 |
54 | var onUploadOpen = (options.onUploadOpen != undefined) ? options.onUploadOpen : function(upload_options,event){};
55 | var onUploadProgress = (options.onUploadProgress != undefined) ? options.onUploadProgress : function(upload_options,progress_event){};
56 | var onUploadHttpStatus = (options.onUploadHttpStatus != undefined) ? options.onUploadHttpStatus : function(upload_options,http_status_event){};
57 | var onUploadComplete = (options.onUploadComplete != undefined) ? options.onUploadComplete : function(upload_options,event){};
58 | var onUploadIOError = (options.onUploadIOError != undefined) ? options.onUploadIOError : function(upload_options,io_error_event){};
59 | var onUploadSecurityError = (options.onUploadSecurityError != undefined) ? options.onUploadSecurityError : function(upload_options,security_error_event){};
60 | var onUploadError = (options.onUploadError != undefined) ? options.onUploadError : function(upload_options,error){};
61 |
62 | var flashvars = {"s3_swf_obj": (options.swfVarObj != undefined ? options.swfVarObj : 's3_swf')}; //fallback to the global var incase script is used outside of view helper
63 | var params = {};
64 | var attributes = {};
65 | params.wmode = "transparent";
66 | params.menu = "false";
67 | params.quality = "low";
68 |
69 | s3_upload_swfobject.embedSWF(swfFilePath+"?t=" + new Date().getTime(), id, buttonWidth, buttonHeight, flashVersion, false, flashvars, params, attributes);
70 |
71 | var signatureUrl = window.location.protocol + '//' + window.location.host + signaturePath;
72 | var buttonUpUrl = window.location.protocol + '//' + window.location.host + buttonUpPath;
73 | var buttonDownUrl = window.location.protocol + '//' + window.location.host + buttonDownPath;
74 | var buttonOverUrl = window.location.protocol + '//' + window.location.host + buttonOverPath;
75 |
76 | s3_swf = {
77 | obj: function() { return document[id]; },
78 |
79 | init: function() { this.obj().init(signatureUrl, keyPrefix, fileSizeLimit, queueSizeLimit, fileTypes, fileTypeDescs, selectMultipleFiles,buttonWidth,buttonHeight,buttonUpUrl,buttonDownUrl,buttonOverUrl); },
80 | clearQueue: function() { this.obj().clearQueue();},
81 | startUploading: function() { this.obj().startUploading();},
82 | stopUploading: function() { this.obj().stopUploading();},
83 | removeFileFromQueue: function(index) { this.obj().removeFileFromQueue(index); },
84 |
85 | onFileAdd: onFileAdd,
86 | onFileRemove: onFileRemove,
87 | onFileSizeLimitReached: onFileSizeLimitReached,
88 | onFileNotInQueue: onFileNotInQueue,
89 |
90 | onQueueChange: onQueueChange,
91 | onQueueClear: onQueueClear,
92 | onQueueSizeLimitReached: onQueueSizeLimitReached,
93 | onQueueEmpty: onQueueEmpty,
94 |
95 | onUploadingStop: onUploadingStop,
96 | onUploadingStart: onUploadingStart,
97 | onUploadingFinish: onUploadingFinish,
98 |
99 | onSignatureOpen: onSignatureOpen,
100 | onSignatureProgress: onSignatureProgress,
101 | onSignatureHttpStatus: onSignatureHttpStatus,
102 | onSignatureComplete: onSignatureComplete,
103 | onSignatureSecurityError: onSignatureSecurityError,
104 | onSignatureIOError: onSignatureIOError,
105 | onSignatureXMLError: onSignatureXMLError,
106 |
107 | onUploadOpen: onUploadOpen,
108 | onUploadProgress: onUploadProgress,
109 | onUploadHttpStatus: onUploadHttpStatus,
110 | onUploadComplete: onUploadComplete,
111 | onUploadIOError: onUploadIOError,
112 | onUploadSecurityError: onUploadSecurityError,
113 | onUploadError: onUploadError
114 |
115 | }
116 |
117 | return(s3_swf);
118 | }
119 |
--------------------------------------------------------------------------------
/lib/s3_swf_upload/railties/generators/uploader/templates/s3_upload.swf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nathancolgate/s3-swf-upload-plugin/7c0ffa717ef9b6212d2ecef9ed7eb6b224a499d2/lib/s3_swf_upload/railties/generators/uploader/templates/s3_upload.swf
--------------------------------------------------------------------------------
/lib/s3_swf_upload/railties/generators/uploader/templates/s3_uploads_controller.rb:
--------------------------------------------------------------------------------
1 | require 'base64'
2 |
3 | class S3UploadsController < ApplicationController
4 |
5 | # You might want to look at https and expiration_date below.
6 | # Possibly these should also be configurable from S3Config...
7 |
8 | skip_before_filter :verify_authenticity_token
9 | include S3SwfUpload::Signature
10 |
11 | def index
12 | bucket = S3SwfUpload::S3Config.bucket
13 | access_key_id = S3SwfUpload::S3Config.access_key_id
14 | acl = S3SwfUpload::S3Config.acl
15 | secret_key = S3SwfUpload::S3Config.secret_access_key
16 | max_file_size = S3SwfUpload::S3Config.max_file_size
17 | key = params[:key]
18 | content_type = params[:content_type]
19 | content_disposition = 'attachment'
20 | https = 'false'
21 | error_message = ''
22 | expiration_date = 1.hours.from_now.utc.strftime('%Y-%m-%dT%H:%M:%S.000Z')
23 | policy = Base64.encode64(
24 | {'expiration' => expiration_date,
25 | 'conditions' => [
26 | {'bucket' => bucket},
27 | {'key'=> key},
28 | {'acl'=> acl},
29 | {'Content-Type'=> content_type},
30 | {'Content-Disposition'=> content_disposition},
31 | ['content-length-range', 1, max_file_size],
32 | ['starts-with', '$Filename', ''],
33 | ['eq', '$success_action_status', '201']
34 | ]
35 | }.to_json).gsub(/\n|\r/, '')
36 |
37 | signature = b64_hmac_sha1(secret_key, policy)
38 |
39 | respond_to do |format|
40 | format.xml {
41 | render :xml => {
42 | :policy => policy,
43 | :signature => signature,
44 | :bucket => bucket,
45 | :accesskeyid => access_key_id,
46 | :acl => acl,
47 | :expirationdate => expiration_date,
48 | :https => https,
49 | :contentDisposition => content_disposition,
50 | :errorMessage => error_message.to_s
51 | }.to_xml
52 | }
53 | end
54 | end
55 | end
56 |
--------------------------------------------------------------------------------
/lib/s3_swf_upload/railties/generators/uploader/uploader_generator.rb:
--------------------------------------------------------------------------------
1 | require 's3_swf_upload/railties/generators/s3_swf_upload'
2 |
3 | module S3SwfUpload
4 | module Generators
5 | class UploaderGenerator < Base
6 |
7 | def create_uploader
8 | copy_file 'amazon_s3.yml', File.join('config','amazon_s3.yml')
9 | copy_file 's3_uploads_controller.rb', File.join('app','controllers', 's3_uploads_controller.rb')
10 | copy_file 's3_upload.js', File.join('public','javascripts', 's3_upload.js')
11 | copy_file 's3_upload.swf', File.join('public','flash', 's3_upload.swf')
12 | copy_file 's3_up_button.gif', File.join('public','flash', 's3_up_button.gif')
13 | copy_file 's3_down_button.gif', File.join('public','flash', 's3_down_button.gif')
14 | copy_file 's3_over_button.gif', File.join('public','flash', 's3_over_button.gif')
15 | route "resources :s3_uploads"
16 | end
17 |
18 | end
19 | end
20 | end
--------------------------------------------------------------------------------
/lib/s3_swf_upload/railties/tasks/crossdomain.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/lib/s3_swf_upload/s3_config.rb:
--------------------------------------------------------------------------------
1 | module S3SwfUpload
2 | class S3Config
3 | require 'erb' unless defined?(ERB)
4 | require 'yaml' unless defined?(YAML)
5 |
6 | cattr_reader :access_key_id, :secret_access_key
7 | cattr_accessor :bucket, :max_file_size, :acl
8 |
9 | def self.load_config
10 | begin
11 | filename = "#{Rails.root}/config/amazon_s3.yml"
12 |
13 | buf = IO.read(filename)
14 | expanded = ERB.new(buf).result(binding)
15 | config = YAML.load(expanded)[Rails.env]
16 |
17 | if config == nil
18 | raise "Could not load config options for #{Rails.env} from #{filename}."
19 | end
20 |
21 | @@access_key_id = config['access_key_id'] || ENV['AWS_ACCESS_KEY_ID']
22 | @@secret_access_key = config['secret_access_key'] || ENV['AWS_SECRET_ACCESS_KEY']
23 | @@bucket = config['bucket']
24 | @@max_file_size = config['max_file_size'] || 5000000000
25 | @@acl = config['acl'] || 'private'
26 |
27 |
28 |
29 | unless @@access_key_id && @@secret_access_key && @@bucket
30 | raise "Please configure your S3 settings in #{filename} before continuing so that S3 SWF Upload can function properly."
31 | end
32 | rescue Errno::ENOENT
33 | # Using put inside a rake task may mess with some rake tasks
34 | # According to: https://github.com/mhodgson/s3-swf-upload-plugin/commit/f5cc849e1d8b43c1f0d30eb92b772c10c9e73891
35 | # Going to comment this out for the time being
36 | # NCC@BNB - 11/16/10
37 | # No config file yet. Not a big deal. Just issue a warning
38 | # puts "WARNING: You are using the S3 SWF Uploader gem, which wants a config file at #{filename}, " +
39 | # "but none could be found. You should try running 'rails generate s3_swf_upload:uploader'"
40 | end
41 | end
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/lib/s3_swf_upload/signature.rb:
--------------------------------------------------------------------------------
1 | module S3SwfUpload
2 | module Signature
3 | $hexcase = false # hex output format. false - lowercase; true - uppercase
4 | $b64pad = "=" # base-64 pad character. "=" for strict RFC compliance
5 | $chrsz = 8 # bits per input character. 8 - ASCII; 16 - Unicode
6 |
7 | def hex_sha1(s)
8 | return binb2hex(core_sha1(str2binb(s), s.length * $chrsz))
9 | end
10 |
11 | def b64_hmac_sha1(key, data)
12 | return binb2b64(core_hmac_sha1(key, data))
13 | end
14 |
15 | # Absolute barebones "unit" tests
16 | def assert(expr)
17 | raise 'Assertion failed' unless (expr)
18 | end
19 |
20 | def self_test
21 | num, cnt = [1732584193, 5]
22 |
23 | assert(core_sha1(str2binb('abc'), 'abc'.length) == [-519653305, -1566383753, -2070791546, -753729183, -204968198])
24 | assert(rol(num, cnt) == -391880660)
25 | assert(safe_add(2042729798, num) == -519653305)
26 | assert((num.js_shl(cnt)) == -391880672)
27 | assert((num.js_shr_zf(32 - cnt)) == 12)
28 | assert(sha1_ft(0, -271733879, -1732584194, 271733878) == -1732584194)
29 | assert(sha1_kt(0) == 1518500249)
30 | assert(safe_add(safe_add(rol(num, cnt), sha1_ft(0, -271733879, -1732584194, 271733878)), safe_add(safe_add(-1009589776, 1902273280), sha1_kt(0))) == 286718899)
31 | assert(str2binb('foo bar hey there') == [1718578976, 1650553376, 1751480608, 1952998770, 1694498816])
32 | assert(hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d")
33 | assert(b64_hmac_sha1("foo", "abc") == "frFXMR9cNoJdsSPnjebZpBhUKzI=")
34 | end
35 |
36 | # Calculate the SHA-1 of an array of big-endian words, and a bit length
37 | def core_sha1(x, len)
38 | # append padding
39 | x[len >> 5] ||= 0
40 | x[len >> 5] |= 0x80 << (24 - len % 32)
41 | x[((len + 64 >> 9) << 4) + 15] = len
42 |
43 | w = Array.new(80, 0)
44 | a = 1732584193
45 | b = -271733879
46 | c = -1732584194
47 | d = 271733878
48 | e = -1009589776
49 |
50 | #for(var i = 0; i < x.length; i += 16)
51 | i = 0
52 | while(i < x.length)
53 | olda = a
54 | oldb = b
55 | oldc = c
56 | oldd = d
57 | olde = e
58 |
59 | #for(var j = 0; j < 80; j++)
60 | j = 0
61 | while(j < 80)
62 | if(j < 16)
63 | w[j] = x[i + j] || 0
64 | else
65 | w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1)
66 | end
67 |
68 | t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)),
69 | safe_add(safe_add(e, w[j]), sha1_kt(j)))
70 | e = d
71 | d = c
72 | c = rol(b, 30)
73 | b = a
74 | a = t
75 | j += 1
76 | end
77 |
78 | a = safe_add(a, olda)
79 | b = safe_add(b, oldb)
80 | c = safe_add(c, oldc)
81 | d = safe_add(d, oldd)
82 | e = safe_add(e, olde)
83 | i += 16
84 | end
85 | return [a, b, c, d, e]
86 | end
87 |
88 | # Perform the appropriate triplet combination function for the current
89 | # iteration
90 | def sha1_ft(t, b, c, d)
91 | return (b & c) | ((~b) & d) if(t < 20)
92 | return b ^ c ^ d if(t < 40)
93 | return (b & c) | (b & d) | (c & d) if(t < 60)
94 | return b ^ c ^ d;
95 | end
96 |
97 | # Determine the appropriate additive constant for the current iteration
98 | def sha1_kt(t)
99 | return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 :
100 | (t < 60) ? -1894007588 : -899497514
101 | end
102 |
103 | # Calculate the HMAC-SHA1 of a key and some data
104 | def core_hmac_sha1(key, data)
105 | bkey = str2binb(key)
106 | if(bkey.length > 16)
107 | bkey = core_sha1(bkey, key.length * $chrsz)
108 | end
109 |
110 | ipad = Array.new(16, 0)
111 | opad = Array.new(16, 0)
112 | #for(var i = 0; i < 16; i++)
113 | i = 0
114 | while(i < 16)
115 | ipad[i] = (bkey[i] || 0) ^ 0x36363636
116 | opad[i] = (bkey[i] || 0) ^ 0x5C5C5C5C
117 | i += 1
118 | end
119 |
120 | hash = core_sha1((ipad + str2binb(data)), 512 + data.length * $chrsz)
121 | return core_sha1((opad + hash), 512 + 160)
122 | end
123 |
124 | # Add integers, wrapping at 2^32. This uses 16-bit operations internally
125 | # to work around bugs in some JS interpreters.
126 | def safe_add(x, y)
127 | v = (x+y) % (2**32)
128 | return v > 2**31 ? v- 2**32 : v
129 | end
130 |
131 | # Bitwise rotate a 32-bit number to the left.
132 | def rol(num, cnt)
133 | #return (num << cnt) | (num >>> (32 - cnt))
134 | return (num.js_shl(cnt)) | (num.js_shr_zf(32 - cnt))
135 | end
136 |
137 | # Convert an 8-bit or 16-bit string to an array of big-endian words
138 | # In 8-bit function, characters >255 have their hi-byte silently ignored.
139 | def str2binb(str)
140 | bin = []
141 | mask = (1 << $chrsz) - 1
142 | #for(var i = 0; i < str.length * $chrsz; i += $chrsz)
143 | i = 0
144 | while(i < str.length * $chrsz)
145 | bin[i>>5] ||= 0
146 | bin[i>>5] |= (str[i / $chrsz].ord & mask) << (32 - $chrsz - i%32)
147 | i += $chrsz
148 | end
149 | return bin
150 | end
151 |
152 | # Convert an array of big-endian words to a string
153 | # function binb2str(bin)
154 | # {
155 | # var str = "";
156 | # var mask = (1 << $chrsz) - 1;
157 | # for(var i = 0; i < bin.length * 32; i += $chrsz)
158 | # str += String.fromCharCode((bin[i>>5] >>> (32 - $chrsz - i%32)) & mask);
159 | # return str;
160 | # }
161 | #
162 |
163 | # Convert an array of big-endian words to a hex string.
164 | def binb2hex(binarray)
165 | hex_tab = $hexcase ? "0123456789ABCDEF" : "0123456789abcdef"
166 | str = ""
167 | #for(var i = 0; i < binarray.length * 4; i++)
168 | i = 0
169 | while(i < binarray.length * 4)
170 | str += hex_tab[(binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF].chr +
171 | hex_tab[(binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF].chr
172 | i += 1
173 | end
174 | return str;
175 | end
176 |
177 | # Convert an array of big-endian words to a base-64 string
178 | def binb2b64(binarray)
179 | tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
180 | str = ""
181 |
182 | #for(var i = 0; i < binarray.length * 4; i += 3)
183 | i = 0
184 | while(i < binarray.length * 4)
185 | triplet = (((binarray[i >> 2].to_i >> 8 * (3 - i %4)) & 0xFF) << 16) |
186 | (((binarray[i+1 >> 2].to_i >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 ) |
187 | ((binarray[i+2 >> 2].to_i >> 8 * (3 - (i+2)%4)) & 0xFF)
188 | #for(var j = 0; j < 4; j++)
189 | j = 0
190 | while(j < 4)
191 | if(i * 8 + j * 6 > binarray.length * 32)
192 | str += $b64pad
193 | else
194 | str += tab[(triplet >> 6*(3-j)) & 0x3F].chr
195 | end
196 | j += 1
197 | end
198 | i += 3
199 | end
200 | return str
201 | end
202 | end
203 | end
204 |
--------------------------------------------------------------------------------
/lib/s3_swf_upload/view_helpers.rb:
--------------------------------------------------------------------------------
1 | module S3SwfUpload
2 | module ViewHelpers
3 | def s3_swf_upload_tag(options = {})
4 | buttonWidth = options[:buttonWidth] || 100
5 | buttonHeight = options[:buttonHeight] || 30
6 | flashVersion = options[:height] || '9.0.0'
7 | queueSizeLimit = options[:queueSizeLimit] || 100
8 | fileSizeLimit = options[:fileSizeLimit] || 524288000
9 | fileTypes = options[:fileTypes] || '*.*'
10 | fileTypeDescs = options[:fileTypeDescs] || 'All Files'
11 | selectMultipleFiles = options.has_key?(:selectMultipleFiles) ? options[:selectMultipleFiles] : true
12 | keyPrefix = options[:keyPrefix] || ''
13 | signaturePath = options[:signaturePath] || '/s3_uploads.xml'
14 | swfFilePath = options[:swfFilePath] || '/flash/s3_upload.swf'
15 | buttonUpPath = options[:buttonUpPath] || '/flash/s3_up_button.gif'
16 | buttonOverPath = options[:buttonOverPath] || '/flash/s3_over_button.gif'
17 | buttonDownPath = options[:buttonDownPath] || '/flash/s3_down_button.gif'
18 |
19 | onFileAdd = options[:onFileAdd] || false
20 | onFileRemove = options[:onFileRemove] || false
21 | onFileSizeLimitReached = options[:onFileSizeLimitReached] || false
22 | onFileNotInQueue = options[:onFileNotInQueue] || false
23 |
24 | onQueueChange = options[:onQueueChange] || false
25 | onQueueClear = options[:onQueueClear] || false
26 | onQueueSizeLimitReached = options[:onQueueSizeLimitReached] || false
27 | onQueueEmpty = options[:onQueueEmpty] || false
28 |
29 | onUploadingStop = options[:onUploadingStop] || false
30 | onUploadingStart = options[:onUploadingStart] || false
31 | onUploadingFinish = options[:onUploadingFinish] || false
32 |
33 | onSignatureOpen = options[:onSignatureOpen] || false
34 | onSignatureProgress = options[:onSignatureProgress] || false
35 | onSignatureHttpStatus = options[:onSignatureHttpStatus] || false
36 | onSignatureComplete = options[:onSignatureComplete] || false
37 | onSignatureSecurityError= options[:onSignatureSecurityError] || false
38 | onSignatureIOError = options[:onSignatureIOError] || false
39 | onSignatureXMLError = options[:onSignatureXMLError] || false
40 |
41 | onUploadOpen = options[:onUploadOpen] || false
42 | onUploadProgress = options[:onUploadProgress] || false
43 | onUploadHttpStatus = options[:onUploadHttpStatus] || false
44 | onUploadComplete = options[:onUploadComplete] || false
45 | onUploadIOError = options[:onUploadIOError] || false
46 | onUploadSecurityError = options[:onUploadSecurityError] || false
47 | onUploadError = options[:onUploadError] || false
48 |
49 | @include_s3_upload ||= false
50 | @count ||= 1
51 |
52 | out = ''
53 |
54 | if Rails.version < '3.1.0'
55 | if !@include_s3_upload
56 | out << javascript_include_tag('s3_upload')
57 | @include_s3_upload = true
58 | end
59 | end
60 |
61 | out << "\n\n"
162 | out << "
\n"
163 | out << "Please Update your Flash Player to Flash v#{flashVersion} or higher...\n"
164 | out << "
\n"
165 |
166 | @count += 1
167 | out
168 | end
169 |
170 | end
171 | end
172 |
173 | ActionView::Base.send(:include, S3SwfUpload::ViewHelpers)
174 |
--------------------------------------------------------------------------------
/s3_swf_upload.gemspec:
--------------------------------------------------------------------------------
1 | # Generated by jeweler
2 | # DO NOT EDIT THIS FILE DIRECTLY
3 | # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4 | # -*- encoding: utf-8 -*-
5 | # stub: s3_swf_upload 0.3.3 ruby lib
6 |
7 | Gem::Specification.new do |s|
8 | s.name = "s3_swf_upload"
9 | s.version = "0.3.3"
10 |
11 | s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12 | s.authors = ["Nathan Colgate"]
13 | s.date = "2014-02-18"
14 | s.description = "Rails 3 gem that allows you to upload files directly to S3 from your application using flex for file management, css for presentation, and javascript for behavior."
15 | s.email = "nathan@brandnewbox.com"
16 | s.extra_rdoc_files = [
17 | "LICENSE.txt",
18 | "README.textile"
19 | ]
20 | s.files = [
21 | "Gemfile",
22 | "Gemfile.lock",
23 | "LICENSE.txt",
24 | "README.textile",
25 | "Rakefile",
26 | "VERSION",
27 | "flex_src/bin-release/flex-config.xml",
28 | "flex_src/compile",
29 | "flex_src/src/Globals.as",
30 | "flex_src/src/S3Uploader.as",
31 | "flex_src/src/com/adobe/net/MimeTypeMap.as",
32 | "flex_src/src/com/elctech/S3UploadOptions.as",
33 | "flex_src/src/com/elctech/S3UploadRequest.as",
34 | "flex_src/src/com/nathancolgate/s3_swf_upload/BrowseButton.as",
35 | "flex_src/src/com/nathancolgate/s3_swf_upload/S3Queue.as",
36 | "flex_src/src/com/nathancolgate/s3_swf_upload/S3Signature.as",
37 | "flex_src/src/com/nathancolgate/s3_swf_upload/S3Upload.as",
38 | "lib/patch/integer.rb",
39 | "lib/s3_swf_upload.rb",
40 | "lib/s3_swf_upload/railtie.rb",
41 | "lib/s3_swf_upload/railties/generators/s3_swf_upload.rb",
42 | "lib/s3_swf_upload/railties/generators/uploader/USAGE",
43 | "lib/s3_swf_upload/railties/generators/uploader/templates/amazon_s3.yml",
44 | "lib/s3_swf_upload/railties/generators/uploader/templates/s3_down_button.gif",
45 | "lib/s3_swf_upload/railties/generators/uploader/templates/s3_over_button.gif",
46 | "lib/s3_swf_upload/railties/generators/uploader/templates/s3_up_button.gif",
47 | "lib/s3_swf_upload/railties/generators/uploader/templates/s3_upload.js",
48 | "lib/s3_swf_upload/railties/generators/uploader/templates/s3_upload.swf",
49 | "lib/s3_swf_upload/railties/generators/uploader/templates/s3_uploads_controller.rb",
50 | "lib/s3_swf_upload/railties/generators/uploader/uploader_generator.rb",
51 | "lib/s3_swf_upload/railties/tasks/crossdomain.xml",
52 | "lib/s3_swf_upload/s3_config.rb",
53 | "lib/s3_swf_upload/signature.rb",
54 | "lib/s3_swf_upload/view_helpers.rb",
55 | "s3_swf_upload.gemspec",
56 | "test/helper.rb",
57 | "test/test_s3_swf_upload.rb"
58 | ]
59 | s.homepage = "http://github.com/nathancolgate/s3-swf-upload-plugin"
60 | s.licenses = ["MIT"]
61 | s.require_paths = ["lib"]
62 | s.rubygems_version = "2.1.11"
63 | s.summary = "Rails 3 gem that allows you to upload files directly to S3 from your application using flex for file management, css for presentation, and javascript for behavior."
64 |
65 | if s.respond_to? :specification_version then
66 | s.specification_version = 4
67 |
68 | if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
69 | s.add_development_dependency(%q, [">= 0"])
70 | s.add_development_dependency(%q, ["~> 3.12"])
71 | s.add_development_dependency(%q, ["~> 1.0"])
72 | s.add_development_dependency(%q, ["~> 2.0.1"])
73 | s.add_development_dependency(%q, [">= 0"])
74 | else
75 | s.add_dependency(%q, [">= 0"])
76 | s.add_dependency(%q, ["~> 3.12"])
77 | s.add_dependency(%q, ["~> 1.0"])
78 | s.add_dependency(%q, ["~> 2.0.1"])
79 | s.add_dependency(%q, [">= 0"])
80 | end
81 | else
82 | s.add_dependency(%q, [">= 0"])
83 | s.add_dependency(%q, ["~> 3.12"])
84 | s.add_dependency(%q, ["~> 1.0"])
85 | s.add_dependency(%q, ["~> 2.0.1"])
86 | s.add_dependency(%q, [">= 0"])
87 | end
88 | end
89 |
90 |
--------------------------------------------------------------------------------
/test/helper.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 |
3 | require 'rubygems'
4 | require 'bundler'
5 | begin
6 | Bundler.setup(:default, :development)
7 | rescue Bundler::BundlerError => e
8 | $stderr.puts e.message
9 | $stderr.puts "Run `bundle install` to install missing gems"
10 | exit e.status_code
11 | end
12 | require 'rake'
13 |
14 | require 'jeweler'
15 | Jeweler::Tasks.new do |gem|
16 | # gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
17 | gem.name = "s3_swf_upload"
18 | gem.homepage = "http://github.com/nathancolgate/s3-swf-upload-plugin"
19 | gem.license = "MIT"
20 | gem.summary = %Q{Rails 3 gem that allows you to upload files directly to S3 from your application using flex for file management, css for presentation, and javascript for behavior.}
21 | gem.description = %Q{Rails 3 gem that allows you to upload files directly to S3 from your application using flex for file management, css for presentation, and javascript for behavior.}
22 | gem.email = "nathan@brandnewbox.com"
23 | gem.authors = ["Nathan Colgate"]
24 | # dependencies defined in Gemfile
25 | end
26 | Jeweler::RubygemsDotOrgTasks.new
27 |
28 | require 'rake/testtask'
29 | Rake::TestTask.new(:test) do |test|
30 | test.libs << 'lib' << 'test'
31 | test.pattern = 'test/**/test_*.rb'
32 | test.verbose = true
33 | end
34 |
35 | desc "Code coverage detail"
36 | task :simplecov do
37 | ENV['COVERAGE'] = "true"
38 | Rake::Task['test'].execute
39 | end
40 |
41 | task :default => :test
42 |
43 | require 'rdoc/task'
44 | Rake::RDocTask.new do |rdoc|
45 | version = File.exist?('VERSION') ? File.read('VERSION') : ""
46 |
47 | rdoc.rdoc_dir = 'rdoc'
48 | rdoc.title = "s3_swf_upload #{version}"
49 | rdoc.rdoc_files.include('README*')
50 | rdoc.rdoc_files.include('lib/**/*.rb')
51 | end
52 |
--------------------------------------------------------------------------------
/test/test_s3_swf_upload.rb:
--------------------------------------------------------------------------------
1 | require 'helper'
2 |
3 | class TestS3SwfUpload < Test::Unit::TestCase
4 | should "probably rename this file and start testing for real" do
5 | flunk "hey buddy, you should probably rename this file and start testing for real"
6 | end
7 | end
8 |
--------------------------------------------------------------------------------