jack_up 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.md +183 -0
- data/Rakefile +40 -0
- data/lib/assets/javascripts/jack_up/base.coffee +1 -0
- data/lib/assets/javascripts/jack_up/drag_and_drop.coffee +24 -0
- data/lib/assets/javascripts/jack_up/events.coffee +11 -0
- data/lib/assets/javascripts/jack_up/file_uploader.coffee +54 -0
- data/lib/assets/javascripts/jack_up/jquery.coffee +7 -0
- data/lib/assets/javascripts/jack_up/processor.coffee +38 -0
- data/lib/assets/javascripts/jack_up.js +3 -0
- data/lib/jack_up/engine.rb +5 -0
- data/lib/jack_up/version.rb +3 -0
- data/lib/jack_up.rb +4 -0
- metadata +77 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2012 Josh Steiner, Josh Clayton, thoughtbot, inc.
|
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,183 @@
|
|
1
|
+
# JackUp
|
2
|
+
|
3
|
+
## Easy AJAX file uploading in Rails.
|
4
|
+
|
5
|
+
### Install
|
6
|
+
|
7
|
+
Modify your `Gemfile`:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'jack_up'
|
11
|
+
```
|
12
|
+
|
13
|
+
and run `bundle install` from your shell.
|
14
|
+
|
15
|
+
Modify your `application.js` manifest:
|
16
|
+
|
17
|
+
```javascript
|
18
|
+
//= require jquery
|
19
|
+
//= require underscore
|
20
|
+
//= require jack_up
|
21
|
+
//= require_tree .
|
22
|
+
```
|
23
|
+
|
24
|
+
### Requirements
|
25
|
+
|
26
|
+
Rails 3.1 (for the asset pipeline), CoffeeScript, and both jQuery and
|
27
|
+
Underscore.js included in your `application.js` manifest.
|
28
|
+
|
29
|
+
### Usage
|
30
|
+
|
31
|
+
Create a JackUp.Processor, binding to various events emitted.
|
32
|
+
|
33
|
+
```coffeescript
|
34
|
+
$ -> # when the document is ready
|
35
|
+
# create a new processor with the endpoint to where your assets are uploaded
|
36
|
+
jackUp = new JackUp.Processor(path: '/assets')
|
37
|
+
|
38
|
+
# called if upload is an image; returns an image jQuery object with src attribute assigned
|
39
|
+
jackUp.on 'upload:imageRenderReady', (e, options) ->
|
40
|
+
# assigns a data-attribute with the file guid for later referencing
|
41
|
+
# set the border color to red, denoting that the image is still being uploaded
|
42
|
+
options.image.attr("data-id", options.file.__guid__).css(border: "5px solid red")
|
43
|
+
$('.file-drop').append(options.image)
|
44
|
+
|
45
|
+
# upload has been sent to server; server will handle processing
|
46
|
+
jackUp.on "upload:sentToServer", (e, options) ->
|
47
|
+
# change the border color to yellow to signify successful upload (server is still processing)
|
48
|
+
$("img[data-id='#{options.file.__guid__}']").css borderColor: 'yellow'
|
49
|
+
|
50
|
+
# when server responds successfully
|
51
|
+
jackUp.on "upload:success", (e, options) ->
|
52
|
+
# server has completed processing the image and has returned a response
|
53
|
+
$("img[data-id='#{options.file.__guid__}']").css(borderColor: "green")
|
54
|
+
|
55
|
+
# when server returns a non-200 response
|
56
|
+
jackUp.on "upload:failure", (e, options) ->
|
57
|
+
# alert the file name
|
58
|
+
alert("'#{options.file.name}' upload failed; please retry")
|
59
|
+
# remove the image from the dom since the upload failed
|
60
|
+
$("img[data-id='#{options.file.__guid__}']").remove()
|
61
|
+
```
|
62
|
+
|
63
|
+
Once the processor is set up, wire up drag-and-drop support:
|
64
|
+
|
65
|
+
```coffeescript
|
66
|
+
$('.file-drop').jackUpDragAndDrop(jackUp)
|
67
|
+
```
|
68
|
+
|
69
|
+
If you just want to bind to a standard `<input type='file'>`:
|
70
|
+
|
71
|
+
```coffeescript
|
72
|
+
$('.standard-attachment').jackUpAjax(jackUp)
|
73
|
+
```
|
74
|
+
|
75
|
+
You can use both at the same time, referencing the same `JackUp.Processor`, in
|
76
|
+
order to provide both options to your users.
|
77
|
+
|
78
|
+
### Example Rails Setup
|
79
|
+
|
80
|
+
For instant file uploading:
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
# Gemfile
|
84
|
+
gem 'rails'
|
85
|
+
gem 'paperclip'
|
86
|
+
gem 'rack-raw-upload'
|
87
|
+
```
|
88
|
+
|
89
|
+
Using the `rack-raw-upload` gem allows for accessing the file posted to the
|
90
|
+
controller via `params[:file]`; this makes it incredibly easy to handle file
|
91
|
+
uploads.
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
# app/models/asset.rb
|
95
|
+
class Asset < ActiveRecord::Base
|
96
|
+
has_attached_file :photo
|
97
|
+
attr_accessible :photo
|
98
|
+
end
|
99
|
+
|
100
|
+
# app/controllers/assets_controller.rb
|
101
|
+
class AssetsController < ApplicationController
|
102
|
+
def create
|
103
|
+
@asset = Asset.new(photo: params[:file])
|
104
|
+
|
105
|
+
if @asset.save
|
106
|
+
render json: @asset
|
107
|
+
else
|
108
|
+
head :bad_request
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
```
|
113
|
+
|
114
|
+
This view code could be placed anywhere for immediate uploading:
|
115
|
+
|
116
|
+
```haml
|
117
|
+
.file-drop
|
118
|
+
%span{ 'data-placeholder' => 'Drop files here' } Drop files here
|
119
|
+
|
120
|
+
%input.standard-attachment{ name: 'standard_attachment', accept: 'image/*', type: :file, multiple: :multiple }
|
121
|
+
```
|
122
|
+
|
123
|
+
If attaching assets to a different model, additionally use:
|
124
|
+
|
125
|
+
```ruby
|
126
|
+
# app/models/post.rb
|
127
|
+
class Post < ActiveRecord::Base
|
128
|
+
has_many :assets, dependent: :destroy
|
129
|
+
|
130
|
+
attr_accessible :asset_ids, :assets_attributes
|
131
|
+
accepts_nested_attributes_for :assets
|
132
|
+
end
|
133
|
+
|
134
|
+
# app/controllers/posts_controller.rb
|
135
|
+
class PostsController < ApplicationController
|
136
|
+
def new
|
137
|
+
@post = Post.new
|
138
|
+
@post.assets.build
|
139
|
+
end
|
140
|
+
|
141
|
+
def create
|
142
|
+
@post = Post.new(params[:post])
|
143
|
+
@post.save
|
144
|
+
respond_with @post
|
145
|
+
end
|
146
|
+
end
|
147
|
+
```
|
148
|
+
|
149
|
+
To wire up the posts view:
|
150
|
+
|
151
|
+
```haml
|
152
|
+
# app/views/posts/new.html.haml
|
153
|
+
= form_for @post, html: { multipart: true } do |form|
|
154
|
+
= form.text_field :title, { placeholder: 'Title' }
|
155
|
+
|
156
|
+
.file-drop
|
157
|
+
%span{ 'data-placeholder' => 'Drop files here' } Drop files here
|
158
|
+
|
159
|
+
%input.standard-attachment{ name: 'standard_attachment', accept: "image/*", type: :file, multiple: :multiple }
|
160
|
+
|
161
|
+
= form.submit 'Create Post'
|
162
|
+
```
|
163
|
+
|
164
|
+
```coffeescript
|
165
|
+
# app/assets/javascripts/posts.coffee
|
166
|
+
# truncated from above to demonstrate additional code to associate uploads
|
167
|
+
# with posts
|
168
|
+
jackUp.on "upload:success", (e, options) ->
|
169
|
+
$("img[data-id='#{options.file.__guid__}']").css(borderColor: "green")
|
170
|
+
|
171
|
+
# read the response from the server
|
172
|
+
asset = JSON.parse(options.responseText)
|
173
|
+
assetId = asset.id
|
174
|
+
# create a hidden input containing the asset id of the uploaded file
|
175
|
+
assetIdsElement = $("<input type='hidden' name='post[asset_ids][]'>").val(assetId)
|
176
|
+
# append it to the form so saving the form associates the created post
|
177
|
+
# with the uploaded assets
|
178
|
+
$(".file-drop").parent("form").append(assetIdsElement)
|
179
|
+
```
|
180
|
+
|
181
|
+
## License
|
182
|
+
|
183
|
+
JackUp is copyright 2012 Josh Steiner, Josh Clayton, and thoughtbot, inc., and may be redistributed under the terms specified in the LICENSE file.
|
data/Rakefile
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'JackUp'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
|
24
|
+
load 'rails/tasks/engine.rake'
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
Bundler::GemHelper.install_tasks
|
29
|
+
|
30
|
+
require 'rake/testtask'
|
31
|
+
|
32
|
+
Rake::TestTask.new(:test) do |t|
|
33
|
+
t.libs << 'lib'
|
34
|
+
t.libs << 'test'
|
35
|
+
t.pattern = 'test/**/*_test.rb'
|
36
|
+
t.verbose = false
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
task :default => :test
|
@@ -0,0 +1 @@
|
|
1
|
+
class @JackUp
|
@@ -0,0 +1,24 @@
|
|
1
|
+
ignoreEvent = (event) ->
|
2
|
+
event.stopPropagation()
|
3
|
+
event.preventDefault()
|
4
|
+
|
5
|
+
class @JackUp.DragAndDrop
|
6
|
+
constructor: (@droppableElement, @processor) ->
|
7
|
+
@droppableElement
|
8
|
+
.bind("dragenter", @_drag)
|
9
|
+
.bind("drop", @_drop)
|
10
|
+
.bind("drop", @_dragOut)
|
11
|
+
|
12
|
+
_drag: (event) =>
|
13
|
+
ignoreEvent event
|
14
|
+
event.originalEvent.dataTransfer.dropEffect = "copy"
|
15
|
+
@droppableElement.addClass("hover")
|
16
|
+
|
17
|
+
_dragOut: (event) =>
|
18
|
+
ignoreEvent event
|
19
|
+
@droppableElement.removeClass("hover")
|
20
|
+
|
21
|
+
_drop: (event) =>
|
22
|
+
ignoreEvent event
|
23
|
+
@droppableElement.find('[data-placeholder]').hide()
|
24
|
+
@processor.processFilesForEvent(event)
|
@@ -0,0 +1,54 @@
|
|
1
|
+
railsCSRFData = ->
|
2
|
+
csrfParam = $('meta[name=csrf-param]').attr('content')
|
3
|
+
csrfToken = $('meta[name=csrf-token]').attr('content')
|
4
|
+
|
5
|
+
formData = {}
|
6
|
+
formData[csrfParam] = csrfToken
|
7
|
+
JSON.stringify formData
|
8
|
+
|
9
|
+
class @JackUp.FileUploader
|
10
|
+
constructor: (@options) ->
|
11
|
+
@path = @options.path
|
12
|
+
@responded = false
|
13
|
+
|
14
|
+
_onProgressHandler: (file) =>
|
15
|
+
(progress) =>
|
16
|
+
if progress.lengthComputable
|
17
|
+
percent = progress.loaded/progress.total*100
|
18
|
+
@trigger 'upload:percentComplete', percentComplete: percent, progress: progress
|
19
|
+
|
20
|
+
if percent == 100
|
21
|
+
@trigger 'upload:sentToServer', file: file
|
22
|
+
|
23
|
+
_onReadyStateChangeHandler: (file) =>
|
24
|
+
(event) =>
|
25
|
+
status = null
|
26
|
+
return if event.target.readyState != 4
|
27
|
+
|
28
|
+
try
|
29
|
+
status = event.target.status
|
30
|
+
catch error
|
31
|
+
return
|
32
|
+
|
33
|
+
if status > 0 && status != 200
|
34
|
+
@trigger 'upload:failure', responseText: event.target.responseText, event: event, file: file
|
35
|
+
|
36
|
+
if status == 200 && event.target.responseText && !@responded
|
37
|
+
@responded = true
|
38
|
+
@trigger 'upload:success', responseText: event.target.responseText, event: event, file: file
|
39
|
+
|
40
|
+
upload: (file) ->
|
41
|
+
xhr = new XMLHttpRequest()
|
42
|
+
xhr.upload.addEventListener 'progress', @_onProgressHandler(file), false
|
43
|
+
xhr.addEventListener 'readystatechange', @_onReadyStateChangeHandler(file), false
|
44
|
+
|
45
|
+
xhr.open 'POST', @path, true
|
46
|
+
|
47
|
+
xhr.setRequestHeader 'Content-Type', file.type
|
48
|
+
xhr.setRequestHeader 'X-File-Name', file.name
|
49
|
+
xhr.setRequestHeader 'X-Query-Params', railsCSRFData()
|
50
|
+
|
51
|
+
@trigger 'upload:start', file: file
|
52
|
+
xhr.send file
|
53
|
+
|
54
|
+
_.extend JackUp.FileUploader.prototype, JackUp.Events
|
@@ -0,0 +1,38 @@
|
|
1
|
+
getFilesFromEvent = (event) ->
|
2
|
+
if event.originalEvent.dataTransfer?
|
3
|
+
event.originalEvent.dataTransfer.files
|
4
|
+
else if event.originalEvent.currentTarget? && event.originalEvent.currentTarget.files?
|
5
|
+
event.originalEvent.currentTarget.files
|
6
|
+
else if event.originalEvent.target? && event.originalEvent.target.files?
|
7
|
+
event.originalEvent.target.files
|
8
|
+
else
|
9
|
+
[]
|
10
|
+
|
11
|
+
filesWithData = (event) ->
|
12
|
+
_.map getFilesFromEvent(event), (file) ->
|
13
|
+
file.__guid__ = Math.random().toString(36)
|
14
|
+
file
|
15
|
+
|
16
|
+
class @JackUp.Processor
|
17
|
+
constructor: (options) ->
|
18
|
+
@uploadPath = options.path
|
19
|
+
|
20
|
+
processFilesForEvent: (event) =>
|
21
|
+
_.each filesWithData(event), (file) =>
|
22
|
+
reader = new FileReader()
|
23
|
+
reader.onload = (event) =>
|
24
|
+
@trigger 'upload:dataRenderReady', result: event.target.result, file: file
|
25
|
+
|
26
|
+
if /^data:image/.test event.target.result
|
27
|
+
image = $("<img>").attr("src", event.target.result)
|
28
|
+
@trigger 'upload:imageRenderReady', image: image, file: file
|
29
|
+
|
30
|
+
reader.readAsDataURL(file)
|
31
|
+
|
32
|
+
fileUploader = new JackUp.FileUploader(path: @uploadPath)
|
33
|
+
@bubble 'upload:success', 'upload:failure', 'upload:sentToServer',
|
34
|
+
from: fileUploader
|
35
|
+
|
36
|
+
fileUploader.upload file
|
37
|
+
|
38
|
+
_.extend JackUp.Processor.prototype, JackUp.Events
|
data/lib/jack_up.rb
ADDED
metadata
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jack_up
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Josh Steiner
|
9
|
+
- Josh Clayton
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2012-08-03 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rails
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ~>
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '3.1'
|
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: '3.1'
|
31
|
+
description: Easy AJAX file uploading in Rails
|
32
|
+
email:
|
33
|
+
- josh@jsteiner.me
|
34
|
+
- jclayton@thoughtbot.com
|
35
|
+
executables: []
|
36
|
+
extensions: []
|
37
|
+
extra_rdoc_files: []
|
38
|
+
files:
|
39
|
+
- lib/assets/javascripts/jack_up/base.coffee
|
40
|
+
- lib/assets/javascripts/jack_up/drag_and_drop.coffee
|
41
|
+
- lib/assets/javascripts/jack_up/events.coffee
|
42
|
+
- lib/assets/javascripts/jack_up/file_uploader.coffee
|
43
|
+
- lib/assets/javascripts/jack_up/jquery.coffee
|
44
|
+
- lib/assets/javascripts/jack_up/processor.coffee
|
45
|
+
- lib/assets/javascripts/jack_up.js
|
46
|
+
- lib/jack_up/engine.rb
|
47
|
+
- lib/jack_up/version.rb
|
48
|
+
- lib/jack_up.rb
|
49
|
+
- LICENSE
|
50
|
+
- Rakefile
|
51
|
+
- README.md
|
52
|
+
homepage: http://github.com/thoughtbot/jack_up
|
53
|
+
licenses: []
|
54
|
+
post_install_message:
|
55
|
+
rdoc_options: []
|
56
|
+
require_paths:
|
57
|
+
- lib
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ! '>='
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
requirements: []
|
71
|
+
rubyforge_project:
|
72
|
+
rubygems_version: 1.8.23
|
73
|
+
signing_key:
|
74
|
+
specification_version: 3
|
75
|
+
summary: Easy AJAX file uploading in Rails
|
76
|
+
test_files: []
|
77
|
+
has_rdoc:
|