rails-uploader 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +33 -0
- data/app/assets/javascripts/uploader/application.js +1 -2
- data/app/views/uploader/default/_container.html.erb +3 -4
- data/config/locales/en.yml +1 -0
- data/lib/uploader/asset.rb +79 -36
- data/lib/uploader/fileuploads.rb +16 -2
- data/lib/uploader/helpers/field_tag.rb +1 -1
- data/lib/uploader/hooks/formtastic.rb +7 -0
- data/lib/uploader/version.rb +1 -1
- data/spec/factories/articles.rb +1 -0
- data/spec/mongoid.yml +17 -0
- data/spec/mongoid_spec.rb +40 -0
- data/spec/spec_helper.rb +10 -3
- data/vendor/assets/javascripts/uploader/jquery.fileupload-fp.js +8 -4
- data/vendor/assets/javascripts/uploader/jquery.fileupload-ui.js +32 -24
- data/vendor/assets/javascripts/uploader/jquery.fileupload.js +199 -120
- data/vendor/assets/stylesheets/uploader/default.css +1 -1
- metadata +39 -6
- data/app/assets/javascripts/uploader/init.js +0 -5
- data/app/views/uploader/default/_init.html.erb +0 -9
data/README.md
CHANGED
@@ -75,6 +75,29 @@ Find asset by foreign key or guid:
|
|
75
75
|
@user.fileupload_asset(:picture)
|
76
76
|
```
|
77
77
|
|
78
|
+
### Mongoid
|
79
|
+
|
80
|
+
No parent asset model is required, one only has to `include Uploader::Asset::Mongoid` into the
|
81
|
+
model that should act like an asset:
|
82
|
+
|
83
|
+
``` ruby
|
84
|
+
class Picture
|
85
|
+
include Mongoid::Document
|
86
|
+
include Uploader::Asset::Mongoid
|
87
|
+
|
88
|
+
belongs_to :user
|
89
|
+
end
|
90
|
+
|
91
|
+
class User
|
92
|
+
include Mongoid::Document
|
93
|
+
include Uploader::Fileuploads
|
94
|
+
|
95
|
+
has_one :picture, :as => :assetable
|
96
|
+
|
97
|
+
fileuploads :picture
|
98
|
+
end
|
99
|
+
```
|
100
|
+
|
78
101
|
### Include assets
|
79
102
|
|
80
103
|
Javascripts:
|
@@ -113,6 +136,16 @@ or FormBuilder:
|
|
113
136
|
<%= f.input :pictures, :as => :uploader, :input_html => {:sortable => true} %>
|
114
137
|
```
|
115
138
|
|
139
|
+
#### Confirming deletions
|
140
|
+
|
141
|
+
This is only working in Formtastic and FormBuilder:
|
142
|
+
|
143
|
+
``` ruby
|
144
|
+
# formtastic
|
145
|
+
<%= f.input :picture, :as => :uploader, :confirm_delete => true %>
|
146
|
+
# the i18n lookup key would be en.formtastic.delete_confirmations.picture
|
147
|
+
```
|
148
|
+
|
116
149
|
## Contributing
|
117
150
|
|
118
151
|
1. Fork it
|
@@ -1,9 +1,8 @@
|
|
1
|
+
//= require uploader/jquery.ui.widget
|
1
2
|
//= require uploader/locales/en
|
2
3
|
//= require uploader/tmpl.min
|
3
4
|
//= require uploader/load-image.min
|
4
|
-
//= require uploader/jquery.ui.widget
|
5
5
|
//= require uploader/jquery.iframe-transport
|
6
6
|
//= require uploader/jquery.fileupload
|
7
7
|
//= require uploader/jquery.fileupload-ui
|
8
|
-
//= require uploader/init
|
9
8
|
|
@@ -4,21 +4,20 @@
|
|
4
4
|
<div class="uploader-files"></div>
|
5
5
|
|
6
6
|
<div class="uploader-dnd-hints">
|
7
|
-
<
|
7
|
+
<span class="uploader-button gray fileinput-button">
|
8
8
|
<span><%= I18n.t('uploader.button') %></span>
|
9
9
|
<%= fields_for field.object do |f| -%>
|
10
10
|
<%= f.fields_for field.method_name, field.klass.new do |m| -%>
|
11
11
|
<%= m.file_field(:data, field.input_html) %>
|
12
12
|
<% end -%>
|
13
13
|
<% end -%>
|
14
|
-
</
|
14
|
+
</span>
|
15
15
|
|
16
16
|
<div class="uploader-dnd-hint">
|
17
17
|
<%= I18n.t('uploader.or') %><span><%= I18n.t('uploader.drop') %></span>
|
18
18
|
</div>
|
19
19
|
</div>
|
20
20
|
|
21
|
-
<%= render :partial => "uploader/#{field.theme}/init", :locals => {:field => field} %>
|
22
21
|
<%= render :partial => "uploader/#{field.theme}/upload", :locals => {:field => field} %>
|
23
22
|
<%= render :partial => "uploader/#{field.theme}/download", :locals => {:field => field} %>
|
24
23
|
<%= render :partial => "uploader/#{field.theme}/sortable", :locals => {:field => field} if field.sortable? %>
|
@@ -28,7 +27,7 @@
|
|
28
27
|
var uploader, container;
|
29
28
|
container = $("#<%= field.id %> div.uploader-files");
|
30
29
|
|
31
|
-
$('#<%= field.id %> input[type="file"]').
|
30
|
+
$('#<%= field.id %> input[type="file"]').each(function(){
|
32
31
|
$(this).fileupload({
|
33
32
|
dataType: 'json',
|
34
33
|
dropZone: $("#<%= field.id %>"),
|
data/config/locales/en.yml
CHANGED
data/lib/uploader/asset.rb
CHANGED
@@ -1,42 +1,85 @@
|
|
1
1
|
module Uploader
|
2
2
|
module Asset
|
3
|
-
|
4
|
-
|
5
|
-
#
|
6
|
-
# class Asset < ActiveRecord::Base
|
7
|
-
# include Uploader::Asset
|
8
|
-
#
|
9
|
-
# def uploader_create(params, request = nil)
|
10
|
-
# self.user = request.env['warden'].user
|
11
|
-
# super
|
12
|
-
# end
|
13
|
-
# end
|
14
|
-
#
|
15
|
-
def uploader_create(params, request = nil)
|
16
|
-
self.guid = params[:guid]
|
17
|
-
self.assetable_type = params[:assetable_type]
|
18
|
-
self.assetable_id = params[:assetable_id]
|
19
|
-
save
|
3
|
+
def self.included(base)
|
4
|
+
base.send(:include, Uploader::Asset::AssetProcessor)
|
20
5
|
end
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
6
|
+
|
7
|
+
module Mongoid
|
8
|
+
def self.included(base)
|
9
|
+
base.send(:include, Uploader::Asset::AssetProcessor)
|
10
|
+
|
11
|
+
base.instance_eval do
|
12
|
+
field :guid, type: String
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def as_json(options = {})
|
17
|
+
json_data = super
|
18
|
+
json_data['filename'] = File.basename(data.path)
|
19
|
+
json_data['size'] = data.file.size
|
20
|
+
json_data['id'] = json_data['_id']
|
21
|
+
|
22
|
+
if data.respond_to?(:thumb)
|
23
|
+
json_data['thumb_url'] = data.thumb.url
|
24
|
+
end
|
25
|
+
|
26
|
+
json_data
|
27
|
+
end
|
28
|
+
|
29
|
+
def assetable_id_format(assetable_id)
|
30
|
+
Moped::BSON::ObjectId.from_string(assetable_id)
|
31
|
+
end
|
32
|
+
|
33
|
+
class << self
|
34
|
+
def include_root_in_json
|
35
|
+
false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
module AssetProcessor
|
41
|
+
# Save asset
|
42
|
+
# Usage:
|
43
|
+
#
|
44
|
+
# class Asset < ActiveRecord::Base
|
45
|
+
# include Uploader::Asset
|
46
|
+
#
|
47
|
+
# def uploader_create(params, request = nil)
|
48
|
+
# self.user = request.env['warden'].user
|
49
|
+
# super
|
50
|
+
# end
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
def uploader_create(params, request = nil)
|
54
|
+
self.guid = params[:guid]
|
55
|
+
self.assetable_type = params[:assetable_type]
|
56
|
+
self.assetable_id = assetable_id_format(params[:assetable_id]) if params[:assetable_id]
|
57
|
+
save
|
58
|
+
end
|
59
|
+
|
60
|
+
# Destroy asset
|
61
|
+
# Usage (cancan example):
|
62
|
+
#
|
63
|
+
# class Asset < ActiveRecord::Base
|
64
|
+
# include Uploader::Asset
|
65
|
+
#
|
66
|
+
# def uploader_destroy(params, request = nil)
|
67
|
+
# ability = Ability.new(request.env['warden'].user)
|
68
|
+
# if ability.can? :delete, self
|
69
|
+
# super
|
70
|
+
# else
|
71
|
+
# errors.add(:id, :access_denied)
|
72
|
+
# end
|
73
|
+
# end
|
74
|
+
# end
|
75
|
+
#
|
76
|
+
def uploader_destroy(params, request)
|
77
|
+
destroy
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def assetable_id_format(assetable_id)
|
82
|
+
assetable_id
|
40
83
|
end
|
41
84
|
end
|
42
85
|
end
|
data/lib/uploader/fileuploads.rb
CHANGED
@@ -3,7 +3,17 @@ module Uploader
|
|
3
3
|
def self.included(base)
|
4
4
|
base.send :extend, SingletonMethods
|
5
5
|
end
|
6
|
-
|
6
|
+
|
7
|
+
module Mongoid
|
8
|
+
def self.included(base)
|
9
|
+
base.send :include, Uploader::Fileuploads
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.include_root_in_json
|
13
|
+
false
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
7
17
|
module SingletonMethods
|
8
18
|
# Join ActiveRecord object with uploaded file
|
9
19
|
# Usage:
|
@@ -77,7 +87,11 @@ module Uploader
|
|
77
87
|
|
78
88
|
def fileupload_multiple?(method)
|
79
89
|
association = self.class.reflect_on_association(method.to_sym)
|
80
|
-
|
90
|
+
|
91
|
+
# many? for Mongoid, :collection? for AR
|
92
|
+
method = association.respond_to?(:many?) ? :many? : :collection?
|
93
|
+
|
94
|
+
!!(association && association.send(method))
|
81
95
|
end
|
82
96
|
|
83
97
|
# Find or build new asset object
|
@@ -13,7 +13,7 @@ module Uploader
|
|
13
13
|
#
|
14
14
|
def initialize(object_name, method_name, template, options = {}) #:nodoc:
|
15
15
|
options = { :object_name => object_name, :method_name => method_name }.merge(options)
|
16
|
-
|
16
|
+
|
17
17
|
@template, @options = template, options.dup
|
18
18
|
|
19
19
|
@theme = (@options.delete(:theme) || "default")
|
@@ -9,4 +9,11 @@ class UploaderInput
|
|
9
9
|
builder.uploader_field(method, input_html_options)
|
10
10
|
end
|
11
11
|
end
|
12
|
+
|
13
|
+
def input_html_options
|
14
|
+
data = super
|
15
|
+
data[:confirm_delete] = options[:confirm_delete]
|
16
|
+
data[:confirm_message] = localized_string(method, method, :delete_confirmation) || I18n.t('uploader.confirm_delete')
|
17
|
+
data
|
18
|
+
end
|
12
19
|
end
|
data/lib/uploader/version.rb
CHANGED
data/spec/factories/articles.rb
CHANGED
data/spec/mongoid.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# Tell Mongoid which environment this configuration is for.
|
2
|
+
test:
|
3
|
+
# This starts the session configuration settings. You may have as
|
4
|
+
# many sessions as you like, but you must have at least 1 named
|
5
|
+
# 'default'.
|
6
|
+
sessions:
|
7
|
+
# Define the default session.
|
8
|
+
default:
|
9
|
+
# A session can have any number of hosts. Usually 1 for a single
|
10
|
+
# server setup, and at least 3 for a replica set. Hosts must be
|
11
|
+
# an array of host:port pairs. This session is single server.
|
12
|
+
hosts:
|
13
|
+
- localhost:27017
|
14
|
+
# Define the default database name.
|
15
|
+
database: rails_uploader_test
|
16
|
+
options:
|
17
|
+
include_root_in_json: false
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class MongoidArticle
|
4
|
+
include Mongoid::Document
|
5
|
+
include Uploader::Fileuploads
|
6
|
+
|
7
|
+
has_one :mongoid_picture, :as => :assetable
|
8
|
+
|
9
|
+
fileuploads :mongoid_picture
|
10
|
+
end
|
11
|
+
|
12
|
+
class MongoidPicture
|
13
|
+
include Mongoid::Document
|
14
|
+
include Uploader::Asset::Mongoid
|
15
|
+
|
16
|
+
belongs_to :assetable, polymorphic: true
|
17
|
+
end
|
18
|
+
|
19
|
+
describe Uploader::Asset::Mongoid do
|
20
|
+
before do
|
21
|
+
@guid = 'guid'
|
22
|
+
@picture = MongoidPicture.create!(:guid => @guid, :assetable_type => 'MongoidArticle')
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should find asset by guid' do
|
26
|
+
asset = MongoidArticle.fileupload_find("mongoid_picture", @picture.guid)
|
27
|
+
asset.should == @picture
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should update asset target_id by guid" do
|
31
|
+
MongoidArticle.fileupload_update(1000, @picture.guid, :mongoid_picture)
|
32
|
+
@picture.reload
|
33
|
+
@picture.assetable_id.should == 1000
|
34
|
+
@picture.guid.should be_nil
|
35
|
+
end
|
36
|
+
|
37
|
+
after do
|
38
|
+
MongoidPicture.destroy_all
|
39
|
+
end
|
40
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -29,6 +29,10 @@ end
|
|
29
29
|
# Load support files
|
30
30
|
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
31
31
|
|
32
|
+
# Mongoid
|
33
|
+
require 'mongoid'
|
34
|
+
Mongoid.load!('spec/mongoid.yml')
|
35
|
+
|
32
36
|
RSpec.configure do |config|
|
33
37
|
# Remove this line if you don't want RSpec's should and should_not
|
34
38
|
# methods or matchers
|
@@ -39,14 +43,17 @@ RSpec.configure do |config|
|
|
39
43
|
config.mock_with :rspec
|
40
44
|
|
41
45
|
config.before(:suite) do
|
42
|
-
DatabaseCleaner.strategy = :truncation
|
46
|
+
DatabaseCleaner[:active_record].strategy = :truncation
|
47
|
+
DatabaseCleaner[:mongoid].strategy = :truncation
|
43
48
|
end
|
44
49
|
|
45
50
|
config.before(:all) do
|
46
|
-
DatabaseCleaner.start
|
51
|
+
DatabaseCleaner[:active_record].start
|
52
|
+
DatabaseCleaner[:mongoid].start
|
47
53
|
end
|
48
54
|
|
49
55
|
config.after(:all) do
|
50
|
-
DatabaseCleaner.clean
|
56
|
+
DatabaseCleaner[:active_record].clean
|
57
|
+
DatabaseCleaner[:mongoid].clean
|
51
58
|
end
|
52
59
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/*
|
2
|
-
* jQuery File Upload File Processing Plugin 1.2.
|
2
|
+
* jQuery File Upload File Processing Plugin 1.2.3
|
3
3
|
* https://github.com/blueimp/jQuery-File-Upload
|
4
4
|
*
|
5
5
|
* Copyright 2012, Sebastian Tschan
|
@@ -62,9 +62,13 @@
|
|
62
62
|
// fileupload widget (via file input selection, drag & drop or add
|
63
63
|
// API call). See the basic file upload widget for more information:
|
64
64
|
add: function (e, data) {
|
65
|
-
|
66
|
-
|
67
|
-
|
65
|
+
if (data.autoUpload || (data.autoUpload !== false &&
|
66
|
+
($(this).data('blueimp-fileupload') ||
|
67
|
+
$(this).data('fileupload')).options.autoUpload)) {
|
68
|
+
$(this).fileupload('process', data).done(function () {
|
69
|
+
data.submit();
|
70
|
+
});
|
71
|
+
}
|
68
72
|
}
|
69
73
|
},
|
70
74
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/*
|
2
|
-
* jQuery File Upload User Interface Plugin 7.
|
2
|
+
* jQuery File Upload User Interface Plugin 7.4.4
|
3
3
|
* https://github.com/blueimp/jQuery-File-Upload
|
4
4
|
*
|
5
5
|
* Copyright 2010, Sebastian Tschan
|
@@ -263,7 +263,7 @@
|
|
263
263
|
// Callback for upload progress events:
|
264
264
|
progress: function (e, data) {
|
265
265
|
if (data.context) {
|
266
|
-
var progress =
|
266
|
+
var progress = Math.floor(data.loaded / data.total * 100);
|
267
267
|
data.context.find('.progress')
|
268
268
|
.attr('aria-valuenow', progress)
|
269
269
|
.find('.bar').css(
|
@@ -275,7 +275,7 @@
|
|
275
275
|
// Callback for global upload progress events:
|
276
276
|
progressall: function (e, data) {
|
277
277
|
var $this = $(this),
|
278
|
-
progress =
|
278
|
+
progress = Math.floor(data.loaded / data.total * 100),
|
279
279
|
globalProgressNode = $this.find('.fileupload-progress'),
|
280
280
|
extendedProgressNode = globalProgressNode
|
281
281
|
.find('.progress-extended');
|
@@ -328,15 +328,16 @@
|
|
328
328
|
var that = $(this).data('blueimp-fileupload') ||
|
329
329
|
$(this).data('fileupload');
|
330
330
|
if (data.url) {
|
331
|
-
$.ajax(data)
|
332
|
-
|
331
|
+
$.ajax(data).done(function () {
|
332
|
+
that._transition(data.context).done(
|
333
|
+
function () {
|
334
|
+
$(this).remove();
|
335
|
+
that._adjustMaxNumberOfFiles(1);
|
336
|
+
that._trigger('destroyed', e, data);
|
337
|
+
}
|
338
|
+
);
|
339
|
+
});
|
333
340
|
}
|
334
|
-
that._transition(data.context).done(
|
335
|
-
function () {
|
336
|
-
$(this).remove();
|
337
|
-
that._trigger('destroyed', e, data);
|
338
|
-
}
|
339
|
-
);
|
340
341
|
}
|
341
342
|
},
|
342
343
|
|
@@ -422,7 +423,7 @@
|
|
422
423
|
|
423
424
|
_formatTime: function (seconds) {
|
424
425
|
var date = new Date(seconds * 1000),
|
425
|
-
days =
|
426
|
+
days = Math.floor(seconds / 86400);
|
426
427
|
days = days ? days + 'd ' : '';
|
427
428
|
return days +
|
428
429
|
('0' + date.getUTCHours()).slice(-2) + ':' +
|
@@ -519,6 +520,12 @@
|
|
519
520
|
// so we have to resolve manually:
|
520
521
|
dfd.resolveWith(node);
|
521
522
|
}
|
523
|
+
node.on('remove', function () {
|
524
|
+
// If the element is removed before the
|
525
|
+
// transition finishes, transition events are
|
526
|
+
// not triggered, resolve manually:
|
527
|
+
dfd.resolveWith(node);
|
528
|
+
});
|
522
529
|
},
|
523
530
|
{
|
524
531
|
maxWidth: options.previewMaxWidth,
|
@@ -595,8 +602,7 @@
|
|
595
602
|
var button = $(e.currentTarget);
|
596
603
|
this._trigger('destroy', e, $.extend({
|
597
604
|
context: button.closest('.template-download'),
|
598
|
-
type: 'DELETE'
|
599
|
-
dataType: this.options.dataType
|
605
|
+
type: 'DELETE'
|
600
606
|
}, button.data()));
|
601
607
|
},
|
602
608
|
|
@@ -607,7 +613,7 @@
|
|
607
613
|
|
608
614
|
_transition: function (node) {
|
609
615
|
var dfd = $.Deferred();
|
610
|
-
if ($.support.transition && node.hasClass('fade')) {
|
616
|
+
if ($.support.transition && node.hasClass('fade') && node.is(':visible')) {
|
611
617
|
node.bind(
|
612
618
|
$.support.transition.end,
|
613
619
|
function (e) {
|
@@ -632,27 +638,28 @@
|
|
632
638
|
this._on(fileUploadButtonBar.find('.start'), {
|
633
639
|
click: function (e) {
|
634
640
|
e.preventDefault();
|
635
|
-
filesList.find('.start
|
641
|
+
filesList.find('.start').click();
|
636
642
|
}
|
637
643
|
});
|
638
644
|
this._on(fileUploadButtonBar.find('.cancel'), {
|
639
645
|
click: function (e) {
|
640
646
|
e.preventDefault();
|
641
|
-
filesList.find('.cancel
|
647
|
+
filesList.find('.cancel').click();
|
642
648
|
}
|
643
649
|
});
|
644
650
|
this._on(fileUploadButtonBar.find('.delete'), {
|
645
651
|
click: function (e) {
|
646
652
|
e.preventDefault();
|
647
|
-
filesList.find('.
|
648
|
-
.
|
653
|
+
filesList.find('.toggle:checked')
|
654
|
+
.closest('.template-download')
|
655
|
+
.find('.delete').click();
|
649
656
|
fileUploadButtonBar.find('.toggle')
|
650
657
|
.prop('checked', false);
|
651
658
|
}
|
652
659
|
});
|
653
660
|
this._on(fileUploadButtonBar.find('.toggle'), {
|
654
661
|
change: function (e) {
|
655
|
-
filesList.find('.
|
662
|
+
filesList.find('.toggle').prop(
|
656
663
|
'checked',
|
657
664
|
$(e.currentTarget).is(':checked')
|
658
665
|
);
|
@@ -662,7 +669,8 @@
|
|
662
669
|
|
663
670
|
_destroyButtonBarEventHandlers: function () {
|
664
671
|
this._off(
|
665
|
-
this.element.find('.fileupload-buttonbar
|
672
|
+
this.element.find('.fileupload-buttonbar')
|
673
|
+
.find('.start, .cancel, .delete'),
|
666
674
|
'click'
|
667
675
|
);
|
668
676
|
this._off(
|
@@ -674,9 +682,9 @@
|
|
674
682
|
_initEventHandlers: function () {
|
675
683
|
this._super();
|
676
684
|
this._on(this.options.filesContainer, {
|
677
|
-
'click .start
|
678
|
-
'click .cancel
|
679
|
-
'click .delete
|
685
|
+
'click .start': this._startHandler,
|
686
|
+
'click .cancel': this._cancelHandler,
|
687
|
+
'click .delete': this._deleteHandler
|
680
688
|
});
|
681
689
|
this._initButtonBarEventHandlers();
|
682
690
|
},
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/*
|
2
|
-
* jQuery File Upload Plugin 5.
|
2
|
+
* jQuery File Upload Plugin 5.28.8
|
3
3
|
* https://github.com/blueimp/jQuery-File-Upload
|
4
4
|
*
|
5
5
|
* Copyright 2010, Sebastian Tschan
|
@@ -33,21 +33,6 @@
|
|
33
33
|
$.support.xhrFileUpload = !!(window.XMLHttpRequestUpload && window.FileReader);
|
34
34
|
$.support.xhrFormDataFileUpload = !!window.FormData;
|
35
35
|
|
36
|
-
// The form.elements propHook is added to filter serialized elements
|
37
|
-
// to not include file inputs in jQuery 1.9.0.
|
38
|
-
// This hooks directly into jQuery.fn.serializeArray.
|
39
|
-
// For more info, see http://bugs.jquery.com/ticket/13306
|
40
|
-
$.propHooks.elements = {
|
41
|
-
get: function (form) {
|
42
|
-
if ($.nodeName(form, 'form')) {
|
43
|
-
return $.grep(form.elements, function (elem) {
|
44
|
-
return !$.nodeName(elem, 'input') || elem.type !== 'file';
|
45
|
-
});
|
46
|
-
}
|
47
|
-
return null;
|
48
|
-
}
|
49
|
-
};
|
50
|
-
|
51
36
|
// The fileupload widget listens for change events on file input fields defined
|
52
37
|
// via fileInput setting and paste or drop events of the given dropZone.
|
53
38
|
// In addition to the default jQuery Widget methods, the fileupload widget
|
@@ -127,6 +112,8 @@
|
|
127
112
|
progressInterval: 100,
|
128
113
|
// Interval in milliseconds to calculate progress bitrate:
|
129
114
|
bitrateInterval: 500,
|
115
|
+
// By default, uploads are started automatically when adding files:
|
116
|
+
autoUpload: true,
|
130
117
|
|
131
118
|
// Additional form data to be sent along with the file uploads can be set
|
132
119
|
// using this option, which accepts an array of objects with name and
|
@@ -151,7 +138,11 @@
|
|
151
138
|
// handlers using jQuery's Deferred callbacks:
|
152
139
|
// data.submit().done(func).fail(func).always(func);
|
153
140
|
add: function (e, data) {
|
154
|
-
data.
|
141
|
+
if (data.autoUpload || (data.autoUpload !== false &&
|
142
|
+
($(this).data('blueimp-fileupload') ||
|
143
|
+
$(this).data('fileupload')).options.autoUpload)) {
|
144
|
+
data.submit();
|
145
|
+
}
|
155
146
|
},
|
156
147
|
|
157
148
|
// Other callbacks:
|
@@ -224,7 +215,7 @@
|
|
224
215
|
],
|
225
216
|
|
226
217
|
_BitrateTimer: function () {
|
227
|
-
this.timestamp =
|
218
|
+
this.timestamp = ((Date.now) ? Date.now() : (new Date()).getTime());
|
228
219
|
this.loaded = 0;
|
229
220
|
this.bitrate = 0;
|
230
221
|
this.getBitrate = function (now, loaded, interval) {
|
@@ -252,7 +243,7 @@
|
|
252
243
|
if ($.isArray(options.formData)) {
|
253
244
|
return options.formData;
|
254
245
|
}
|
255
|
-
if (options.formData) {
|
246
|
+
if ($.type(options.formData) === 'object') {
|
256
247
|
formData = [];
|
257
248
|
$.each(options.formData, function (name, value) {
|
258
249
|
formData.push({name: name, value: value});
|
@@ -270,10 +261,35 @@
|
|
270
261
|
return total;
|
271
262
|
},
|
272
263
|
|
264
|
+
_initProgressObject: function (obj) {
|
265
|
+
var progress = {
|
266
|
+
loaded: 0,
|
267
|
+
total: 0,
|
268
|
+
bitrate: 0
|
269
|
+
};
|
270
|
+
if (obj._progress) {
|
271
|
+
$.extend(obj._progress, progress);
|
272
|
+
} else {
|
273
|
+
obj._progress = progress;
|
274
|
+
}
|
275
|
+
},
|
276
|
+
|
277
|
+
_initResponseObject: function (obj) {
|
278
|
+
var prop;
|
279
|
+
if (obj._response) {
|
280
|
+
for (prop in obj._response) {
|
281
|
+
if (obj._response.hasOwnProperty(prop)) {
|
282
|
+
delete obj._response[prop];
|
283
|
+
}
|
284
|
+
}
|
285
|
+
} else {
|
286
|
+
obj._response = {};
|
287
|
+
}
|
288
|
+
},
|
289
|
+
|
273
290
|
_onProgress: function (e, data) {
|
274
291
|
if (e.lengthComputable) {
|
275
|
-
var now =
|
276
|
-
total,
|
292
|
+
var now = ((Date.now) ? Date.now() : (new Date()).getTime()),
|
277
293
|
loaded;
|
278
294
|
if (data._time && data.progressInterval &&
|
279
295
|
(now - data._time < data.progressInterval) &&
|
@@ -281,16 +297,19 @@
|
|
281
297
|
return;
|
282
298
|
}
|
283
299
|
data._time = now;
|
284
|
-
|
285
|
-
|
286
|
-
e.loaded / e.total * (data.chunkSize || total),
|
287
|
-
10
|
300
|
+
loaded = Math.floor(
|
301
|
+
e.loaded / e.total * (data.chunkSize || data._progress.total)
|
288
302
|
) + (data.uploadedBytes || 0);
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
303
|
+
// Add the difference from the previously loaded state
|
304
|
+
// to the global loaded counter:
|
305
|
+
this._progress.loaded += (loaded - data._progress.loaded);
|
306
|
+
this._progress.bitrate = this._bitrateTimer.getBitrate(
|
307
|
+
now,
|
308
|
+
this._progress.loaded,
|
309
|
+
data.bitrateInterval
|
310
|
+
);
|
311
|
+
data._progress.loaded = data.loaded = loaded;
|
312
|
+
data._progress.bitrate = data.bitrate = data._bitrateTimer.getBitrate(
|
294
313
|
now,
|
295
314
|
loaded,
|
296
315
|
data.bitrateInterval
|
@@ -301,16 +320,7 @@
|
|
301
320
|
this._trigger('progress', e, data);
|
302
321
|
// Trigger a global progress event for all current file uploads,
|
303
322
|
// including ajax calls queued for sequential file uploads:
|
304
|
-
this._trigger('progressall', e,
|
305
|
-
lengthComputable: true,
|
306
|
-
loaded: this._loaded,
|
307
|
-
total: this._total,
|
308
|
-
bitrate: this._bitrateTimer.getBitrate(
|
309
|
-
now,
|
310
|
-
this._loaded,
|
311
|
-
data.bitrateInterval
|
312
|
-
)
|
313
|
-
});
|
323
|
+
this._trigger('progressall', e, this._progress);
|
314
324
|
}
|
315
325
|
},
|
316
326
|
|
@@ -334,8 +344,14 @@
|
|
334
344
|
}
|
335
345
|
},
|
336
346
|
|
347
|
+
_isInstanceOf: function (type, obj) {
|
348
|
+
// Cross-frame instanceof check
|
349
|
+
return Object.prototype.toString.call(obj) === '[object ' + type + ']';
|
350
|
+
},
|
351
|
+
|
337
352
|
_initXHRData: function (options) {
|
338
|
-
var
|
353
|
+
var that = this,
|
354
|
+
formData,
|
339
355
|
file = options.files[0],
|
340
356
|
// Ignore non-multipart setting if not supported:
|
341
357
|
multipart = options.multipart || !$.support.xhrFileUpload,
|
@@ -370,7 +386,7 @@
|
|
370
386
|
});
|
371
387
|
}
|
372
388
|
} else {
|
373
|
-
if (options.formData
|
389
|
+
if (that._isInstanceOf('FormData', options.formData)) {
|
374
390
|
formData = options.formData;
|
375
391
|
} else {
|
376
392
|
formData = new FormData();
|
@@ -384,12 +400,10 @@
|
|
384
400
|
formData.append(paramName, options.blob, file.name);
|
385
401
|
} else {
|
386
402
|
$.each(options.files, function (index, file) {
|
387
|
-
// Files are also Blob instances, but some browsers
|
388
|
-
// (Firefox 3.6) support the File API but not Blobs.
|
389
403
|
// This check allows the tests to run with
|
390
404
|
// dummy objects:
|
391
|
-
if ((
|
392
|
-
(
|
405
|
+
if (that._isInstanceOf('File', file) ||
|
406
|
+
that._isInstanceOf('Blob', file)) {
|
393
407
|
formData.append(
|
394
408
|
options.paramName[index] || paramName,
|
395
409
|
file,
|
@@ -434,7 +448,7 @@
|
|
434
448
|
options.dataType = 'postmessage ' + (options.dataType || '');
|
435
449
|
}
|
436
450
|
} else {
|
437
|
-
this._initIframeSettings(options
|
451
|
+
this._initIframeSettings(options);
|
438
452
|
}
|
439
453
|
},
|
440
454
|
|
@@ -495,6 +509,21 @@
|
|
495
509
|
return options;
|
496
510
|
},
|
497
511
|
|
512
|
+
// jQuery 1.6 doesn't provide .state(),
|
513
|
+
// while jQuery 1.8+ removed .isRejected() and .isResolved():
|
514
|
+
_getDeferredState: function (deferred) {
|
515
|
+
if (deferred.state) {
|
516
|
+
return deferred.state();
|
517
|
+
}
|
518
|
+
if (deferred.isResolved()) {
|
519
|
+
return 'resolved';
|
520
|
+
}
|
521
|
+
if (deferred.isRejected()) {
|
522
|
+
return 'rejected';
|
523
|
+
}
|
524
|
+
return 'pending';
|
525
|
+
},
|
526
|
+
|
498
527
|
// Maps jqXHR callbacks to the equivalent
|
499
528
|
// methods of the given Promise object:
|
500
529
|
_enhancePromise: function (promise) {
|
@@ -519,6 +548,36 @@
|
|
519
548
|
return this._enhancePromise(promise);
|
520
549
|
},
|
521
550
|
|
551
|
+
// Adds convenience methods to the callback arguments:
|
552
|
+
_addConvenienceMethods: function (e, data) {
|
553
|
+
var that = this;
|
554
|
+
data.submit = function () {
|
555
|
+
if (this.state() !== 'pending') {
|
556
|
+
data.jqXHR = this.jqXHR =
|
557
|
+
(that._trigger('submit', e, this) !== false) &&
|
558
|
+
that._onSend(e, this);
|
559
|
+
}
|
560
|
+
return this.jqXHR || that._getXHRPromise();
|
561
|
+
};
|
562
|
+
data.abort = function () {
|
563
|
+
if (this.jqXHR) {
|
564
|
+
return this.jqXHR.abort();
|
565
|
+
}
|
566
|
+
return that._getXHRPromise();
|
567
|
+
};
|
568
|
+
data.state = function () {
|
569
|
+
if (this.jqXHR) {
|
570
|
+
return that._getDeferredState(this.jqXHR);
|
571
|
+
}
|
572
|
+
};
|
573
|
+
data.progress = function () {
|
574
|
+
return this._progress;
|
575
|
+
};
|
576
|
+
data.response = function () {
|
577
|
+
return this._response;
|
578
|
+
};
|
579
|
+
},
|
580
|
+
|
522
581
|
// Parses the Range header from the server response
|
523
582
|
// and returns the uploaded bytes:
|
524
583
|
_getUploadedBytes: function (jqXHR) {
|
@@ -563,7 +622,8 @@
|
|
563
622
|
// The chunk upload method:
|
564
623
|
upload = function () {
|
565
624
|
// Clone the options object for each chunk upload:
|
566
|
-
var o = $.extend({}, options)
|
625
|
+
var o = $.extend({}, options),
|
626
|
+
currentLoaded = o._progress.loaded;
|
567
627
|
o.blob = slice.call(
|
568
628
|
file,
|
569
629
|
ub,
|
@@ -585,10 +645,10 @@
|
|
585
645
|
.done(function (result, textStatus, jqXHR) {
|
586
646
|
ub = that._getUploadedBytes(jqXHR) ||
|
587
647
|
(ub + o.chunkSize);
|
588
|
-
// Create a progress event if
|
589
|
-
//
|
590
|
-
//
|
591
|
-
if (
|
648
|
+
// Create a progress event if no final progress event
|
649
|
+
// with loaded equaling total has been triggered
|
650
|
+
// for this chunk:
|
651
|
+
if (o._progress.loaded === currentLoaded) {
|
592
652
|
that._onProgress($.Event('progress', {
|
593
653
|
lengthComputable: true,
|
594
654
|
loaded: ub - o.uploadedBytes,
|
@@ -640,61 +700,66 @@
|
|
640
700
|
this._trigger('start');
|
641
701
|
// Set timer for global bitrate progress calculation:
|
642
702
|
this._bitrateTimer = new this._BitrateTimer();
|
703
|
+
// Reset the global progress values:
|
704
|
+
this._progress.loaded = this._progress.total = 0;
|
705
|
+
this._progress.bitrate = 0;
|
643
706
|
}
|
707
|
+
// Make sure the container objects for the .response() and
|
708
|
+
// .progress() methods on the data object are available
|
709
|
+
// and reset to their initial state:
|
710
|
+
this._initResponseObject(data);
|
711
|
+
this._initProgressObject(data);
|
712
|
+
data._progress.loaded = data.loaded = data.uploadedBytes || 0;
|
713
|
+
data._progress.total = data.total = this._getTotal(data.files) || 1;
|
714
|
+
data._progress.bitrate = data.bitrate = 0;
|
644
715
|
this._active += 1;
|
645
716
|
// Initialize the global progress values:
|
646
|
-
this.
|
647
|
-
this.
|
717
|
+
this._progress.loaded += data.loaded;
|
718
|
+
this._progress.total += data.total;
|
648
719
|
},
|
649
720
|
|
650
721
|
_onDone: function (result, textStatus, jqXHR, options) {
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
// Create a progress event
|
655
|
-
//
|
656
|
-
// loaded equaling total for XHR uploads:
|
722
|
+
var total = options._progress.total,
|
723
|
+
response = options._response;
|
724
|
+
if (options._progress.loaded < total) {
|
725
|
+
// Create a progress event if no final progress event
|
726
|
+
// with loaded equaling total has been triggered:
|
657
727
|
this._onProgress($.Event('progress', {
|
658
728
|
lengthComputable: true,
|
659
729
|
loaded: total,
|
660
730
|
total: total
|
661
731
|
}), options);
|
662
732
|
}
|
663
|
-
options.result = result;
|
664
|
-
options.textStatus = textStatus;
|
665
|
-
options.jqXHR = jqXHR;
|
733
|
+
response.result = options.result = result;
|
734
|
+
response.textStatus = options.textStatus = textStatus;
|
735
|
+
response.jqXHR = options.jqXHR = jqXHR;
|
666
736
|
this._trigger('done', null, options);
|
667
737
|
},
|
668
738
|
|
669
739
|
_onFail: function (jqXHR, textStatus, errorThrown, options) {
|
670
|
-
|
671
|
-
options.textStatus = textStatus;
|
672
|
-
options.errorThrown = errorThrown;
|
673
|
-
this._trigger('fail', null, options);
|
740
|
+
var response = options._response;
|
674
741
|
if (options.recalculateProgress) {
|
675
742
|
// Remove the failed (error or abort) file upload from
|
676
743
|
// the global progress calculation:
|
677
|
-
this.
|
678
|
-
this.
|
744
|
+
this._progress.loaded -= options._progress.loaded;
|
745
|
+
this._progress.total -= options._progress.total;
|
679
746
|
}
|
747
|
+
response.jqXHR = options.jqXHR = jqXHR;
|
748
|
+
response.textStatus = options.textStatus = textStatus;
|
749
|
+
response.errorThrown = options.errorThrown = errorThrown;
|
750
|
+
this._trigger('fail', null, options);
|
680
751
|
},
|
681
752
|
|
682
753
|
_onAlways: function (jqXHRorResult, textStatus, jqXHRorError, options) {
|
683
754
|
// jqXHRorResult, textStatus and jqXHRorError are added to the
|
684
755
|
// options object via done and fail callbacks
|
685
|
-
this._active -= 1;
|
686
756
|
this._trigger('always', null, options);
|
687
|
-
if (this._active === 0) {
|
688
|
-
// The stop callback is triggered when all uploads have
|
689
|
-
// been completed, equivalent to the global ajaxStop event:
|
690
|
-
this._trigger('stop');
|
691
|
-
// Reset the global progress values:
|
692
|
-
this._loaded = this._total = 0;
|
693
|
-
this._bitrateTimer = null;
|
694
|
-
}
|
695
757
|
},
|
696
758
|
|
697
759
|
_onSend: function (e, data) {
|
760
|
+
if (!data.submit) {
|
761
|
+
this._addConvenienceMethods(e, data);
|
762
|
+
}
|
698
763
|
var that = this,
|
699
764
|
jqXHR,
|
700
765
|
aborted,
|
@@ -714,32 +779,32 @@
|
|
714
779
|
}).fail(function (jqXHR, textStatus, errorThrown) {
|
715
780
|
that._onFail(jqXHR, textStatus, errorThrown, options);
|
716
781
|
}).always(function (jqXHRorResult, textStatus, jqXHRorError) {
|
717
|
-
that._sending -= 1;
|
718
782
|
that._onAlways(
|
719
783
|
jqXHRorResult,
|
720
784
|
textStatus,
|
721
785
|
jqXHRorError,
|
722
786
|
options
|
723
787
|
);
|
788
|
+
that._sending -= 1;
|
789
|
+
that._active -= 1;
|
724
790
|
if (options.limitConcurrentUploads &&
|
725
791
|
options.limitConcurrentUploads > that._sending) {
|
726
792
|
// Start the next queued upload,
|
727
793
|
// that has not been aborted:
|
728
|
-
var nextSlot = that._slots.shift()
|
729
|
-
isPending;
|
794
|
+
var nextSlot = that._slots.shift();
|
730
795
|
while (nextSlot) {
|
731
|
-
|
732
|
-
// while jQuery 1.8+ removed .isRejected():
|
733
|
-
isPending = nextSlot.state ?
|
734
|
-
nextSlot.state() === 'pending' :
|
735
|
-
!nextSlot.isRejected();
|
736
|
-
if (isPending) {
|
796
|
+
if (that._getDeferredState(nextSlot) === 'pending') {
|
737
797
|
nextSlot.resolve();
|
738
798
|
break;
|
739
799
|
}
|
740
800
|
nextSlot = that._slots.shift();
|
741
801
|
}
|
742
802
|
}
|
803
|
+
if (that._active === 0) {
|
804
|
+
// The stop callback is triggered when all uploads have
|
805
|
+
// been completed, equivalent to the global ajaxStop event:
|
806
|
+
that._trigger('stop');
|
807
|
+
}
|
743
808
|
});
|
744
809
|
return jqXHR;
|
745
810
|
};
|
@@ -805,12 +870,9 @@
|
|
805
870
|
var newData = $.extend({}, data);
|
806
871
|
newData.files = fileSet ? element : [element];
|
807
872
|
newData.paramName = paramNameSet[index];
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
that._onSend(e, this);
|
812
|
-
return this.jqXHR;
|
813
|
-
};
|
873
|
+
that._initResponseObject(newData);
|
874
|
+
that._initProgressObject(newData);
|
875
|
+
that._addConvenienceMethods(e, newData);
|
814
876
|
result = that._trigger('add', e, newData);
|
815
877
|
return result;
|
816
878
|
});
|
@@ -987,44 +1049,50 @@
|
|
987
1049
|
},
|
988
1050
|
|
989
1051
|
_onPaste: function (e) {
|
990
|
-
var
|
991
|
-
|
1052
|
+
var items = e.originalEvent && e.originalEvent.clipboardData &&
|
1053
|
+
e.originalEvent.clipboardData.items,
|
992
1054
|
data = {files: []};
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
1055
|
+
if (items && items.length) {
|
1056
|
+
$.each(items, function (index, item) {
|
1057
|
+
var file = item.getAsFile && item.getAsFile();
|
1058
|
+
if (file) {
|
1059
|
+
data.files.push(file);
|
1060
|
+
}
|
1061
|
+
});
|
1062
|
+
if (this._trigger('paste', e, data) === false ||
|
1063
|
+
this._onAdd(e, data) === false) {
|
1064
|
+
return false;
|
997
1065
|
}
|
998
|
-
});
|
999
|
-
if (this._trigger('paste', e, data) === false ||
|
1000
|
-
this._onAdd(e, data) === false) {
|
1001
|
-
return false;
|
1002
1066
|
}
|
1003
1067
|
},
|
1004
1068
|
|
1005
1069
|
_onDrop: function (e) {
|
1006
1070
|
var that = this,
|
1007
|
-
dataTransfer = e.dataTransfer = e.originalEvent
|
1071
|
+
dataTransfer = e.dataTransfer = e.originalEvent &&
|
1072
|
+
e.originalEvent.dataTransfer,
|
1008
1073
|
data = {};
|
1009
1074
|
if (dataTransfer && dataTransfer.files && dataTransfer.files.length) {
|
1010
1075
|
e.preventDefault();
|
1076
|
+
this._getDroppedFiles(dataTransfer).always(function (files) {
|
1077
|
+
data.files = files;
|
1078
|
+
if (that._trigger('drop', e, data) !== false) {
|
1079
|
+
that._onAdd(e, data);
|
1080
|
+
}
|
1081
|
+
});
|
1011
1082
|
}
|
1012
|
-
this._getDroppedFiles(dataTransfer).always(function (files) {
|
1013
|
-
data.files = files;
|
1014
|
-
if (that._trigger('drop', e, data) !== false) {
|
1015
|
-
that._onAdd(e, data);
|
1016
|
-
}
|
1017
|
-
});
|
1018
1083
|
},
|
1019
1084
|
|
1020
1085
|
_onDragOver: function (e) {
|
1021
|
-
var dataTransfer = e.dataTransfer = e.originalEvent
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1086
|
+
var dataTransfer = e.dataTransfer = e.originalEvent &&
|
1087
|
+
e.originalEvent.dataTransfer;
|
1088
|
+
if (dataTransfer) {
|
1089
|
+
if (this._trigger('dragover', e) === false) {
|
1090
|
+
return false;
|
1091
|
+
}
|
1092
|
+
if ($.inArray('Files', dataTransfer.types) !== -1) {
|
1093
|
+
dataTransfer.dropEffect = 'copy';
|
1094
|
+
e.preventDefault();
|
1095
|
+
}
|
1028
1096
|
}
|
1029
1097
|
},
|
1030
1098
|
|
@@ -1084,12 +1152,23 @@
|
|
1084
1152
|
this._initSpecialOptions();
|
1085
1153
|
this._slots = [];
|
1086
1154
|
this._sequence = this._getXHRPromise(true);
|
1087
|
-
this._sending = this._active =
|
1155
|
+
this._sending = this._active = 0;
|
1156
|
+
this._initProgressObject(this);
|
1088
1157
|
this._initEventHandlers();
|
1089
1158
|
},
|
1090
1159
|
|
1091
|
-
|
1092
|
-
|
1160
|
+
// This method is exposed to the widget API and allows to query
|
1161
|
+
// the number of active uploads:
|
1162
|
+
active: function () {
|
1163
|
+
return this._active;
|
1164
|
+
},
|
1165
|
+
|
1166
|
+
// This method is exposed to the widget API and allows to query
|
1167
|
+
// the widget upload progress.
|
1168
|
+
// It returns an object with loaded, total and bitrate properties
|
1169
|
+
// for the running uploads:
|
1170
|
+
progress: function () {
|
1171
|
+
return this._progress;
|
1093
1172
|
},
|
1094
1173
|
|
1095
1174
|
// This method is exposed to the widget API and allows adding files
|
@@ -35,7 +35,7 @@
|
|
35
35
|
line-height: 31px;
|
36
36
|
}
|
37
37
|
.uploader-button {
|
38
|
-
display: block;
|
38
|
+
display: inline-block;
|
39
39
|
background: #972da0;
|
40
40
|
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#982da1', endColorstr='#892891');
|
41
41
|
background: -webkit-linear-gradient(left top, left bottom, #982da1, #892891);
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails-uploader
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,8 +10,24 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2013-
|
13
|
+
date: 2013-04-09 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: jquery-ui-rails
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ! '>='
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '0'
|
15
31
|
- !ruby/object:Gem::Dependency
|
16
32
|
name: sqlite3
|
17
33
|
requirement: !ruby/object:Gem::Requirement
|
@@ -44,6 +60,22 @@ dependencies:
|
|
44
60
|
- - ! '>='
|
45
61
|
- !ruby/object:Gem::Version
|
46
62
|
version: '0'
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: mongoid
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
type: :development
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
47
79
|
description: Rails HTML5 FileUpload helpers
|
48
80
|
email: superp1987@gmail.com
|
49
81
|
executables: []
|
@@ -54,10 +86,8 @@ files:
|
|
54
86
|
- app/views/uploader/default/_upload.html.erb
|
55
87
|
- app/views/uploader/default/_sortable.html.erb
|
56
88
|
- app/views/uploader/default/_container.html.erb
|
57
|
-
- app/views/uploader/default/_init.html.erb
|
58
89
|
- app/views/uploader/default/_download.html.erb
|
59
90
|
- app/assets/stylesheets/uploader/application.css
|
60
|
-
- app/assets/javascripts/uploader/init.js
|
61
91
|
- app/assets/javascripts/uploader/application.js
|
62
92
|
- app/controllers/uploader/attachments_controller.rb
|
63
93
|
- lib/uploader.rb
|
@@ -134,11 +164,13 @@ files:
|
|
134
164
|
- spec/dummy/README.rdoc
|
135
165
|
- spec/dummy/script/rails
|
136
166
|
- spec/spec_helper.rb
|
167
|
+
- spec/mongoid_spec.rb
|
137
168
|
- spec/uploader_spec.rb
|
138
169
|
- spec/requests/attachments_controller_spec.rb
|
139
170
|
- spec/factories/articles.rb
|
140
171
|
- spec/factories/assets.rb
|
141
172
|
- spec/factories/files/rails.png
|
173
|
+
- spec/mongoid.yml
|
142
174
|
- spec/fileuploads_spec.rb
|
143
175
|
homepage: https://github.com/superp/rails-uploader
|
144
176
|
licenses: []
|
@@ -160,7 +192,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
160
192
|
version: '0'
|
161
193
|
requirements: []
|
162
194
|
rubyforge_project: rails-uploader
|
163
|
-
rubygems_version: 1.8.
|
195
|
+
rubygems_version: 1.8.25
|
164
196
|
signing_key:
|
165
197
|
specification_version: 3
|
166
198
|
summary: Rails file upload implementation with jQuery-File-Upload
|
@@ -204,10 +236,11 @@ test_files:
|
|
204
236
|
- spec/dummy/README.rdoc
|
205
237
|
- spec/dummy/script/rails
|
206
238
|
- spec/spec_helper.rb
|
239
|
+
- spec/mongoid_spec.rb
|
207
240
|
- spec/uploader_spec.rb
|
208
241
|
- spec/requests/attachments_controller_spec.rb
|
209
242
|
- spec/factories/articles.rb
|
210
243
|
- spec/factories/assets.rb
|
211
244
|
- spec/factories/files/rails.png
|
245
|
+
- spec/mongoid.yml
|
212
246
|
- spec/fileuploads_spec.rb
|
213
|
-
has_rdoc:
|
@@ -1,9 +0,0 @@
|
|
1
|
-
<script type="text/javascript">
|
2
|
-
(function(d, s, id) {
|
3
|
-
var js, fjs = d.getElementsByTagName(s)[0];
|
4
|
-
if (d.getElementById(id)) return;
|
5
|
-
js = d.createElement(s); js.id = id;
|
6
|
-
js.src = "/assets/uploader/application.js";
|
7
|
-
fjs.parentNode.appendChild(js);
|
8
|
-
}(document, 'script', 'uploader-jssdk'));
|
9
|
-
</script>
|