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