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