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