jack_up 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: