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