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