s3_direct_rails 0.1.0

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