s3_direct_rails 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,171 @@
1
+ /*
2
+ * jQuery Iframe Transport Plugin 1.4
3
+ * https://github.com/blueimp/jQuery-File-Upload
4
+ *
5
+ * Copyright 2011, Sebastian Tschan
6
+ * https://blueimp.net
7
+ *
8
+ * Licensed under the MIT license:
9
+ * http://www.opensource.org/licenses/MIT
10
+ */
11
+
12
+ /*jslint unparam: true, nomen: true */
13
+ /*global define, window, document */
14
+
15
+ (function (factory) {
16
+ 'use strict';
17
+ if (typeof define === 'function' && define.amd) {
18
+ // Register as an anonymous AMD module:
19
+ define(['jquery'], factory);
20
+ } else {
21
+ // Browser globals:
22
+ factory(window.jQuery);
23
+ }
24
+ }(function ($) {
25
+ 'use strict';
26
+
27
+ // Helper variable to create unique names for the transport iframes:
28
+ var counter = 0;
29
+
30
+ // The iframe transport accepts three additional options:
31
+ // options.fileInput: a jQuery collection of file input fields
32
+ // options.paramName: the parameter name for the file form data,
33
+ // overrides the name property of the file input field(s),
34
+ // can be a string or an array of strings.
35
+ // options.formData: an array of objects with name and value properties,
36
+ // equivalent to the return data of .serializeArray(), e.g.:
37
+ // [{name: 'a', value: 1}, {name: 'b', value: 2}]
38
+ $.ajaxTransport('iframe', function (options) {
39
+ if (options.async && (options.type === 'POST' || options.type === 'GET')) {
40
+ var form,
41
+ iframe;
42
+ return {
43
+ send: function (_, completeCallback) {
44
+ form = $('<form style="display:none;"></form>');
45
+ // javascript:false as initial iframe src
46
+ // prevents warning popups on HTTPS in IE6.
47
+ // IE versions below IE8 cannot set the name property of
48
+ // elements that have already been added to the DOM,
49
+ // so we set the name along with the iframe HTML markup:
50
+ iframe = $(
51
+ '<iframe src="javascript:false;" name="iframe-transport-' +
52
+ (counter += 1) + '"></iframe>'
53
+ ).bind('load', function () {
54
+ var fileInputClones,
55
+ paramNames = $.isArray(options.paramName) ?
56
+ options.paramName : [options.paramName];
57
+ iframe
58
+ .unbind('load')
59
+ .bind('load', function () {
60
+ var response;
61
+ // Wrap in a try/catch block to catch exceptions thrown
62
+ // when trying to access cross-domain iframe contents:
63
+ try {
64
+ response = iframe.contents();
65
+ // Google Chrome and Firefox do not throw an
66
+ // exception when calling iframe.contents() on
67
+ // cross-domain requests, so we unify the response:
68
+ if (!response.length || !response[0].firstChild) {
69
+ throw new Error();
70
+ }
71
+ } catch (e) {
72
+ response = undefined;
73
+ }
74
+ // The complete callback returns the
75
+ // iframe content document as response object:
76
+ completeCallback(
77
+ 200,
78
+ 'success',
79
+ {'iframe': response}
80
+ );
81
+ // Fix for IE endless progress bar activity bug
82
+ // (happens on form submits to iframe targets):
83
+ $('<iframe src="javascript:false;"></iframe>')
84
+ .appendTo(form);
85
+ form.remove();
86
+ });
87
+ form
88
+ .prop('target', iframe.prop('name'))
89
+ .prop('action', options.url)
90
+ .prop('method', options.type);
91
+ if (options.formData) {
92
+ $.each(options.formData, function (index, field) {
93
+ $('<input type="hidden"/>')
94
+ .prop('name', field.name)
95
+ .val(field.value)
96
+ .appendTo(form);
97
+ });
98
+ }
99
+ if (options.fileInput && options.fileInput.length &&
100
+ options.type === 'POST') {
101
+ fileInputClones = options.fileInput.clone();
102
+ // Insert a clone for each file input field:
103
+ options.fileInput.after(function (index) {
104
+ return fileInputClones[index];
105
+ });
106
+ if (options.paramName) {
107
+ options.fileInput.each(function (index) {
108
+ $(this).prop(
109
+ 'name',
110
+ paramNames[index] || options.paramName
111
+ );
112
+ });
113
+ }
114
+ // Appending the file input fields to the hidden form
115
+ // removes them from their original location:
116
+ form
117
+ .append(options.fileInput)
118
+ .prop('enctype', 'multipart/form-data')
119
+ // enctype must be set as encoding for IE:
120
+ .prop('encoding', 'multipart/form-data');
121
+ }
122
+ form.submit();
123
+ // Insert the file input fields at their original location
124
+ // by replacing the clones with the originals:
125
+ if (fileInputClones && fileInputClones.length) {
126
+ options.fileInput.each(function (index, input) {
127
+ var clone = $(fileInputClones[index]);
128
+ $(input).prop('name', clone.prop('name'));
129
+ clone.replaceWith(input);
130
+ });
131
+ }
132
+ });
133
+ form.append(iframe).appendTo(document.body);
134
+ },
135
+ abort: function () {
136
+ if (iframe) {
137
+ // javascript:false as iframe src aborts the request
138
+ // and prevents warning popups on HTTPS in IE6.
139
+ // concat is used to avoid the "Script URL" JSLint error:
140
+ iframe
141
+ .unbind('load')
142
+ .prop('src', 'javascript'.concat(':false;'));
143
+ }
144
+ if (form) {
145
+ form.remove();
146
+ }
147
+ }
148
+ };
149
+ }
150
+ });
151
+
152
+ // The iframe transport returns the iframe content document as response.
153
+ // The following adds converters from iframe to text, json, html, and script:
154
+ $.ajaxSetup({
155
+ converters: {
156
+ 'iframe text': function (iframe) {
157
+ return $(iframe[0].body).text();
158
+ },
159
+ 'iframe json': function (iframe) {
160
+ return $.parseJSON($(iframe[0].body).text());
161
+ },
162
+ 'iframe html': function (iframe) {
163
+ return $(iframe[0].body).html();
164
+ },
165
+ 'iframe script': function (iframe) {
166
+ return $.globalEval($(iframe[0].body).text());
167
+ }
168
+ }
169
+ });
170
+
171
+ }));
@@ -0,0 +1,88 @@
1
+ jQuery(function() {
2
+
3
+ var host = 'http://localhost:3000';
4
+
5
+ var params = decodeURIComponent(location.href).split('?')[1].split('&');
6
+ var s3BucketUrl;
7
+ var jqXHR = new Array();
8
+
9
+ for (x in params){
10
+ var key = params[x].split('=')[0];
11
+ var val = params[x].substring(params[x].search('=')+1);
12
+ if( key == 'bucket' )
13
+ s3BucketUrl = val;
14
+ else
15
+ $('#file_upload input[name=' + key.replace(/^_/,'') + ']').val(val);
16
+ }
17
+
18
+ // Opera doesn't handle multiple files properly so use single file selection there
19
+ if (navigator.appName == 'Opera') {
20
+ $('#file_upload').find('input:file').each(function () {
21
+ $(this).removeAttr('multiple')
22
+ // Fix for Opera, which ignores just removing the multiple attribute:
23
+ .replaceWith($(this).clone(true));
24
+ });
25
+ }
26
+
27
+ function randomString(length) {
28
+ var chars = '0123456789abcdefghiklmnopqrstuvwxyz';
29
+ var sRnd = '';
30
+ for (var i=0; i<length; i++){
31
+ var randomPoz = Math.floor(Math.random() * chars.length);
32
+ sRnd += chars.substring(randomPoz,randomPoz+1);
33
+ }
34
+ return sRnd;
35
+ }
36
+
37
+ $(window).on("message", function (e) {
38
+ e.preventDefault();
39
+ if (e.originalEvent.origin !== host)
40
+ return;
41
+ var data = JSON.parse(e.originalEvent.data)
42
+ jqXHR[data.uuid].abort();
43
+ });
44
+
45
+ $('#file_upload').fileupload({
46
+
47
+ url: s3BucketUrl,
48
+
49
+ formData: function (form) {
50
+ var data = form.serializeArray();
51
+ var fileType = '';
52
+ if ('type' in this.files[0] )
53
+ fileType = this.files[0].type;
54
+ data.push({ name: 'Content-Type', value: fileType })
55
+ data[0].value = data[0].value.replace(':uuid', this.context);
56
+ return data;
57
+ },
58
+
59
+ add: function (e, data) {
60
+ var postData = { eventType: 'add upload' }
61
+ postData.uuidInKey = $('#file_upload input[name=key]').val().search(':uuid') != -1;
62
+ postData.file_name = data.files[0].name;
63
+ postData.uuid = randomString(20);
64
+
65
+ window.parent.postMessage(JSON.stringify(postData), host);
66
+
67
+ data.context = postData.uuid;
68
+ jqXHR[postData.uuid] = data.submit();
69
+ },
70
+
71
+ progress: function (e, data) {
72
+ window.parent.postMessage( JSON.stringify({ eventType: 'upload progress',
73
+ uuid: data.context,
74
+ progress: parseInt(data.loaded / data.total * 100, 10) }),
75
+ host);
76
+ },
77
+
78
+ done: function (e, data) {
79
+ var file = data.files[0];
80
+ var postData = { eventType: 'upload done', uuid: data.context };
81
+ postData.file_name = file.name;
82
+ postData.s3_key = $('#file_upload input[name=key]').val().replace('/${filename}', '').replace(':uuid', data.context);
83
+ if( 'size' in file ) postData.file_size = file.size;
84
+ if( 'type' in file ) postData.file_type = file.type;
85
+ window.parent.postMessage(JSON.stringify(postData), host);
86
+ }
87
+ });
88
+ });
@@ -0,0 +1,59 @@
1
+ jQuery ->
2
+
3
+ uploaderHost = "http://#{$('#uploader').data('s3-bucket')}.s3.amazonaws.com"
4
+
5
+ xhrUploadProgressSupported = () ->
6
+ xhr = new XMLHttpRequest()
7
+ xhr && ('upload' of xhr) && ('onprogress' of xhr.upload)
8
+
9
+
10
+ # Can only track progress if size property is present on files.
11
+ progressSupported = xhrUploadProgressSupported()
12
+
13
+
14
+ $('#uploading_files').on 'click', '.uploading_file .remove_link', (e) ->
15
+ uuid = $(this).parent().data('uuid')
16
+ $(this).parent().remove()
17
+ $('#uploader iframe')[0].contentWindow.postMessage(JSON.stringify({ eventType: 'abort upload', uuid: uuid }), uploaderHost);
18
+
19
+
20
+ $(window).on "message", (event) ->
21
+
22
+ event = event.originalEvent
23
+
24
+ if event.origin != uploaderHost
25
+ return
26
+
27
+ data = JSON.parse(event.data)
28
+
29
+ eventType = data.eventType
30
+ delete data.eventType
31
+
32
+ switch eventType
33
+
34
+ when 'upload done'
35
+
36
+ $(".uploading_file[data-uuid=#{data.uuid}]").remove()
37
+
38
+ $.ajax $('#uploader iframe').data('create-resource-url'),
39
+ type: 'POST',
40
+ data: data
41
+
42
+
43
+ when 'add upload'
44
+
45
+ if progressSupported
46
+ uploadPercent = "<br/><progress value='0' max='100' class='upload_progress_bar'>0</progress> <span class='upload_percentage'>0</span> %";
47
+ $('#uploading_files').append("<p class='uploading_file'>#{data.file_name + uploadPercent} <a href='#' class='remove_link'>X</a></p>");
48
+ else
49
+ $('#uploading_files').append("<p class='uploading_file'>#{data.file_name}<br/><img src='<%= asset_path('uploading.gif') %>'/></p>");
50
+
51
+ $('.uploading_file').last().attr 'data-uuid', data.uuid
52
+
53
+
54
+ when 'upload progress'
55
+
56
+ if progressSupported
57
+ $(".uploading_file[data-uuid=#{data.uuid}]").find('.upload_percentage').html(data.progress)
58
+ $(".uploading_file[data-uuid=#{data.uuid}]").find('.upload_progress_bar').val(data.progress)
59
+
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: s3_direct_rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Cory Kaufman-Schofied
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-05-09 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: aws-s3
16
+ requirement: &70328903805420 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70328903805420
25
+ description: Upload files directly to S3 using Rails, Carrierwave and jQuery Fileupload
26
+ email: cory@corykaufman.com
27
+ executables: []
28
+ extensions: []
29
+ extra_rdoc_files: []
30
+ files:
31
+ - .gitignore
32
+ - Gemfile
33
+ - LICENSE
34
+ - README.md
35
+ - Rakefile
36
+ - lib/s3_direct_rails.rb
37
+ - lib/s3_direct_rails/railtie.rb
38
+ - lib/s3_direct_rails/uploader_helper.rb
39
+ - lib/s3_direct_rails/version.rb
40
+ - lib/tasks/s3_direct_rails.rake
41
+ - s3_direct_rails.gemspec
42
+ - vendor/assets/javascripts/s3_uploader/jquery.fileupload.js
43
+ - vendor/assets/javascripts/s3_uploader/jquery.iframe-transport.js
44
+ - vendor/assets/javascripts/s3_uploader/s3_uploader.js
45
+ - vendor/assets/javascripts/uploads.js.coffee.erb
46
+ homepage: https://github.com/allspiritseve/s3_direct_rails
47
+ licenses: []
48
+ post_install_message:
49
+ rdoc_options: []
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ! '>='
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ! '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ requirements: []
65
+ rubyforge_project:
66
+ rubygems_version: 1.8.16
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: S3 Direct Rails
70
+ test_files: []