instant-upload 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +141 -0
- data/Rakefile +29 -0
- data/app/assets/javascripts/instant_upload.js +4 -0
- data/app/assets/javascripts/instant_upload/angular/angular.js +14401 -0
- data/app/assets/javascripts/instant_upload/multi.js.coffee +149 -0
- data/app/assets/javascripts/instant_upload/single.js.coffee +143 -0
- data/app/assets/stylesheets/instant_upload.css +12 -0
- data/app/assets/stylesheets/instant_upload/multi.css.scss +54 -0
- data/app/assets/stylesheets/instant_upload/single.css.scss +32 -0
- data/app/controllers/instant_upload/application_controller.rb +4 -0
- data/app/helpers/instant_upload/application_helper.rb +4 -0
- data/app/models/instant_upload/upload.rb +5 -0
- data/app/uploaders/instant_upload/file_uploader.rb +13 -0
- data/app/views/instant_upload/_multi.html.haml +20 -0
- data/app/views/instant_upload/_single.html.haml +11 -0
- data/app/views/layouts/instant_upload/application.html.erb +14 -0
- data/config/routes.rb +2 -0
- data/db/migrate/20130509140233_create_instant_upload_uploads.rb +9 -0
- data/lib/instant_upload.rb +7 -0
- data/lib/instant_upload/engine.rb +26 -0
- data/lib/instant_upload/helpers.rb +6 -0
- data/lib/instant_upload/helpers/controller_helper.rb +72 -0
- data/lib/instant_upload/helpers/upload_helper.rb +14 -0
- data/lib/instant_upload/version.rb +3 -0
- data/lib/tasks/instant_upload_tasks.rake +4 -0
- metadata +349 -0
@@ -0,0 +1,149 @@
|
|
1
|
+
app = angular.module('instantUpload', [])
|
2
|
+
|
3
|
+
@multiIuCtrl = ['$scope', '$element', ($scope, $element) ->
|
4
|
+
|
5
|
+
# upload event handler
|
6
|
+
class UploadHandler
|
7
|
+
|
8
|
+
constructor: ($uploader) ->
|
9
|
+
@url = $uploader.parents('form').attr('action')
|
10
|
+
|
11
|
+
$scope.persisted = $uploader.data('persisted')
|
12
|
+
$scope.limit = $uploader.data('limit')
|
13
|
+
$scope.multi = $uploader.data('multi')
|
14
|
+
$scope.version = $uploader.data('version')
|
15
|
+
|
16
|
+
@uploader = $uploader
|
17
|
+
@element = $uploader.find('.iu-multi-dropzone')
|
18
|
+
|
19
|
+
@element.bind 'dragenter', @dragEnter
|
20
|
+
@element.bind 'dragover', @dragEnter
|
21
|
+
@element.bind 'dragleave', @dragLeave
|
22
|
+
@element.bind 'drop', @drop
|
23
|
+
|
24
|
+
$fileInput = $uploader.find('input[type="file"]')
|
25
|
+
$fileInput.bind 'change', @drop
|
26
|
+
|
27
|
+
$uploader.find('.iu-multi-select').show 0, ->
|
28
|
+
$selectFiles = $uploader.find('.iu-multi-select-files')
|
29
|
+
offset = $selectFiles.position()
|
30
|
+
|
31
|
+
$fileInput.css
|
32
|
+
opacity: 0
|
33
|
+
cursor: 'pointer'
|
34
|
+
position: 'absolute'
|
35
|
+
left: offset.left
|
36
|
+
top: offset.top
|
37
|
+
width: $selectFiles.width() + 10
|
38
|
+
height: $selectFiles.height() + 10
|
39
|
+
'margin-left': -5
|
40
|
+
'margin-top': -25
|
41
|
+
'z-index': 2
|
42
|
+
'-ms-filter': '"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"'
|
43
|
+
'filter': 'alpha(opacity=0)'
|
44
|
+
|
45
|
+
@fileinput = $fileInput
|
46
|
+
|
47
|
+
dragEnter: (e) =>
|
48
|
+
# console.log 'dragEnter'
|
49
|
+
|
50
|
+
e.stopPropagation()
|
51
|
+
e.preventDefault()
|
52
|
+
|
53
|
+
@element.addClass 'iu-drag-over'
|
54
|
+
|
55
|
+
# settings.dragEnter(e)
|
56
|
+
return false
|
57
|
+
|
58
|
+
dragLeave: (e) =>
|
59
|
+
# console.log 'dragLeave'
|
60
|
+
|
61
|
+
e.stopPropagation()
|
62
|
+
e.preventDefault()
|
63
|
+
|
64
|
+
@element.removeClass 'iu-drag-over'
|
65
|
+
|
66
|
+
# settings.dragLeave(e)
|
67
|
+
return false
|
68
|
+
|
69
|
+
drop: (e) =>
|
70
|
+
# console.log 'drop'
|
71
|
+
|
72
|
+
e.stopPropagation()
|
73
|
+
e.preventDefault()
|
74
|
+
|
75
|
+
@element.removeClass 'iu-drag-over'
|
76
|
+
|
77
|
+
# get files from drag and drop dataTransfer
|
78
|
+
if typeof e.originalEvent.dataTransfer == 'undefined'
|
79
|
+
files = e.originalEvent.target.files
|
80
|
+
else
|
81
|
+
files = e.originalEvent.dataTransfer.files
|
82
|
+
|
83
|
+
if $scope.limit != undefined && $scope.files.length + files.length > parseInt($scope.limit)
|
84
|
+
@uploader.find('.iu-alert').show()
|
85
|
+
return
|
86
|
+
|
87
|
+
fd = new FormData
|
88
|
+
|
89
|
+
for file in files
|
90
|
+
fd.append @fileinput.attr('name'), file
|
91
|
+
|
92
|
+
$scope.$apply ->
|
93
|
+
$scope.uploaded = false
|
94
|
+
$scope.uploadProgress = 0
|
95
|
+
|
96
|
+
xhr = new XMLHttpRequest
|
97
|
+
|
98
|
+
xhr.upload.addEventListener 'progress', ( (e) =>
|
99
|
+
# console.log 'progress'
|
100
|
+
percent = Math.ceil(e.loaded / e.total * 100)
|
101
|
+
$scope.$apply ->
|
102
|
+
$scope.uploadProgress = percent
|
103
|
+
), false
|
104
|
+
|
105
|
+
xhr.addEventListener 'load', ( (e) =>
|
106
|
+
# console.log 'load'
|
107
|
+
$scope.$apply ->
|
108
|
+
$scope.uploaded = true
|
109
|
+
|
110
|
+
# $scope.files = []
|
111
|
+
for image in $.parseJSON(xhr.response)
|
112
|
+
$scope.files.push { path: image[$scope.multi][$scope.version].url }
|
113
|
+
), false
|
114
|
+
|
115
|
+
xhr.addEventListener 'error', ( (e) =>
|
116
|
+
# console.log 'error'
|
117
|
+
), false
|
118
|
+
|
119
|
+
xhr.addEventListener 'abort', ( (e) =>
|
120
|
+
# console.log 'abort'
|
121
|
+
), false
|
122
|
+
|
123
|
+
|
124
|
+
if $scope.persisted
|
125
|
+
method = 'PATCH'
|
126
|
+
else
|
127
|
+
method = 'POST'
|
128
|
+
|
129
|
+
xhr.open method, "#{@url}.json"
|
130
|
+
xhr.setRequestHeader 'X-Instant-Upload', true
|
131
|
+
xhr.send fd
|
132
|
+
|
133
|
+
return false
|
134
|
+
|
135
|
+
|
136
|
+
$scope.init = ($uploader) ->
|
137
|
+
handler = new UploadHandler($uploader)
|
138
|
+
$uploader.find('.iu-multi-dropzone').addClass('active')
|
139
|
+
$uploader.find('.iu-multi-files').show()
|
140
|
+
|
141
|
+
$scope.files = []
|
142
|
+
|
143
|
+
$scope.$apply ->
|
144
|
+
$uploader.find('.iu-multi-files-cache li').each ->
|
145
|
+
$scope.files.push { path: $(this).find('img').attr('src') }
|
146
|
+
|
147
|
+
$ -> $scope.init($($element)) if !!window.FormData
|
148
|
+
|
149
|
+
]
|
@@ -0,0 +1,143 @@
|
|
1
|
+
app = angular.module('instantUpload', [])
|
2
|
+
|
3
|
+
@singleIuCtrl = ['$scope', '$element', ($scope, $element) ->
|
4
|
+
|
5
|
+
# upload event handler
|
6
|
+
class UploadHandler
|
7
|
+
|
8
|
+
constructor: ($uploader) ->
|
9
|
+
@url = $uploader.parents('form').attr('action')
|
10
|
+
$scope.persisted = $uploader.data('persisted')
|
11
|
+
$scope.field = $uploader.data('field')
|
12
|
+
$scope.version = $uploader.data('version')
|
13
|
+
|
14
|
+
@element = $uploader.find('.iu-simple-dropzone')
|
15
|
+
|
16
|
+
@element.bind 'dragenter', @dragEnter
|
17
|
+
@element.bind 'dragover', @dragEnter
|
18
|
+
@element.bind 'dragleave', @dragLeave
|
19
|
+
@element.bind 'drop', @drop
|
20
|
+
|
21
|
+
$fileInput = $uploader.find('input[type="file"]')
|
22
|
+
$fileInput.bind 'change', @drop
|
23
|
+
|
24
|
+
$uploader.find('.iu-simple-select').show 0, ->
|
25
|
+
$selectFiles = $uploader.find('.iu-simple-select-files')
|
26
|
+
offset = $selectFiles.position()
|
27
|
+
|
28
|
+
$fileInput.css
|
29
|
+
opacity: 0
|
30
|
+
cursor: 'pointer'
|
31
|
+
position: 'absolute'
|
32
|
+
left: offset.left
|
33
|
+
top: offset.top
|
34
|
+
width: $selectFiles.width() + 10
|
35
|
+
height: $selectFiles.height() + 10
|
36
|
+
'margin-left': -5
|
37
|
+
'margin-top': -25
|
38
|
+
'z-index': 2
|
39
|
+
'-ms-filter': '"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"'
|
40
|
+
'filter': 'alpha(opacity=0)'
|
41
|
+
|
42
|
+
@fileinput = $fileInput
|
43
|
+
|
44
|
+
dragEnter: (e) =>
|
45
|
+
# console.log 'dragEnter'
|
46
|
+
|
47
|
+
e.stopPropagation()
|
48
|
+
e.preventDefault()
|
49
|
+
|
50
|
+
@element.addClass 'iu-drag-over'
|
51
|
+
|
52
|
+
# settings.dragEnter(e)
|
53
|
+
return false
|
54
|
+
|
55
|
+
dragLeave: (e) =>
|
56
|
+
# console.log 'dragLeave'
|
57
|
+
|
58
|
+
e.stopPropagation()
|
59
|
+
e.preventDefault()
|
60
|
+
|
61
|
+
@element.removeClass 'iu-drag-over'
|
62
|
+
|
63
|
+
# settings.dragLeave(e)
|
64
|
+
return false
|
65
|
+
|
66
|
+
drop: (e) =>
|
67
|
+
# console.log 'drop'
|
68
|
+
|
69
|
+
e.stopPropagation()
|
70
|
+
e.preventDefault()
|
71
|
+
|
72
|
+
@element.removeClass 'iu-drag-over'
|
73
|
+
|
74
|
+
# get files from drag and drop dataTransfer
|
75
|
+
if typeof e.originalEvent.dataTransfer == 'undefined'
|
76
|
+
files = e.originalEvent.target.files
|
77
|
+
else
|
78
|
+
files = e.originalEvent.dataTransfer.files
|
79
|
+
|
80
|
+
fd = new FormData
|
81
|
+
fd.append @fileinput.attr('name'), files[0]
|
82
|
+
|
83
|
+
xhr = new XMLHttpRequest
|
84
|
+
|
85
|
+
$scope.$apply ->
|
86
|
+
$scope.uploaded = false
|
87
|
+
$scope.uploadProgress = 0
|
88
|
+
|
89
|
+
xhr.upload.addEventListener 'progress', ( (e) =>
|
90
|
+
# console.log 'progress'
|
91
|
+
percent = Math.ceil(e.loaded / e.total * 100)
|
92
|
+
$scope.$apply ->
|
93
|
+
$scope.uploadProgress = percent
|
94
|
+
), false
|
95
|
+
|
96
|
+
xhr.addEventListener 'load', ( (e) =>
|
97
|
+
# console.log 'load'
|
98
|
+
$scope.$apply ->
|
99
|
+
$scope.uploaded = true
|
100
|
+
|
101
|
+
@element.find('img').attr('src', $.parseJSON(xhr.response)[$scope.field][$scope.version].url)
|
102
|
+
), false
|
103
|
+
|
104
|
+
xhr.addEventListener 'error', ( (e) =>
|
105
|
+
# console.log 'error'
|
106
|
+
), false
|
107
|
+
|
108
|
+
xhr.addEventListener 'abort', ( (e) =>
|
109
|
+
# console.log 'abort'
|
110
|
+
), false
|
111
|
+
|
112
|
+
|
113
|
+
if $scope.persisted
|
114
|
+
method = 'PATCH'
|
115
|
+
else
|
116
|
+
method = 'POST'
|
117
|
+
|
118
|
+
xhr.open method, "#{@url}.json"
|
119
|
+
xhr.setRequestHeader 'X-Instant-Upload', true
|
120
|
+
xhr.send fd
|
121
|
+
|
122
|
+
return false
|
123
|
+
|
124
|
+
|
125
|
+
$scope.init = ($uploader) ->
|
126
|
+
handler = new UploadHandler($uploader)
|
127
|
+
|
128
|
+
# set width of the dropzone div for progressbar
|
129
|
+
$uploader.find('.iu-simple-dropzone').each ->
|
130
|
+
$this = $(this)
|
131
|
+
|
132
|
+
width = $this.find('img').width()
|
133
|
+
height = $this.find('img').height()
|
134
|
+
|
135
|
+
$this.width width
|
136
|
+
$this.height height
|
137
|
+
|
138
|
+
$this.find('img').css 'width', width
|
139
|
+
$this.find('img').css 'height', height
|
140
|
+
|
141
|
+
$ -> $scope.init($($element)) if !!window.FormData
|
142
|
+
|
143
|
+
]
|
@@ -0,0 +1,12 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the top of the
|
9
|
+
* compiled file, but it's generally better to create a new file per style scope.
|
10
|
+
*
|
11
|
+
*= require_tree ./instant_upload
|
12
|
+
*/
|
@@ -0,0 +1,54 @@
|
|
1
|
+
.iu-multi {
|
2
|
+
position: relative;
|
3
|
+
|
4
|
+
.iu-alert {
|
5
|
+
display: none;
|
6
|
+
}
|
7
|
+
|
8
|
+
.iu-multi-dropzone {
|
9
|
+
&.active {
|
10
|
+
position: relative;
|
11
|
+
overflow: hidden;
|
12
|
+
|
13
|
+
width: 300px;
|
14
|
+
height: 100px;
|
15
|
+
|
16
|
+
border: 5px solid black;
|
17
|
+
|
18
|
+
&.iu-drag-over {
|
19
|
+
background: silver;
|
20
|
+
}
|
21
|
+
|
22
|
+
&.uploading {
|
23
|
+
.iu-progress-bar {
|
24
|
+
height: 5px;
|
25
|
+
background: red;
|
26
|
+
position: absolute;
|
27
|
+
top: 0;
|
28
|
+
left: 0;
|
29
|
+
}
|
30
|
+
}
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
.iu-multi-select {
|
35
|
+
display: none;
|
36
|
+
|
37
|
+
.iu-select-files {
|
38
|
+
z-index: 1;
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
.iu-multi-files-cache, .iu-multi-files {
|
43
|
+
display: none;
|
44
|
+
overflow: auto;
|
45
|
+
|
46
|
+
li {
|
47
|
+
float: left;
|
48
|
+
list-style: none;
|
49
|
+
margin: 3px;
|
50
|
+
}
|
51
|
+
}
|
52
|
+
|
53
|
+
}
|
54
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
.iu-simple {
|
2
|
+
position: relative;
|
3
|
+
|
4
|
+
.iu-simple-dropzone {
|
5
|
+
position: relative;
|
6
|
+
overflow: hidden;
|
7
|
+
|
8
|
+
&.iu-drag-over {
|
9
|
+
border: 5px solid black;
|
10
|
+
}
|
11
|
+
|
12
|
+
&.uploading {
|
13
|
+
.iu-progress-bar {
|
14
|
+
height: 5px;
|
15
|
+
background: red;
|
16
|
+
position: absolute;
|
17
|
+
top: 0;
|
18
|
+
left: 0;
|
19
|
+
}
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
.iu-simple-select {
|
24
|
+
display: none;
|
25
|
+
|
26
|
+
.iu-select-files {
|
27
|
+
z-index: 1;
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
}
|
32
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
.iu-multi{ 'ng-controller' => 'multiIuCtrl', data: options }
|
2
|
+
.iu-multi-dropzone{ 'ng-class' => '{uploading:uploaded == false}' }
|
3
|
+
.iu-progress-bar{ style: "width: {{ uploadProgress }}%;" }
|
4
|
+
= file_field_tag "#{record.class.name.downcase}[#{field}_attributes][][#{options[:multi]}]", multiple: true
|
5
|
+
|
6
|
+
.iu-multi-select
|
7
|
+
drag & drop or
|
8
|
+
= link_to 'select file from disk', '#', class: 'iu-multi-select-files'
|
9
|
+
|
10
|
+
%ul.iu-multi-files-cache
|
11
|
+
- record.send(field).each do |img|
|
12
|
+
%li= image_tag img.send(options[:multi]).send(options[:version]).url
|
13
|
+
|
14
|
+
.iu-alert Too much, only #{options[:limit]}
|
15
|
+
|
16
|
+
%ul.iu-multi-files
|
17
|
+
%li{ 'ng-repeat' => 'file in files'}
|
18
|
+
%img{ src: "{{ file.path }}" }
|
19
|
+
|
20
|
+
|