multiuploader 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.txt +20 -0
- data/README.md +164 -0
- data/lib/multiuploader.rb +4 -0
- data/multiuploader.gemspec +63 -0
- data/vendor/assets/images/easyuploader/empty.png +0 -0
- data/vendor/assets/images/easyuploader/filled.png +0 -0
- data/vendor/assets/javascripts/easyuploader.js.coffee.erb +74 -0
- data/vendor/assets/javascripts/multiuploader.js.coffee +121 -0
- data/vendor/assets/stylesheets/easyuploader.css.scss.erb +51 -0
- metadata +172 -0
data/LICENSE.txt
ADDED
@@ -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.
|
data/README.md
ADDED
@@ -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,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
|
+
|
Binary file
|
Binary file
|
@@ -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: []
|