remotipart 1.0.5 → 1.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
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:
|