remotipart 1.0.5 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: