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