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