remotipart 1.0 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CONTRIBUTING.md +53 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +20 -0
- data/History.rdoc +45 -0
- data/README.rdoc +7 -7
- data/Rakefile +6 -11
- data/lib/remotipart/middleware.rb +12 -15
- data/lib/remotipart/rails.rb +1 -1
- data/lib/remotipart/rails/version.rb +2 -2
- data/lib/remotipart/render_overrides.rb +14 -6
- data/remotipart.gemspec +36 -41
- data/vendor/assets/javascripts/jquery.iframe-transport.js +99 -97
- data/vendor/assets/javascripts/jquery.remotipart.js +24 -5
- metadata +55 -60
- data/.gitignore +0 -21
- data/test/helper.rb +0 -10
- data/test/test_remotipart.rb +0 -7
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
## Note on Patches/Pull Requests
|
2
|
+
|
3
|
+
* Fork the project.
|
4
|
+
* Make your feature addition or bug fix.
|
5
|
+
* Add tests for it. This is important so I don't break it in a
|
6
|
+
future version unintentionally.
|
7
|
+
* Commit, do not mess with rakefile, version, or history.
|
8
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
9
|
+
* Send me a pull request. Bonus points for topic branches.
|
10
|
+
|
11
|
+
## Tests
|
12
|
+
|
13
|
+
Because of the nature of AJAX file uploads and certain browser restrictions, we could not simply create unit tests (using qunit or jasmine)
|
14
|
+
to test the file upload functionality of remotipart (since the browsers running those test suites won't allow us to set the target of a file
|
15
|
+
upload input using javascript). So, instead we created a demo Rails app using remotipart with all remotipart functionality tested using RSpec and Capybara.
|
16
|
+
|
17
|
+
* [Demo Rails App with
|
18
|
+
Tests](https://github.com/JangoSteve/Rails-jQuery-Demo/tree/remotipart)
|
19
|
+
* [Tests](https://github.com/JangoSteve/Rails-jQuery-Demo/blob/remotipart/spec/features/comments_spec.rb)
|
20
|
+
|
21
|
+
To run tests:
|
22
|
+
|
23
|
+
Clone the remotipart branch of the demo app
|
24
|
+
|
25
|
+
```
|
26
|
+
git clone -b remotipart git://github.com/JangoSteve/Rails-jQuery-Demo.git
|
27
|
+
```
|
28
|
+
|
29
|
+
Install the dependencies
|
30
|
+
|
31
|
+
```
|
32
|
+
bundle install
|
33
|
+
```
|
34
|
+
|
35
|
+
Run the tests
|
36
|
+
|
37
|
+
```
|
38
|
+
bundle exec rspec spec/
|
39
|
+
```
|
40
|
+
|
41
|
+
If you need to test your own changes to remotipart, just update the Gemfile with your own fork/branch of remotipart:
|
42
|
+
|
43
|
+
```
|
44
|
+
gem 'remotipart', :git => 'git://github.com/MY_FORK/remotipart.git', :branch => 'MY_BRANCH'
|
45
|
+
```
|
46
|
+
|
47
|
+
To save time, you can also just bundle remotipart from your current
|
48
|
+
local machine / filesystem without having to commit your changes
|
49
|
+
or push them remotely:
|
50
|
+
|
51
|
+
```
|
52
|
+
gem 'remotipart', :path => '../remotipart'
|
53
|
+
```
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
git (1.2.5)
|
5
|
+
jeweler (1.8.4)
|
6
|
+
bundler (~> 1.0)
|
7
|
+
git (>= 1.2.5)
|
8
|
+
rake
|
9
|
+
rdoc
|
10
|
+
json (1.7.6)
|
11
|
+
rake (10.0.3)
|
12
|
+
rdoc (3.12)
|
13
|
+
json (~> 1.4)
|
14
|
+
|
15
|
+
PLATFORMS
|
16
|
+
ruby
|
17
|
+
|
18
|
+
DEPENDENCIES
|
19
|
+
jeweler
|
20
|
+
rake
|
data/History.rdoc
CHANGED
@@ -1,5 +1,50 @@
|
|
1
1
|
= History
|
2
2
|
|
3
|
+
=== 1.2.1 / 2013-07-07
|
4
|
+
|
5
|
+
* Added automatic authenticity_token detection and appending to iframe submission.
|
6
|
+
|
7
|
+
=== 1.2.0 / 2013-07-06
|
8
|
+
|
9
|
+
* Removed support for older jquery-ujs and jquery < 1.7.
|
10
|
+
* Fixed json (and other type) parsing issues, only html_escape HTML responses.
|
11
|
+
|
12
|
+
=== 1.1.1 / 2013-07-05
|
13
|
+
|
14
|
+
* Fixed issue with GET params not being available in middleware.
|
15
|
+
* Fixed issue with clicked submit button not being submitted via remotipart ajax.
|
16
|
+
* Fixed issue with HTML not being escaped correctly.
|
17
|
+
* Fixed issue with iframe-transport on jQuery 1.10.x.
|
18
|
+
* Fixed compatibility issue with Rails 4.
|
19
|
+
|
20
|
+
=== 1.1.0 / 2013-07-04
|
21
|
+
|
22
|
+
* Updated to latest iframe-transport.
|
23
|
+
* Added status-text to js response.
|
24
|
+
|
25
|
+
=== 1.0.5 / 2013-02-09
|
26
|
+
|
27
|
+
* Fixed gem dependency info.
|
28
|
+
|
29
|
+
=== 1.0.4 / 2013-02-09
|
30
|
+
|
31
|
+
* Fixed render override compatibility with other gems that override render (e.g. wicked_pdf)
|
32
|
+
|
33
|
+
=== 1.0.3 / 2013-02-08
|
34
|
+
|
35
|
+
* Fixed for jquery-rails v2.2.x (i.e. jQuery v1.9.x)
|
36
|
+
|
37
|
+
=== 1.0.2 / 2012-02-03
|
38
|
+
|
39
|
+
* Minor Enhancements
|
40
|
+
* Fixed rendering when JS response contains `textarea` tag
|
41
|
+
|
42
|
+
=== 1.0.1 / 2011-11-27
|
43
|
+
|
44
|
+
* Minor Enhancements
|
45
|
+
* Added support for non-post methods from Rails's `_method` hidden input.
|
46
|
+
* Fixed IE form submit-bubbling support for jquery 1.7
|
47
|
+
|
3
48
|
=== 1.0 / 2011-08-26
|
4
49
|
|
5
50
|
* New Features
|
data/README.rdoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
= Remotipart
|
1
|
+
= Remotipart: Rails jQuery File Upload
|
2
2
|
|
3
|
-
Remotipart is a Ruby on Rails gem enabling AJAX file uploads with jQuery in Rails 3
|
3
|
+
Remotipart is a Ruby on Rails gem enabling AJAX file uploads with jQuery in Rails 3 and Rails 4 remote forms.
|
4
4
|
This gem augments the native Rails jQuery remote form functionality enabling asynchronous file uploads with little to no modification to your application.
|
5
5
|
|
6
6
|
* {Homepage and Demos}[http://www.alfajango.com/blog/remotipart-rails-gem/]
|
@@ -8,12 +8,12 @@ This gem augments the native Rails jQuery remote form functionality enabling asy
|
|
8
8
|
|
9
9
|
== Dependencies
|
10
10
|
|
11
|
-
* {Rails 3}[http://github.com/rails/rails]
|
12
|
-
* {The jquery-rails gem}[http://rubygems.org/gems/jquery-rails], which
|
11
|
+
* {Rails 3 or Rails 4}[http://github.com/rails/rails]
|
12
|
+
* {The jquery-rails gem}[http://rubygems.org/gems/jquery-rails] (included in Rails 3 and Rails 4 by default), which installs {jQuery}[http://jquery.com] and the {Rails jQuery driver (jquery-ujs)}[https://github.com/rails/jquery-ujs]
|
13
13
|
|
14
14
|
== Installation
|
15
15
|
|
16
|
-
<b>Your app should be using jquery-rails gem
|
16
|
+
<b>Your app should be using jquery-rails gem v2.3.0 or above.</b>
|
17
17
|
|
18
18
|
If you're using an old version of the jquery-rails gem,
|
19
19
|
make sure you have a supported jquery-ujs (rails.js or jquery_ujs.js) version from {VERSION_COMPATIBILITY}[https://github.com/JangoSteve/remotipart/blob/master/VERSION_COMPATIBILITY.rdoc].
|
@@ -23,7 +23,7 @@ make sure you have a supported jquery-ujs (rails.js or jquery_ujs.js) version fr
|
|
23
23
|
|
24
24
|
* Add this line to your GEMFILE (use the appropriate version from the compatibilty chart if needed)
|
25
25
|
|
26
|
-
gem 'remotipart', '~> 1.
|
26
|
+
gem 'remotipart', '~> 1.2'
|
27
27
|
|
28
28
|
* And run
|
29
29
|
|
@@ -139,4 +139,4 @@ Thank you to {Adam Kerr}[https://github.com/ajrkerr] for helping move over to th
|
|
139
139
|
|
140
140
|
== Copyright
|
141
141
|
|
142
|
-
Copyright (c)
|
142
|
+
Copyright (c) 2013 {Steve Schwartz}[https://github.com/JangoSteve], {Greg Leppert}[https://github.com/leppert]. See LICENSE for details.
|
data/Rakefile
CHANGED
@@ -6,18 +6,17 @@ begin
|
|
6
6
|
require 'jeweler'
|
7
7
|
Jeweler::Tasks.new do |gem|
|
8
8
|
gem.name = "remotipart"
|
9
|
-
gem.summary = %Q{Remotipart is a Ruby on Rails gem enabling remote multipart forms (AJAX style file uploads) with
|
10
|
-
gem.description = %Q{Remotipart is a Ruby on Rails gem enabling remote multipart forms (AJAX style file uploads) with
|
9
|
+
gem.summary = %Q{Remotipart is a Ruby on Rails gem enabling remote multipart forms (AJAX style file uploads) with jquery-rails.}
|
10
|
+
gem.description = %Q{Remotipart is a Ruby on Rails gem enabling remote multipart forms (AJAX style file uploads) with jquery-rails.
|
11
11
|
This gem augments the native Rails 3 jQuery-UJS remote form function enabling asynchronous file uploads with little to no modification to your application.
|
12
12
|
}
|
13
13
|
gem.email = %w{greg@formasfunction.com steve@alfajango.com}
|
14
|
-
gem.homepage = "http://
|
14
|
+
gem.homepage = "http://opensource.alfajango.com/remotipart/"
|
15
15
|
gem.authors = ["Greg Leppert", "Steve Schwartz"]
|
16
|
-
gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
|
17
16
|
gem.version = Remotipart::Rails::VERSION
|
18
17
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
19
18
|
end
|
20
|
-
Jeweler::
|
19
|
+
Jeweler::RubygemsDotOrgTasks.new
|
21
20
|
rescue LoadError
|
22
21
|
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
23
22
|
end
|
@@ -42,12 +41,8 @@ rescue LoadError
|
|
42
41
|
end
|
43
42
|
end
|
44
43
|
|
45
|
-
task
|
46
|
-
|
47
|
-
task :default => :test
|
48
|
-
|
49
|
-
require 'rake/rdoctask'
|
50
|
-
require 'lib/remotipart/rails/version'
|
44
|
+
require 'rdoc/task'
|
45
|
+
require File.expand_path('../lib/remotipart/rails/version', __FILE__)
|
51
46
|
Rake::RDocTask.new do |rdoc|
|
52
47
|
version = Remotipart::Rails::VERSION
|
53
48
|
|
@@ -8,23 +8,20 @@ module Remotipart
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def call env
|
11
|
-
#
|
12
|
-
|
13
|
-
# and call the `POST` method on it
|
14
|
-
if ::Rails.version < "3.1"
|
15
|
-
Rack::Request.new(env).POST
|
16
|
-
end
|
17
|
-
params = env['rack.request.form_hash']
|
11
|
+
# Get request params
|
12
|
+
params = Rack::Request.new(env).params
|
18
13
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
14
|
+
if params
|
15
|
+
# This was using an iframe transport, and is therefore an XHR
|
16
|
+
# This is required if we're going to override the http_accept
|
17
|
+
if params['X-Requested-With'] == 'IFrame'
|
18
|
+
env['HTTP_X_REQUESTED_WITH'] = 'xmlhttprequest'
|
19
|
+
end
|
24
20
|
|
25
|
-
|
26
|
-
|
27
|
-
|
21
|
+
# Override the accepted format, because it isn't what we really want
|
22
|
+
if params['X-Http-Accept']
|
23
|
+
env['HTTP_ACCEPT'] = params['X-Http-Accept']
|
24
|
+
end
|
28
25
|
end
|
29
26
|
|
30
27
|
@app.call(env)
|
data/lib/remotipart/rails.rb
CHANGED
@@ -1,12 +1,20 @@
|
|
1
1
|
module Remotipart
|
2
|
-
|
3
|
-
#
|
4
|
-
# as expected by iframe-transport
|
2
|
+
# Responder used to automagically wrap any non-xml replies in a text-area
|
3
|
+
# as expected by iframe-transport.
|
5
4
|
module RenderOverrides
|
6
|
-
|
7
|
-
|
5
|
+
include ERB::Util
|
6
|
+
|
7
|
+
def self.included(base)
|
8
|
+
base.class_eval do
|
9
|
+
alias_method_chain :render, :remotipart
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def render_with_remotipart *args
|
14
|
+
render_without_remotipart *args
|
8
15
|
if remotipart_submitted?
|
9
|
-
response.
|
16
|
+
textarea_body = response.content_type == 'text/html' ? html_escape(response.body) : response.body
|
17
|
+
response.body = %{<textarea data-type=\"#{response.content_type}\" data-status=\"#{response.response_code}\" data-statusText=\"#{response.message}\">#{textarea_body}</textarea>}
|
10
18
|
response.content_type = Mime::HTML
|
11
19
|
end
|
12
20
|
response_body
|
data/remotipart.gemspec
CHANGED
@@ -1,68 +1,63 @@
|
|
1
1
|
# Generated by jeweler
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
|
-
s.name =
|
8
|
-
s.version = "1.
|
7
|
+
s.name = "remotipart"
|
8
|
+
s.version = "1.2.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Greg Leppert", "Steve Schwartz"]
|
12
|
-
s.date =
|
13
|
-
s.description =
|
14
|
-
This gem augments the native Rails 3 jQuery-UJS remote form function enabling asynchronous file uploads with little to no modification to your application.
|
15
|
-
}
|
12
|
+
s.date = "2013-07-08"
|
13
|
+
s.description = "Remotipart is a Ruby on Rails gem enabling remote multipart forms (AJAX style file uploads) with jquery-rails.\n This gem augments the native Rails 3 jQuery-UJS remote form function enabling asynchronous file uploads with little to no modification to your application.\n "
|
16
14
|
s.email = ["greg@formasfunction.com", "steve@alfajango.com"]
|
17
15
|
s.extra_rdoc_files = [
|
18
16
|
"LICENSE",
|
19
|
-
|
17
|
+
"README.rdoc"
|
20
18
|
]
|
21
19
|
s.files = [
|
22
20
|
".document",
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
21
|
+
"CONTRIBUTING.md",
|
22
|
+
"Gemfile",
|
23
|
+
"Gemfile.lock",
|
24
|
+
"History.rdoc",
|
25
|
+
"LICENSE",
|
26
|
+
"README.rdoc",
|
27
|
+
"Rakefile",
|
28
|
+
"VERSION_COMPATIBILITY.rdoc",
|
29
|
+
"lib/generators/remotipart/install/install_generator.rb",
|
30
|
+
"lib/remotipart.rb",
|
31
|
+
"lib/remotipart/middleware.rb",
|
32
|
+
"lib/remotipart/rails.rb",
|
33
|
+
"lib/remotipart/rails/engine.rb",
|
34
|
+
"lib/remotipart/rails/railtie.rb",
|
35
|
+
"lib/remotipart/rails/version.rb",
|
36
|
+
"lib/remotipart/render_overrides.rb",
|
37
|
+
"lib/remotipart/request_helper.rb",
|
38
|
+
"lib/remotipart/view_helper.rb",
|
39
|
+
"remotipart.gemspec",
|
40
|
+
"vendor/assets/javascripts/jquery.iframe-transport.js",
|
41
|
+
"vendor/assets/javascripts/jquery.remotipart.js"
|
44
42
|
]
|
45
|
-
s.homepage =
|
46
|
-
s.rdoc_options = ["--charset=UTF-8"]
|
43
|
+
s.homepage = "http://opensource.alfajango.com/remotipart/"
|
47
44
|
s.require_paths = ["lib"]
|
48
|
-
s.rubygems_version =
|
49
|
-
s.summary =
|
50
|
-
s.test_files = [
|
51
|
-
"test/helper.rb",
|
52
|
-
"test/test_remotipart.rb"
|
53
|
-
]
|
45
|
+
s.rubygems_version = "1.8.15"
|
46
|
+
s.summary = "Remotipart is a Ruby on Rails gem enabling remote multipart forms (AJAX style file uploads) with jquery-rails."
|
54
47
|
|
55
48
|
if s.respond_to? :specification_version then
|
56
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
57
49
|
s.specification_version = 3
|
58
50
|
|
59
51
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
60
|
-
s.add_development_dependency(%q<
|
52
|
+
s.add_development_dependency(%q<rake>, [">= 0"])
|
53
|
+
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
61
54
|
else
|
62
|
-
s.add_dependency(%q<
|
55
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
56
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
63
57
|
end
|
64
58
|
else
|
65
|
-
s.add_dependency(%q<
|
59
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
60
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
66
61
|
end
|
67
62
|
end
|
68
63
|
|
@@ -1,8 +1,8 @@
|
|
1
1
|
// This [jQuery](http://jquery.com/) plugin implements an `<iframe>`
|
2
2
|
// [transport](http://api.jquery.com/extending-ajax/#Transports) so that
|
3
3
|
// `$.ajax()` calls support the uploading of files using standard HTML file
|
4
|
-
// input fields. This is done by switching the exchange from `XMLHttpRequest`
|
5
|
-
// a hidden `iframe` element containing a form that is submitted.
|
4
|
+
// input fields. This is done by switching the exchange from `XMLHttpRequest`
|
5
|
+
// to a hidden `iframe` element containing a form that is submitted.
|
6
6
|
|
7
7
|
// The [source for the plugin](http://github.com/cmlenz/jquery-iframe-transport)
|
8
8
|
// is available on [Github](http://github.com/) and dual licensed under the MIT
|
@@ -10,7 +10,7 @@
|
|
10
10
|
|
11
11
|
// ## Usage
|
12
12
|
|
13
|
-
// To use this plugin, you simply add
|
13
|
+
// To use this plugin, you simply add an `iframe` option with the value `true`
|
14
14
|
// to the Ajax settings an `$.ajax()` call, and specify the file fields to
|
15
15
|
// include in the submssion using the `files` option, which can be a selector,
|
16
16
|
// jQuery object, or a list of DOM elements containing one or more
|
@@ -25,12 +25,11 @@
|
|
25
25
|
// });
|
26
26
|
// });
|
27
27
|
|
28
|
-
// The plugin will construct
|
29
|
-
//
|
30
|
-
// explicitly included, submit that form, and process the response.
|
28
|
+
// The plugin will construct hidden `<iframe>` and `<form>` elements, add the
|
29
|
+
// file field(s) to that form, submit the form, and process the response.
|
31
30
|
|
32
|
-
// If you want to include other form fields in the form submission, include
|
33
|
-
// in the `data` option, and set the `processData` option to `false`:
|
31
|
+
// If you want to include other form fields in the form submission, include
|
32
|
+
// them in the `data` option, and set the `processData` option to `false`:
|
34
33
|
|
35
34
|
// $("#myform").submit(function() {
|
36
35
|
// $.ajax(this.action, {
|
@@ -43,123 +42,115 @@
|
|
43
42
|
// });
|
44
43
|
// });
|
45
44
|
|
46
|
-
// ###
|
45
|
+
// ### Response Data Types
|
47
46
|
|
48
|
-
//
|
49
|
-
//
|
50
|
-
//
|
47
|
+
// As the transport does not have access to the HTTP headers of the server
|
48
|
+
// response, it is not as simple to make use of the automatic content type
|
49
|
+
// detection provided by jQuery as with regular XHR. If you can't set the
|
50
|
+
// expected response data type (for example because it may vary depending on
|
51
|
+
// the outcome of processing by the server), you will need to employ a
|
52
|
+
// workaround on the server side: Send back an HTML document containing just a
|
53
|
+
// `<textarea>` element with a `data-type` attribute that specifies the MIME
|
51
54
|
// type, and put the actual payload in the textarea:
|
52
55
|
|
53
56
|
// <textarea data-type="application/json">
|
54
57
|
// {"ok": true, "message": "Thanks so much"}
|
55
58
|
// </textarea>
|
56
59
|
|
57
|
-
// The iframe transport plugin will detect this and
|
58
|
-
//
|
59
|
-
//
|
60
|
-
//
|
61
|
-
// `
|
60
|
+
// The iframe transport plugin will detect this and pass the value of the
|
61
|
+
// `data-type` attribute on to jQuery as if it was the "Content-Type" response
|
62
|
+
// header, thereby enabling the same kind of conversions that jQuery applies
|
63
|
+
// to regular responses. For the example above you should get a Javascript
|
64
|
+
// object as the `data` parameter of the `complete` callback, with the
|
65
|
+
// properties `ok: true` and `message: "Thanks so much"`.
|
66
|
+
|
67
|
+
// ### Handling Server Errors
|
68
|
+
|
69
|
+
// Another problem with using an `iframe` for file uploads is that it is
|
70
|
+
// impossible for the javascript code to determine the HTTP status code of the
|
71
|
+
// servers response. Effectively, all of the calls you make will look like they
|
72
|
+
// are getting successful responses, and thus invoke the `done()` or
|
73
|
+
// `complete()` callbacks. You can only determine communicate problems using
|
74
|
+
// the content of the response payload. For example, consider using a JSON
|
75
|
+
// response such as the following to indicate a problem with an uploaded file:
|
76
|
+
|
77
|
+
// <textarea data-type="application/json">
|
78
|
+
// {"ok": false, "message": "Please only upload reasonably sized files."}
|
79
|
+
// </textarea>
|
62
80
|
|
63
81
|
// ### Compatibility
|
64
82
|
|
65
|
-
// This plugin has primarily been tested on Safari 5, Firefox 4
|
66
|
-
// Explorer all the way back to version 6. While I
|
67
|
-
// it so far, I'm fairly sure it still doesn't
|
68
|
-
// different browsers. But the code is still
|
69
|
-
// should be able to fix it and contribute a
|
83
|
+
// This plugin has primarily been tested on Safari 5 (or later), Firefox 4 (or
|
84
|
+
// later), and Internet Explorer (all the way back to version 6). While I
|
85
|
+
// haven't found any issues with it so far, I'm fairly sure it still doesn't
|
86
|
+
// work around all the quirks in all different browsers. But the code is still
|
87
|
+
// pretty simple overall, so you should be able to fix it and contribute a
|
88
|
+
// patch :)
|
70
89
|
|
71
90
|
// ## Annotated Source
|
72
91
|
|
73
92
|
(function($, undefined) {
|
93
|
+
"use strict";
|
74
94
|
|
75
95
|
// Register a prefilter that checks whether the `iframe` option is set, and
|
76
|
-
// switches to the iframe
|
96
|
+
// switches to the "iframe" data type if it is `true`.
|
77
97
|
$.ajaxPrefilter(function(options, origOptions, jqXHR) {
|
78
98
|
if (options.iframe) {
|
79
99
|
return "iframe";
|
80
100
|
}
|
81
101
|
});
|
82
102
|
|
83
|
-
// Register
|
84
|
-
//
|
85
|
-
//
|
103
|
+
// Register a transport for the "iframe" data type. It will only activate
|
104
|
+
// when the "files" option has been set to a non-empty list of enabled file
|
105
|
+
// inputs.
|
86
106
|
$.ajaxTransport("iframe", function(options, origOptions, jqXHR) {
|
87
107
|
var form = null,
|
88
108
|
iframe = null,
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
disabledFields = [],
|
94
|
-
files = $(options.files).filter(":file:enabled");
|
109
|
+
name = "iframe-" + $.now(),
|
110
|
+
files = $(options.files).filter(":file:enabled"),
|
111
|
+
markers = null,
|
112
|
+
accepts;
|
95
113
|
|
96
114
|
// This function gets called after a successful submission or an abortion
|
97
115
|
// and should revert all changes made to the page to enable the
|
98
116
|
// submission via this transport.
|
99
117
|
function cleanUp() {
|
100
|
-
|
101
|
-
|
102
|
-
});
|
103
|
-
|
104
|
-
this.disabled = false;
|
105
|
-
});
|
106
|
-
form.attr("action", origAction || "")
|
107
|
-
.attr("target", origTarget || "")
|
108
|
-
.attr("enctype", origEnctype || "");
|
109
|
-
iframe.attr("src", "javascript:false;").remove();
|
118
|
+
markers.prop('disabled', false);
|
119
|
+
form.remove();
|
120
|
+
iframe.bind("load", function() { iframe.remove(); });
|
121
|
+
iframe.attr("src", "javascript:false;");
|
110
122
|
}
|
111
123
|
|
112
124
|
// Remove "iframe" from the data types list so that further processing is
|
113
125
|
// based on the content type returned by the server, without attempting an
|
114
126
|
// (unsupported) conversion from "iframe" to the actual type.
|
115
127
|
options.dataTypes.shift();
|
116
|
-
|
128
|
+
|
117
129
|
if (files.length) {
|
118
|
-
|
119
|
-
|
120
|
-
files.each(function() {
|
121
|
-
if (form !== null && this.form !== form) {
|
122
|
-
jQuery.error("All file fields must belong to the same form");
|
123
|
-
}
|
124
|
-
form = this.form;
|
125
|
-
});
|
126
|
-
form = $(form);
|
127
|
-
|
128
|
-
// Store the original form attributes that we'll be replacing temporarily.
|
129
|
-
origAction = form.attr("action");
|
130
|
-
origTarget = form.attr("target");
|
131
|
-
origEnctype = form.attr("enctype");
|
132
|
-
|
133
|
-
// We need to disable all other inputs in the form so that they don't get
|
134
|
-
// included in the submitted data unexpectedly.
|
135
|
-
form.find(":input:not(:submit)").each(function() {
|
136
|
-
if (!this.disabled && (this.type != "file" || files.index(this) < 0)) {
|
137
|
-
this.disabled = true;
|
138
|
-
disabledFields.push(this);
|
139
|
-
}
|
140
|
-
});
|
130
|
+
form = $("<form enctype='multipart/form-data' method='post'></form>").
|
131
|
+
hide().attr({action: options.url, target: name});
|
141
132
|
|
142
133
|
// If there is any additional data specified via the `data` option,
|
143
134
|
// we add it as hidden fields to the form. This (currently) requires
|
144
135
|
// the `processData` option to be set to false so that the data doesn't
|
145
136
|
// get serialized to a string.
|
146
137
|
if (typeof(options.data) === "string" && options.data.length > 0) {
|
147
|
-
|
138
|
+
$.error("data must not be serialized");
|
148
139
|
}
|
149
140
|
$.each(options.data || {}, function(name, value) {
|
150
141
|
if ($.isPlainObject(value)) {
|
151
142
|
name = value.name;
|
152
143
|
value = value.value;
|
153
144
|
}
|
154
|
-
|
155
|
-
|
145
|
+
$("<input type='hidden' />").attr({name: name, value: value}).
|
146
|
+
appendTo(form);
|
156
147
|
});
|
157
148
|
|
158
149
|
// Add a hidden `X-Requested-With` field with the value `IFrame` to the
|
159
150
|
// field, to help server-side code to determine that the upload happened
|
160
151
|
// through this transport.
|
161
|
-
|
162
|
-
|
152
|
+
$("<input type='hidden' value='IFrame' name='X-Requested-With' />").
|
153
|
+
appendTo(form);
|
163
154
|
|
164
155
|
// Borrowed straight from the JQuery source
|
165
156
|
// Provides a way of specifying the accepted data type similar to HTTP_ACCEPTS
|
@@ -167,17 +158,26 @@
|
|
167
158
|
options.accepts[ options.dataTypes[0] ] + ( options.dataTypes[ 0 ] !== "*" ? ", */*; q=0.01" : "" ) :
|
168
159
|
options.accepts[ "*" ]
|
169
160
|
|
170
|
-
|
171
|
-
.attr("value", accepts).appendTo(form)
|
161
|
+
$("<input type='hidden' name='X-Http-Accept'>")
|
162
|
+
.attr("value", accepts).appendTo(form);
|
163
|
+
|
164
|
+
// Move the file fields into the hidden form, but first remember their
|
165
|
+
// original locations in the document by replacing them with disabled
|
166
|
+
// clones. This should also avoid introducing unwanted changes to the
|
167
|
+
// page layout during submission.
|
168
|
+
markers = files.after(function(idx) {
|
169
|
+
return $(this).clone().prop("disabled", true);
|
170
|
+
}).next();
|
171
|
+
files.appendTo(form);
|
172
172
|
|
173
173
|
return {
|
174
174
|
|
175
175
|
// The `send` function is called by jQuery when the request should be
|
176
176
|
// sent.
|
177
177
|
send: function(headers, completeCallback) {
|
178
|
-
iframe = $("<iframe src='javascript:false;' name='
|
179
|
-
+ "' style='display:none'></iframe>");
|
180
|
-
|
178
|
+
iframe = $("<iframe src='javascript:false;' name='" + name +
|
179
|
+
"' id='" + name + "' style='display:none'></iframe>");
|
180
|
+
|
181
181
|
// The first load event gets fired after the iframe has been injected
|
182
182
|
// into the DOM, and is used to prepare the actual submission.
|
183
183
|
iframe.bind("load", function() {
|
@@ -187,34 +187,36 @@
|
|
187
187
|
// actual payload is embedded in a `<textarea>` element, and
|
188
188
|
// prepares the required conversions to be made in that case.
|
189
189
|
iframe.unbind("load").bind("load", function() {
|
190
|
-
|
191
190
|
var doc = this.contentWindow ? this.contentWindow.document :
|
192
191
|
(this.contentDocument ? this.contentDocument : this.document),
|
193
192
|
root = doc.documentElement ? doc.documentElement : doc.body,
|
194
193
|
textarea = root.getElementsByTagName("textarea")[0],
|
195
|
-
type = textarea
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
194
|
+
type = textarea && textarea.getAttribute("data-type") || null,
|
195
|
+
status = textarea && textarea.getAttribute("data-status") || 200,
|
196
|
+
statusText = textarea && textarea.getAttribute("data-statusText") || "OK",
|
197
|
+
content = {
|
198
|
+
html: root.innerHTML,
|
199
|
+
text: type ?
|
200
|
+
textarea.value :
|
201
|
+
root ? (root.textContent || root.innerText) : null
|
202
|
+
};
|
203
|
+
cleanUp();
|
204
|
+
if (!jqXHR.responseText) {
|
205
|
+
jqXHR.responseText = content.text;
|
206
|
+
}
|
207
|
+
completeCallback(status, statusText, content, type ?
|
208
|
+
("Content-Type: " + type) :
|
209
|
+
null);
|
205
210
|
});
|
206
|
-
|
207
|
-
// Now that the load handler has been set up,
|
208
|
-
|
209
|
-
form.attr("action", options.url)
|
210
|
-
.attr("target", iframe.attr("name"))
|
211
|
-
.attr("enctype", "multipart/form-data")
|
212
|
-
.get(0).submit();
|
211
|
+
|
212
|
+
// Now that the load handler has been set up, submit the form.
|
213
|
+
form[0].submit();
|
213
214
|
});
|
214
215
|
|
215
|
-
// After everything has been set up correctly, the iframe
|
216
|
-
// injected into the DOM so that the submission can be
|
217
|
-
|
216
|
+
// After everything has been set up correctly, the form and iframe
|
217
|
+
// get injected into the DOM so that the submission can be
|
218
|
+
// initiated.
|
219
|
+
$("body").append(form, iframe);
|
218
220
|
},
|
219
221
|
|
220
222
|
// The `abort` function is called by jQuery when the request should be
|
@@ -8,6 +8,12 @@
|
|
8
8
|
$.remotipart = remotipart = {
|
9
9
|
|
10
10
|
setup: function(form) {
|
11
|
+
// Preserve form.data('ujs:submit-button') before it gets nulled by $.ajax.handleRemote
|
12
|
+
var button = form.data('ujs:submit-button'),
|
13
|
+
csrfParam = $('meta[name="csrf-param"]').attr('content'),
|
14
|
+
csrfToken = $('meta[name="csrf-token"]').attr('content'),
|
15
|
+
csrfInput = form.find('input[name="' + csrfParam + '"]').length;
|
16
|
+
|
11
17
|
form
|
12
18
|
// Allow setup part of $.rails.handleRemote to setup remote settings before canceling default remote handler
|
13
19
|
// This is required in order to change the remote settings using the form details
|
@@ -20,16 +26,33 @@
|
|
20
26
|
settings.iframe = true;
|
21
27
|
settings.files = $($.rails.fileInputSelector, form);
|
22
28
|
settings.data = form.serializeArray();
|
29
|
+
|
30
|
+
// Insert the name/value of the clicked submit button, if any
|
31
|
+
if (button)
|
32
|
+
settings.data.push(button);
|
33
|
+
|
34
|
+
// jQuery 1.9 serializeArray() contains input:file entries
|
35
|
+
// so exclude them from settings.data, otherwise files will not be sent
|
36
|
+
settings.files.each(function(i, file){
|
37
|
+
for (var j = settings.data.length - 1; j >= 0; j--)
|
38
|
+
if (settings.data[j].name == file.name)
|
39
|
+
settings.data.splice(j, 1);
|
40
|
+
})
|
41
|
+
|
23
42
|
settings.processData = false;
|
24
43
|
|
25
44
|
// Modify some settings to integrate JS request with rails helpers and middleware
|
26
45
|
if (settings.dataType === undefined) { settings.dataType = 'script *'; }
|
27
46
|
settings.data.push({name: 'remotipart_submitted', value: true});
|
47
|
+
if (csrfToken && csrfParam && !csrfInput) {
|
48
|
+
settings.data.push({name: csrfParam, value: csrfToken});
|
49
|
+
}
|
28
50
|
|
29
51
|
// Allow remotipartSubmit to be cancelled if needed
|
30
52
|
if ($.rails.fire(form, 'ajax:remotipartSubmit', [xhr, settings])) {
|
31
53
|
// Second verse, same as the first
|
32
54
|
$.rails.ajax(settings);
|
55
|
+
setTimeout(function(){ $.rails.disableFormElements(form); }, 20);
|
33
56
|
}
|
34
57
|
|
35
58
|
//Run cleanup
|
@@ -51,15 +74,11 @@
|
|
51
74
|
}
|
52
75
|
};
|
53
76
|
|
54
|
-
$(
|
77
|
+
$(document).on('ajax:aborted:file', 'form', function(){
|
55
78
|
var form = $(this);
|
56
79
|
|
57
80
|
remotipart.setup(form);
|
58
81
|
|
59
|
-
// If browser does not support submit bubbling, then this live-binding will be called before direct
|
60
|
-
// bindings. Therefore, we should directly call any direct bindings before remotely submitting form.
|
61
|
-
if (!$.support.submitBubbles && $.rails.callFormSubmitBindings(form) === false) return $.rails.stopEverything(e);
|
62
|
-
|
63
82
|
// Manually call jquery-ujs remote call so that it can setup form and settings as usual,
|
64
83
|
// and trigger the `ajax:beforeSend` callback to which remotipart binds functionality.
|
65
84
|
$.rails.handleRemote(form);
|
metadata
CHANGED
@@ -1,51 +1,56 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: remotipart
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
6
|
-
segments:
|
7
|
-
- 1
|
8
|
-
- 0
|
9
|
-
version: "1.0"
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.2.1
|
5
|
+
prerelease:
|
10
6
|
platform: ruby
|
11
|
-
authors:
|
7
|
+
authors:
|
12
8
|
- Greg Leppert
|
13
9
|
- Steve Schwartz
|
14
10
|
autorequire:
|
15
11
|
bindir: bin
|
16
12
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
13
|
+
date: 2013-07-08 00:00:00.000000000Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rake
|
17
|
+
requirement: &70170920954340 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :development
|
23
24
|
prerelease: false
|
24
|
-
|
25
|
+
version_requirements: *70170920954340
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: jeweler
|
28
|
+
requirement: &70170920953080 !ruby/object:Gem::Requirement
|
25
29
|
none: false
|
26
|
-
requirements:
|
27
|
-
- -
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
|
30
|
-
segments:
|
31
|
-
- 0
|
32
|
-
version: "0"
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
33
34
|
type: :development
|
34
|
-
|
35
|
-
|
36
|
-
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *70170920953080
|
37
|
+
description: ! "Remotipart is a Ruby on Rails gem enabling remote multipart forms
|
38
|
+
(AJAX style file uploads) with jquery-rails.\n This gem augments the native Rails
|
39
|
+
3 jQuery-UJS remote form function enabling asynchronous file uploads with little
|
40
|
+
to no modification to your application.\n "
|
41
|
+
email:
|
37
42
|
- greg@formasfunction.com
|
38
43
|
- steve@alfajango.com
|
39
44
|
executables: []
|
40
|
-
|
41
45
|
extensions: []
|
42
|
-
|
43
|
-
extra_rdoc_files:
|
46
|
+
extra_rdoc_files:
|
44
47
|
- LICENSE
|
45
48
|
- README.rdoc
|
46
|
-
files:
|
49
|
+
files:
|
47
50
|
- .document
|
48
|
-
- .
|
51
|
+
- CONTRIBUTING.md
|
52
|
+
- Gemfile
|
53
|
+
- Gemfile.lock
|
49
54
|
- History.rdoc
|
50
55
|
- LICENSE
|
51
56
|
- README.rdoc
|
@@ -62,44 +67,34 @@ files:
|
|
62
67
|
- lib/remotipart/request_helper.rb
|
63
68
|
- lib/remotipart/view_helper.rb
|
64
69
|
- remotipart.gemspec
|
65
|
-
- test/helper.rb
|
66
|
-
- test/test_remotipart.rb
|
67
70
|
- vendor/assets/javascripts/jquery.iframe-transport.js
|
68
71
|
- vendor/assets/javascripts/jquery.remotipart.js
|
69
|
-
|
70
|
-
homepage: http://www.alfajango.com/blog/remotipart-rails-gem/
|
72
|
+
homepage: http://opensource.alfajango.com/remotipart/
|
71
73
|
licenses: []
|
72
|
-
|
73
74
|
post_install_message:
|
74
|
-
rdoc_options:
|
75
|
-
|
76
|
-
require_paths:
|
75
|
+
rdoc_options: []
|
76
|
+
require_paths:
|
77
77
|
- lib
|
78
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
78
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
79
79
|
none: false
|
80
|
-
requirements:
|
81
|
-
- -
|
82
|
-
- !ruby/object:Gem::Version
|
83
|
-
|
84
|
-
segments:
|
80
|
+
requirements:
|
81
|
+
- - ! '>='
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
segments:
|
85
85
|
- 0
|
86
|
-
|
87
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
hash: -3061483236240277448
|
87
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
88
|
none: false
|
89
|
-
requirements:
|
90
|
-
- -
|
91
|
-
- !ruby/object:Gem::Version
|
92
|
-
|
93
|
-
segments:
|
94
|
-
- 0
|
95
|
-
version: "0"
|
89
|
+
requirements:
|
90
|
+
- - ! '>='
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
96
93
|
requirements: []
|
97
|
-
|
98
94
|
rubyforge_project:
|
99
|
-
rubygems_version: 1.
|
95
|
+
rubygems_version: 1.8.15
|
100
96
|
signing_key:
|
101
97
|
specification_version: 3
|
102
|
-
summary: Remotipart is a Ruby on Rails gem enabling remote multipart forms (AJAX style
|
103
|
-
|
104
|
-
|
105
|
-
- test/test_remotipart.rb
|
98
|
+
summary: Remotipart is a Ruby on Rails gem enabling remote multipart forms (AJAX style
|
99
|
+
file uploads) with jquery-rails.
|
100
|
+
test_files: []
|
data/.gitignore
DELETED
data/test/helper.rb
DELETED