remotipart 1.0.5 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
data/History.rdoc
CHANGED
@@ -13,7 +13,7 @@ module Remotipart
|
|
13
13
|
def render_with_remotipart *args
|
14
14
|
render_without_remotipart *args
|
15
15
|
if remotipart_submitted?
|
16
|
-
response.body = %{<textarea data-type=\"#{content_type}\"
|
16
|
+
response.body = %{<textarea data-type=\"#{response.content_type}\" data-status=\"#{response.response_code}\" data-statusText=\"#{response.message}\">#{response.body}</textarea>}
|
17
17
|
response.content_type = Mime::HTML
|
18
18
|
end
|
19
19
|
response_body
|
data/remotipart.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "remotipart"
|
8
|
-
s.version = "1.0
|
8
|
+
s.version = "1.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"]
|
12
|
-
s.date = "2013-
|
12
|
+
s.date = "2013-07-05"
|
13
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 "
|
14
14
|
s.email = ["greg@formasfunction.com", "steve@alfajango.com"]
|
15
15
|
s.extra_rdoc_files = [
|
@@ -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,70 +42,83 @@
|
|
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
|
@@ -115,51 +127,30 @@
|
|
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,16 +158,25 @@
|
|
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>");
|
178
|
+
iframe = $("<iframe src='javascript:false;' name='" + name +
|
179
|
+
"' id='" + name + "' style='display:none'></iframe>");
|
180
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.
|
@@ -187,34 +187,33 @@
|
|
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
|
+
completeCallback(status, statusText, content, type ?
|
205
|
+
("Content-Type: " + type) :
|
206
|
+
null);
|
205
207
|
});
|
206
208
|
|
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();
|
209
|
+
// Now that the load handler has been set up, submit the form.
|
210
|
+
form[0].submit();
|
213
211
|
});
|
214
212
|
|
215
|
-
// After everything has been set up correctly, the iframe
|
216
|
-
// injected into the DOM so that the submission can be
|
217
|
-
|
213
|
+
// After everything has been set up correctly, the form and iframe
|
214
|
+
// get injected into the DOM so that the submission can be
|
215
|
+
// initiated.
|
216
|
+
$("body").append(form, iframe);
|
218
217
|
},
|
219
218
|
|
220
219
|
// The `abort` function is called by jQuery when the request should be
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: remotipart
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,11 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2013-
|
13
|
+
date: 2013-07-05 00:00:00.000000000Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rake
|
17
|
-
requirement: &
|
17
|
+
requirement: &70284363199260 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: '0'
|
23
23
|
type: :development
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *70284363199260
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: jeweler
|
28
|
-
requirement: &
|
28
|
+
requirement: &70284363198060 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ! '>='
|
@@ -33,7 +33,7 @@ dependencies:
|
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *70284363198060
|
37
37
|
description: ! "Remotipart is a Ruby on Rails gem enabling remote multipart forms
|
38
38
|
(AJAX style file uploads) with jquery-rails.\n This gem augments the native Rails
|
39
39
|
3 jQuery-UJS remote form function enabling asynchronous file uploads with little
|
@@ -82,7 +82,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
82
82
|
version: '0'
|
83
83
|
segments:
|
84
84
|
- 0
|
85
|
-
hash:
|
85
|
+
hash: 1233962955920476353
|
86
86
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
87
|
none: false
|
88
88
|
requirements:
|