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