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