jack_up 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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,11 @@
1
+ @JackUp.Events =
2
+ trigger: ->
3
+ $(@).trigger arguments...
4
+
5
+ on: ->
6
+ $(@).bind arguments...
7
+
8
+ bubble: (eventList..., options) ->
9
+ _.each eventList, (eventName) =>
10
+ options.from.on eventName, =>
11
+ @trigger eventName, arguments[1]
@@ -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,7 @@
1
+ $.fn.jackUpAjax = (processor) ->
2
+ $(@).change(processor.processFilesForEvent)
3
+ @
4
+
5
+ $.fn.jackUpDragAndDrop = (processor) ->
6
+ new JackUp.DragAndDrop($(@), processor)
7
+ @
@@ -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
@@ -0,0 +1,3 @@
1
+ //= require jack_up/base
2
+ //= require jack_up/events
3
+ //= require_tree ./jack_up
@@ -0,0 +1,5 @@
1
+ module JackUp
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace JackUp
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ module JackUp
2
+ VERSION = '0.1.0'
3
+ end
data/lib/jack_up.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'jack_up/engine'
2
+
3
+ module JackUp
4
+ end
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: