jquery.iframe-transport.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /*
  2. * jQuery Iframe Transport Plugin 1.3
  3. * https://github.com/blueimp/jQuery-File-Upload
  4. *
  5. * Copyright 2011, Sebastian Tschan
  6. * https://blueimp.net
  7. *
  8. * Licensed under the MIT license:
  9. * http://www.opensource.org/licenses/MIT
  10. */
  11. /*jslint unparam: true, nomen: true */
  12. /*global define, window, document */
  13. (function (factory) {
  14. 'use strict';
  15. if (typeof define === 'function' && define.amd) {
  16. // Register as an anonymous AMD module:
  17. define(['jquery'], factory);
  18. } else {
  19. // Browser globals:
  20. factory(window.jQuery);
  21. }
  22. }(function ($) {
  23. 'use strict';
  24. // Helper variable to create unique names for the transport iframes:
  25. var counter = 0;
  26. // The iframe transport accepts three additional options:
  27. // options.fileInput: a jQuery collection of file input fields
  28. // options.paramName: the parameter name for the file form data,
  29. // overrides the name property of the file input field(s)
  30. // options.formData: an array of objects with name and value properties,
  31. // equivalent to the return data of .serializeArray(), e.g.:
  32. // [{name: 'a', value: 1}, {name: 'b', value: 2}]
  33. $.ajaxTransport('iframe', function (options) {
  34. if (options.async && (options.type === 'POST' || options.type === 'GET')) {
  35. var form,
  36. iframe;
  37. return {
  38. send: function (_, completeCallback) {
  39. form = $('<form style="display:none;"></form>');
  40. // javascript:false as initial iframe src
  41. // prevents warning popups on HTTPS in IE6.
  42. // IE versions below IE8 cannot set the name property of
  43. // elements that have already been added to the DOM,
  44. // so we set the name along with the iframe HTML markup:
  45. iframe = $(
  46. '<iframe src="javascript:false;" name="iframe-transport-' +
  47. (counter += 1) + '"></iframe>'
  48. ).bind('load', function () {
  49. var fileInputClones;
  50. iframe
  51. .unbind('load')
  52. .bind('load', function () {
  53. var response;
  54. // Wrap in a try/catch block to catch exceptions thrown
  55. // when trying to access cross-domain iframe contents:
  56. try {
  57. response = iframe.contents();
  58. // Google Chrome and Firefox do not throw an
  59. // exception when calling iframe.contents() on
  60. // cross-domain requests, so we unify the response:
  61. if (!response.length || !response[0].firstChild) {
  62. throw new Error();
  63. }
  64. } catch (e) {
  65. response = undefined;
  66. }
  67. // The complete callback returns the
  68. // iframe content document as response object:
  69. completeCallback(
  70. 200,
  71. 'success',
  72. {'iframe': response}
  73. );
  74. // Fix for IE endless progress bar activity bug
  75. // (happens on form submits to iframe targets):
  76. $('<iframe src="javascript:false;"></iframe>')
  77. .appendTo(form);
  78. form.remove();
  79. });
  80. form
  81. .prop('target', iframe.prop('name'))
  82. .prop('action', options.url)
  83. .prop('method', options.type);
  84. if (options.formData) {
  85. $.each(options.formData, function (index, field) {
  86. $('<input type="hidden"/>')
  87. .prop('name', field.name)
  88. .val(field.value)
  89. .appendTo(form);
  90. });
  91. }
  92. if (options.fileInput && options.fileInput.length &&
  93. options.type === 'POST') {
  94. fileInputClones = options.fileInput.clone();
  95. // Insert a clone for each file input field:
  96. options.fileInput.after(function (index) {
  97. return fileInputClones[index];
  98. });
  99. if (options.paramName) {
  100. options.fileInput.each(function () {
  101. $(this).prop('name', options.paramName);
  102. });
  103. }
  104. // Appending the file input fields to the hidden form
  105. // removes them from their original location:
  106. form
  107. .append(options.fileInput)
  108. .prop('enctype', 'multipart/form-data')
  109. // enctype must be set as encoding for IE:
  110. .prop('encoding', 'multipart/form-data');
  111. }
  112. form.submit();
  113. // Insert the file input fields at their original location
  114. // by replacing the clones with the originals:
  115. if (fileInputClones && fileInputClones.length) {
  116. options.fileInput.each(function (index, input) {
  117. var clone = $(fileInputClones[index]);
  118. $(input).prop('name', clone.prop('name'));
  119. clone.replaceWith(input);
  120. });
  121. }
  122. });
  123. form.append(iframe).appendTo(document.body);
  124. },
  125. abort: function () {
  126. if (iframe) {
  127. // javascript:false as iframe src aborts the request
  128. // and prevents warning popups on HTTPS in IE6.
  129. // concat is used to avoid the "Script URL" JSLint error:
  130. iframe
  131. .unbind('load')
  132. .prop('src', 'javascript'.concat(':false;'));
  133. }
  134. if (form) {
  135. form.remove();
  136. }
  137. }
  138. };
  139. }
  140. });
  141. // The iframe transport returns the iframe content document as response.
  142. // The following adds converters from iframe to text, json, html, and script:
  143. $.ajaxSetup({
  144. converters: {
  145. 'iframe text': function (iframe) {
  146. return $(iframe[0].body).text();
  147. },
  148. 'iframe json': function (iframe) {
  149. return $.parseJSON($(iframe[0].body).text());
  150. },
  151. 'iframe html': function (iframe) {
  152. return $(iframe[0].body).html();
  153. },
  154. 'iframe script': function (iframe) {
  155. return $.globalEval($(iframe[0].body).text());
  156. }
  157. }
  158. });
  159. }));