rev |
line source |
bos@574
|
1 /*
|
bos@574
|
2 * jQuery Form Plugin
|
bos@574
|
3 * @requires jQuery v1.1 or later
|
bos@574
|
4 *
|
bos@574
|
5 * Examples at: http://malsup.com/jquery/form/
|
bos@574
|
6 * Dual licensed under the MIT and GPL licenses:
|
bos@574
|
7 * http://www.opensource.org/licenses/mit-license.php
|
bos@574
|
8 * http://www.gnu.org/licenses/gpl.html
|
bos@574
|
9 *
|
bos@574
|
10 * Revision: $Id$
|
bos@574
|
11 */
|
bos@574
|
12 (function($) {
|
bos@574
|
13 /**
|
bos@574
|
14 * ajaxSubmit() provides a mechanism for submitting an HTML form using AJAX.
|
bos@574
|
15 *
|
bos@574
|
16 * ajaxSubmit accepts a single argument which can be either a success callback function
|
bos@574
|
17 * or an options Object. If a function is provided it will be invoked upon successful
|
bos@574
|
18 * completion of the submit and will be passed the response from the server.
|
bos@574
|
19 * If an options Object is provided, the following attributes are supported:
|
bos@574
|
20 *
|
bos@574
|
21 * target: Identifies the element(s) in the page to be updated with the server response.
|
bos@574
|
22 * This value may be specified as a jQuery selection string, a jQuery object,
|
bos@574
|
23 * or a DOM element.
|
bos@574
|
24 * default value: null
|
bos@574
|
25 *
|
bos@574
|
26 * url: URL to which the form data will be submitted.
|
bos@574
|
27 * default value: value of form's 'action' attribute
|
bos@574
|
28 *
|
bos@574
|
29 * type: The method in which the form data should be submitted, 'GET' or 'POST'.
|
bos@574
|
30 * default value: value of form's 'method' attribute (or 'GET' if none found)
|
bos@574
|
31 *
|
bos@574
|
32 * data: Additional data to add to the request, specified as key/value pairs (see $.ajax).
|
bos@574
|
33 *
|
bos@574
|
34 * beforeSubmit: Callback method to be invoked before the form is submitted.
|
bos@574
|
35 * default value: null
|
bos@574
|
36 *
|
bos@574
|
37 * success: Callback method to be invoked after the form has been successfully submitted
|
bos@574
|
38 * and the response has been returned from the server
|
bos@574
|
39 * default value: null
|
bos@574
|
40 *
|
bos@574
|
41 * dataType: Expected dataType of the response. One of: null, 'xml', 'script', or 'json'
|
bos@574
|
42 * default value: null
|
bos@574
|
43 *
|
bos@574
|
44 * semantic: Boolean flag indicating whether data must be submitted in semantic order (slower).
|
bos@574
|
45 * default value: false
|
bos@574
|
46 *
|
bos@574
|
47 * resetForm: Boolean flag indicating whether the form should be reset if the submit is successful
|
bos@574
|
48 *
|
bos@574
|
49 * clearForm: Boolean flag indicating whether the form should be cleared if the submit is successful
|
bos@574
|
50 *
|
bos@574
|
51 *
|
bos@574
|
52 * The 'beforeSubmit' callback can be provided as a hook for running pre-submit logic or for
|
bos@574
|
53 * validating the form data. If the 'beforeSubmit' callback returns false then the form will
|
bos@574
|
54 * not be submitted. The 'beforeSubmit' callback is invoked with three arguments: the form data
|
bos@574
|
55 * in array format, the jQuery object, and the options object passed into ajaxSubmit.
|
bos@574
|
56 * The form data array takes the following form:
|
bos@574
|
57 *
|
bos@574
|
58 * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
|
bos@574
|
59 *
|
bos@574
|
60 * If a 'success' callback method is provided it is invoked after the response has been returned
|
bos@574
|
61 * from the server. It is passed the responseText or responseXML value (depending on dataType).
|
bos@574
|
62 * See jQuery.ajax for further details.
|
bos@574
|
63 *
|
bos@574
|
64 *
|
bos@574
|
65 * The dataType option provides a means for specifying how the server response should be handled.
|
bos@574
|
66 * This maps directly to the jQuery.httpData method. The following values are supported:
|
bos@574
|
67 *
|
bos@574
|
68 * 'xml': if dataType == 'xml' the server response is treated as XML and the 'success'
|
bos@574
|
69 * callback method, if specified, will be passed the responseXML value
|
bos@574
|
70 * 'json': if dataType == 'json' the server response will be evaluted and passed to
|
bos@574
|
71 * the 'success' callback, if specified
|
bos@574
|
72 * 'script': if dataType == 'script' the server response is evaluated in the global context
|
bos@574
|
73 *
|
bos@574
|
74 *
|
bos@574
|
75 * Note that it does not make sense to use both the 'target' and 'dataType' options. If both
|
bos@574
|
76 * are provided the target will be ignored.
|
bos@574
|
77 *
|
bos@574
|
78 * The semantic argument can be used to force form serialization in semantic order.
|
bos@574
|
79 * This is normally true anyway, unless the form contains input elements of type='image'.
|
bos@574
|
80 * If your form must be submitted with name/value pairs in semantic order and your form
|
bos@574
|
81 * contains an input of type='image" then pass true for this arg, otherwise pass false
|
bos@574
|
82 * (or nothing) to avoid the overhead for this logic.
|
bos@574
|
83 *
|
bos@574
|
84 *
|
bos@574
|
85 * When used on its own, ajaxSubmit() is typically bound to a form's submit event like this:
|
bos@574
|
86 *
|
bos@574
|
87 * $("#form-id").submit(function() {
|
bos@574
|
88 * $(this).ajaxSubmit(options);
|
bos@574
|
89 * return false; // cancel conventional submit
|
bos@574
|
90 * });
|
bos@574
|
91 *
|
bos@574
|
92 * When using ajaxForm(), however, this is done for you.
|
bos@574
|
93 *
|
bos@574
|
94 * @example
|
bos@574
|
95 * $('#myForm').ajaxSubmit(function(data) {
|
bos@574
|
96 * alert('Form submit succeeded! Server returned: ' + data);
|
bos@574
|
97 * });
|
bos@574
|
98 * @desc Submit form and alert server response
|
bos@574
|
99 *
|
bos@574
|
100 *
|
bos@574
|
101 * @example
|
bos@574
|
102 * var options = {
|
bos@574
|
103 * target: '#myTargetDiv'
|
bos@574
|
104 * };
|
bos@574
|
105 * $('#myForm').ajaxSubmit(options);
|
bos@574
|
106 * @desc Submit form and update page element with server response
|
bos@574
|
107 *
|
bos@574
|
108 *
|
bos@574
|
109 * @example
|
bos@574
|
110 * var options = {
|
bos@574
|
111 * success: function(responseText) {
|
bos@574
|
112 * alert(responseText);
|
bos@574
|
113 * }
|
bos@574
|
114 * };
|
bos@574
|
115 * $('#myForm').ajaxSubmit(options);
|
bos@574
|
116 * @desc Submit form and alert the server response
|
bos@574
|
117 *
|
bos@574
|
118 *
|
bos@574
|
119 * @example
|
bos@574
|
120 * var options = {
|
bos@574
|
121 * beforeSubmit: function(formArray, jqForm) {
|
bos@574
|
122 * if (formArray.length == 0) {
|
bos@574
|
123 * alert('Please enter data.');
|
bos@574
|
124 * return false;
|
bos@574
|
125 * }
|
bos@574
|
126 * }
|
bos@574
|
127 * };
|
bos@574
|
128 * $('#myForm').ajaxSubmit(options);
|
bos@574
|
129 * @desc Pre-submit validation which aborts the submit operation if form data is empty
|
bos@574
|
130 *
|
bos@574
|
131 *
|
bos@574
|
132 * @example
|
bos@574
|
133 * var options = {
|
bos@574
|
134 * url: myJsonUrl.php,
|
bos@574
|
135 * dataType: 'json',
|
bos@574
|
136 * success: function(data) {
|
bos@574
|
137 * // 'data' is an object representing the the evaluated json data
|
bos@574
|
138 * }
|
bos@574
|
139 * };
|
bos@574
|
140 * $('#myForm').ajaxSubmit(options);
|
bos@574
|
141 * @desc json data returned and evaluated
|
bos@574
|
142 *
|
bos@574
|
143 *
|
bos@574
|
144 * @example
|
bos@574
|
145 * var options = {
|
bos@574
|
146 * url: myXmlUrl.php,
|
bos@574
|
147 * dataType: 'xml',
|
bos@574
|
148 * success: function(responseXML) {
|
bos@574
|
149 * // responseXML is XML document object
|
bos@574
|
150 * var data = $('myElement', responseXML).text();
|
bos@574
|
151 * }
|
bos@574
|
152 * };
|
bos@574
|
153 * $('#myForm').ajaxSubmit(options);
|
bos@574
|
154 * @desc XML data returned from server
|
bos@574
|
155 *
|
bos@574
|
156 *
|
bos@574
|
157 * @example
|
bos@574
|
158 * var options = {
|
bos@574
|
159 * resetForm: true
|
bos@574
|
160 * };
|
bos@574
|
161 * $('#myForm').ajaxSubmit(options);
|
bos@574
|
162 * @desc submit form and reset it if successful
|
bos@574
|
163 *
|
bos@574
|
164 * @example
|
bos@574
|
165 * $('#myForm).submit(function() {
|
bos@574
|
166 * $(this).ajaxSubmit();
|
bos@574
|
167 * return false;
|
bos@574
|
168 * });
|
bos@574
|
169 * @desc Bind form's submit event to use ajaxSubmit
|
bos@574
|
170 *
|
bos@574
|
171 *
|
bos@574
|
172 * @name ajaxSubmit
|
bos@574
|
173 * @type jQuery
|
bos@574
|
174 * @param options object literal containing options which control the form submission process
|
bos@574
|
175 * @cat Plugins/Form
|
bos@574
|
176 * @return jQuery
|
bos@574
|
177 */
|
bos@574
|
178 $.fn.ajaxSubmit = function(options) {
|
bos@574
|
179 if (typeof options == 'function')
|
bos@574
|
180 options = { success: options };
|
bos@574
|
181
|
bos@574
|
182 options = $.extend({
|
bos@574
|
183 url: this.attr('action') || window.location,
|
bos@574
|
184 type: this.attr('method') || 'GET'
|
bos@574
|
185 }, options || {});
|
bos@574
|
186
|
bos@574
|
187 // hook for manipulating the form data before it is extracted;
|
bos@574
|
188 // convenient for use with rich editors like tinyMCE or FCKEditor
|
bos@574
|
189 var veto = {};
|
bos@574
|
190 $.event.trigger('form.pre.serialize', [this, options, veto]);
|
bos@574
|
191 if (veto.veto) return this;
|
bos@574
|
192
|
bos@574
|
193 var a = this.formToArray(options.semantic);
|
bos@574
|
194 if (options.data) {
|
bos@574
|
195 for (var n in options.data)
|
bos@574
|
196 a.push( { name: n, value: options.data[n] } );
|
bos@574
|
197 }
|
bos@574
|
198
|
bos@574
|
199 // give pre-submit callback an opportunity to abort the submit
|
bos@574
|
200 if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) return this;
|
bos@574
|
201
|
bos@574
|
202 // fire vetoable 'validate' event
|
bos@574
|
203 $.event.trigger('form.submit.validate', [a, this, options, veto]);
|
bos@574
|
204 if (veto.veto) return this;
|
bos@574
|
205
|
bos@574
|
206 var q = $.param(a);//.replace(/%20/g,'+');
|
bos@574
|
207
|
bos@574
|
208 if (options.type.toUpperCase() == 'GET') {
|
bos@574
|
209 options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
|
bos@574
|
210 options.data = null; // data is null for 'get'
|
bos@574
|
211 }
|
bos@574
|
212 else
|
bos@574
|
213 options.data = q; // data is the query string for 'post'
|
bos@574
|
214
|
bos@574
|
215 var $form = this, callbacks = [];
|
bos@574
|
216 if (options.resetForm) callbacks.push(function() { $form.resetForm(); });
|
bos@574
|
217 if (options.clearForm) callbacks.push(function() { $form.clearForm(); });
|
bos@574
|
218
|
bos@574
|
219 // perform a load on the target only if dataType is not provided
|
bos@574
|
220 if (!options.dataType && options.target) {
|
bos@574
|
221 var oldSuccess = options.success || function(){};
|
bos@574
|
222 callbacks.push(function(data) {
|
bos@574
|
223 if (this.evalScripts)
|
bos@574
|
224 $(options.target).attr("innerHTML", data).evalScripts().each(oldSuccess, arguments);
|
bos@574
|
225 else // jQuery v1.1.4
|
bos@574
|
226 $(options.target).html(data).each(oldSuccess, arguments);
|
bos@574
|
227 });
|
bos@574
|
228 }
|
bos@574
|
229 else if (options.success)
|
bos@574
|
230 callbacks.push(options.success);
|
bos@574
|
231
|
bos@574
|
232 options.success = function(data, status) {
|
bos@574
|
233 for (var i=0, max=callbacks.length; i < max; i++)
|
bos@574
|
234 callbacks[i](data, status, $form);
|
bos@574
|
235 };
|
bos@574
|
236
|
bos@574
|
237 // are there files to upload?
|
bos@574
|
238 var files = $('input:file', this).fieldValue();
|
bos@574
|
239 var found = false;
|
bos@574
|
240 for (var j=0; j < files.length; j++)
|
bos@574
|
241 if (files[j])
|
bos@574
|
242 found = true;
|
bos@574
|
243
|
bos@574
|
244 if (options.iframe || found) // options.iframe allows user to force iframe mode
|
bos@574
|
245 fileUpload();
|
bos@574
|
246 else
|
bos@574
|
247 $.ajax(options);
|
bos@574
|
248
|
bos@574
|
249 // fire 'notify' event
|
bos@574
|
250 $.event.trigger('form.submit.notify', [this, options]);
|
bos@574
|
251 return this;
|
bos@574
|
252
|
bos@574
|
253
|
bos@574
|
254 // private function for handling file uploads (hat tip to YAHOO!)
|
bos@574
|
255 function fileUpload() {
|
bos@574
|
256 var form = $form[0];
|
bos@574
|
257 var opts = $.extend({}, $.ajaxSettings, options);
|
bos@574
|
258
|
bos@574
|
259 var id = 'jqFormIO' + $.fn.ajaxSubmit.counter++;
|
bos@574
|
260 var $io = $('<iframe id="' + id + '" name="' + id + '" />');
|
bos@574
|
261 var io = $io[0];
|
bos@574
|
262 var op8 = $.browser.opera && window.opera.version() < 9;
|
bos@574
|
263 if ($.browser.msie || op8) io.src = 'javascript:false;document.write("");';
|
bos@574
|
264 $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
|
bos@574
|
265
|
bos@574
|
266 var xhr = { // mock object
|
bos@574
|
267 responseText: null,
|
bos@574
|
268 responseXML: null,
|
bos@574
|
269 status: 0,
|
bos@574
|
270 statusText: 'n/a',
|
bos@574
|
271 getAllResponseHeaders: function() {},
|
bos@574
|
272 getResponseHeader: function() {},
|
bos@574
|
273 setRequestHeader: function() {}
|
bos@574
|
274 };
|
bos@574
|
275
|
bos@574
|
276 var g = opts.global;
|
bos@574
|
277 // trigger ajax global events so that activity/block indicators work like normal
|
bos@574
|
278 if (g && ! $.active++) $.event.trigger("ajaxStart");
|
bos@574
|
279 if (g) $.event.trigger("ajaxSend", [xhr, opts]);
|
bos@574
|
280
|
bos@574
|
281 var cbInvoked = 0;
|
bos@574
|
282 var timedOut = 0;
|
bos@574
|
283
|
bos@574
|
284 // take a breath so that pending repaints get some cpu time before the upload starts
|
bos@574
|
285 setTimeout(function() {
|
bos@574
|
286 $io.appendTo('body');
|
bos@574
|
287 // jQuery's event binding doesn't work for iframe events in IE
|
bos@574
|
288 io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
|
bos@574
|
289
|
bos@574
|
290 // make sure form attrs are set
|
bos@574
|
291 var encAttr = form.encoding ? 'encoding' : 'enctype';
|
bos@574
|
292 var t = $form.attr('target');
|
bos@574
|
293 $form.attr({
|
bos@574
|
294 target: id,
|
bos@574
|
295 method: 'POST',
|
bos@574
|
296 action: opts.url
|
bos@574
|
297 });
|
bos@574
|
298 form[encAttr] = 'multipart/form-data';
|
bos@574
|
299
|
bos@574
|
300 // support timout
|
bos@574
|
301 if (opts.timeout)
|
bos@574
|
302 setTimeout(function() { timedOut = true; cb(); }, opts.timeout);
|
bos@574
|
303
|
bos@574
|
304 form.submit();
|
bos@574
|
305 $form.attr('target', t); // reset target
|
bos@574
|
306 }, 10);
|
bos@574
|
307
|
bos@574
|
308 function cb() {
|
bos@574
|
309 if (cbInvoked++) return;
|
bos@574
|
310
|
bos@574
|
311 io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);
|
bos@574
|
312
|
bos@574
|
313 var ok = true;
|
bos@574
|
314 try {
|
bos@574
|
315 if (timedOut) throw 'timeout';
|
bos@574
|
316 // extract the server response from the iframe
|
bos@574
|
317 var data, doc;
|
bos@574
|
318 doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
|
bos@574
|
319 xhr.responseText = doc.body ? doc.body.innerHTML : null;
|
bos@574
|
320 xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
|
bos@574
|
321
|
bos@574
|
322 if (opts.dataType == 'json' || opts.dataType == 'script') {
|
bos@574
|
323 var ta = doc.getElementsByTagName('textarea')[0];
|
bos@574
|
324 data = ta ? ta.value : xhr.responseText;
|
bos@574
|
325 if (opts.dataType == 'json')
|
bos@574
|
326 eval("data = " + data);
|
bos@574
|
327 else
|
bos@574
|
328 $.globalEval(data);
|
bos@574
|
329 }
|
bos@574
|
330 else if (opts.dataType == 'xml') {
|
bos@574
|
331 data = xhr.responseXML;
|
bos@574
|
332 if (!data && xhr.responseText != null)
|
bos@574
|
333 data = toXml(xhr.responseText);
|
bos@574
|
334 }
|
bos@574
|
335 else {
|
bos@574
|
336 data = xhr.responseText;
|
bos@574
|
337 }
|
bos@574
|
338 }
|
bos@574
|
339 catch(e){
|
bos@574
|
340 ok = false;
|
bos@574
|
341 $.handleError(opts, xhr, 'error', e);
|
bos@574
|
342 }
|
bos@574
|
343
|
bos@574
|
344 // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
|
bos@574
|
345 if (ok) {
|
bos@574
|
346 opts.success(data, 'success');
|
bos@574
|
347 if (g) $.event.trigger("ajaxSuccess", [xhr, opts]);
|
bos@574
|
348 }
|
bos@574
|
349 if (g) $.event.trigger("ajaxComplete", [xhr, opts]);
|
bos@574
|
350 if (g && ! --$.active) $.event.trigger("ajaxStop");
|
bos@574
|
351 if (opts.complete) opts.complete(xhr, ok ? 'success' : 'error');
|
bos@574
|
352
|
bos@574
|
353 // clean up
|
bos@574
|
354 setTimeout(function() {
|
bos@574
|
355 $io.remove();
|
bos@574
|
356 xhr.responseXML = null;
|
bos@574
|
357 }, 100);
|
bos@574
|
358 };
|
bos@574
|
359
|
bos@574
|
360 function toXml(s, doc) {
|
bos@574
|
361 if (window.ActiveXObject) {
|
bos@574
|
362 doc = new ActiveXObject('Microsoft.XMLDOM');
|
bos@574
|
363 doc.async = 'false';
|
bos@574
|
364 doc.loadXML(s);
|
bos@574
|
365 }
|
bos@574
|
366 else
|
bos@574
|
367 doc = (new DOMParser()).parseFromString(s, 'text/xml');
|
bos@574
|
368 return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null;
|
bos@574
|
369 };
|
bos@574
|
370 };
|
bos@574
|
371 };
|
bos@574
|
372 $.fn.ajaxSubmit.counter = 0; // used to create unique iframe ids
|
bos@574
|
373
|
bos@574
|
374 /**
|
bos@574
|
375 * ajaxForm() provides a mechanism for fully automating form submission.
|
bos@574
|
376 *
|
bos@574
|
377 * The advantages of using this method instead of ajaxSubmit() are:
|
bos@574
|
378 *
|
bos@574
|
379 * 1: This method will include coordinates for <input type="image" /> elements (if the element
|
bos@574
|
380 * is used to submit the form).
|
bos@574
|
381 * 2. This method will include the submit element's name/value data (for the element that was
|
bos@574
|
382 * used to submit the form).
|
bos@574
|
383 * 3. This method binds the submit() method to the form for you.
|
bos@574
|
384 *
|
bos@574
|
385 * Note that for accurate x/y coordinates of image submit elements in all browsers
|
bos@574
|
386 * you need to also use the "dimensions" plugin (this method will auto-detect its presence).
|
bos@574
|
387 *
|
bos@574
|
388 * The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely
|
bos@574
|
389 * passes the options argument along after properly binding events for submit elements and
|
bos@574
|
390 * the form itself. See ajaxSubmit for a full description of the options argument.
|
bos@574
|
391 *
|
bos@574
|
392 *
|
bos@574
|
393 * @example
|
bos@574
|
394 * var options = {
|
bos@574
|
395 * target: '#myTargetDiv'
|
bos@574
|
396 * };
|
bos@574
|
397 * $('#myForm').ajaxSForm(options);
|
bos@574
|
398 * @desc Bind form's submit event so that 'myTargetDiv' is updated with the server response
|
bos@574
|
399 * when the form is submitted.
|
bos@574
|
400 *
|
bos@574
|
401 *
|
bos@574
|
402 * @example
|
bos@574
|
403 * var options = {
|
bos@574
|
404 * success: function(responseText) {
|
bos@574
|
405 * alert(responseText);
|
bos@574
|
406 * }
|
bos@574
|
407 * };
|
bos@574
|
408 * $('#myForm').ajaxSubmit(options);
|
bos@574
|
409 * @desc Bind form's submit event so that server response is alerted after the form is submitted.
|
bos@574
|
410 *
|
bos@574
|
411 *
|
bos@574
|
412 * @example
|
bos@574
|
413 * var options = {
|
bos@574
|
414 * beforeSubmit: function(formArray, jqForm) {
|
bos@574
|
415 * if (formArray.length == 0) {
|
bos@574
|
416 * alert('Please enter data.');
|
bos@574
|
417 * return false;
|
bos@574
|
418 * }
|
bos@574
|
419 * }
|
bos@574
|
420 * };
|
bos@574
|
421 * $('#myForm').ajaxSubmit(options);
|
bos@574
|
422 * @desc Bind form's submit event so that pre-submit callback is invoked before the form
|
bos@574
|
423 * is submitted.
|
bos@574
|
424 *
|
bos@574
|
425 *
|
bos@574
|
426 * @name ajaxForm
|
bos@574
|
427 * @param options object literal containing options which control the form submission process
|
bos@574
|
428 * @return jQuery
|
bos@574
|
429 * @cat Plugins/Form
|
bos@574
|
430 * @type jQuery
|
bos@574
|
431 */
|
bos@574
|
432 $.fn.ajaxForm = function(options) {
|
bos@574
|
433 return this.ajaxFormUnbind().submit(submitHandler).each(function() {
|
bos@574
|
434 // store options in hash
|
bos@574
|
435 this.formPluginId = $.fn.ajaxForm.counter++;
|
bos@574
|
436 $.fn.ajaxForm.optionHash[this.formPluginId] = options;
|
bos@574
|
437 $(":submit,input:image", this).click(clickHandler);
|
bos@574
|
438 });
|
bos@574
|
439 };
|
bos@574
|
440
|
bos@574
|
441 $.fn.ajaxForm.counter = 1;
|
bos@574
|
442 $.fn.ajaxForm.optionHash = {};
|
bos@574
|
443
|
bos@574
|
444 function clickHandler(e) {
|
bos@574
|
445 var $form = this.form;
|
bos@574
|
446 $form.clk = this;
|
bos@574
|
447 if (this.type == 'image') {
|
bos@574
|
448 if (e.offsetX != undefined) {
|
bos@574
|
449 $form.clk_x = e.offsetX;
|
bos@574
|
450 $form.clk_y = e.offsetY;
|
bos@574
|
451 } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
|
bos@574
|
452 var offset = $(this).offset();
|
bos@574
|
453 $form.clk_x = e.pageX - offset.left;
|
bos@574
|
454 $form.clk_y = e.pageY - offset.top;
|
bos@574
|
455 } else {
|
bos@574
|
456 $form.clk_x = e.pageX - this.offsetLeft;
|
bos@574
|
457 $form.clk_y = e.pageY - this.offsetTop;
|
bos@574
|
458 }
|
bos@574
|
459 }
|
bos@574
|
460 // clear form vars
|
bos@574
|
461 setTimeout(function() { $form.clk = $form.clk_x = $form.clk_y = null; }, 10);
|
bos@574
|
462 };
|
bos@574
|
463
|
bos@574
|
464 function submitHandler() {
|
bos@574
|
465 // retrieve options from hash
|
bos@574
|
466 var id = this.formPluginId;
|
bos@574
|
467 var options = $.fn.ajaxForm.optionHash[id];
|
bos@574
|
468 $(this).ajaxSubmit(options);
|
bos@574
|
469 return false;
|
bos@574
|
470 };
|
bos@574
|
471
|
bos@574
|
472 /**
|
bos@574
|
473 * ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
|
bos@574
|
474 *
|
bos@574
|
475 * @name ajaxFormUnbind
|
bos@574
|
476 * @return jQuery
|
bos@574
|
477 * @cat Plugins/Form
|
bos@574
|
478 * @type jQuery
|
bos@574
|
479 */
|
bos@574
|
480 $.fn.ajaxFormUnbind = function() {
|
bos@574
|
481 this.unbind('submit', submitHandler);
|
bos@574
|
482 return this.each(function() {
|
bos@574
|
483 $(":submit,input:image", this).unbind('click', clickHandler);
|
bos@574
|
484 });
|
bos@574
|
485
|
bos@574
|
486 };
|
bos@574
|
487
|
bos@574
|
488 /**
|
bos@574
|
489 * formToArray() gathers form element data into an array of objects that can
|
bos@574
|
490 * be passed to any of the following ajax functions: $.get, $.post, or load.
|
bos@574
|
491 * Each object in the array has both a 'name' and 'value' property. An example of
|
bos@574
|
492 * an array for a simple login form might be:
|
bos@574
|
493 *
|
bos@574
|
494 * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
|
bos@574
|
495 *
|
bos@574
|
496 * It is this array that is passed to pre-submit callback functions provided to the
|
bos@574
|
497 * ajaxSubmit() and ajaxForm() methods.
|
bos@574
|
498 *
|
bos@574
|
499 * The semantic argument can be used to force form serialization in semantic order.
|
bos@574
|
500 * This is normally true anyway, unless the form contains input elements of type='image'.
|
bos@574
|
501 * If your form must be submitted with name/value pairs in semantic order and your form
|
bos@574
|
502 * contains an input of type='image" then pass true for this arg, otherwise pass false
|
bos@574
|
503 * (or nothing) to avoid the overhead for this logic.
|
bos@574
|
504 *
|
bos@574
|
505 * @example var data = $("#myForm").formToArray();
|
bos@574
|
506 * $.post( "myscript.cgi", data );
|
bos@574
|
507 * @desc Collect all the data from a form and submit it to the server.
|
bos@574
|
508 *
|
bos@574
|
509 * @name formToArray
|
bos@574
|
510 * @param semantic true if serialization must maintain strict semantic ordering of elements (slower)
|
bos@574
|
511 * @type Array<Object>
|
bos@574
|
512 * @cat Plugins/Form
|
bos@574
|
513 */
|
bos@574
|
514 $.fn.formToArray = function(semantic) {
|
bos@574
|
515 var a = [];
|
bos@574
|
516 if (this.length == 0) return a;
|
bos@574
|
517
|
bos@574
|
518 var form = this[0];
|
bos@574
|
519 var els = semantic ? form.getElementsByTagName('*') : form.elements;
|
bos@574
|
520 if (!els) return a;
|
bos@574
|
521 for(var i=0, max=els.length; i < max; i++) {
|
bos@574
|
522 var el = els[i];
|
bos@574
|
523 var n = el.name;
|
bos@574
|
524 if (!n) continue;
|
bos@574
|
525
|
bos@574
|
526 if (semantic && form.clk && el.type == "image") {
|
bos@574
|
527 // handle image inputs on the fly when semantic == true
|
bos@574
|
528 if(!el.disabled && form.clk == el)
|
bos@574
|
529 a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
|
bos@574
|
530 continue;
|
bos@574
|
531 }
|
bos@574
|
532
|
bos@574
|
533 var v = $.fieldValue(el, true);
|
bos@574
|
534 if (v && v.constructor == Array) {
|
bos@574
|
535 for(var j=0, jmax=v.length; j < jmax; j++)
|
bos@574
|
536 a.push({name: n, value: v[j]});
|
bos@574
|
537 }
|
bos@574
|
538 else if (v !== null && typeof v != 'undefined')
|
bos@574
|
539 a.push({name: n, value: v});
|
bos@574
|
540 }
|
bos@574
|
541
|
bos@574
|
542 if (!semantic && form.clk) {
|
bos@574
|
543 // input type=='image' are not found in elements array! handle them here
|
bos@574
|
544 var inputs = form.getElementsByTagName("input");
|
bos@574
|
545 for(var i=0, max=inputs.length; i < max; i++) {
|
bos@574
|
546 var input = inputs[i];
|
bos@574
|
547 var n = input.name;
|
bos@574
|
548 if(n && !input.disabled && input.type == "image" && form.clk == input)
|
bos@574
|
549 a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
|
bos@574
|
550 }
|
bos@574
|
551 }
|
bos@574
|
552 return a;
|
bos@574
|
553 };
|
bos@574
|
554
|
bos@574
|
555
|
bos@574
|
556 /**
|
bos@574
|
557 * Serializes form data into a 'submittable' string. This method will return a string
|
bos@574
|
558 * in the format: name1=value1&name2=value2
|
bos@574
|
559 *
|
bos@574
|
560 * The semantic argument can be used to force form serialization in semantic order.
|
bos@574
|
561 * If your form must be submitted with name/value pairs in semantic order then pass
|
bos@574
|
562 * true for this arg, otherwise pass false (or nothing) to avoid the overhead for
|
bos@574
|
563 * this logic (which can be significant for very large forms).
|
bos@574
|
564 *
|
bos@574
|
565 * @example var data = $("#myForm").formSerialize();
|
bos@574
|
566 * $.ajax('POST', "myscript.cgi", data);
|
bos@574
|
567 * @desc Collect all the data from a form into a single string
|
bos@574
|
568 *
|
bos@574
|
569 * @name formSerialize
|
bos@574
|
570 * @param semantic true if serialization must maintain strict semantic ordering of elements (slower)
|
bos@574
|
571 * @type String
|
bos@574
|
572 * @cat Plugins/Form
|
bos@574
|
573 */
|
bos@574
|
574 $.fn.formSerialize = function(semantic) {
|
bos@574
|
575 //hand off to jQuery.param for proper encoding
|
bos@574
|
576 return $.param(this.formToArray(semantic));
|
bos@574
|
577 };
|
bos@574
|
578
|
bos@574
|
579
|
bos@574
|
580 /**
|
bos@574
|
581 * Serializes all field elements in the jQuery object into a query string.
|
bos@574
|
582 * This method will return a string in the format: name1=value1&name2=value2
|
bos@574
|
583 *
|
bos@574
|
584 * The successful argument controls whether or not serialization is limited to
|
bos@574
|
585 * 'successful' controls (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
|
bos@574
|
586 * The default value of the successful argument is true.
|
bos@574
|
587 *
|
bos@574
|
588 * @example var data = $("input").formSerialize();
|
bos@574
|
589 * @desc Collect the data from all successful input elements into a query string
|
bos@574
|
590 *
|
bos@574
|
591 * @example var data = $(":radio").formSerialize();
|
bos@574
|
592 * @desc Collect the data from all successful radio input elements into a query string
|
bos@574
|
593 *
|
bos@574
|
594 * @example var data = $("#myForm :checkbox").formSerialize();
|
bos@574
|
595 * @desc Collect the data from all successful checkbox input elements in myForm into a query string
|
bos@574
|
596 *
|
bos@574
|
597 * @example var data = $("#myForm :checkbox").formSerialize(false);
|
bos@574
|
598 * @desc Collect the data from all checkbox elements in myForm (even the unchecked ones) into a query string
|
bos@574
|
599 *
|
bos@574
|
600 * @example var data = $(":input").formSerialize();
|
bos@574
|
601 * @desc Collect the data from all successful input, select, textarea and button elements into a query string
|
bos@574
|
602 *
|
bos@574
|
603 * @name fieldSerialize
|
bos@574
|
604 * @param successful true if only successful controls should be serialized (default is true)
|
bos@574
|
605 * @type String
|
bos@574
|
606 * @cat Plugins/Form
|
bos@574
|
607 */
|
bos@574
|
608 $.fn.fieldSerialize = function(successful) {
|
bos@574
|
609 var a = [];
|
bos@574
|
610 this.each(function() {
|
bos@574
|
611 var n = this.name;
|
bos@574
|
612 if (!n) return;
|
bos@574
|
613 var v = $.fieldValue(this, successful);
|
bos@574
|
614 if (v && v.constructor == Array) {
|
bos@574
|
615 for (var i=0,max=v.length; i < max; i++)
|
bos@574
|
616 a.push({name: n, value: v[i]});
|
bos@574
|
617 }
|
bos@574
|
618 else if (v !== null && typeof v != 'undefined')
|
bos@574
|
619 a.push({name: this.name, value: v});
|
bos@574
|
620 });
|
bos@574
|
621 //hand off to jQuery.param for proper encoding
|
bos@574
|
622 return $.param(a);
|
bos@574
|
623 };
|
bos@574
|
624
|
bos@574
|
625
|
bos@574
|
626 /**
|
bos@574
|
627 * Returns the value(s) of the element in the matched set. For example, consider the following form:
|
bos@574
|
628 *
|
bos@574
|
629 * <form><fieldset>
|
bos@574
|
630 * <input name="A" type="text" />
|
bos@574
|
631 * <input name="A" type="text" />
|
bos@574
|
632 * <input name="B" type="checkbox" value="B1" />
|
bos@574
|
633 * <input name="B" type="checkbox" value="B2"/>
|
bos@574
|
634 * <input name="C" type="radio" value="C1" />
|
bos@574
|
635 * <input name="C" type="radio" value="C2" />
|
bos@574
|
636 * </fieldset></form>
|
bos@574
|
637 *
|
bos@574
|
638 * var v = $(':text').fieldValue();
|
bos@574
|
639 * // if no values are entered into the text inputs
|
bos@574
|
640 * v == ['','']
|
bos@574
|
641 * // if values entered into the text inputs are 'foo' and 'bar'
|
bos@574
|
642 * v == ['foo','bar']
|
bos@574
|
643 *
|
bos@574
|
644 * var v = $(':checkbox').fieldValue();
|
bos@574
|
645 * // if neither checkbox is checked
|
bos@574
|
646 * v === undefined
|
bos@574
|
647 * // if both checkboxes are checked
|
bos@574
|
648 * v == ['B1', 'B2']
|
bos@574
|
649 *
|
bos@574
|
650 * var v = $(':radio').fieldValue();
|
bos@574
|
651 * // if neither radio is checked
|
bos@574
|
652 * v === undefined
|
bos@574
|
653 * // if first radio is checked
|
bos@574
|
654 * v == ['C1']
|
bos@574
|
655 *
|
bos@574
|
656 * The successful argument controls whether or not the field element must be 'successful'
|
bos@574
|
657 * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
|
bos@574
|
658 * The default value of the successful argument is true. If this value is false the value(s)
|
bos@574
|
659 * for each element is returned.
|
bos@574
|
660 *
|
bos@574
|
661 * Note: This method *always* returns an array. If no valid value can be determined the
|
bos@574
|
662 * array will be empty, otherwise it will contain one or more values.
|
bos@574
|
663 *
|
bos@574
|
664 * @example var data = $("#myPasswordElement").fieldValue();
|
bos@574
|
665 * alert(data[0]);
|
bos@574
|
666 * @desc Alerts the current value of the myPasswordElement element
|
bos@574
|
667 *
|
bos@574
|
668 * @example var data = $("#myForm :input").fieldValue();
|
bos@574
|
669 * @desc Get the value(s) of the form elements in myForm
|
bos@574
|
670 *
|
bos@574
|
671 * @example var data = $("#myForm :checkbox").fieldValue();
|
bos@574
|
672 * @desc Get the value(s) for the successful checkbox element(s) in the jQuery object.
|
bos@574
|
673 *
|
bos@574
|
674 * @example var data = $("#mySingleSelect").fieldValue();
|
bos@574
|
675 * @desc Get the value(s) of the select control
|
bos@574
|
676 *
|
bos@574
|
677 * @example var data = $(':text').fieldValue();
|
bos@574
|
678 * @desc Get the value(s) of the text input or textarea elements
|
bos@574
|
679 *
|
bos@574
|
680 * @example var data = $("#myMultiSelect").fieldValue();
|
bos@574
|
681 * @desc Get the values for the select-multiple control
|
bos@574
|
682 *
|
bos@574
|
683 * @name fieldValue
|
bos@574
|
684 * @param Boolean successful true if only the values for successful controls should be returned (default is true)
|
bos@574
|
685 * @type Array<String>
|
bos@574
|
686 * @cat Plugins/Form
|
bos@574
|
687 */
|
bos@574
|
688 $.fn.fieldValue = function(successful) {
|
bos@574
|
689 for (var val=[], i=0, max=this.length; i < max; i++) {
|
bos@574
|
690 var el = this[i];
|
bos@574
|
691 var v = $.fieldValue(el, successful);
|
bos@574
|
692 if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length))
|
bos@574
|
693 continue;
|
bos@574
|
694 v.constructor == Array ? $.merge(val, v) : val.push(v);
|
bos@574
|
695 }
|
bos@574
|
696 return val;
|
bos@574
|
697 };
|
bos@574
|
698
|
bos@574
|
699 /**
|
bos@574
|
700 * Returns the value of the field element.
|
bos@574
|
701 *
|
bos@574
|
702 * The successful argument controls whether or not the field element must be 'successful'
|
bos@574
|
703 * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
|
bos@574
|
704 * The default value of the successful argument is true. If the given element is not
|
bos@574
|
705 * successful and the successful arg is not false then the returned value will be null.
|
bos@574
|
706 *
|
bos@574
|
707 * Note: If the successful flag is true (default) but the element is not successful, the return will be null
|
bos@574
|
708 * Note: The value returned for a successful select-multiple element will always be an array.
|
bos@574
|
709 * Note: If the element has no value the return value will be undefined.
|
bos@574
|
710 *
|
bos@574
|
711 * @example var data = jQuery.fieldValue($("#myPasswordElement")[0]);
|
bos@574
|
712 * @desc Gets the current value of the myPasswordElement element
|
bos@574
|
713 *
|
bos@574
|
714 * @name fieldValue
|
bos@574
|
715 * @param Element el The DOM element for which the value will be returned
|
bos@574
|
716 * @param Boolean successful true if value returned must be for a successful controls (default is true)
|
bos@574
|
717 * @type String or Array<String> or null or undefined
|
bos@574
|
718 * @cat Plugins/Form
|
bos@574
|
719 */
|
bos@574
|
720 $.fieldValue = function(el, successful) {
|
bos@574
|
721 var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
|
bos@574
|
722 if (typeof successful == 'undefined') successful = true;
|
bos@574
|
723
|
bos@574
|
724 if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
|
bos@574
|
725 (t == 'checkbox' || t == 'radio') && !el.checked ||
|
bos@574
|
726 (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
|
bos@574
|
727 tag == 'select' && el.selectedIndex == -1))
|
bos@574
|
728 return null;
|
bos@574
|
729
|
bos@574
|
730 if (tag == 'select') {
|
bos@574
|
731 var index = el.selectedIndex;
|
bos@574
|
732 if (index < 0) return null;
|
bos@574
|
733 var a = [], ops = el.options;
|
bos@574
|
734 var one = (t == 'select-one');
|
bos@574
|
735 var max = (one ? index+1 : ops.length);
|
bos@574
|
736 for(var i=(one ? index : 0); i < max; i++) {
|
bos@574
|
737 var op = ops[i];
|
bos@574
|
738 if (op.selected) {
|
bos@574
|
739 // extra pain for IE...
|
bos@574
|
740 var v = $.browser.msie && !(op.attributes['value'].specified) ? op.text : op.value;
|
bos@574
|
741 if (one) return v;
|
bos@574
|
742 a.push(v);
|
bos@574
|
743 }
|
bos@574
|
744 }
|
bos@574
|
745 return a;
|
bos@574
|
746 }
|
bos@574
|
747 return el.value;
|
bos@574
|
748 };
|
bos@574
|
749
|
bos@574
|
750
|
bos@574
|
751 /**
|
bos@574
|
752 * Clears the form data. Takes the following actions on the form's input fields:
|
bos@574
|
753 * - input text fields will have their 'value' property set to the empty string
|
bos@574
|
754 * - select elements will have their 'selectedIndex' property set to -1
|
bos@574
|
755 * - checkbox and radio inputs will have their 'checked' property set to false
|
bos@574
|
756 * - inputs of type submit, button, reset, and hidden will *not* be effected
|
bos@574
|
757 * - button elements will *not* be effected
|
bos@574
|
758 *
|
bos@574
|
759 * @example $('form').clearForm();
|
bos@574
|
760 * @desc Clears all forms on the page.
|
bos@574
|
761 *
|
bos@574
|
762 * @name clearForm
|
bos@574
|
763 * @type jQuery
|
bos@574
|
764 * @cat Plugins/Form
|
bos@574
|
765 */
|
bos@574
|
766 $.fn.clearForm = function() {
|
bos@574
|
767 return this.each(function() {
|
bos@574
|
768 $('input,select,textarea', this).clearFields();
|
bos@574
|
769 });
|
bos@574
|
770 };
|
bos@574
|
771
|
bos@574
|
772 /**
|
bos@574
|
773 * Clears the selected form elements. Takes the following actions on the matched elements:
|
bos@574
|
774 * - input text fields will have their 'value' property set to the empty string
|
bos@574
|
775 * - select elements will have their 'selectedIndex' property set to -1
|
bos@574
|
776 * - checkbox and radio inputs will have their 'checked' property set to false
|
bos@574
|
777 * - inputs of type submit, button, reset, and hidden will *not* be effected
|
bos@574
|
778 * - button elements will *not* be effected
|
bos@574
|
779 *
|
bos@574
|
780 * @example $('.myInputs').clearFields();
|
bos@574
|
781 * @desc Clears all inputs with class myInputs
|
bos@574
|
782 *
|
bos@574
|
783 * @name clearFields
|
bos@574
|
784 * @type jQuery
|
bos@574
|
785 * @cat Plugins/Form
|
bos@574
|
786 */
|
bos@574
|
787 $.fn.clearFields = $.fn.clearInputs = function() {
|
bos@574
|
788 return this.each(function() {
|
bos@574
|
789 var t = this.type, tag = this.tagName.toLowerCase();
|
bos@574
|
790 if (t == 'text' || t == 'password' || tag == 'textarea')
|
bos@574
|
791 this.value = '';
|
bos@574
|
792 else if (t == 'checkbox' || t == 'radio')
|
bos@574
|
793 this.checked = false;
|
bos@574
|
794 else if (tag == 'select')
|
bos@574
|
795 this.selectedIndex = -1;
|
bos@574
|
796 });
|
bos@574
|
797 };
|
bos@574
|
798
|
bos@574
|
799
|
bos@574
|
800 /**
|
bos@574
|
801 * Resets the form data. Causes all form elements to be reset to their original value.
|
bos@574
|
802 *
|
bos@574
|
803 * @example $('form').resetForm();
|
bos@574
|
804 * @desc Resets all forms on the page.
|
bos@574
|
805 *
|
bos@574
|
806 * @name resetForm
|
bos@574
|
807 * @type jQuery
|
bos@574
|
808 * @cat Plugins/Form
|
bos@574
|
809 */
|
bos@574
|
810 $.fn.resetForm = function() {
|
bos@574
|
811 return this.each(function() {
|
bos@574
|
812 // guard against an input with the name of 'reset'
|
bos@574
|
813 // note that IE reports the reset function as an 'object'
|
bos@574
|
814 if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType))
|
bos@574
|
815 this.reset();
|
bos@574
|
816 });
|
bos@574
|
817 };
|
bos@574
|
818
|
bos@574
|
819 })(jQuery);
|