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