ajax-form.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. function replaceDocument(docString) {
  2. var doc = document.open("text/html");
  3. doc.write(docString);
  4. doc.close();
  5. }
  6. function doAjaxSubmit(e) {
  7. var form = $(this);
  8. var btn = $(this.clk);
  9. var method = (
  10. btn.data('method') ||
  11. form.data('method') ||
  12. form.attr('method') || 'GET'
  13. ).toUpperCase();
  14. if (method === 'GET') {
  15. // GET requests can always use standard form submits.
  16. return;
  17. }
  18. var contentType =
  19. form.find('input[data-override="content-type"]').val() ||
  20. form.find('select[data-override="content-type"] option:selected').text();
  21. if (method === 'POST' && !contentType) {
  22. // POST requests can use standard form submits, unless we have
  23. // overridden the content type.
  24. return;
  25. }
  26. // At this point we need to make an AJAX form submission.
  27. e.preventDefault();
  28. var url = form.attr('action');
  29. var data;
  30. if (contentType) {
  31. data = form.find('[data-override="content"]').val() || ''
  32. if (contentType === 'multipart/form-data') {
  33. // We need to add a boundary parameter to the header
  34. // We assume the first valid-looking boundary line in the body is correct
  35. // regex is from RFC 2046 appendix A
  36. var boundaryCharNoSpace = "0-9A-Z'()+_,-./:=?";
  37. var boundaryChar = boundaryCharNoSpace + ' ';
  38. var re = new RegExp('^--([' + boundaryChar + ']{0,69}[' + boundaryCharNoSpace + '])[\\s]*?$', 'im');
  39. var boundary = data.match(re);
  40. if (boundary !== null) {
  41. contentType += '; boundary="' + boundary[1] + '"';
  42. }
  43. // Fix textarea.value EOL normalisation (multipart/form-data should use CR+NL, not NL)
  44. data = data.replace(/\n/g, '\r\n');
  45. }
  46. } else {
  47. contentType = form.attr('enctype') || form.attr('encoding')
  48. if (contentType === 'multipart/form-data') {
  49. if (!window.FormData) {
  50. alert('Your browser does not support AJAX multipart form submissions');
  51. return;
  52. }
  53. // Use the FormData API and allow the content type to be set automatically,
  54. // so it includes the boundary string.
  55. // See https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects
  56. contentType = false;
  57. data = new FormData(form[0]);
  58. } else {
  59. contentType = 'application/x-www-form-urlencoded; charset=UTF-8'
  60. data = form.serialize();
  61. }
  62. }
  63. var ret = $.ajax({
  64. url: url,
  65. method: method,
  66. data: data,
  67. contentType: contentType,
  68. processData: false,
  69. headers: {
  70. 'Accept': 'text/html; q=1.0, */*'
  71. },
  72. });
  73. ret.always(function(data, textStatus, jqXHR) {
  74. if (textStatus != 'success') {
  75. jqXHR = data;
  76. }
  77. var responseContentType = jqXHR.getResponseHeader("content-type") || "";
  78. if (responseContentType.toLowerCase().indexOf('text/html') === 0) {
  79. replaceDocument(jqXHR.responseText);
  80. try {
  81. // Modify the location and scroll to top, as if after page load.
  82. history.replaceState({}, '', url);
  83. scroll(0, 0);
  84. } catch (err) {
  85. // History API not supported, so redirect.
  86. window.location = url;
  87. }
  88. } else {
  89. // Not HTML content. We can't open this directly, so redirect.
  90. window.location = url;
  91. }
  92. });
  93. return ret;
  94. }
  95. function captureSubmittingElement(e) {
  96. var target = e.target;
  97. var form = this;
  98. form.clk = target;
  99. }
  100. $.fn.ajaxForm = function() {
  101. var options = {}
  102. return this
  103. .unbind('submit.form-plugin click.form-plugin')
  104. .bind('submit.form-plugin', options, doAjaxSubmit)
  105. .bind('click.form-plugin', options, captureSubmittingElement);
  106. };