remotipart 0.4.2 → 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/History.rdoc +8 -1
- data/README.rdoc +55 -33
- data/lib/generators/remotipart/install/install_generator.rb +4 -4
- data/lib/remotipart/middleware.rb +33 -0
- data/lib/remotipart/rails/engine.rb +5 -0
- data/lib/remotipart/rails/railtie.rb +6 -1
- data/lib/remotipart/rails/version.rb +2 -2
- data/lib/remotipart/render_overrides.rb +15 -0
- data/lib/remotipart/request_helper.rb +1 -0
- data/lib/remotipart/view_helper.rb +3 -7
- data/lib/remotipart.rb +2 -0
- data/remotipart.gemspec +4 -2
- data/vendor/assets/javascripts/jquery.iframe-transport.js +233 -0
- data/vendor/assets/javascripts/jquery.remotipart.js +25 -40
- metadata +6 -5
- data/vendor/assets/javascripts/jquery.form.js +0 -911
data/History.rdoc
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
= History
|
2
2
|
|
3
|
-
=== 0
|
3
|
+
=== 1.0 / 2011-08-26
|
4
|
+
|
5
|
+
* New Features
|
6
|
+
* New dependency on simpler jquery.iframe-transport.js (no more form.js)
|
7
|
+
* New Rack middleware, making `remotipart_response` block obsolete in js.erb responses
|
8
|
+
* Better support for all requested ajax data-types
|
9
|
+
|
10
|
+
=== 0.4.2 / 2011-08-26
|
4
11
|
|
5
12
|
* Minor Enhancements
|
6
13
|
* Updated to jquery.form.js v2.84
|
data/README.rdoc
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
= Remotipart
|
2
2
|
|
3
|
-
Remotipart is a Ruby on Rails gem enabling
|
4
|
-
This gem augments the native Rails jQuery remote form
|
3
|
+
Remotipart is a Ruby on Rails gem enabling AJAX file uploads with jQuery in Rails 3.0 and Rails 3.1 remote forms.
|
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/]
|
7
|
+
* {How AJAX File Uploads Work}[http://www.alfajango.com/blog/ajax-file-uploads-with-the-iframe-method/]
|
7
8
|
|
8
9
|
== Dependencies
|
9
10
|
|
@@ -12,24 +13,33 @@ This gem augments the native Rails jQuery remote form function enabling asynchro
|
|
12
13
|
|
13
14
|
== Installation
|
14
15
|
|
15
|
-
<b>
|
16
|
-
|
16
|
+
<b>Your app should be using jquery-rails gem v1.0.12 or above.</b>
|
17
|
+
|
18
|
+
If you're using an old version of the jquery-rails gem,
|
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].
|
17
20
|
|
18
21
|
[1.]
|
19
22
|
Install the Remotipart gem
|
20
23
|
|
21
|
-
* Add this line to your GEMFILE (
|
24
|
+
* Add this line to your GEMFILE (use the appropriate version from the compatibilty chart if needed)
|
22
25
|
|
23
|
-
gem 'remotipart', '~> 0
|
26
|
+
gem 'remotipart', '~> 1.0'
|
24
27
|
|
25
28
|
* And run
|
26
29
|
|
27
30
|
bundle install
|
28
31
|
|
32
|
+
=== Rails 3.1
|
33
|
+
|
34
|
+
[2.]
|
35
|
+
The necessary js files will automatically be added to the asset pipeline, so add the following to app/assets/javascripts/application.js (right after <tt>//= require jquery_ujs</tt>):
|
36
|
+
|
37
|
+
//= require jquery.remotipart
|
38
|
+
|
29
39
|
=== Rails 3.0
|
30
40
|
|
31
41
|
[2.]
|
32
|
-
Run the Remotipart install generator to add jquery.
|
42
|
+
Run the Remotipart install generator to add jquery.iframe-transport.js and jquery.remotipart.js to public/javascripts/
|
33
43
|
|
34
44
|
rails g remotipart:install
|
35
45
|
|
@@ -38,28 +48,12 @@ make sure you have a supported jquery-ujs (rails.js or jquery_ujs.js) version fr
|
|
38
48
|
|
39
49
|
<%= javascript_include_tag :defaults %>
|
40
50
|
|
41
|
-
=== Rails 3.1
|
42
|
-
|
43
|
-
[2.]
|
44
|
-
The necessary js files will automatically be added to the asset pipeline, so add the following to app/assets/javascripts/application.js (right after <tt>//= require jquery_ujs</tt>):
|
45
|
-
|
46
|
-
//= require jquery.form
|
47
|
-
//= require jquery.remotipart
|
48
|
-
|
49
51
|
== Usage
|
50
52
|
|
51
53
|
* For multipart / forms with file inputs, set your form_for to remote as you would for a normal ajax form:
|
52
54
|
:remote => true
|
53
55
|
* When Javascript is enabled in the user's browser, the form, including the file, will be submitted asynchronously to your controller with:
|
54
56
|
:format == 'js'
|
55
|
-
* In the JS response template for your controller action, wrap all of your response code in one remotipart_response block:
|
56
|
-
<%= remotipart_response do %> All Javascript response code goes here <% end %>
|
57
|
-
* The options available to the text_area_tag[http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html#method-i-text_area_tag] can be passed to remotipart_response for further control over the response. For instance:
|
58
|
-
<%= remotipart_response({:escape => false}) do %> All Javascript response code goes here <% end %>
|
59
|
-
* Anything inside the +remotipart_response+ block will be rendered normally, unless the request actually did come from a remotipart-submitted form. So <tt>js.erb</tt> responses can be shared between remotipart and non-remotipart forms.
|
60
|
-
<%= remotipart_response do %>
|
61
|
-
// do stuff here
|
62
|
-
<% end %>
|
63
57
|
* If you need to determine if a particular request was made via a remotipart-enabled form...
|
64
58
|
* from your Rails controller or view:
|
65
59
|
|
@@ -93,14 +87,12 @@ sample_controller.rb
|
|
93
87
|
end
|
94
88
|
|
95
89
|
create.js.erb
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
alert('submitted via native jquery-ujs')
|
103
|
-
<% end %>
|
90
|
+
// Display a Javascript alert
|
91
|
+
alert('success!');
|
92
|
+
<% if remotipart_submitted? %>
|
93
|
+
alert('submitted via remotipart')
|
94
|
+
<% else %>
|
95
|
+
alert('submitted via native jquery-ujs')
|
104
96
|
<% end %>
|
105
97
|
|
106
98
|
== Note on Patches/Pull Requests
|
@@ -115,6 +107,36 @@ create.js.erb
|
|
115
107
|
(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)
|
116
108
|
* Send me a pull request. Bonus points for topic branches.
|
117
109
|
|
110
|
+
== Tests
|
111
|
+
|
112
|
+
Because of the nature of AJAX file uploads and certain browser restrictions, we could not simply create unit tests (using qunit or jasmine)
|
113
|
+
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
|
114
|
+
upload input using javascript). So, instead we created a demo Rails app using remotipart with all remotipart functionality tested using RSpec and Capybara.
|
115
|
+
|
116
|
+
* {Demo Rails App with Tests}[https://github.com/JangoSteve/Rails-jQuery-Demo/tree/remotipart]
|
117
|
+
* {Tests}[https://github.com/JangoSteve/Rails-jQuery-Demo/blob/remotipart/spec/integration/comments_spec.rb]
|
118
|
+
|
119
|
+
To run tests:
|
120
|
+
|
121
|
+
Clone the remotipart branch of the demo app
|
122
|
+
git clone -b remotipart git://github.com/JangoSteve/Rails-jQuery-Demo.git
|
123
|
+
|
124
|
+
Install the dependencies
|
125
|
+
bundle install
|
126
|
+
|
127
|
+
Run the tests
|
128
|
+
bundle exec rspec spec/
|
129
|
+
|
130
|
+
If you need to test your own changes to remotipart, just update the Gemfile with your own fork/branch of remotipart:
|
131
|
+
|
132
|
+
gem 'remotipart', :git => 'git://github.com/MY_FORK/remotipart.git', :branch => 'MY_BRANCH'
|
133
|
+
|
134
|
+
== Special Thanks
|
135
|
+
|
136
|
+
Thank you to Greg Leppert for writing the original version of this gem and providing inspiration for the gem in its current incarnation.
|
137
|
+
|
138
|
+
Thank you to {Adam Kerr}[https://github.com/ajrkerr] for helping move over to the simpler jQuery 1.6-compatible iframe-transport.js and for helping write the rack middleware, making remotipart even easier to use in Rails.
|
139
|
+
|
118
140
|
== Copyright
|
119
141
|
|
120
|
-
Copyright (c) 2011
|
142
|
+
Copyright (c) 2011 {Steve Schwartz}[https://github.com/JangoSteve], {Greg Leppert}[https://github.com/leppert]. See LICENSE for details.
|
@@ -4,12 +4,12 @@ module Remotipart
|
|
4
4
|
module Generators
|
5
5
|
class InstallGenerator < ::Rails::Generators::Base
|
6
6
|
|
7
|
-
desc "This generator installs
|
7
|
+
desc "This generator installs IframeTransport.js #{Remotipart::Rails::IFRAMETRANSPORT_VERSION} and Remotipart #{Remotipart::Rails::VERSION}"
|
8
8
|
source_root File.expand_path('../../../../../vendor/assets/javascripts', __FILE__)
|
9
9
|
|
10
|
-
def
|
11
|
-
say_status "copying", "
|
12
|
-
copy_file "jquery.
|
10
|
+
def install_iframe_transport
|
11
|
+
say_status "copying", "IframeTransport.js #{Remotipart::Rails::IFRAMETRANSPORT_VERSION}", :green
|
12
|
+
copy_file "jquery.iframe-transport.js", "public/javascripts/jquery.iframe-transport.js"
|
13
13
|
end
|
14
14
|
|
15
15
|
def install_remotipart
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Remotipart
|
2
|
+
|
3
|
+
# A middleware to look for our form parameters and
|
4
|
+
# encourage Rails to respond with the requested format
|
5
|
+
class Middleware
|
6
|
+
def initialize app
|
7
|
+
@app = app
|
8
|
+
end
|
9
|
+
|
10
|
+
def call env
|
11
|
+
# For some reason, in Rails 3.0, `env['rack.request.form_hash']`
|
12
|
+
# isn't populated unless we manually initialize a new Rack::Request
|
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']
|
18
|
+
|
19
|
+
# This was using an iframe transport, and is therefore an XHR
|
20
|
+
# This is required if we're going to override the http_accept
|
21
|
+
if params and params['X-Requested-With'] == 'IFrame'
|
22
|
+
env['HTTP_X_REQUESTED_WITH'] = 'xmlhttprequest'
|
23
|
+
end
|
24
|
+
|
25
|
+
# Override the accepted format, because it isn't what we really want
|
26
|
+
if params and params['X-Http-Accept']
|
27
|
+
env['HTTP_ACCEPT'] = params['X-Http-Accept']
|
28
|
+
end
|
29
|
+
|
30
|
+
@app.call(env)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -10,6 +10,11 @@ module Remotipart
|
|
10
10
|
|
11
11
|
initializer "remotipart.controller_helper" do
|
12
12
|
ActionController::Base.send :include, RequestHelper
|
13
|
+
ActionController::Base.send :include, RenderOverrides
|
14
|
+
end
|
15
|
+
|
16
|
+
initializer "remotipart.include_middelware" do
|
17
|
+
config.app_middleware.insert_after ActionDispatch::ParamsParser, Middleware
|
13
18
|
end
|
14
19
|
end
|
15
20
|
|
@@ -5,7 +5,7 @@ module Remotipart
|
|
5
5
|
class Railtie < ::Rails::Railtie
|
6
6
|
config.before_configuration do
|
7
7
|
# Files to be added to :defaults
|
8
|
-
FILES = ['jquery.
|
8
|
+
FILES = ['jquery.iframe-transport', 'jquery.remotipart']
|
9
9
|
|
10
10
|
# Figure out where rails.js (aka jquery_ujs.js if install by jquery-rails gem) is
|
11
11
|
# in the :defaults array
|
@@ -29,6 +29,11 @@ module Remotipart
|
|
29
29
|
|
30
30
|
initializer "remotipart.controller_helper" do
|
31
31
|
ActionController::Base.send :include, RequestHelper
|
32
|
+
ActionController::Base.send :include, RenderOverrides
|
33
|
+
end
|
34
|
+
|
35
|
+
initializer "remotipart.include_middelware" do
|
36
|
+
config.app_middleware.insert_after ActionDispatch::ParamsParser, Middleware
|
32
37
|
end
|
33
38
|
end
|
34
39
|
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Remotipart
|
2
|
+
|
3
|
+
#Responder used to automagically wrap any non-xml replies in a text-area
|
4
|
+
# as expected by iframe-transport
|
5
|
+
module RenderOverrides
|
6
|
+
def render *args
|
7
|
+
super
|
8
|
+
if remotipart_submitted?
|
9
|
+
response.body = %{<textarea data-type=\"#{content_type}\">#{response.body}</textarea>}
|
10
|
+
response.content_type = Mime::HTML
|
11
|
+
end
|
12
|
+
response_body
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -1,13 +1,9 @@
|
|
1
1
|
module Remotipart
|
2
2
|
module ViewHelper
|
3
|
+
#No longer used
|
4
|
+
#Retrained to prevent issues while updating
|
3
5
|
def remotipart_response(options = {}, &block)
|
4
|
-
|
5
|
-
if remotipart_submitted?
|
6
|
-
response.content_type = Mime::HTML
|
7
|
-
text_area_tag('remotipart_response', String.new(content), options)
|
8
|
-
else
|
9
|
-
content
|
10
|
-
end
|
6
|
+
with_output_buffer(&block)
|
11
7
|
end
|
12
8
|
end
|
13
9
|
end
|
data/lib/remotipart.rb
CHANGED
data/remotipart.gemspec
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{remotipart}
|
8
|
-
s.version = "0
|
8
|
+
s.version = "1.0"
|
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"]
|
@@ -28,16 +28,18 @@ Gem::Specification.new do |s|
|
|
28
28
|
"VERSION_COMPATIBILITY.rdoc",
|
29
29
|
"lib/generators/remotipart/install/install_generator.rb",
|
30
30
|
"lib/remotipart.rb",
|
31
|
+
"lib/remotipart/middleware.rb",
|
31
32
|
"lib/remotipart/rails.rb",
|
32
33
|
"lib/remotipart/rails/engine.rb",
|
33
34
|
"lib/remotipart/rails/railtie.rb",
|
34
35
|
"lib/remotipart/rails/version.rb",
|
36
|
+
"lib/remotipart/render_overrides.rb",
|
35
37
|
"lib/remotipart/request_helper.rb",
|
36
38
|
"lib/remotipart/view_helper.rb",
|
37
39
|
"remotipart.gemspec",
|
38
40
|
"test/helper.rb",
|
39
41
|
"test/test_remotipart.rb",
|
40
|
-
"vendor/assets/javascripts/jquery.
|
42
|
+
"vendor/assets/javascripts/jquery.iframe-transport.js",
|
41
43
|
"vendor/assets/javascripts/jquery.remotipart.js"
|
42
44
|
]
|
43
45
|
s.homepage = %q{http://www.alfajango.com/blog/remotipart-rails-gem/}
|
@@ -0,0 +1,233 @@
|
|
1
|
+
// This [jQuery](http://jquery.com/) plugin implements an `<iframe>`
|
2
|
+
// [transport](http://api.jquery.com/extending-ajax/#Transports) so that
|
3
|
+
// `$.ajax()` calls support the uploading of files using standard HTML file
|
4
|
+
// input fields. This is done by switching the exchange from `XMLHttpRequest` to
|
5
|
+
// a hidden `iframe` element containing a form that is submitted.
|
6
|
+
|
7
|
+
// The [source for the plugin](http://github.com/cmlenz/jquery-iframe-transport)
|
8
|
+
// is available on [Github](http://github.com/) and dual licensed under the MIT
|
9
|
+
// or GPL Version 2 licenses.
|
10
|
+
|
11
|
+
// ## Usage
|
12
|
+
|
13
|
+
// To use this plugin, you simply add a `iframe` option with the value `true`
|
14
|
+
// to the Ajax settings an `$.ajax()` call, and specify the file fields to
|
15
|
+
// include in the submssion using the `files` option, which can be a selector,
|
16
|
+
// jQuery object, or a list of DOM elements containing one or more
|
17
|
+
// `<input type="file">` elements:
|
18
|
+
|
19
|
+
// $("#myform").submit(function() {
|
20
|
+
// $.ajax(this.action, {
|
21
|
+
// files: $(":file", this),
|
22
|
+
// iframe: true
|
23
|
+
// }).complete(function(data) {
|
24
|
+
// console.log(data);
|
25
|
+
// });
|
26
|
+
// });
|
27
|
+
|
28
|
+
// The plugin will construct a hidden `<iframe>` element containing a copy of
|
29
|
+
// the form the file field belongs to, will disable any form fields not
|
30
|
+
// explicitly included, submit that form, and process the response.
|
31
|
+
|
32
|
+
// If you want to include other form fields in the form submission, include them
|
33
|
+
// in the `data` option, and set the `processData` option to `false`:
|
34
|
+
|
35
|
+
// $("#myform").submit(function() {
|
36
|
+
// $.ajax(this.action, {
|
37
|
+
// data: $(":text", this).serializeArray(),
|
38
|
+
// files: $(":file", this),
|
39
|
+
// iframe: true,
|
40
|
+
// processData: false
|
41
|
+
// }).complete(function(data) {
|
42
|
+
// console.log(data);
|
43
|
+
// });
|
44
|
+
// });
|
45
|
+
|
46
|
+
// ### The Server Side
|
47
|
+
|
48
|
+
// If the response is not HTML or XML, you (unfortunately) need to apply some
|
49
|
+
// trickery on the server side. To send back a JSON payload, send back an HTML
|
50
|
+
// `<textarea>` element with a `data-type` attribute that contains the MIME
|
51
|
+
// type, and put the actual payload in the textarea:
|
52
|
+
|
53
|
+
// <textarea data-type="application/json">
|
54
|
+
// {"ok": true, "message": "Thanks so much"}
|
55
|
+
// </textarea>
|
56
|
+
|
57
|
+
// The iframe transport plugin will detect this and attempt to apply the same
|
58
|
+
// conversions that jQuery applies to regular responses. That means for the
|
59
|
+
// example above you should get a Javascript object as the `data` parameter of
|
60
|
+
// the `complete` callback, with the properties `ok: true` and
|
61
|
+
// `message: "Thanks so much"`.
|
62
|
+
|
63
|
+
// ### Compatibility
|
64
|
+
|
65
|
+
// This plugin has primarily been tested on Safari 5, Firefox 4, and Internet
|
66
|
+
// Explorer all the way back to version 6. While I haven't found any issues with
|
67
|
+
// it so far, I'm fairly sure it still doesn't work around all the quirks in all
|
68
|
+
// different browsers. But the code is still pretty simple overall, so you
|
69
|
+
// should be able to fix it and contribute a patch :)
|
70
|
+
|
71
|
+
// ## Annotated Source
|
72
|
+
|
73
|
+
(function($, undefined) {
|
74
|
+
|
75
|
+
// Register a prefilter that checks whether the `iframe` option is set, and
|
76
|
+
// switches to the iframe transport if it is `true`.
|
77
|
+
$.ajaxPrefilter(function(options, origOptions, jqXHR) {
|
78
|
+
if (options.iframe) {
|
79
|
+
return "iframe";
|
80
|
+
}
|
81
|
+
});
|
82
|
+
|
83
|
+
// Register an iframe transport, independent of requested data type. It will
|
84
|
+
// only activate when the "files" option has been set to a non-empty list of
|
85
|
+
// enabled file inputs.
|
86
|
+
$.ajaxTransport("iframe", function(options, origOptions, jqXHR) {
|
87
|
+
var form = null,
|
88
|
+
iframe = null,
|
89
|
+
origAction = null,
|
90
|
+
origTarget = null,
|
91
|
+
origEnctype = null,
|
92
|
+
addedFields = [],
|
93
|
+
disabledFields = [],
|
94
|
+
files = $(options.files).filter(":file:enabled");
|
95
|
+
|
96
|
+
// This function gets called after a successful submission or an abortion
|
97
|
+
// and should revert all changes made to the page to enable the
|
98
|
+
// submission via this transport.
|
99
|
+
function cleanUp() {
|
100
|
+
$(addedFields).each(function() {
|
101
|
+
this.remove();
|
102
|
+
});
|
103
|
+
$(disabledFields).each(function() {
|
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();
|
110
|
+
}
|
111
|
+
|
112
|
+
// Remove "iframe" from the data types list so that further processing is
|
113
|
+
// based on the content type returned by the server, without attempting an
|
114
|
+
// (unsupported) conversion from "iframe" to the actual type.
|
115
|
+
options.dataTypes.shift();
|
116
|
+
|
117
|
+
if (files.length) {
|
118
|
+
// Determine the form the file fields belong to, and make sure they all
|
119
|
+
// actually belong to the same form.
|
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
|
+
});
|
141
|
+
|
142
|
+
// If there is any additional data specified via the `data` option,
|
143
|
+
// we add it as hidden fields to the form. This (currently) requires
|
144
|
+
// the `processData` option to be set to false so that the data doesn't
|
145
|
+
// get serialized to a string.
|
146
|
+
if (typeof(options.data) === "string" && options.data.length > 0) {
|
147
|
+
jQuery.error("data must not be serialized");
|
148
|
+
}
|
149
|
+
$.each(options.data || {}, function(name, value) {
|
150
|
+
if ($.isPlainObject(value)) {
|
151
|
+
name = value.name;
|
152
|
+
value = value.value;
|
153
|
+
}
|
154
|
+
addedFields.push($("<input type='hidden'>").attr("name", name)
|
155
|
+
.attr("value", value).appendTo(form));
|
156
|
+
});
|
157
|
+
|
158
|
+
// Add a hidden `X-Requested-With` field with the value `IFrame` to the
|
159
|
+
// field, to help server-side code to determine that the upload happened
|
160
|
+
// through this transport.
|
161
|
+
addedFields.push($("<input type='hidden' name='X-Requested-With'>")
|
162
|
+
.attr("value", "IFrame").appendTo(form));
|
163
|
+
|
164
|
+
// Borrowed straight from the JQuery source
|
165
|
+
// Provides a way of specifying the accepted data type similar to HTTP_ACCEPTS
|
166
|
+
accepts = options.dataTypes[ 0 ] && options.accepts[ options.dataTypes[0] ] ?
|
167
|
+
options.accepts[ options.dataTypes[0] ] + ( options.dataTypes[ 0 ] !== "*" ? ", */*; q=0.01" : "" ) :
|
168
|
+
options.accepts[ "*" ]
|
169
|
+
|
170
|
+
addedFields.push($("<input type='hidden' name='X-Http-Accept'>")
|
171
|
+
.attr("value", accepts).appendTo(form));
|
172
|
+
|
173
|
+
return {
|
174
|
+
|
175
|
+
// The `send` function is called by jQuery when the request should be
|
176
|
+
// sent.
|
177
|
+
send: function(headers, completeCallback) {
|
178
|
+
iframe = $("<iframe src='javascript:false;' name='iframe-" + $.now()
|
179
|
+
+ "' style='display:none'></iframe>");
|
180
|
+
|
181
|
+
// The first load event gets fired after the iframe has been injected
|
182
|
+
// into the DOM, and is used to prepare the actual submission.
|
183
|
+
iframe.bind("load", function() {
|
184
|
+
|
185
|
+
// The second load event gets fired when the response to the form
|
186
|
+
// submission is received. The implementation detects whether the
|
187
|
+
// actual payload is embedded in a `<textarea>` element, and
|
188
|
+
// prepares the required conversions to be made in that case.
|
189
|
+
iframe.unbind("load").bind("load", function() {
|
190
|
+
|
191
|
+
var doc = this.contentWindow ? this.contentWindow.document :
|
192
|
+
(this.contentDocument ? this.contentDocument : this.document),
|
193
|
+
root = doc.documentElement ? doc.documentElement : doc.body,
|
194
|
+
textarea = root.getElementsByTagName("textarea")[0],
|
195
|
+
type = textarea ? textarea.getAttribute("data-type") : null;
|
196
|
+
|
197
|
+
var status = 200,
|
198
|
+
statusText = "OK",
|
199
|
+
responses = { text: type ? textarea.value : root ? root.innerHTML : null },
|
200
|
+
headers = "Content-Type: " + (type || "text/html")
|
201
|
+
|
202
|
+
completeCallback(status, statusText, responses, headers);
|
203
|
+
|
204
|
+
setTimeout(cleanUp, 50);
|
205
|
+
});
|
206
|
+
|
207
|
+
// Now that the load handler has been set up, reconfigure and
|
208
|
+
// submit the form.
|
209
|
+
form.attr("action", options.url)
|
210
|
+
.attr("target", iframe.attr("name"))
|
211
|
+
.attr("enctype", "multipart/form-data")
|
212
|
+
.get(0).submit();
|
213
|
+
});
|
214
|
+
|
215
|
+
// After everything has been set up correctly, the iframe gets
|
216
|
+
// injected into the DOM so that the submission can be initiated.
|
217
|
+
iframe.insertAfter(form);
|
218
|
+
},
|
219
|
+
|
220
|
+
// The `abort` function is called by jQuery when the request should be
|
221
|
+
// aborted.
|
222
|
+
abort: function() {
|
223
|
+
if (iframe !== null) {
|
224
|
+
iframe.unbind("load").attr("src", "javascript:false;");
|
225
|
+
cleanUp();
|
226
|
+
}
|
227
|
+
}
|
228
|
+
|
229
|
+
};
|
230
|
+
}
|
231
|
+
});
|
232
|
+
|
233
|
+
})(jQuery);
|