s3upload 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +3 -0
- data/LICENSE +21 -0
- data/Manifest +13 -0
- data/README.md +97 -0
- data/Rakefile +8 -0
- data/bin/jquery.s3upload.min.js +32 -0
- data/bin/s3upload.swf +0 -0
- data/lib/s3upload.rb +68 -0
- data/s3upload.gemspec +31 -0
- data/src/build.hxml +5 -0
- data/src/hx/MimeTypes.hx +158 -0
- data/src/hx/S3Upload.hx +314 -0
- data/src/js/jquery.s3upload.js +227 -0
- metadata +78 -0
data/CHANGELOG
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2010 Robert Sköld
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/Manifest
ADDED
data/README.md
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
S3Upload
|
2
|
+
========
|
3
|
+
|
4
|
+
A jQuery plugin for direct upload to an Amazon S3 bucket.
|
5
|
+
|
6
|
+
It works by replacing a file input with a html element overlaid with a transparent SWF. The same way [Flickr](http://www.flickr.com/photos/upload/) does it.
|
7
|
+
|
8
|
+
By signing the request server side we also avoid the security issue of showing the Amazon AWS Access Id Key and Secure Key in plain text. A library for signing the request in Ruby is included, but the logic should be very easy to replicate in other languages like PHP or Python.
|
9
|
+
|
10
|
+
The Javascript API also allows these callback functions:
|
11
|
+
|
12
|
+
* onselect(info) - Called when a user has selected a file.
|
13
|
+
* oncancel(info) - Called if the user decides to abort the file browsing.
|
14
|
+
* onstart(info) - Called after the request has been signed and the file upload to S3 is starting.
|
15
|
+
* onprogress(progress,info) - Called while uploading, "progress" being a float between 0 and 1 of the current upload progress.
|
16
|
+
* oncomplete(info) - Called when the upload has finished successfully.
|
17
|
+
* onerror(msg,info) - Called if there's been a problem with a message saying what failed.
|
18
|
+
* onenabled() - Called when the SWF has been enabled. Usually when swf.enable() has been called. Called first thing when the SWF is finished initializing.
|
19
|
+
* ondisabled() - Called when the SWF has been disabled. Usually when swf.disable() has been called.
|
20
|
+
|
21
|
+
_info_ is an object containing "name", "size" and "type" of the selected file.
|
22
|
+
|
23
|
+
And these mouse callbacks:
|
24
|
+
|
25
|
+
* onmouseover(x,y)
|
26
|
+
* onmouseout(x,y)
|
27
|
+
* onmousedown(x,y)
|
28
|
+
* onmouseup(x,y)
|
29
|
+
* onmousemove(x,y)
|
30
|
+
* onclick(x,y)
|
31
|
+
* onrollover(x,y)
|
32
|
+
* onrollout(x,y)
|
33
|
+
* ondoubleclick(x,y)
|
34
|
+
|
35
|
+
The mouse events are also triggered as regular jQuery events (i.e. `$('#input_replaced').rollover(function(){alert('over!')});` should work just fine as well).
|
36
|
+
|
37
|
+
Every callback is scoped to the DOM element which has replaced the previous input (i.e. "this" in the callbacks points to the html element). Also by returning `true` in a callback function the default callback will be used.
|
38
|
+
|
39
|
+
Which file types that can be selected may be defined with the _file\_types_ option, see the "Usage Example" below for more info. If none is defined all files are acceptable.
|
40
|
+
|
41
|
+
|
42
|
+
Requirements
|
43
|
+
-------------
|
44
|
+
|
45
|
+
* jQuery 1.3+
|
46
|
+
* SWFObject 2.1+
|
47
|
+
|
48
|
+
Both available from Google AJAX APIs (recommended as it likely speeds things up).
|
49
|
+
|
50
|
+
|
51
|
+
Example Usage
|
52
|
+
-------------
|
53
|
+
|
54
|
+
The HTML/JS part:
|
55
|
+
|
56
|
+
<script type="text/javascript" charset="utf-8" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
|
57
|
+
<script type="text/javascript" charset="utf-8" src="http://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
|
58
|
+
<script type="text/javascript" charset="utf-8" src="jquery.s3upload.js"></script>
|
59
|
+
|
60
|
+
<script type="text/javascript" charset="utf-8">
|
61
|
+
$(function(){
|
62
|
+
var max_file_size = 2 * 1024 * 1024; // = 2Mb
|
63
|
+
$("form").s3upload({
|
64
|
+
prefix: "s3upload/",
|
65
|
+
required: true,
|
66
|
+
onselect: function(info) {
|
67
|
+
if( parseInt( info.size ) < max_file_size )
|
68
|
+
return true; // Default is to show the filename in the element.
|
69
|
+
else
|
70
|
+
$(this).html("Too big file! Must be smaller than " + max_file_size + " (was "+info.size+")");
|
71
|
+
},
|
72
|
+
file_types: [
|
73
|
+
[ "Images" , "*.png;*.jpg;*.bmp"],
|
74
|
+
[ "Documents" , "*.pdf;*.doc;*.txt"]
|
75
|
+
]
|
76
|
+
});
|
77
|
+
});
|
78
|
+
</script>
|
79
|
+
|
80
|
+
<form action="/media/new" method="post" accept-charset="utf-8" enctype="multipart/form-data">
|
81
|
+
<label for="media_title">Title</label>
|
82
|
+
<input type="text" name="media[title]" value="" id="media_title" />
|
83
|
+
<label for="media_video">Video</label>
|
84
|
+
<input type="file" name="media[video]" value="" id="media_video" />
|
85
|
+
<label for="media_thumbnail">Thumbnail</label>
|
86
|
+
<input type="file" name="media[thumbnail]" value="" id="media_thumbnail" />
|
87
|
+
<input type="submit" value="Upload" />
|
88
|
+
</form>
|
89
|
+
|
90
|
+
|
91
|
+
The Sinatra part (assumes the _s3upload_ gem is installed):
|
92
|
+
|
93
|
+
require "s3upload"
|
94
|
+
get "/s3upload" do
|
95
|
+
up = S3::Upload.new( options.s3_upload_access_key_id , options.s3_upload_secret_key , options.s3_upload_bucket )
|
96
|
+
up.to_xml( params[:key] , params[:contentType] )
|
97
|
+
end
|
data/Rakefile
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
/* S3Upload 0.1.0 <http://github.com/slaskis/s3upload>
|
2
|
+
is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
|
3
|
+
*/
|
4
|
+
|
5
|
+
(function($){$.fn.s3upload=function(settings){var config={text:"<a href='#basic'>Select file...</a>",path:"/s3upload.swf",prefix:"",signature_url:"/s3upload",required:false,submit_on_all_complete:true,error_class:"s3_error",file_types:[]};if(settings)$.extend(config,settings);var elements=this.map(function(){if($(this).is("form"))
|
6
|
+
return $(this).find(":file").toArray();return $(this);});$.fn.s3upload.instances=$.fn.s3upload.instances||0;var started=0;var completed=0;return elements.each(function(){var form=$(this).closest("form");var id=$(this).attr("id")||"s3upload_"+$.fn.s3upload.instances;var name=$(this).attr("name");$(this).replaceWith("<div id='"+id+"'></div>");var el=$("#"+id);el.attr("class",$(this).attr("class"));var flash_div=$("<div id='s3upload_"+id+"'><div id='flash_"+id+"'></div></div>").appendTo("body");var filters=$.map(config.file_types,function(f,i){return f.join("#");}).join("|");var fv={id:"flash_"+id,prefix:config.prefix,signatureURL:config.signature_url,filters:filters};var params={wmode:"transparent",menu:false};swfobject.embedSWF(config.path,fv.id,"100%","100%","9.0.0",false,fv,params,false,function(e){if(e.success){var swf=e.ref;el.html(config.text);swf.update_interval=setInterval(function(){var pos=el.offset();flash_div.css({width:el.width(),height:el.height(),position:"absolute",top:pos.top,left:pos.left});},100);var formSubmit=function(){if(config.required&&!swf.info)
|
7
|
+
swf.onerror("Error: No file selected.");else
|
8
|
+
swf.upload();return false;}
|
9
|
+
form.submit(formSubmit);swf.onmouseevent=function(type,x,y){var def=true;if($.isFunction(config["on"+type]))
|
10
|
+
def=config["on"+type].call(el,x,y);if(def){el.trigger(type);}}
|
11
|
+
swf.onselect=function(name,size,type){swf.info={name:name,size:size,type:type};var def=true;if($.isFunction(config.onselect))
|
12
|
+
def=config.onselect.call(el,swf.info);if(def){el.html(name);}}
|
13
|
+
swf.oncancel=function(){var def=true;if($.isFunction(config.oncancel))
|
14
|
+
def=config.oncancel.call(el,swf.info);if(def){el.html(config.text);}
|
15
|
+
swf.info=null;}
|
16
|
+
swf.onstart=function(){var def=true;if($.isFunction(config.onstart))
|
17
|
+
def=config.onstart.call(el,swf.info);if(def){}
|
18
|
+
started++;swf.disable();}
|
19
|
+
swf.onprogress=function(p){var def=true;if($.isFunction(config.onprogress))
|
20
|
+
def=config.onprogress.call(el,p,swf.info);if(def){el.html(Math.ceil(p*100)+"%");}}
|
21
|
+
swf.onerror=function(msg){var def=true;if($.isFunction(config.onerror))
|
22
|
+
def=config.onerror.call(el,msg,swf.info);if(def){el.html("<span class='"+config.error_class+"'>"+msg+"</span>");}
|
23
|
+
swf.enable();}
|
24
|
+
swf.oncomplete=function(key){swf.info.key=key;var def=true;if($.isFunction(config.oncomplete))
|
25
|
+
def=config.oncomplete.call(el,swf.info);if(def){}
|
26
|
+
if(el.nextAll("input[name^="+name+"]").length==0)
|
27
|
+
for(var k in swf.info)
|
28
|
+
el.after("<input type='hidden' name='"+name+"["+k+"]' value='"+swf.info[k]+"' />");else
|
29
|
+
for(var k in swf.info)
|
30
|
+
el.siblings("input[name="+name+"["+k+"]]").val(swf.info[k]);completed++;form.unbind("submit",formSubmit);if(!config.submit_on_all_complete)
|
31
|
+
swf.enable();else if(started==completed)
|
32
|
+
form.submit();}}});$.fn.s3upload.instances++;});};})(jQuery);
|
data/bin/s3upload.swf
ADDED
Binary file
|
data/lib/s3upload.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'digest/sha1'
|
3
|
+
require "base64"
|
4
|
+
|
5
|
+
module S3
|
6
|
+
class Upload
|
7
|
+
|
8
|
+
attr_accessor :bucket, :expires, :secret_key, :access_key_id, :acl
|
9
|
+
|
10
|
+
def initialize( access_key_id , secret_key , bucket , acl="public-read" , expires=nil)
|
11
|
+
@access_key_id = access_key_id
|
12
|
+
@secret_key = secret_key
|
13
|
+
@bucket = bucket
|
14
|
+
@acl = acl
|
15
|
+
|
16
|
+
# default to one hour from now
|
17
|
+
@expires = expires || (Time.now + 3600)
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_xml( key , content_type )
|
22
|
+
@key = key
|
23
|
+
@content_type = content_type
|
24
|
+
|
25
|
+
props = {
|
26
|
+
:accessKeyId => access_key_id,
|
27
|
+
:acl => acl,
|
28
|
+
:bucket => bucket,
|
29
|
+
:contentType => @content_type,
|
30
|
+
:expires => expiration_str,
|
31
|
+
:key => @key,
|
32
|
+
:secure => false,
|
33
|
+
:signature => signature,
|
34
|
+
:policy => policy
|
35
|
+
}
|
36
|
+
|
37
|
+
# Create xml of the properties
|
38
|
+
xml = "<s3>"
|
39
|
+
props.each {|k,v| xml << "<#{k}>#{v}</#{k}>"}
|
40
|
+
xml << "</s3>"
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def expiration_str
|
46
|
+
@expires.utc.strftime('%Y-%m-%dT%H:%M:%S.000Z')
|
47
|
+
end
|
48
|
+
|
49
|
+
def policy
|
50
|
+
@policy ||= Base64.encode64( "{
|
51
|
+
'expiration': '#{expiration_str}',
|
52
|
+
'conditions': [
|
53
|
+
{'bucket': '#{bucket}'},
|
54
|
+
{'key': '#{@key}'},
|
55
|
+
{'acl': '#{acl}'},
|
56
|
+
{'Content-Type': '#{@content_type}'},
|
57
|
+
['starts-with', '$Filename', ''],
|
58
|
+
['eq', '$success_action_status', '201']
|
59
|
+
]
|
60
|
+
}").gsub(/\n|\r/, '')
|
61
|
+
end
|
62
|
+
|
63
|
+
def signature
|
64
|
+
[OpenSSL::HMAC.digest(OpenSSL::Digest::Digest.new('sha1'), secret_key, policy)].pack("m").strip
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
data/s3upload.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{s3upload}
|
5
|
+
s.version = "0.1.0"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Robert Sk\303\266ld"]
|
9
|
+
s.date = %q{2010-01-25}
|
10
|
+
s.description = %q{A jQuery plugin for direct upload to an Amazon S3 bucket.}
|
11
|
+
s.email = %q{}
|
12
|
+
s.executables = ["jquery.s3upload.min.js", "s3upload.swf"]
|
13
|
+
s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README.md", "bin/jquery.s3upload.min.js", "bin/s3upload.swf", "lib/s3upload.rb"]
|
14
|
+
s.files = ["CHANGELOG", "LICENSE", "Manifest", "README.md", "Rakefile", "bin/jquery.s3upload.min.js", "bin/s3upload.swf", "lib/s3upload.rb", "s3upload.gemspec", "src/build.hxml", "src/hx/MimeTypes.hx", "src/hx/S3Upload.hx", "src/js/jquery.s3upload.js"]
|
15
|
+
s.homepage = %q{http://github.com/slaskis/s3upload}
|
16
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "S3upload", "--main", "README.md"]
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
s.rubyforge_project = %q{s3upload}
|
19
|
+
s.rubygems_version = %q{1.3.5}
|
20
|
+
s.summary = %q{A jQuery plugin for direct upload to an Amazon S3 bucket.}
|
21
|
+
|
22
|
+
if s.respond_to? :specification_version then
|
23
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
24
|
+
s.specification_version = 3
|
25
|
+
|
26
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
27
|
+
else
|
28
|
+
end
|
29
|
+
else
|
30
|
+
end
|
31
|
+
end
|
data/src/build.hxml
ADDED
data/src/hx/MimeTypes.hx
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
class MimeTypes {
|
2
|
+
static var TYPES = [
|
3
|
+
["application/andrew-inset","ez"],
|
4
|
+
["application/atom+xml","atom"],
|
5
|
+
["application/mac-binhex40","hqx"],
|
6
|
+
["application/mac-compactpro","cpt"],
|
7
|
+
["application/mathml+xml","mathml"],
|
8
|
+
["application/msword","doc"],
|
9
|
+
["application/octet-stream","bin","dms","lha","lzh","exe","class","so","dll","dmg"],
|
10
|
+
["application/oda","oda"],
|
11
|
+
["application/ogg","ogg"],
|
12
|
+
["application/pdf","pdf"],
|
13
|
+
["application/postscript","ai","eps","ps"],
|
14
|
+
["application/rdf+xml","rdf"],
|
15
|
+
["application/smil","smi","smil"],
|
16
|
+
["application/srgs","gram"],
|
17
|
+
["application/srgs+xml","grxml"],
|
18
|
+
["application/vnd.adobe.apollo-application-installer-package+zip","air"],
|
19
|
+
["application/vnd.mif","mif"],
|
20
|
+
["application/vnd.mozilla.xul+xml","xul"],
|
21
|
+
["application/vnd.ms-excel","xls"],
|
22
|
+
["application/vnd.ms-powerpoint","ppt"],
|
23
|
+
["application/vnd.rn-realmedia","rm"],
|
24
|
+
["application/vnd.wap.wbxml","wbxml"],
|
25
|
+
["application/vnd.wap.wmlc","wmlc"],
|
26
|
+
["application/vnd.wap.wmlscriptc","wmlsc"],
|
27
|
+
["application/voicexml+xml","vxml"],
|
28
|
+
["application/x-bcpio","bcpio"],
|
29
|
+
["application/x-cdlink","vcd"],
|
30
|
+
["application/x-chess-pgn","pgn"],
|
31
|
+
["application/x-cpio","cpio"],
|
32
|
+
["application/x-csh","csh"],
|
33
|
+
["application/x-director","dcr","dir","dxr"],
|
34
|
+
["application/x-dvi","dvi"],
|
35
|
+
["application/x-futuresplash","spl"],
|
36
|
+
["application/x-gtar","gtar"],
|
37
|
+
["application/x-hdf","hdf"],
|
38
|
+
["application/x-javascript","js"],
|
39
|
+
["application/x-koan","skp","skd","skt","skm"],
|
40
|
+
["application/x-latex","latex"],
|
41
|
+
["application/x-netcdf","nc","cdf"],
|
42
|
+
["application/x-photoshop","psd"],
|
43
|
+
["application/x-sh","sh"],
|
44
|
+
["application/x-shar","shar"],
|
45
|
+
["application/x-shockwave-flash","swf"],
|
46
|
+
["application/x-stuffit","sit"],
|
47
|
+
["application/x-sv4cpio","sv4cpio"],
|
48
|
+
["application/x-sv4crc","sv4crc"],
|
49
|
+
["application/x-tar","tar"],
|
50
|
+
["application/x-tcl","tcl"],
|
51
|
+
["application/x-tex","tex"],
|
52
|
+
["application/x-texinfo","texinfo","texi"],
|
53
|
+
["application/x-troff","t","tr","roff"],
|
54
|
+
["application/x-troff-man","man"],
|
55
|
+
["application/x-troff-me","me"],
|
56
|
+
["application/x-troff-ms","ms"],
|
57
|
+
["application/x-ustar","ustar"],
|
58
|
+
["application/x-wais-source","src"],
|
59
|
+
["application/xhtml+xml","xhtml","xht"],
|
60
|
+
["application/xml","xml","xsl"],
|
61
|
+
["application/xml-dtd","dtd"],
|
62
|
+
["application/xslt+xml","xslt"],
|
63
|
+
["application/zip","zip"],
|
64
|
+
["audio/basic","au","snd"],
|
65
|
+
["audio/midi","mid","midi","kar"],
|
66
|
+
["audio/mpeg","mp3","mpga","mp2"],
|
67
|
+
["audio/x-aiff","aif","aiff","aifc"],
|
68
|
+
["audio/x-mpegurl","m3u"],
|
69
|
+
["audio/x-pn-realaudio","ram","ra"],
|
70
|
+
["audio/x-wav","wav"],
|
71
|
+
["chemical/x-pdb","pdb"],
|
72
|
+
["chemical/x-xyz","xyz"],
|
73
|
+
["image/bmp","bmp"],
|
74
|
+
["image/cgm","cgm"],
|
75
|
+
["image/gif","gif"],
|
76
|
+
["image/ief","ief"],
|
77
|
+
["image/jpeg","jpg","jpeg","jpe"],
|
78
|
+
["image/png","png"],
|
79
|
+
["image/svg+xml","svg"],
|
80
|
+
["image/tiff","tiff","tif"],
|
81
|
+
["image/vnd.djvu","djvu","djv"],
|
82
|
+
["image/vnd.wap.wbmp","wbmp"],
|
83
|
+
["image/x-cmu-raster","ras"],
|
84
|
+
["image/x-icon","ico"],
|
85
|
+
["image/x-portable-anymap","pnm"],
|
86
|
+
["image/x-portable-bitmap","pbm"],
|
87
|
+
["image/x-portable-graymap","pgm"],
|
88
|
+
["image/x-portable-pixmap","ppm"],
|
89
|
+
["image/x-rgb","rgb"],
|
90
|
+
["image/x-xbitmap","xbm"],
|
91
|
+
["image/x-xpixmap","xpm"],
|
92
|
+
["image/x-xwindowdump","xwd"],
|
93
|
+
["model/iges","igs","iges"],
|
94
|
+
["model/mesh","msh","mesh","silo"],
|
95
|
+
["model/vrml","wrl","vrml"],
|
96
|
+
["text/calendar","ics","ifb"],
|
97
|
+
["text/css","css"],
|
98
|
+
["text/html","html","htm"],
|
99
|
+
["text/plain","txt","asc"],
|
100
|
+
["text/richtext","rtx"],
|
101
|
+
["text/rtf","rtf"],
|
102
|
+
["text/sgml","sgml","sgm"],
|
103
|
+
["text/tab-separated-values","tsv"],
|
104
|
+
["text/vnd.wap.wml","wml"],
|
105
|
+
["text/vnd.wap.wmlscript","wmls"],
|
106
|
+
["text/x-setext","etx"],
|
107
|
+
["video/mpeg","mpg","mpeg","mpe"],
|
108
|
+
["video/quicktime","mov","qt"],
|
109
|
+
["video/vnd.mpegurl","m4u","mxu"],
|
110
|
+
["video/x-flv","flv"],
|
111
|
+
["video/x-msvideo","avi"],
|
112
|
+
["video/x-sgi-movie","movie"],
|
113
|
+
["x-conference/x-cooltalk","ice"]
|
114
|
+
];
|
115
|
+
|
116
|
+
var types : Array<Array<String>>;
|
117
|
+
|
118
|
+
public function new() types = TYPES.copy()
|
119
|
+
|
120
|
+
/**
|
121
|
+
* Returns the mimetype for the given extension.
|
122
|
+
*/
|
123
|
+
public function getMimeType(extension:String):String {
|
124
|
+
extension = extension.toLowerCase();
|
125
|
+
for( a in types ) {
|
126
|
+
for( b in a ) {
|
127
|
+
if (b == extension) {
|
128
|
+
return a[0];
|
129
|
+
}
|
130
|
+
}
|
131
|
+
}
|
132
|
+
return null;
|
133
|
+
}
|
134
|
+
|
135
|
+
/**
|
136
|
+
* Returns the prefered extension for the given mimetype.
|
137
|
+
*/
|
138
|
+
public function getExtension(mimetype:String):String {
|
139
|
+
mimetype = mimetype.toLowerCase();
|
140
|
+
for( a in types ) {
|
141
|
+
if(a[0] == mimetype) {
|
142
|
+
return a[1];
|
143
|
+
}
|
144
|
+
}
|
145
|
+
return null;
|
146
|
+
}
|
147
|
+
|
148
|
+
/**
|
149
|
+
* Adds a mimetype to the map. The order of the extensions matters. The most preferred should come first.
|
150
|
+
*/
|
151
|
+
public function addMimeType(mimetype:String, extensions:Array<String>) {
|
152
|
+
var newType = [mimetype];
|
153
|
+
for( a in extensions ) {
|
154
|
+
newType.push(a);
|
155
|
+
}
|
156
|
+
types.push(newType);
|
157
|
+
}
|
158
|
+
}
|
data/src/hx/S3Upload.hx
ADDED
@@ -0,0 +1,314 @@
|
|
1
|
+
class S3Upload extends flash.display.Sprite {
|
2
|
+
|
3
|
+
static var _id : String;
|
4
|
+
|
5
|
+
var _signatureURL : String;
|
6
|
+
var _prefix : String;
|
7
|
+
var _fr : flash.net.FileReference;
|
8
|
+
var _filters : Array<flash.net.FileFilter>;
|
9
|
+
|
10
|
+
public function new() super()
|
11
|
+
|
12
|
+
public function init() {
|
13
|
+
_id = stage.loaderInfo.parameters.id;
|
14
|
+
_signatureURL = stage.loaderInfo.parameters.signatureURL;
|
15
|
+
_prefix = stage.loaderInfo.parameters.prefix;
|
16
|
+
_filters = [];
|
17
|
+
if( stage.loaderInfo.parameters.filters != null && stage.loaderInfo.parameters.filters != "" ) {
|
18
|
+
for( filter in stage.loaderInfo.parameters.filters.split("|") ) {
|
19
|
+
var f = filter.split("#");
|
20
|
+
_filters.push( new flash.net.FileFilter( f[0] , f[1] ) );
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
if( flash.external.ExternalInterface.available ) {
|
25
|
+
flash.external.ExternalInterface.addCallback( "disable" , disable );
|
26
|
+
flash.external.ExternalInterface.addCallback( "enable" , enable );
|
27
|
+
flash.external.ExternalInterface.addCallback( "upload" , upload );
|
28
|
+
}
|
29
|
+
stage.addEventListener( "resize" , onStageResize );
|
30
|
+
onStageResize();
|
31
|
+
enable();
|
32
|
+
}
|
33
|
+
|
34
|
+
function onBrowse( e ) {
|
35
|
+
var fr = new flash.net.FileReference();
|
36
|
+
fr.addEventListener( "cancel" , function(e) { call( e.type , [] ); } );
|
37
|
+
fr.addEventListener( "select" , function(e) { call( e.type , [fr.name,fr.size,extractType(fr)]); } );
|
38
|
+
if( _filters.length > 0 )
|
39
|
+
fr.browse( _filters );
|
40
|
+
else
|
41
|
+
fr.browse();
|
42
|
+
_fr = fr;
|
43
|
+
}
|
44
|
+
|
45
|
+
function enable() {
|
46
|
+
buttonMode = true;
|
47
|
+
doubleClickEnabled = true;
|
48
|
+
addEventListener( "click" , onBrowse );
|
49
|
+
addEventListener( "click" , onMouseEvent );
|
50
|
+
addEventListener( "rollOver" , onMouseEvent );
|
51
|
+
addEventListener( "rollOut" , onMouseEvent );
|
52
|
+
addEventListener( "mouseMove" , onMouseEvent );
|
53
|
+
addEventListener( "mouseDown" , onMouseEvent );
|
54
|
+
addEventListener( "mouseUp" , onMouseEvent );
|
55
|
+
addEventListener( "mouseOver" , onMouseEvent );
|
56
|
+
addEventListener( "mouseOut" , onMouseEvent );
|
57
|
+
addEventListener( "doubleClick" , onMouseEvent );
|
58
|
+
call("enabled");
|
59
|
+
}
|
60
|
+
|
61
|
+
function disable() {
|
62
|
+
buttonMode = false;
|
63
|
+
doubleClickEnabled = false;
|
64
|
+
removeEventListener( "click" , onBrowse );
|
65
|
+
removeEventListener( "click" , onMouseEvent );
|
66
|
+
removeEventListener( "rollOver" , onMouseEvent );
|
67
|
+
removeEventListener( "rollOut" , onMouseEvent );
|
68
|
+
removeEventListener( "mouseMove" , onMouseEvent );
|
69
|
+
removeEventListener( "mouseDown" , onMouseEvent );
|
70
|
+
removeEventListener( "mouseUp" , onMouseEvent );
|
71
|
+
removeEventListener( "mouseOver" , onMouseEvent );
|
72
|
+
removeEventListener( "mouseOut" , onMouseEvent );
|
73
|
+
removeEventListener( "doubleClick" , onMouseEvent );
|
74
|
+
call("disabled");
|
75
|
+
}
|
76
|
+
|
77
|
+
function onMouseEvent(e) {
|
78
|
+
call( "mouseevent" , [e.type.toLowerCase(),e.stageX,e.stageY] );
|
79
|
+
}
|
80
|
+
|
81
|
+
function upload() {
|
82
|
+
// No browse has been called
|
83
|
+
if( _fr == null )
|
84
|
+
return;
|
85
|
+
|
86
|
+
// Fetch a signature and other good things from the backend
|
87
|
+
var vars = new flash.net.URLVariables();
|
88
|
+
vars.fileName = _fr.name;
|
89
|
+
vars.fileSize = _fr.size;
|
90
|
+
vars.contentType = extractType( _fr );
|
91
|
+
vars.key = _prefix + _fr.name;
|
92
|
+
|
93
|
+
var req = new flash.net.URLRequest(_signatureURL);
|
94
|
+
req.method = flash.net.URLRequestMethod.GET;
|
95
|
+
req.data = vars;
|
96
|
+
|
97
|
+
var load = new flash.net.URLLoader();
|
98
|
+
load.dataFormat = flash.net.URLLoaderDataFormat.TEXT;
|
99
|
+
load.addEventListener( "complete" , onSignatureComplete );
|
100
|
+
load.addEventListener( "securityError" , onSignatureError );
|
101
|
+
load.addEventListener( "ioError" , onSignatureError );
|
102
|
+
load.load( req );
|
103
|
+
}
|
104
|
+
|
105
|
+
static function extractType( fr : flash.net.FileReference ) {
|
106
|
+
if( fr.type == null || fr.type.indexOf( "/" ) == -1 ) {
|
107
|
+
var ext = fr.name.split(".").pop();
|
108
|
+
var mime = new MimeTypes().getMimeType( ext );
|
109
|
+
if( mime == null )
|
110
|
+
return "application/octet-stream";
|
111
|
+
else
|
112
|
+
return mime;
|
113
|
+
}
|
114
|
+
return fr.type;
|
115
|
+
}
|
116
|
+
|
117
|
+
function onSignatureError(e) {
|
118
|
+
call( "error" , ["Could not get signature because: " + e.text] );
|
119
|
+
}
|
120
|
+
|
121
|
+
function onSignatureComplete(e) {
|
122
|
+
// Now that we have the signature we can send the file to S3.
|
123
|
+
|
124
|
+
var load = cast( e.target , flash.net.URLLoader );
|
125
|
+
var sign = new haxe.xml.Fast( Xml.parse( load.data ).firstElement() );
|
126
|
+
|
127
|
+
if( sign.has.error ) {
|
128
|
+
call( "error" , ["There was an error while making the signature: " + sign.node.error.innerData] );
|
129
|
+
return;
|
130
|
+
}
|
131
|
+
|
132
|
+
// Create an S3Options object from the signature xml
|
133
|
+
var opts = {
|
134
|
+
accessKeyId: sign.node.accessKeyId.innerData,
|
135
|
+
acl: sign.node.acl.innerData,
|
136
|
+
bucket: sign.node.bucket.innerData,
|
137
|
+
contentType: sign.node.contentType.innerData,
|
138
|
+
expires: sign.node.expires.innerData,
|
139
|
+
key: sign.node.key.innerData,
|
140
|
+
secure: sign.node.secure.innerData == "true",
|
141
|
+
signature: sign.node.signature.innerData,
|
142
|
+
policy: sign.node.policy.innerData
|
143
|
+
};
|
144
|
+
|
145
|
+
var fr = _fr;
|
146
|
+
|
147
|
+
var req = new S3Request( opts );
|
148
|
+
req.onError = function(msg) { call( "error" , [msg] ); }
|
149
|
+
req.onProgress = function(p) { call( "progress" , [p] ); }
|
150
|
+
req.onComplete = function() { call( "complete" , [opts.key] ); }
|
151
|
+
req.upload( _fr );
|
152
|
+
call( "start" , [] );
|
153
|
+
}
|
154
|
+
|
155
|
+
static function call( eventType , args : Array<Dynamic> = null ) {
|
156
|
+
if( args == null )
|
157
|
+
args = [];
|
158
|
+
var method = "on"+eventType;
|
159
|
+
if( _id != null && flash.external.ExternalInterface.available ) {
|
160
|
+
var c = "function(){
|
161
|
+
var swf = document.getElementById('"+_id+"');
|
162
|
+
if( swf )
|
163
|
+
swf['"+method+"'].apply(swf,['"+args.join("','")+"']);
|
164
|
+
}()";
|
165
|
+
flash.external.ExternalInterface.call( c , [] );
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
169
|
+
function onStageResize(e=null) {
|
170
|
+
graphics.clear();
|
171
|
+
graphics.beginFill( 0 , 0 );
|
172
|
+
graphics.drawRect( 0 , 0 , stage.stageWidth , stage.stageHeight );
|
173
|
+
}
|
174
|
+
|
175
|
+
public static function main() {
|
176
|
+
flash.Lib.current.stage.align = flash.display.StageAlign.TOP_LEFT;
|
177
|
+
flash.Lib.current.stage.scaleMode = flash.display.StageScaleMode.NO_SCALE;
|
178
|
+
|
179
|
+
var s = new S3Upload();
|
180
|
+
flash.Lib.current.addChild( s );
|
181
|
+
s.init();
|
182
|
+
}
|
183
|
+
|
184
|
+
|
185
|
+
}
|
186
|
+
|
187
|
+
typedef S3Options = {
|
188
|
+
var accessKeyId : String;
|
189
|
+
var acl : String;
|
190
|
+
var bucket : String;
|
191
|
+
var contentType : String;
|
192
|
+
var expires : String;
|
193
|
+
var key : String;
|
194
|
+
var secure : Bool;
|
195
|
+
var signature : String;
|
196
|
+
var policy : String;
|
197
|
+
}
|
198
|
+
|
199
|
+
class S3Request {
|
200
|
+
|
201
|
+
static inline var AMAZON_BASE_URL = "s3.amazonaws.com";
|
202
|
+
|
203
|
+
var _opts : S3Options;
|
204
|
+
var _httpStatus : Bool;
|
205
|
+
|
206
|
+
public var onComplete : Void -> Void;
|
207
|
+
public var onProgress : Float -> Void;
|
208
|
+
public var onError : String -> Void;
|
209
|
+
|
210
|
+
public function new( opts : S3Options ) {
|
211
|
+
_opts = opts;
|
212
|
+
_httpStatus = false;
|
213
|
+
}
|
214
|
+
|
215
|
+
function getUrl() {
|
216
|
+
var vanity = canUseVanityStyle();
|
217
|
+
|
218
|
+
if( _opts.secure && vanity && _opts.bucket.indexOf( "." ) > -1 )
|
219
|
+
throw new flash.errors.IllegalOperationError( "Cannot use SSL with bucket name containing '.': " + _opts.bucket );
|
220
|
+
|
221
|
+
var url = "http" + ( _opts.secure ? "s" : "" ) + "://";
|
222
|
+
|
223
|
+
if( vanity )
|
224
|
+
url += _opts.bucket + "." + AMAZON_BASE_URL;
|
225
|
+
else
|
226
|
+
url += AMAZON_BASE_URL + "/" + _opts.bucket;
|
227
|
+
|
228
|
+
return url;
|
229
|
+
}
|
230
|
+
|
231
|
+
function getVars() {
|
232
|
+
var vars = new flash.net.URLVariables();
|
233
|
+
vars.key = _opts.key;
|
234
|
+
vars.acl = _opts.acl;
|
235
|
+
vars.AWSAccessKeyId = _opts.accessKeyId;
|
236
|
+
vars.signature = _opts.signature;
|
237
|
+
Reflect.setField( vars , "Content-Type" , _opts.contentType );
|
238
|
+
vars.policy = _opts.policy;
|
239
|
+
vars.success_action_status = "201";
|
240
|
+
return vars;
|
241
|
+
}
|
242
|
+
|
243
|
+
function canUseVanityStyle() {
|
244
|
+
if( _opts.bucket.length < 3 || _opts.bucket.length > 63 )
|
245
|
+
return false;
|
246
|
+
|
247
|
+
var periodPosition = _opts.bucket.indexOf( "." );
|
248
|
+
if( periodPosition == 0 && periodPosition == _opts.bucket.length - 1 )
|
249
|
+
return false;
|
250
|
+
|
251
|
+
if( ~/^[0-9]|+\.[0-9]|+\.[0-9]|+\.[0-9]|+$/.match( _opts.bucket ) )
|
252
|
+
return false;
|
253
|
+
|
254
|
+
if( _opts.bucket.toLowerCase() != _opts.bucket )
|
255
|
+
return false;
|
256
|
+
|
257
|
+
return true;
|
258
|
+
}
|
259
|
+
|
260
|
+
public function upload( fr : flash.net.FileReference ) {
|
261
|
+
var url = getUrl();
|
262
|
+
flash.system.Security.loadPolicyFile(url + "/crossdomain.xml");
|
263
|
+
|
264
|
+
var req = new flash.net.URLRequest( url );
|
265
|
+
req.method = flash.net.URLRequestMethod.POST;
|
266
|
+
req.data = getVars();
|
267
|
+
|
268
|
+
fr.addEventListener( "uploadCompleteData" , onUploadComplete );
|
269
|
+
fr.addEventListener( "securityError" , onUploadError );
|
270
|
+
fr.addEventListener( "ioError" , onUploadError );
|
271
|
+
fr.addEventListener( "progress" , onUploadProgress);
|
272
|
+
fr.addEventListener( "open" , onUploadOpen);
|
273
|
+
fr.addEventListener( "httpStatus", onUploadHttpStatus);
|
274
|
+
|
275
|
+
fr.upload(req, "file", false);
|
276
|
+
}
|
277
|
+
|
278
|
+
function onUploadComplete( e ) {
|
279
|
+
if( isError( e.data ) )
|
280
|
+
onError( "Amazon S3 returned an error: " + e.data );
|
281
|
+
else {
|
282
|
+
onProgress( 1 );
|
283
|
+
onComplete();
|
284
|
+
}
|
285
|
+
}
|
286
|
+
|
287
|
+
function onUploadHttpStatus( e ) {
|
288
|
+
_httpStatus = true;
|
289
|
+
if( e.status >= 200 && e.status < 300 )
|
290
|
+
onComplete();
|
291
|
+
else
|
292
|
+
onError( "Amazon S3 returned an error: " + e.status );
|
293
|
+
}
|
294
|
+
|
295
|
+
function onUploadOpen( e ) {
|
296
|
+
onProgress( 0 );
|
297
|
+
}
|
298
|
+
|
299
|
+
function onUploadProgress( e ) {
|
300
|
+
onProgress( e.bytesLoaded / e.bytesTotal );
|
301
|
+
}
|
302
|
+
|
303
|
+
function onUploadError( e ) {
|
304
|
+
if( !_httpStatus ) // ignore io errors if we already had a valid http status
|
305
|
+
onError( "Amazon S3 returned an error: " + e.message );
|
306
|
+
}
|
307
|
+
|
308
|
+
function isError(responseText:String):Bool {
|
309
|
+
var xml = Xml.parse(responseText);
|
310
|
+
var root = xml.firstChild();
|
311
|
+
return root != null && root.nodeName == "Error";
|
312
|
+
}
|
313
|
+
|
314
|
+
}
|
@@ -0,0 +1,227 @@
|
|
1
|
+
(function($){
|
2
|
+
$.fn.s3upload = function( settings ) {
|
3
|
+
var config = {
|
4
|
+
text: null, // Defaults to the previous value of content of the element
|
5
|
+
path: "/s3upload.swf",
|
6
|
+
prefix: "",
|
7
|
+
element: "<input type='text' />",
|
8
|
+
signature_url: "/s3upload",
|
9
|
+
required: false,
|
10
|
+
submit_on_all_complete: true,
|
11
|
+
error_class: "s3_error",
|
12
|
+
file_types: []
|
13
|
+
};
|
14
|
+
if( settings ) $.extend( config , settings );
|
15
|
+
|
16
|
+
// TODO Define settings for the default visuals (like progress percentage or bar)
|
17
|
+
|
18
|
+
// if any element is a form find all :file inputs inside instead.
|
19
|
+
var elements = this.map( function() {
|
20
|
+
if( $(this).is("form") )
|
21
|
+
return $(this).find(":file").toArray();
|
22
|
+
return $(this);
|
23
|
+
} );
|
24
|
+
|
25
|
+
$.fn.s3upload.instances = $.fn.s3upload.instances || [];
|
26
|
+
var started = 0;
|
27
|
+
var completed = 0;
|
28
|
+
|
29
|
+
return elements.each( function() {
|
30
|
+
var form = $(this).closest("form");
|
31
|
+
var id = $(this).attr("id") || "s3upload_" + $.fn.s3upload.instances.length;
|
32
|
+
var name = $(this).attr("name");
|
33
|
+
|
34
|
+
// Ignore already created instances
|
35
|
+
if( $.inArray( id , $.fn.s3upload.instances ) != -1 )
|
36
|
+
return;
|
37
|
+
|
38
|
+
// replace the file input
|
39
|
+
var el = $(config.element);
|
40
|
+
el.attr( {
|
41
|
+
id: id,
|
42
|
+
"class": $(this).attr("class")
|
43
|
+
});
|
44
|
+
$(this).replaceWith(el);
|
45
|
+
|
46
|
+
// Find the value of the original to use (useful for when a previous "upload" exists)
|
47
|
+
var val = config.text;
|
48
|
+
if( !val ) {
|
49
|
+
if( $(this).is(":file") )
|
50
|
+
val = $(this).attr("defaultValue");
|
51
|
+
else if( $(this).is("input") )
|
52
|
+
val = $(this).val();
|
53
|
+
else
|
54
|
+
val = $(this).html();
|
55
|
+
}
|
56
|
+
|
57
|
+
// A helper method to set the value, even if it's an input element
|
58
|
+
var setValue = function(v) {
|
59
|
+
if( el.is("input") )
|
60
|
+
el.val(v);
|
61
|
+
else
|
62
|
+
el.html(v);
|
63
|
+
}
|
64
|
+
|
65
|
+
// create a div for the transparent flash button and absolute position it above the created element.
|
66
|
+
var flash_div = $( "<div id='s3upload_"+id+"'><div id='flash_"+id+"'></div></div>" ).appendTo( "body" );
|
67
|
+
|
68
|
+
// "Serialize" the filters
|
69
|
+
var filters = $.map( config.file_types , function(f,i) { return f.join("#"); }).join("|");
|
70
|
+
|
71
|
+
// Instantiate a swfobject in that div with js callbacks for selected, start, cancel, progress, error and complete
|
72
|
+
var fv = {
|
73
|
+
id: "flash_"+id,
|
74
|
+
prefix: config.prefix,
|
75
|
+
signatureURL: config.signature_url,
|
76
|
+
filters: filters
|
77
|
+
};
|
78
|
+
|
79
|
+
var params = { wmode: "transparent" , menu: false };
|
80
|
+
swfobject.embedSWF(config.path, fv.id, "100%", "100%", "9.0.0" , false, fv, params, false, function(e){
|
81
|
+
if( e.success ) {
|
82
|
+
var swf = e.ref;
|
83
|
+
|
84
|
+
// Now that the flash has been initialized, show the initial text
|
85
|
+
setValue(val);
|
86
|
+
|
87
|
+
// Position the swf on top of the element (and keep it positioned)
|
88
|
+
swf.update_interval = setInterval( function(){
|
89
|
+
var pos = el.offset();
|
90
|
+
flash_div.css({
|
91
|
+
width: el.outerWidth(),
|
92
|
+
height: el.outerHeight(),
|
93
|
+
position: "absolute",
|
94
|
+
top: pos.top,
|
95
|
+
left: pos.left
|
96
|
+
});
|
97
|
+
} , 100 );
|
98
|
+
|
99
|
+
// add a submit listener to the elements form which starts the upload in the flash instances.
|
100
|
+
var formSubmit = function(e){
|
101
|
+
if( config.required && !swf.info )
|
102
|
+
swf.onerror( "Error: No file selected." );
|
103
|
+
else if( swf.info )
|
104
|
+
swf.upload();
|
105
|
+
return false;
|
106
|
+
}
|
107
|
+
|
108
|
+
// Create SWF-JS callbacks
|
109
|
+
swf.onenabled = function() {
|
110
|
+
if( $.isFunction( config.onenabled ) )
|
111
|
+
config.onenabled.call(el);
|
112
|
+
if( !$.isFunction( swf.upload ) ) {
|
113
|
+
swf.onerror( "S3UploadError: Callbacks could not be initialized. Try enabling the browser cache." );
|
114
|
+
$(swf).parent().remove();
|
115
|
+
}
|
116
|
+
}
|
117
|
+
swf.ondisabled = function() {
|
118
|
+
if( $.isFunction( config.ondisabled ) )
|
119
|
+
config.ondisabled.call(el);
|
120
|
+
form.unbind("submit",formSubmit);
|
121
|
+
}
|
122
|
+
swf.onmouseevent = function(type,x,y) {
|
123
|
+
var def = true;
|
124
|
+
if( $.isFunction( config["on"+type] ) )
|
125
|
+
def = config["on"+type].call(el,x,y);
|
126
|
+
if( def ) {
|
127
|
+
// Do default stuff: Run the regular dom events on "el"?
|
128
|
+
el.trigger(type);
|
129
|
+
}
|
130
|
+
}
|
131
|
+
swf.onselect = function(name,size,type) {
|
132
|
+
swf.info = {name: name, size: size, type: type};
|
133
|
+
var def = true;
|
134
|
+
if( $.isFunction( config.onselect ) )
|
135
|
+
def = config.onselect.call(el,swf.info);
|
136
|
+
if( def ) {
|
137
|
+
// Do default stuff: Replace the text of the div with the filename?
|
138
|
+
setValue(config.prefix + name);
|
139
|
+
}
|
140
|
+
form.data("s3_selected",(form.data("s3_selected")||0) + 1 );
|
141
|
+
form.submit(formSubmit);
|
142
|
+
}
|
143
|
+
swf.oncancel = function() {
|
144
|
+
var def = true;
|
145
|
+
if( $.isFunction( config.oncancel ) )
|
146
|
+
def = config.oncancel.call(el,swf.info);
|
147
|
+
if( def ) {
|
148
|
+
// Do default stuff: Show a message? Go back to "Select file..." text?
|
149
|
+
setValue(val);
|
150
|
+
}
|
151
|
+
swf.info = null;
|
152
|
+
}
|
153
|
+
swf.onstart = function() {
|
154
|
+
var def = true;
|
155
|
+
if( $.isFunction( config.onstart ) )
|
156
|
+
def = config.onstart.call(el,swf.info);
|
157
|
+
if( def ) {
|
158
|
+
// Do default stuff: Replace the text of the div?
|
159
|
+
}
|
160
|
+
if( $.isFunction( swf.disable ) )
|
161
|
+
swf.disable();
|
162
|
+
}
|
163
|
+
swf.onprogress = function(p) {
|
164
|
+
var def = true;
|
165
|
+
if( $.isFunction( config.onprogress ) )
|
166
|
+
def = config.onprogress.call(el,p,swf.info);
|
167
|
+
if( def ) {
|
168
|
+
// Do default stuff: Fill the background of the div?
|
169
|
+
setValue( Math.ceil( p * 100 ) + "%" );
|
170
|
+
}
|
171
|
+
}
|
172
|
+
swf.onerror = function(msg) {
|
173
|
+
var def = true;
|
174
|
+
if( $.isFunction( config.onerror ) )
|
175
|
+
def = config.onerror.call(el,msg,swf.info);
|
176
|
+
if( def ) {
|
177
|
+
// Do default stuff: Replace the text with the error message?
|
178
|
+
if( !el.is("input") )
|
179
|
+
setValue( "<span class='"+config.error_class+"'>" + msg + "</span>" );
|
180
|
+
else
|
181
|
+
setValue( msg );
|
182
|
+
}
|
183
|
+
if( $.isFunction( swf.enable ) )
|
184
|
+
swf.enable();
|
185
|
+
}
|
186
|
+
swf.oncomplete = function(key) {
|
187
|
+
// Add the key to the info object
|
188
|
+
swf.info.key = key;
|
189
|
+
|
190
|
+
var def = true;
|
191
|
+
if( $.isFunction( config.oncomplete ) )
|
192
|
+
def = config.oncomplete.call(el,swf.info);
|
193
|
+
if( def ) {
|
194
|
+
// Do default stuff...
|
195
|
+
}
|
196
|
+
|
197
|
+
// Create/Update the hidden inputs
|
198
|
+
if( el.nextAll("input[name^="+name+"]").length == 0 )
|
199
|
+
for( var k in swf.info )
|
200
|
+
el.after( "<input type='hidden' name='"+name+"["+k+"]' value='"+swf.info[k]+"' />" );
|
201
|
+
else
|
202
|
+
for( var k in swf.info )
|
203
|
+
el.siblings( "input[name="+name+"["+k+"]]" ).val( swf.info[k] );
|
204
|
+
|
205
|
+
// Add to the total upload complete counter, and if it matches the number of uploads we submit the form.
|
206
|
+
form.data("s3_completed",(form.data("s3_completed")||0) + 1 );
|
207
|
+
|
208
|
+
var done = form.data("s3_completed") / form.data("s3_selected");
|
209
|
+
|
210
|
+
// All Done! Do a regular form submit or just re-enable the flash.
|
211
|
+
if( done == 1 ) {
|
212
|
+
if( !config.submit_on_all_complete ) {
|
213
|
+
if( $.isFunction( swf.enable ) )
|
214
|
+
swf.enable();
|
215
|
+
} else {
|
216
|
+
form.unbind();
|
217
|
+
form.submit();
|
218
|
+
}
|
219
|
+
}
|
220
|
+
}
|
221
|
+
|
222
|
+
}
|
223
|
+
});
|
224
|
+
$.fn.s3upload.instances.push( id );
|
225
|
+
} );
|
226
|
+
};
|
227
|
+
})(jQuery);
|
metadata
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: s3upload
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- "Robert Sk\xC3\xB6ld"
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-01-25 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: A jQuery plugin for direct upload to an Amazon S3 bucket.
|
17
|
+
email: ""
|
18
|
+
executables:
|
19
|
+
- jquery.s3upload.min.js
|
20
|
+
- s3upload.swf
|
21
|
+
extensions: []
|
22
|
+
|
23
|
+
extra_rdoc_files:
|
24
|
+
- CHANGELOG
|
25
|
+
- LICENSE
|
26
|
+
- README.md
|
27
|
+
- bin/jquery.s3upload.min.js
|
28
|
+
- bin/s3upload.swf
|
29
|
+
- lib/s3upload.rb
|
30
|
+
files:
|
31
|
+
- CHANGELOG
|
32
|
+
- LICENSE
|
33
|
+
- Manifest
|
34
|
+
- README.md
|
35
|
+
- Rakefile
|
36
|
+
- bin/jquery.s3upload.min.js
|
37
|
+
- bin/s3upload.swf
|
38
|
+
- lib/s3upload.rb
|
39
|
+
- s3upload.gemspec
|
40
|
+
- src/build.hxml
|
41
|
+
- src/hx/MimeTypes.hx
|
42
|
+
- src/hx/S3Upload.hx
|
43
|
+
- src/js/jquery.s3upload.js
|
44
|
+
has_rdoc: true
|
45
|
+
homepage: http://github.com/slaskis/s3upload
|
46
|
+
licenses: []
|
47
|
+
|
48
|
+
post_install_message:
|
49
|
+
rdoc_options:
|
50
|
+
- --line-numbers
|
51
|
+
- --inline-source
|
52
|
+
- --title
|
53
|
+
- S3upload
|
54
|
+
- --main
|
55
|
+
- README.md
|
56
|
+
require_paths:
|
57
|
+
- lib
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: "0"
|
63
|
+
version:
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: "1.2"
|
69
|
+
version:
|
70
|
+
requirements: []
|
71
|
+
|
72
|
+
rubyforge_project: s3upload
|
73
|
+
rubygems_version: 1.3.5
|
74
|
+
signing_key:
|
75
|
+
specification_version: 3
|
76
|
+
summary: A jQuery plugin for direct upload to an Amazon S3 bucket.
|
77
|
+
test_files: []
|
78
|
+
|