multiuploader 1.0.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,20 @@
1
+ Copyright (c) 2012 Tim Morgan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,164 @@
1
+ MultiUploader
2
+ =============
3
+
4
+ A Ruby on Rails engine that adds drag-and-drop streaming multi-file uploader
5
+ that uses strictly modern standard Web technologies.
6
+
7
+ | | |
8
+ |:------------|:--------------------------------|
9
+ | **Author** | Tim Morgan |
10
+ | **Version** | 1.0 (Apr 20, 2012) |
11
+ | **License** | Released under the MIT license. |
12
+
13
+ About
14
+ -----
15
+
16
+ This gem adds a JavaScript library that draws a drag-and-drop target. When a
17
+ file is dragged to this target, it is queued for upload. Files are uploaded to
18
+ an endpoint with a configured amount of maximum parallel uploads. JavaScript
19
+ callbacks are used to track file progress.
20
+
21
+ In addition to the uploader itself, a higher-level abstraction, called
22
+ "EasyUploader", is also included. EasyUploader is powered by MultiUploader, but
23
+ also includes a quick-'n'-ugly™ user interface. You can use EasyUploader to
24
+ quickly start testing MultiUploader in your app, or you can even use it in
25
+ production if you really hate rolling your own designs. It also makes for
26
+ excellent example code for learning MultiUploader!
27
+
28
+ ### Requirements
29
+
30
+ * **Rails 3.1**: This gem uses Rails engines.
31
+ * **jQuery**: The carousel and lightbox is rendered and managed using jQuery.
32
+ * **Sass**: The carousel layout is written using SCSS.
33
+
34
+ #### Client Requirements
35
+
36
+ For people to use this gem, they will need support for XmlHttpRequest level 2
37
+ and the JavaScript drag-and-drop API. If you use the theme that ships with this
38
+ gem, your clients will also need CSS level 3. All of these are supported on
39
+ recent versions of Safari and Google Chrome.
40
+
41
+ Installation
42
+ ------------
43
+
44
+ To use this gem, add to your Gemfile:
45
+
46
+ ```` ruby
47
+ gem 'multiuploader'
48
+ ````
49
+
50
+ To your `application.js` file (or some other JavaScript manifest file), add:
51
+
52
+ ```` javascript
53
+ //= require multiuploader
54
+ ````
55
+
56
+ You may also need to add the following if it is not already there:
57
+
58
+ ```` javascript
59
+ //= require jquery
60
+ ````
61
+
62
+ ### EasyUploader
63
+
64
+ If you wish to additionally use EasyUploader, you must add the following to
65
+ your `application.css` file (or some other CSS manifest file);
66
+
67
+ ```` css
68
+ /*
69
+ *= require multiuploader
70
+ *= require easyuploader
71
+ */
72
+ ````
73
+
74
+ To your `application.js` file (or some other JavaScript manifest file), add:
75
+
76
+ ```` javascript
77
+ //= require easyuploader
78
+ ````
79
+
80
+ Usage
81
+ -----
82
+
83
+ We'll get started with EasyUploader first, since that's the ... easiest. If you
84
+ want to skip the baby stuff and get right into hot hot adult uploading, flip to
85
+ the next subsection.
86
+
87
+ ### EasyUploader
88
+
89
+ All you need to do to start using EasyUploader is create a DIV element and call
90
+ the `easyUploader` jQuery method on it:
91
+
92
+ ```` javascript
93
+ $('#easyuploader').easyUploader("http://some/endpoint", 'file');
94
+ ````
95
+
96
+ The first parameter is the URL to upload the files to, and the second is the
97
+ name of the form field to associate the file data with. The encoding will always
98
+ be `application/x-www-form-urlencoded`.
99
+
100
+ If you use the `easyuploader` ID, the styles in the `easyuploader.css.scss.erb`
101
+ file will kick in and you should get an instant drag-and-drop target. Drag one
102
+ or more files in there and you should start seeing the magic happen on your
103
+ server.
104
+
105
+ There is a third parameter, not used above, that allows you to pass in
106
+ additional options to the underlying MultiUploader:
107
+
108
+ ```` javascript
109
+ $('#easyuploader').easyUploader("http://some/endpoint", 'file', {
110
+ maxSimultaneousUploads: 4
111
+ });
112
+ ````
113
+
114
+ Read the MultiUploader documentation for a full list of options.
115
+
116
+ ### MultiUploader
117
+
118
+ For more low-level control of the upload process, you'll need to use
119
+ MultiUploader directly. The signature is the same as EasyUploader:
120
+
121
+ ```` javascript
122
+ $('#easyuploader').multiUploader("http://some/endpoint", 'file');
123
+ ````
124
+
125
+ The only difference is, this time you need to implement the callbacks yourself.
126
+ There are four: `startHandler`, `progressHandler`, `loadHandler`, and
127
+ `errorHandler`. Their method signatures are as follows:
128
+
129
+ ```` javascript
130
+ $('#easyuploader').multiUploader("http://some/endpoint", 'file', {
131
+ startHandler: function(file_unique_id, file) {
132
+ // called when a file begins uploading
133
+ },
134
+ progressHandler: function(file_unique_id, state, position, total) {
135
+ // called periodically as a file is uploaded
136
+ // (position/total)*100 gives the percent complete
137
+ },
138
+ loadHandler: function(file_unique_id, xhr) {
139
+ // called when the upload is complete and the response has been received
140
+ // use the xhr (an XmlHttpRequest instance) to get response data
141
+ },
142
+ errorHandler: function(file_unique_id, xhr) {
143
+ // called when the upload fails or an error response is received
144
+ // same arguments as loadHandler
145
+ }
146
+ });
147
+ ````
148
+
149
+ Notice that each callback receives a unique ID for the file. These are randomly
150
+ generated and have no meaningful information. They're just used to keep track of
151
+ your files. You should associate each upload's unique ID with the page element
152
+ that displays its progress.
153
+
154
+ Also note that the `startHandler` will not necessarily be called the moment the
155
+ user releases his mouse button. If the `maxSimultaneousUploads` option is set,
156
+ additional uploads beyond this number will be queued and put into a pending
157
+ state until an "upload slot" is vacated.
158
+
159
+ The `progressHandler` method receives a state parameter. The value will be
160
+ "upload" when the file is uploading, and "download" when the upload has
161
+ completed and the client is downloading the server's response.
162
+
163
+ For more information, and a list of additional options, see the MultiUploader
164
+ class documentation.
@@ -0,0 +1,4 @@
1
+ # The Rails engine for MultiUploader.
2
+
3
+ class MultiUploader < Rails::Engine
4
+ end
@@ -0,0 +1,63 @@
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
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "multiuploader"
8
+ s.version = "1.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Tim Morgan"]
12
+ s.date = "2012-04-21"
13
+ s.description = "A drag-and-drop multi-streaming uploader that uses XHR level 2 and the drag-drop JS API (and no Flash!)."
14
+ s.email = "github@timothymorgan.info"
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.md"
18
+ ]
19
+ s.files = [
20
+ "LICENSE.txt",
21
+ "README.md",
22
+ "lib/multiuploader.rb",
23
+ "multiuploader.gemspec",
24
+ "vendor/assets/images/easyuploader/empty.png",
25
+ "vendor/assets/images/easyuploader/filled.png",
26
+ "vendor/assets/javascripts/easyuploader.js.coffee.erb",
27
+ "vendor/assets/javascripts/multiuploader.js.coffee",
28
+ "vendor/assets/stylesheets/easyuploader.css.scss.erb"
29
+ ]
30
+ s.homepage = "http://github.com/RISCfuture/multiuploader"
31
+ s.licenses = ["MIT"]
32
+ s.require_paths = ["lib"]
33
+ s.rubygems_version = "1.8.23"
34
+ s.summary = "Multi-file drag-and-drop file uploader using strictly HTML5"
35
+
36
+ if s.respond_to? :specification_version then
37
+ s.specification_version = 3
38
+
39
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
40
+ s.add_runtime_dependency(%q<rails>, [">= 0"])
41
+ s.add_runtime_dependency(%q<compass>, [">= 0"])
42
+ s.add_runtime_dependency(%q<jquery-rails>, [">= 0"])
43
+ s.add_development_dependency(%q<yard>, [">= 0"])
44
+ s.add_development_dependency(%q<bundler>, [">= 0"])
45
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
46
+ else
47
+ s.add_dependency(%q<rails>, [">= 0"])
48
+ s.add_dependency(%q<compass>, [">= 0"])
49
+ s.add_dependency(%q<jquery-rails>, [">= 0"])
50
+ s.add_dependency(%q<yard>, [">= 0"])
51
+ s.add_dependency(%q<bundler>, [">= 0"])
52
+ s.add_dependency(%q<jeweler>, [">= 0"])
53
+ end
54
+ else
55
+ s.add_dependency(%q<rails>, [">= 0"])
56
+ s.add_dependency(%q<compass>, [">= 0"])
57
+ s.add_dependency(%q<jquery-rails>, [">= 0"])
58
+ s.add_dependency(%q<yard>, [">= 0"])
59
+ s.add_dependency(%q<bundler>, [">= 0"])
60
+ s.add_dependency(%q<jeweler>, [">= 0"])
61
+ end
62
+ end
63
+
@@ -0,0 +1,74 @@
1
+ root = exports ? this
2
+
3
+ # A basic implementation of the {MultiUploader} class. Use this class in
4
+ # conjunction with the "easyuploader" assets in `vendor/assets` for a
5
+ # quick-and-dirty file uploader.
6
+ #
7
+ # Use the `$(...).easyUploader(...)` method for a more jQuery-like syntax.
8
+ #
9
+ # In order to take advantage of the included quick-'n'-ugly theme, your target
10
+ # div needs to have an ID of `#easyuploader`.
11
+ #
12
+ class EasyUploader
13
+
14
+ # Creates a new upload manager.
15
+ #
16
+ # @param [jQuery element array] element The element to render the uploader in.
17
+ # @param [String] url The URL endpoint to post files to.
18
+ # @param [String] name The name of the file field.
19
+ # @param [Object] options Additional options to pass to {MultiUploader}.
20
+ #
21
+ constructor: (element, url, name, options) ->
22
+ options = $.extend({}, options,
23
+ startHandler: (uid, file) =>
24
+ if !@currentRow || @currentRow.find('>div.file').length == 5
25
+ @currentRow = $('<div/>').addClass('file-row').appendTo(element)
26
+
27
+ # preload images
28
+ (new Image()).src = "<%= image_path('easyuploader/empty.png') %>"
29
+ (new Image()).src = "<%= image_path('easyuploader/filled.png') %>"
30
+
31
+ fileDiv = $('<div/>').addClass('file').attr('id', "file_#{uid}").appendTo(@currentRow)
32
+ empty = $('<div/>').addClass('empty').appendTo(fileDiv)
33
+ $('<div/>').addClass('filled').appendTo empty
34
+ filename = $('<p/>').text(file.fileName).appendTo(fileDiv)
35
+ progressHandler: (uid, phase, position, total) =>
36
+ if (phase == 'upload')
37
+ amount = Math.round((position/total)*44)
38
+ $("#file_#{uid} .filled").css 'width', "#{amount}px"
39
+ loadHandler: (uid, xhr) =>
40
+ if Math.round(xhr.status/100) == 2
41
+ $("#file_#{uid}").addClass 'finished'
42
+ else
43
+ $("#file_#{uid}").addClass 'error'
44
+ if (xhr.status == 422)
45
+ errors = JSON.parse(xhr.responseText)
46
+ errorList = []
47
+
48
+ for fieldErrors in errors
49
+ do (fieldErrors) -> errorList = errorList.concat(fieldErrors)
50
+ $('<p/>').addClass('message').text(errorList.join(', ')).appendTo $("#file_#{uid}")
51
+ else
52
+ $('<p/>').addClass('message').text(xhr.statusText).appendTo $("#file_#{uid}")
53
+
54
+ if uploader.isFinished() && !uploader.isFailed() then window.location.reload()
55
+ errorHandler: (uid, xhr) =>
56
+ $("#file_#{uid}").addClass 'error'
57
+ if uploader.isFinished() && !uploader.isFailed() then window.location.reload()
58
+
59
+ )
60
+ uploader = element.multiUploader url, name, options
61
+ element.text "Drag files here to upload"
62
+
63
+
64
+ $.fn.extend
65
+
66
+ # Creates an EasyUploader in the target element.
67
+ #
68
+ # @param [String] url The URL endpoint to post files to.
69
+ # @param [String] name The name of the file field.
70
+ # @param [Object] options Additional options to pass to {MultiUploader}.
71
+ # @return [EasyUploader] The new upload manager.
72
+ #
73
+ easyUploader: (url, name, options={}) ->
74
+ new EasyUploader(this, url, name, options)
@@ -0,0 +1,121 @@
1
+ # A drag-and-drop multi-file uploader using strictly modern standard Web
2
+ # technologies.
3
+ #
4
+ # Use the `$(...).multiUploader(...)` method for a more jQuery-like syntax.
5
+
6
+ class MultiUploader
7
+
8
+ # Creates a new upload manager. Files dropped into `elem` will be uploaded (or
9
+ # queued for upload). The callbacks will be invoked at each phase of each
10
+ # file's upload.
11
+ #
12
+ # @param [jQuery element array] elem The drop target.
13
+ # @param [String] url The URL endpoint to post files to.
14
+ # @param [String] name The name of the file field.
15
+ # @param [Object] options Additional options.
16
+ # @option options [Integer] maxSimultaneousUploads The maximum number of
17
+ # parallel uploads. If not set, unlimited.
18
+ # @option options [String] method ("POST") The request method.
19
+ # @option options [Object] data Additional key-value pairs to include in the
20
+ # request form body.
21
+ # @option options [Function] startHandler Called when a file begins uploading.
22
+ # @option options [Function] progressHandler Called when some file data is
23
+ # uploaded.
24
+ # @option options [Function] loadHandler Called when a file finishes
25
+ # uploading.
26
+ # @option options [Function] errorHandler Called when a file upload fails or a
27
+ # bad response is received.
28
+ #
29
+ constructor: (elem, @url, @name, @options={}) ->
30
+ @method = @options.method || 'POST'
31
+ @element = $(elem)
32
+
33
+ @activeUploads = 0
34
+ @successfulUploads = 0
35
+ @failedUploads = 0
36
+ @pendingUploads = []
37
+
38
+ @element.bind 'dragenter', (event) ->
39
+ event.stopPropagation()
40
+ event.preventDefault()
41
+ false
42
+ @element.bind 'dragover', (event) ->
43
+ event.stopPropagation()
44
+ event.preventDefault()
45
+ false
46
+ @element.bind 'drop', this.drop
47
+
48
+ # @private
49
+ drop: (event) =>
50
+ event.stopPropagation()
51
+ event.preventDefault()
52
+
53
+ @element.text ''
54
+
55
+ $.each event.originalEvent.dataTransfer.files, (_, file) =>
56
+ this.upload file
57
+
58
+ # @private
59
+ isFinished: =>
60
+ @activeUploads == 0 && @pendingUploads.length == 0
61
+
62
+ # @private
63
+ isFailed: =>
64
+ @failedUploads > 0
65
+
66
+ # Uploads a file, or enqueues it for uploading.
67
+ #
68
+ # @param [File] file The file to upload.
69
+ #
70
+ upload: (file) =>
71
+ if @options.maxSimultaneousUploads && @activeUploads > @options.maxSimultaneousUploads
72
+ @pendingUploads.push file
73
+ return
74
+
75
+ @activeUploads++
76
+ uid = Math.round(Math.random()*0x1000000).toString(16); # so that the listeners can keep their files apart
77
+ @options.startHandler(uid, file) if @options.startHandler
78
+
79
+ xhr = new XMLHttpRequest()
80
+
81
+ data = new FormData()
82
+ data.append @name, file
83
+ if @options.data
84
+ for key, value of @options.data
85
+ do (key, value) -> data.append key, value
86
+
87
+ xhr.addEventListener 'load', (event) =>
88
+ @activeUploads--
89
+ if xhr.status >= 400 then @failedUploads++ else @successfulUploads++
90
+ this.upload @pendingUploads.pop() if @pendingUploads.length > 0
91
+ xhr.addEventListener 'error', (event) =>
92
+ @activeUploads--
93
+ @failedUploads++
94
+ this.upload @pendingUploads.pop() if @pendingUploads.length > 0
95
+
96
+ if @options.progressHandler
97
+ xhr.upload.addEventListener 'progress', (event) =>
98
+ @options.progressHandler uid, 'upload', event.position, event.total
99
+ xhr.addEventListener 'progress', (event) =>
100
+ @options.progressHandler uid, 'download', event.position, event.total
101
+ if @options.errorHandler
102
+ xhr.addEventListener 'error', (event) =>
103
+ @options.errorHandler uid, xhr
104
+ if @options.loadHandler
105
+ xhr.addEventListener 'load', (event) =>
106
+ @options.loadHandler uid, xhr
107
+
108
+ xhr.open @method, @url, true
109
+ xhr.send data
110
+
111
+ $.fn.extend
112
+
113
+ # Creates a new file uploader using the target element as the drop zone.
114
+ #
115
+ # @param [String] url The URL endpoint to post files to.
116
+ # @param [String] name The name of the file field.
117
+ # @param [Object] options Additional options to pass to {MultiUploader}.
118
+ # @return [MultiUploader] The new upload manager.
119
+ #
120
+ multiUploader: (url, name, options={}) ->
121
+ new MultiUploader(this, url, name, options)
@@ -0,0 +1,51 @@
1
+ @import "compass/css3/box";
2
+ $theme-color: gray;
3
+
4
+ #easyuploader {
5
+ color: $theme-color;
6
+ font-size: 14pt;
7
+ font-weight: bold;
8
+ text-align: center;
9
+ padding: 20px 10px;
10
+ background-color: lighten($theme-color, 40%);
11
+ border: 5px dashed lighten($theme-color, 25%);
12
+
13
+ .file-row {
14
+ @include display-box;
15
+ @include box-orient(horizontal);
16
+ @include box-pack(center);
17
+ }
18
+
19
+ .file {
20
+ margin: 20px;
21
+ width: 100px;
22
+
23
+ .empty {
24
+ background: url("<%= image_path 'easyuploader/empty.png' %>") no-repeat left top;
25
+ width: 44px;
26
+ height: 56px;
27
+ margin-left: 28px;
28
+ }
29
+
30
+ .filled {
31
+ background: url("<%= image_path 'easyuploader/filled.png' %>") no-repeat left top;
32
+ width: 0;
33
+ height: 56px;
34
+ }
35
+
36
+ p {
37
+ text-align: center;
38
+ overflow: hidden;
39
+ text-overflow: ellipsis;
40
+ }
41
+
42
+ &.finished p { color: black; }
43
+ &.error p { color: #900; }
44
+
45
+ p.message {
46
+ font-size: 10pt;
47
+ font-style: italic;
48
+ font-weight: normal;
49
+ }
50
+ }
51
+ }
metadata ADDED
@@ -0,0 +1,172 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: multiuploader
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Tim Morgan
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-21 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: !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: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: compass
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: jquery-rails
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: yard
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: redcarpet
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: bundler
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: jeweler
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ description: A drag-and-drop multi-streaming uploader that uses XHR level 2 and the
127
+ drag-drop JS API (and no Flash!).
128
+ email: github@timothymorgan.info
129
+ executables: []
130
+ extensions: []
131
+ extra_rdoc_files:
132
+ - LICENSE.txt
133
+ - README.md
134
+ files:
135
+ - LICENSE.txt
136
+ - README.md
137
+ - lib/multiuploader.rb
138
+ - multiuploader.gemspec
139
+ - vendor/assets/images/easyuploader/empty.png
140
+ - vendor/assets/images/easyuploader/filled.png
141
+ - vendor/assets/javascripts/easyuploader.js.coffee.erb
142
+ - vendor/assets/javascripts/multiuploader.js.coffee
143
+ - vendor/assets/stylesheets/easyuploader.css.scss.erb
144
+ homepage: http://github.com/RISCfuture/multiuploader
145
+ licenses:
146
+ - MIT
147
+ post_install_message:
148
+ rdoc_options: []
149
+ require_paths:
150
+ - lib
151
+ required_ruby_version: !ruby/object:Gem::Requirement
152
+ none: false
153
+ requirements:
154
+ - - ! '>='
155
+ - !ruby/object:Gem::Version
156
+ version: '0'
157
+ segments:
158
+ - 0
159
+ hash: -4392674048479711301
160
+ required_rubygems_version: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ! '>='
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ requirements: []
167
+ rubyforge_project:
168
+ rubygems_version: 1.8.23
169
+ signing_key:
170
+ specification_version: 3
171
+ summary: Multi-file drag-and-drop file uploader using strictly HTML5
172
+ test_files: []