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