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