1/*! 2 * jQuery Form Plugin 3 * version: 2.96 (16-FEB-2012) 4 * @requires jQuery v1.3.2 or later 5 * 6 * Examples and documentation at: http://malsup.com/jquery/form/ 7 * Dual licensed under the MIT and GPL licenses: 8 * http://www.opensource.org/licenses/mit-license.php 9 * http://www.gnu.org/licenses/gpl.html 10 */ 11;(function($) { 12 13/* 14 Usage Note: 15 ----------- 16 Do not use both ajaxSubmit and ajaxForm on the same form. These 17 functions are mutually exclusive. Use ajaxSubmit if you want 18 to bind your own submit handler to the form. For example, 19 20 $(document).ready(function() { 21 $('#myForm').bind('submit', function(e) { 22 e.preventDefault(); // <-- important 23 $(this).ajaxSubmit({ 24 target: '#output' 25 }); 26 }); 27 }); 28 29 Use ajaxForm when you want the plugin to manage all the event binding 30 for you. For example, 31 32 $(document).ready(function() { 33 $('#myForm').ajaxForm({ 34 target: '#output' 35 }); 36 }); 37 38 You can also use ajaxForm with delegation (requires jQuery v1.7+), so the 39 form does not have to exist when you invoke ajaxForm: 40 41 $('#myForm').ajaxForm({ 42 delegation: true, 43 target: '#output' 44 }); 45 46 When using ajaxForm, the ajaxSubmit function will be invoked for you 47 at the appropriate time. 48*/ 49 50/** 51 * ajaxSubmit() provides a mechanism for immediately submitting 52 * an HTML form using AJAX. 53 */ 54$.fn.ajaxSubmit = function(options) { 55 // fast fail if nothing selected (http://dev.jquery.com/ticket/2752) 56 if (!this.length) { 57 log('ajaxSubmit: skipping submit process - no element selected'); 58 return this; 59 } 60 61 var method, action, url, $form = this; 62 63 if (typeof options == 'function') { 64 options = { success: options }; 65 } 66 67 method = this.attr('method'); 68 action = this.attr('action'); 69 url = (typeof action === 'string') ? $.trim(action) : ''; 70 url = url || window.location.href || ''; 71 if (url) { 72 // clean url (don't include hash vaue) 73 url = (url.match(/^([^#]+)/)||[])[1]; 74 } 75 76 options = $.extend(true, { 77 url: url, 78 success: $.ajaxSettings.success, 79 type: method || 'GET', 80 iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank' 81 }, options); 82 83 // hook for manipulating the form data before it is extracted; 84 // convenient for use with rich editors like tinyMCE or FCKEditor 85 var veto = {}; 86 this.trigger('form-pre-serialize', [this, options, veto]); 87 if (veto.veto) { 88 log('ajaxSubmit: submit vetoed via form-pre-serialize trigger'); 89 return this; 90 } 91 92 // provide opportunity to alter form data before it is serialized 93 if (options.beforeSerialize && options.beforeSerialize(this, options) === false) { 94 log('ajaxSubmit: submit aborted via beforeSerialize callback'); 95 return this; 96 } 97 98 var traditional = options.traditional; 99 if ( traditional === undefined ) { 100 traditional = $.ajaxSettings.traditional; 101 } 102 103 var qx,n,v,a = this.formToArray(options.semantic); 104 if (options.data) { 105 options.extraData = options.data; 106 qx = $.param(options.data, traditional); 107 } 108 109 // give pre-submit callback an opportunity to abort the submit 110 if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) { 111 log('ajaxSubmit: submit aborted via beforeSubmit callback'); 112 return this; 113 } 114 115 // fire vetoable 'validate' event 116 this.trigger('form-submit-validate', [a, this, options, veto]); 117 if (veto.veto) { 118 log('ajaxSubmit: submit vetoed via form-submit-validate trigger'); 119 return this; 120 } 121 122 var q = $.param(a, traditional); 123 if (qx) { 124 q = ( q ? (q + '&' + qx) : qx ); 125 } 126 if (options.type.toUpperCase() == 'GET') { 127 options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q; 128 options.data = null; // data is null for 'get' 129 } 130 else { 131 options.data = q; // data is the query string for 'post' 132 } 133 134 var callbacks = []; 135 if (options.resetForm) { 136 callbacks.push(function() { $form.resetForm(); }); 137 } 138 if (options.clearForm) { 139 callbacks.push(function() { $form.clearForm(options.includeHidden); }); 140 } 141 142 // perform a load on the target only if dataType is not provided 143 if (!options.dataType && options.target) { 144 var oldSuccess = options.success || function(){}; 145 callbacks.push(function(data) { 146 var fn = options.replaceTarget ? 'replaceWith' : 'html'; 147 $(options.target)[fn](data).each(oldSuccess, arguments); 148 }); 149 } 150 else if (options.success) { 151 callbacks.push(options.success); 152 } 153 154 options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg 155 var context = options.context || options; // jQuery 1.4+ supports scope context 156 for (var i=0, max=callbacks.length; i < max; i++) { 157 callbacks[i].apply(context, [data, status, xhr || $form, $form]); 158 } 159 }; 160 161 // are there files to upload? 162 var fileInputs = $('input:file:enabled[value]', this); // [value] (issue #113) 163 var hasFileInputs = fileInputs.length > 0; 164 var mp = 'multipart/form-data'; 165 var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp); 166 167 var fileAPI = !!(hasFileInputs && fileInputs.get(0).files && window.FormData); 168 log("fileAPI :" + fileAPI); 169 var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI; 170 171 // options.iframe allows user to force iframe mode 172 // 06-NOV-09: now defaulting to iframe mode if file input is detected 173 if (options.iframe !== false && (options.iframe || shouldUseFrame)) { 174 // hack to fix Safari hang (thanks to Tim Molendijk for this) 175 // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d 176 if (options.closeKeepAlive) { 177 $.get(options.closeKeepAlive, function() { 178 fileUploadIframe(a); 179 }); 180 } 181 else { 182 fileUploadIframe(a); 183 } 184 } 185 else if ((hasFileInputs || multipart) && fileAPI) { 186 options.progress = options.progress || $.noop; 187 fileUploadXhr(a); 188 } 189 else { 190 $.ajax(options); 191 } 192 193 // fire 'notify' event 194 this.trigger('form-submit-notify', [this, options]); 195 return this; 196 197 // XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz) 198 function fileUploadXhr(a) { 199 var formdata = new FormData(); 200 201 for (var i=0; i < a.length; i++) { 202 if (a[i].type == 'file') 203 continue; 204 formdata.append(a[i].name, a[i].value); 205 } 206
207 $form.find('input:file:enabled').each(function(){ 208 var name = $(this).attr('name'), files = this.files; 209 if (name) { 210 for (var i=0; i < files.length; i++) 211 formdata.append(name, files[i]); 212 } 213 }); 214 215 if (options.extraData) { 216 for (var k in options.extraData) 217 formdata.append(k, options.extraData[k]) 218 } 219 220 options.data = null; 221 222 var s = $.extend(true, {}, $.ajaxSettings, options, { 223 contentType: false, 224 processData: false, 225 cache: false, 226 type: 'POST' 227 }); 228 229 //s.context = s.context || s; 230 231 s.data = null; 232 var beforeSend = s.beforeSend; 233 s.beforeSend = function(xhr, o) { 234 o.data = formdata; 235 if(xhr.upload) { // unfortunately, jQuery doesn't expose this prop (http://bugs.jquery.com/ticket/10190) 236 xhr.upload.onprogress = function(event) { 237 o.progress(event.position, event.total); 238 }; 239 } 240 if(beforeSend) 241 beforeSend.call(o, xhr, options); 242 }; 243 $.ajax(s); 244 } 245 246 // private function for handling file uploads (hat tip to YAHOO!) 247 function fileUploadIframe(a) { 248 var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle; 249 var useProp = !!$.fn.prop; 250 251 if (a) { 252 if ( useProp ) { 253 // ensure that every serialized input is still enabled 254 for (i=0; i < a.length; i++) { 255 el = $(form[a[i].name]); 256 el.prop('disabled', false); 257 } 258 } else { 259 for (i=0; i < a.length; i++) { 260 el = $(form[a[i].name]); 261 el.removeAttr('disabled'); 262 } 263 }; 264 } 265 266 if ($(':input[name=submit],:input[id=submit]', form).length) { 267 // if there is an input with a name or id of 'submit' then we won't be 268 // able to invoke the submit fn on the form (at least not x-browser) 269 alert('Error: Form elements must not have name or id of "submit".'); 270 return; 271 } 272 273 s = $.extend(true, {}, $.ajaxSettings, options); 274 s.context = s.context || s; 275 id = 'jqFormIO' + (new Date().getTime()); 276 if (s.iframeTarget) { 277 $io = $(s.iframeTarget); 278 n = $io.attr('name'); 279 if (n == null) 280 $io.attr('name', id); 281 else 282 id = n; 283 } 284 else { 285 $io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />'); 286 $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' }); 287 } 288 io = $io[0]; 289 290 291 xhr = { // mock object 292 aborted: 0, 293 responseText: null, 294 responseXML: null, 295 status: 0, 296 statusText: 'n/a', 297 getAllResponseHeaders: function() {}, 298 getResponseHeader: function() {}, 299 setRequestHeader: function() {}, 300 abort: function(status) { 301 var e = (status === 'timeout' ? 'timeout' : 'aborted'); 302 log('aborting upload... ' + e); 303 this.aborted = 1; 304 $io.attr('src', s.iframeSrc); // abort op in progress 305 xhr.error = e; 306 s.error && s.error.call(s.context, xhr, e, status); 307 g && $.event.trigger("ajaxError", [xhr, s, e]); 308 s.complete && s.complete.call(s.context, xhr, e); 309 } 310 }; 311 312 g = s.global; 313 // trigger ajax global events so that activity/block indicators work like normal 314 if (g && ! $.active++) { 315 $.event.trigger("ajaxStart"); 316 } 317 if (g) { 318 $.event.trigger("ajaxSend", [xhr, s]); 319 } 320 321 if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) { 322 if (s.global) { 323 $.active--; 324 } 325 return; 326 } 327 if (xhr.aborted) { 328 return; 329 } 330 331 // add submitting element to data if we know it 332 sub = form.clk; 333 if (sub) { 334 n = sub.name; 335 if (n && !sub.disabled) { 336 s.extraData = s.extraData || {}; 337 s.extraData[n] = sub.value; 338 if (sub.type == "image") { 339 s.extraData[n+'.x'] = form.clk_x; 340 s.extraData[n+'.y'] = form.clk_y; 341 } 342 } 343 } 344 345 var CLIENT_TIMEOUT_ABORT = 1; 346 var SERVER_ABORT = 2; 347 348 function getDoc(frame) { 349 var doc = frame.contentWindow ? frame.contentWindow.document : frame.contentDocument ? frame.contentDocument : frame.document; 350 return doc; 351 } 352 353 // Rails CSRF hack (thanks to Yvan Barthelemy) 354 var csrf_token = $('meta[name=csrf-token]').attr('content'); 355 var csrf_param = $('meta[name=csrf-param]').attr('content'); 356 if (csrf_param && csrf_token) { 357 s.extraData = s.extraData || {}; 358 s.extraData[csrf_param] = csrf_token; 359 } 360 361 // take a breath so that pending repaints get some cpu time before the upload starts 362 function doSubmit() { 363 // make sure form attrs are set 364 var t = $form.attr('target'), a = $form.attr('action'); 365 366 // update form attrs in IE friendly way 367 form.setAttribute('target',id);
368 if (!method) { 369 form.setAttribute('method', 'POST'); 370 } 371 if (a != s.url) { 372 form.setAttribute('action', s.url); 373 } 374 375 // ie borks in some cases when setting encoding 376 if (! s.skipEncodingOverride && (!method || /post/i.test(method))) { 377 $form.attr({ 378 encoding: 'multipart/form-data', 379 enctype: 'multipart/form-data' 380 }); 381 } 382 383 // support timout 384 if (s.timeout) { 385 timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout); 386 } 387 388 // look for server aborts 389 function checkState() { 390 try { 391 var state = getDoc(io).readyState; 392 log('state = ' + state); 393 if (state.toLowerCase() == 'uninitialized') 394 setTimeout(checkState,50); 395 } 396 catch(e) { 397 log('Server abort: ' , e, ' (', e.name, ')'); 398 cb(SERVER_ABORT); 399 timeoutHandle && clearTimeout(timeoutHandle); 400 timeoutHandle = undefined; 401 } 402 } 403 404 // add "extra" data to form if provided in options 405 var extraInputs = []; 406 try { 407 if (s.extraData) { 408 for (var n in s.extraData) { 409 extraInputs.push( 410 $('<input type="hidden" name="'+n+'">').attr('value',s.extraData[n]) 411 .appendTo(form)[0]); 412 } 413 } 414 415 if (!s.iframeTarget) { 416 // add iframe to doc and submit the form 417 $io.appendTo('body'); 418 io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false); 419 } 420 setTimeout(checkState,15); 421 form.submit(); 422 } 423 finally { 424 // reset attrs and remove "extra" input elements 425 form.setAttribute('action',a); 426 if(t) { 427 form.setAttribute('target', t); 428 } else { 429 $form.removeAttr('target'); 430 } 431 $(extraInputs).remove(); 432 } 433 } 434 435 if (s.forceSync) { 436 doSubmit(); 437 } 438 else { 439 setTimeout(doSubmit, 10); // this lets dom updates render 440 } 441 442 var data, doc, domCheckCount = 50, callbackProcessed; 443 444 function cb(e) { 445 if (xhr.aborted || callbackProcessed) { 446 return; 447 } 448 try { 449 doc = getDoc(io); 450 } 451 catch(ex) { 452 log('cannot access response document: ', ex); 453 e = SERVER_ABORT; 454 } 455 if (e === CLIENT_TIMEOUT_ABORT && xhr) { 456 xhr.abort('timeout'); 457 return; 458 } 459 else if (e == SERVER_ABORT && xhr) { 460 xhr.abort('server abort'); 461 return; 462 } 463 464 if (!doc || doc.location.href == s.iframeSrc) { 465 // response not received yet 466 if (!timedOut) 467 return; 468 } 469 io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false); 470 471 var status = 'success', errMsg; 472 try { 473 if (timedOut) { 474 throw 'timeout'; 475 } 476 477 var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc); 478 log('isXml='+isXml); 479 if (!isXml && window.opera && (doc.body == null || doc.body.innerHTML == '')) { 480 if (--domCheckCount) { 481 // in some browsers (Opera) the iframe DOM is not always traversable when 482 // the onload callback fires, so we loop a bit to accommodate 483 log('requeing onLoad callback, DOM not available'); 484 setTimeout(cb, 250); 485 return; 486 } 487 // let this fall through because server response could be an empty document 488 //log('Could not access iframe DOM after mutiple tries.'); 489 //throw 'DOMException: not available'; 490 } 491 492 //log('response detected'); 493 var docRoot = doc.body ? doc.body : doc.documentElement; 494 xhr.responseText = docRoot ? docRoot.innerHTML : null; 495 xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc; 496 if (isXml) 497 s.dataType = 'xml'; 498 xhr.getResponseHeader = function(header){ 499 var headers = {'content-type': s.dataType}; 500 return headers[header]; 501 }; 502 // support for XHR 'status' & 'statusText' emulation : 503 if (docRoot) { 504 xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status; 505 xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText; 506 } 507 508 var dt = (s.dataType || '').toLowerCase(); 509 var scr = /(json|script|text)/.test(dt); 510 if (scr || s.textarea) { 511 // see if user embedded response in textarea 512 var ta = doc.getElementsByTagName('textarea')[0]; 513 if (ta) { 514 xhr.responseText = ta.value; 515 // support for XHR 'status' & 'statusText' emulation : 516 xhr.status = Number( ta.getAttribute('status') ) || xhr.status; 517 xhr.statusText = ta.getAttribute('statusText') || xhr.statusText; 518 } 519 else if (scr) { 520 // account for browsers injecting pre around json response 521 var pre = doc.getElementsByTagName('pre')[0]; 522 var b = doc.getElementsByTagName('body')[0]; 523 if (pre) { 524 xhr.responseText = pre.textContent ? pre.textContent : pre.innerText; 525 } 526 else if (b) { 527 xhr.responseText = b.textContent ? b.textContent : b.innerText; 528 } 529 } 530 } 531 else if (dt == 'xml' && !xhr.responseXML && xhr.responseText != null) { 532 xhr.responseXML = toXml(xhr.responseText); 533 } 534 535 try { 536 data = httpData(xhr, dt, s); 537 } 538 catch (e) { 539 status = 'parsererror'; 540 xhr.error = errMsg = (e || status); 541 } 542 } 543 catch (e) { 544 log('error caught: ',e); 545 status = 'error'; 546 xhr.error = errMsg = (e || status); 547 } 548 549 if (xhr.aborted) { 550 log('upload aborted'); 551 status = null; 552 } 553 554 if (xhr.status) { // we've set xhr.status 555 status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error'; 556 } 557 558 // ordering of these callbacks/triggers is odd, but that's how $.ajax does it 559 if (status === 'success') { 560 s.success && s.success.call(s.context, data, 'success', xhr); 561 g && $.event.trigger("ajaxSuccess", [xhr, s]); 562 } 563 else if (status) { 564 if (errMsg == undefined) 565 errMsg = xhr.statusText; 566 s.error && s.error.call(s.context, xhr, status, errMsg); 567 g && $.event.trigger("ajaxError", [xhr, s, errMsg]); 568 } 569
570 g && $.event.trigger("ajaxComplete", [xhr, s]); 571 572 if (g && ! --$.active) { 573 $.event.trigger("ajaxStop"); 574 } 575 576 s.complete && s.complete.call(s.context, xhr, status); 577 578 callbackProcessed = true; 579 if (s.timeout) 580 clearTimeout(timeoutHandle); 581 582 // clean up 583 setTimeout(function() { 584 if (!s.iframeTarget) 585 $io.remove(); 586 xhr.responseXML = null; 587 }, 100); 588 } 589 590 var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+) 591 if (window.ActiveXObject) { 592 doc = new ActiveXObject('Microsoft.XMLDOM'); 593 doc.async = 'false'; 594 doc.loadXML(s); 595 } 596 else { 597 doc = (new DOMParser()).parseFromString(s, 'text/xml'); 598 } 599 return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null; 600 }; 601 var parseJSON = $.parseJSON || function(s) { 602 return window['eval']('(' + s + ')'); 603 }; 604 605 var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4 606 607 var ct = xhr.getResponseHeader('content-type') || '', 608 xml = type === 'xml' || !type && ct.indexOf('xml') >= 0, 609 data = xml ? xhr.responseXML : xhr.responseText; 610 611 if (xml && data.documentElement.nodeName === 'parsererror') { 612 $.error && $.error('parsererror'); 613 } 614 if (s && s.dataFilter) { 615 data = s.dataFilter(data, type); 616 } 617 if (typeof data === 'string') { 618 if (type === 'json' || !type && ct.indexOf('json') >= 0) { 619 data = parseJSON(data); 620 } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) { 621 $.globalEval(data); 622 } 623 } 624 return data; 625 }; 626 } 627}; 628 629/** 630 * ajaxForm() provides a mechanism for fully automating form submission. 631 * 632 * The advantages of using this method instead of ajaxSubmit() are: 633 * 634 * 1: This method will include coordinates for <input type="image" /> elements (if the element 635 * is used to submit the form). 636 * 2. This method will include the submit element's name/value data (for the element that was 637 * used to submit the form). 638 * 3. This method binds the submit() method to the form for you. 639 * 640 * The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely 641 * passes the options argument along after properly binding events for submit elements and 642 * the form itself. 643 */ 644$.fn.ajaxForm = function(options) { 645 options = options || {}; 646 options.delegation = options.delegation && $.isFunction($.fn.on); 647 648 // in jQuery 1.3+ we can fix mistakes with the ready state 649 if (!options.delegation && this.length === 0) { 650 var o = { s: this.selector, c: this.context }; 651 if (!$.isReady && o.s) { 652 log('DOM not ready, queuing ajaxForm'); 653 $(function() { 654 $(o.s,o.c).ajaxForm(options); 655 }); 656 return this; 657 } 658 // is your DOM ready? http://docs.jquery.com/Tutorials:Introducing_$(document).ready() 659 log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)')); 660 return this; 661 } 662 663 if ( options.delegation ) { 664 $(document) 665 .off('submit.form-plugin', this.selector, doAjaxSubmit) 666 .off('click.form-plugin', this.selector, captureSubmittingElement) 667 .on('submit.form-plugin', this.selector, options, doAjaxSubmit) 668 .on('click.form-plugin', this.selector, options, captureSubmittingElement); 669 return this; 670 } 671 672 return this.ajaxFormUnbind() 673 .bind('submit.form-plugin', options, doAjaxSubmit) 674 .bind('click.form-plugin', options, captureSubmittingElement); 675}; 676 677// private event handlers 678function doAjaxSubmit(e) { 679 var options = e.data; 680 if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed 681 e.preventDefault(); 682 $(this).ajaxSubmit(options); 683 } 684} 685 686function captureSubmittingElement(e) { 687 var target = e.target; 688 var $el = $(target); 689 if (!($el.is(":submit,input:image"))) { 690 // is this a child element of the submit el? (ex: a span within a button) 691 var t = $el.closest(':submit'); 692 if (t.length == 0) { 693 return; 694 } 695 target = t[0]; 696 } 697 var form = this; 698 form.clk = target; 699 if (target.type == 'image') { 700 if (e.offsetX != undefined) { 701 form.clk_x = e.offsetX; 702 form.clk_y = e.offsetY; 703 } else if (typeof $.fn.offset == 'function') { 704 var offset = $el.offset(); 705 form.clk_x = e.pageX - offset.left; 706 form.clk_y = e.pageY - offset.top; 707 } else { 708 form.clk_x = e.pageX - target.offsetLeft; 709 form.clk_y = e.pageY - target.offsetTop; 710 } 711 } 712 // clear form vars 713 setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100); 714}; 715 716 717// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm 718$.fn.ajaxFormUnbind = function() { 719 return this.unbind('submit.form-plugin click.form-plugin'); 720}; 721 722/** 723 * formToArray() gathers form element data into an array of objects that can 724 * be passed to any of the following ajax functions: $.get, $.post, or load. 725 * Each object in the array has both a 'name' and 'value' property. An example of 726 * an array for a simple login form might be: 727 * 728 * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ] 729 * 730 * It is this array that is passed to pre-submit callback functions provided to the 731 * ajaxSubmit() and ajaxForm() methods. 732 */ 733$.fn.formToArray = function(semantic) { 734 var a = []; 735 if (this.length === 0) { 736 return a; 737 } 738 739 var form = this[0]; 740 var els = semantic ? form.getElementsByTagName('*') : form.elements; 741 if (!els) { 742 return a; 743 } 744 745 var i,j,n,v,el,max,jmax; 746 for(i=0, max=els.length; i < max; i++) { 747 el = els[i]; 748 n = el.name; 749 if (!n) { 750 continue; 751 } 752 753 if (semantic && form.clk && el.type == "image") { 754 // handle image inputs on the fly when semantic == true 755 if(!el.disabled && form.clk == el) { 756 a.push({name: n, value: $(el).val(), type: el.type }); 757 a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y}); 758 } 759 continue; 760 } 761 762 v = $.fieldValue(el, true); 763 if (v && v.constructor == Array) { 764 for(j=0, jmax=v.length; j < jmax; j++) { 765 a.push({name: n, value: v[j]}); 766 } 767 } 768 else if (v !== null && typeof v != 'undefined') { 769 a.push({name: n, value: v, type: el.type}); 770 } 771 } 772 773 if (!semantic && form.clk) { 774 // input type=='image' are not found in elements array! handle it here 775 var $input = $(form.clk), input = $input[0]; 776 n = input.name; 777 if (n && !input.disabled && input.type == 'image') { 778 a.push({name: n, value: $input.val()}); 779 a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y}); 780 } 781 } 782 return a; 783}; 784 785/** 786 * Serializes form data into a 'submittable' string. This method will return a string 787 * in the format: name1=value1&name2=value2 788 */
789$.fn.formSerialize = function(semantic) { 790 //hand off to jQuery.param for proper encoding 791 return $.param(this.formToArray(semantic)); 792}; 793 794/** 795 * Serializes all field elements in the jQuery object into a query string. 796 * This method will return a string in the format: name1=value1&name2=value2 797 */ 798$.fn.fieldSerialize = function(successful) { 799 var a = []; 800 this.each(function() { 801 var n = this.name; 802 if (!n) { 803 return; 804 } 805 var v = $.fieldValue(this, successful); 806 if (v && v.constructor == Array) { 807 for (var i=0,max=v.length; i < max; i++) { 808 a.push({name: n, value: v[i]}); 809 } 810 } 811 else if (v !== null && typeof v != 'undefined') { 812 a.push({name: this.name, value: v}); 813 } 814 }); 815 //hand off to jQuery.param for proper encoding 816 return $.param(a); 817}; 818 819/** 820 * Returns the value(s) of the element in the matched set. For example, consider the following form: 821 * 822 * <form><fieldset> 823 * <input name="A" type="text" /> 824 * <input name="A" type="text" /> 825 * <input name="B" type="checkbox" value="B1" /> 826 * <input name="B" type="checkbox" value="B2"/> 827 * <input name="C" type="radio" value="C1" /> 828 * <input name="C" type="radio" value="C2" /> 829 * </fieldset></form> 830 * 831 * var v = $(':text').fieldValue(); 832 * // if no values are entered into the text inputs 833 * v == ['',''] 834 * // if values entered into the text inputs are 'foo' and 'bar' 835 * v == ['foo','bar'] 836 * 837 * var v = $(':checkbox').fieldValue(); 838 * // if neither checkbox is checked 839 * v === undefined 840 * // if both checkboxes are checked 841 * v == ['B1', 'B2'] 842 * 843 * var v = $(':radio').fieldValue(); 844 * // if neither radio is checked 845 * v === undefined 846 * // if first radio is checked 847 * v == ['C1'] 848 * 849 * The successful argument controls whether or not the field element must be 'successful' 850 * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls). 851 * The default value of the successful argument is true. If this value is false the value(s) 852 * for each element is returned. 853 * 854 * Note: This method *always* returns an array. If no valid value can be determined the 855 * array will be empty, otherwise it will contain one or more values. 856 */ 857$.fn.fieldValue = function(successful) { 858 for (var val=[], i=0, max=this.length; i < max; i++) { 859 var el = this[i]; 860 var v = $.fieldValue(el, successful); 861 if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) { 862 continue; 863 } 864 v.constructor == Array ? $.merge(val, v) : val.push(v); 865 } 866 return val; 867}; 868 869/** 870 * Returns the value of the field element. 871 */ 872$.fieldValue = function(el, successful) { 873 var n = el.name, t = el.type, tag = el.tagName.toLowerCase(); 874 if (successful === undefined) { 875 successful = true; 876 } 877 878 if (successful && (!n || el.disabled || t == 'reset' || t == 'button' || 879 (t == 'checkbox' || t == 'radio') && !el.checked || 880 (t == 'submit' || t == 'image') && el.form && el.form.clk != el || 881 tag == 'select' && el.selectedIndex == -1)) { 882 return null; 883 } 884 885 if (tag == 'select') { 886 var index = el.selectedIndex; 887 if (index < 0) { 888 return null; 889 } 890 var a = [], ops = el.options; 891 var one = (t == 'select-one'); 892 var max = (one ? index+1 : ops.length); 893 for(var i=(one ? index : 0); i < max; i++) { 894 var op = ops[i]; 895 if (op.selected) { 896 var v = op.value; 897 if (!v) { // extra pain for IE... 898 v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value; 899 } 900 if (one) { 901 return v; 902 } 903 a.push(v); 904 } 905 } 906 return a; 907 } 908 return $(el).val(); 909}; 910 911/** 912 * Clears the form data. Takes the following actions on the form's input fields: 913 * - input text fields will have their 'value' property set to the empty string 914 * - select elements will have their 'selectedIndex' property set to -1 915 * - checkbox and radio inputs will have their 'checked' property set to false 916 * - inputs of type submit, button, reset, and hidden will *not* be effected 917 * - button elements will *not* be effected 918 */ 919$.fn.clearForm = function(includeHidden) { 920 return this.each(function() { 921 $('input,select,textarea', this).clearFields(includeHidden); 922 }); 923}; 924 925/** 926 * Clears the selected form elements. 927 */ 928$.fn.clearFields = $.fn.clearInputs = function(includeHidden) { 929 var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list 930 return this.each(function() { 931 var t = this.type, tag = this.tagName.toLowerCase(); 932 if (re.test(t) || tag == 'textarea' || (includeHidden && /hidden/.test(t)) ) { 933 this.value = ''; 934 } 935 else if (t == 'checkbox' || t == 'radio') { 936 this.checked = false;
937 } 938 else if (tag == 'select') { 939 this.selectedIndex = -1; 940 } 941 }); 942}; 943 944/** 945 * Resets the form data. Causes all form elements to be reset to their original value. 946 */ 947$.fn.resetForm = function() { 948 return this.each(function() { 949 // guard against an input with the name of 'reset' 950 // note that IE reports the reset function as an 'object' 951 if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) { 952 this.reset(); 953 } 954 }); 955}; 956 957/** 958 * Enables or disables any matching elements. 959 */ 960$.fn.enable = function(b) { 961 if (b === undefined) { 962 b = true; 963 } 964 return this.each(function() { 965 this.disabled = !b; 966 }); 967}; 968 969/** 970 * Checks/unchecks any matching checkboxes or radio buttons and 971 * selects/deselects and matching option elements. 972 */ 973$.fn.selected = function(select) { 974 if (select === undefined) { 975 select = true; 976 } 977 return this.each(function() { 978 var t = this.type; 979 if (t == 'checkbox' || t == 'radio') { 980 this.checked = select; 981 } 982 else if (this.tagName.toLowerCase() == 'option') { 983 var $sel = $(this).parent('select'); 984 if (select && $sel[0] && $sel[0].type == 'select-one') { 985 // deselect all other options 986 $sel.find('option').selected(false); 987 } 988 this.selected = select; 989 } 990 }); 991}; 992 993// expose debug var 994$.fn.ajaxSubmit.debug = false; 995 996// helper fn for console logging 997function log() { 998 if (!$.fn.ajaxSubmit.debug) 999 return; 1000 var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,''); 1001 if (window.console && window.console.log) { 1002 window.console.log(msg); 1003 } 1004 else if (window.opera && window.opera.postError) { 1005 window.opera.postError(msg); 1006 } 1007}; 1008 1009})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.