jquery.unobtrusive-ajax.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /*!
  2. ** Unobtrusive Ajax support library for jQuery
  3. ** Copyright (C) Microsoft Corporation. All rights reserved.
  4. */
  5. /*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */
  6. /*global window: false, jQuery: false */
  7. (function ($) {
  8. var data_click = "unobtrusiveAjaxClick",
  9. data_validation = "unobtrusiveValidation";
  10. function getFunction(code, argNames) {
  11. var fn = window, parts = (code || "").split(".");
  12. while (fn && parts.length) {
  13. fn = fn[parts.shift()];
  14. }
  15. if (typeof (fn) === "function") {
  16. return fn;
  17. }
  18. argNames.push(code);
  19. return Function.constructor.apply(null, argNames);
  20. }
  21. function isMethodProxySafe(method) {
  22. return method === "GET" || method === "POST";
  23. }
  24. function asyncOnBeforeSend(xhr, method) {
  25. if (!isMethodProxySafe(method)) {
  26. xhr.setRequestHeader("X-HTTP-Method-Override", method);
  27. }
  28. }
  29. function asyncOnSuccess(element, data, contentType) {
  30. var mode;
  31. if (contentType.indexOf("application/x-javascript") !== -1) { // jQuery already executes JavaScript for us
  32. return;
  33. }
  34. mode = (element.getAttribute("data-ajax-mode") || "").toUpperCase();
  35. $(element.getAttribute("data-ajax-update")).each(function (i, update) {
  36. var top;
  37. switch (mode) {
  38. case "BEFORE":
  39. top = update.firstChild;
  40. $("<div />").html(data).contents().each(function () {
  41. update.insertBefore(this, top);
  42. });
  43. break;
  44. case "AFTER":
  45. $("<div />").html(data).contents().each(function () {
  46. update.appendChild(this);
  47. });
  48. break;
  49. default:
  50. $(update).html(data);
  51. break;
  52. }
  53. });
  54. }
  55. function asyncRequest(element, options) {
  56. var confirm, loading, method, duration;
  57. confirm = element.getAttribute("data-ajax-confirm");
  58. if (confirm && !window.confirm(confirm)) {
  59. return;
  60. }
  61. loading = $(element.getAttribute("data-ajax-loading"));
  62. duration = element.getAttribute("data-ajax-loading-duration") || 0;
  63. $.extend(options, {
  64. type: element.getAttribute("data-ajax-method") || undefined,
  65. url: element.getAttribute("data-ajax-url") || undefined,
  66. beforeSend: function (xhr) {
  67. var result;
  68. asyncOnBeforeSend(xhr, method);
  69. result = getFunction(element.getAttribute("data-ajax-begin"), ["xhr"]).apply(this, arguments);
  70. if (result !== false) {
  71. loading.show(duration);
  72. }
  73. return result;
  74. },
  75. complete: function () {
  76. loading.hide(duration);
  77. getFunction(element.getAttribute("data-ajax-complete"), ["xhr", "status"]).apply(this, arguments);
  78. },
  79. success: function (data, status, xhr) {
  80. asyncOnSuccess(element, data, xhr.getResponseHeader("Content-Type") || "text/html");
  81. getFunction(element.getAttribute("data-ajax-success"), ["data", "status", "xhr"]).apply(this, arguments);
  82. },
  83. error: getFunction(element.getAttribute("data-ajax-failure"), ["xhr", "status", "error"])
  84. });
  85. options.data.push({ name: "X-Requested-With", value: "XMLHttpRequest" });
  86. method = options.type.toUpperCase();
  87. if (!isMethodProxySafe(method)) {
  88. options.type = "POST";
  89. options.data.push({ name: "X-HTTP-Method-Override", value: method });
  90. }
  91. $.ajax(options);
  92. }
  93. function validate(form) {
  94. var validationInfo = $(form).data(data_validation);
  95. return !validationInfo || !validationInfo.validate || validationInfo.validate();
  96. }
  97. $("a[data-ajax=true]").live("click", function (evt) {
  98. evt.preventDefault();
  99. asyncRequest(this, {
  100. url: this.href,
  101. type: "GET",
  102. data: []
  103. });
  104. });
  105. $("form[data-ajax=true] input[type=image]").live("click", function (evt) {
  106. var name = evt.target.name,
  107. $target = $(evt.target),
  108. form = $target.parents("form")[0],
  109. offset = $target.offset();
  110. $(form).data(data_click, [
  111. { name: name + ".x", value: Math.round(evt.pageX - offset.left) },
  112. { name: name + ".y", value: Math.round(evt.pageY - offset.top) }
  113. ]);
  114. setTimeout(function () {
  115. $(form).removeData(data_click);
  116. }, 0);
  117. });
  118. $("form[data-ajax=true] :submit").live("click", function (evt) {
  119. var name = evt.target.name,
  120. form = $(evt.target).parents("form")[0];
  121. $(form).data(data_click, name ? [{ name: name, value: evt.target.value }] : []);
  122. setTimeout(function () {
  123. $(form).removeData(data_click);
  124. }, 0);
  125. });
  126. $("form[data-ajax=true]").live("submit", function (evt) {
  127. var clickInfo = $(this).data(data_click) || [];
  128. evt.preventDefault();
  129. if (!validate(this)) {
  130. return;
  131. }
  132. asyncRequest(this, {
  133. url: this.action,
  134. type: this.method || "GET",
  135. data: clickInfo.concat($(this).serializeArray())
  136. });
  137. });
  138. }(jQuery));