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