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.
@@ -1,5 +1,10 @@
1
1
  = History
2
2
 
3
+ === 1.1.0 / 2013-07-04
4
+
5
+ * Updated to latest iframe-transport.
6
+ * Added status-text to js response.
7
+
3
8
  === 1.0.5 / 2013-02-09
4
9
 
5
10
  * Fixed gem dependency info.
@@ -1,6 +1,6 @@
1
1
  module Remotipart
2
2
  module Rails
3
- VERSION = "1.0.5"
4
- IFRAMETRANSPORT_VERSION = "07.05.2011"
3
+ VERSION = "1.1.0"
4
+ IFRAMETRANSPORT_VERSION = "02.06.2013"
5
5
  end
6
6
  end
@@ -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}\" response-code=\"#{response.response_code}\">#{escape_once(response.body)}</textarea>}
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
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "remotipart"
8
- s.version = "1.0.5"
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-02-09"
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` to
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 a `iframe` option with the value `true`
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 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.
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 them
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
- // ### The Server Side
45
+ // ### Response Data Types
47
46
 
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
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 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"`.
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, 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 :)
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 transport if it is `true`.
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 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.
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
- origAction = null,
90
- origTarget = null,
91
- origEnctype = null,
92
- addedFields = [],
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
- $(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();
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
- // 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
- });
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
- jQuery.error("data must not be serialized");
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
- addedFields.push($("<input type='hidden'>").attr("name", name)
155
- .attr("value", value).appendTo(form));
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
- addedFields.push($("<input type='hidden' name='X-Requested-With'>")
162
- .attr("value", "IFrame").appendTo(form));
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
- addedFields.push($("<input type='hidden' name='X-Http-Accept'>")
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='iframe-" + $.now()
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 ? textarea.getAttribute("data-type") : null;
196
-
197
- var status = textarea ? parseInt(textarea.getAttribute("response-code")) : 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);
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, 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();
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 gets
216
- // injected into the DOM so that the submission can be initiated.
217
- iframe.insertAfter(form);
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
@@ -39,6 +39,7 @@
39
39
  if ($.rails.fire(form, 'ajax:remotipartSubmit', [xhr, settings])) {
40
40
  // Second verse, same as the first
41
41
  $.rails.ajax(settings);
42
+ setTimeout(function(){ $.rails.disableFormElements(form); }, 20);
42
43
  }
43
44
 
44
45
  //Run cleanup
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.5
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-02-09 00:00:00.000000000Z
13
+ date: 2013-07-05 00:00:00.000000000Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rake
17
- requirement: &70318770174740 !ruby/object:Gem::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: *70318770174740
25
+ version_requirements: *70284363199260
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: jeweler
28
- requirement: &70318770173180 !ruby/object:Gem::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: *70318770173180
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: -3595294083198888121
85
+ hash: 1233962955920476353
86
86
  required_rubygems_version: !ruby/object:Gem::Requirement
87
87
  none: false
88
88
  requirements: