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 } else if (e === SERVER_ABORT && xhr) { 740 xhr.abort('server abort'); 741 deferred.reject(xhr, 'error', 'server abort'); 742 743 return; 744 } 745 746 if (!doc || doc.location.href === s.iframeSrc) { 747 // response not received yet 748 if (!timedOut) { 749 return; 750 } 751 } 752 753 if (io.detachEvent) { 754 io.detachEvent('onload', cb); 755 } else { 756 io.removeEventListener('load', cb, false); 757 } 758 759 var status = 'success', errMsg; 760 761 try { 762 if (timedOut) { 763 throw 'timeout'; 764 } 765 766 var isXml = s.dataType === 'xml' || doc.XMLDocument || $.isXMLDoc(doc); 767 768 log('isXml=' + isXml); 769 770 if (!isXml && window.opera && (doc.body === null || !doc.body.innerHTML)) { 771 if (--domCheckCount) { 772 // in some browsers (Opera) the iframe DOM is not always traversable when 773 // the onload callback fires, so we loop a bit to accommodate 774 log('requeing onLoad callback, DOM not available'); 775 setTimeout(cb, 250); 776 777 return; 778 } 779 // let this fall through because server response could be an empty document 780 // log('Could not access iframe DOM after mutiple tries.'); 781 // throw 'DOMException: not available'; 782 } 783 784 // log('response detected'); 785 var docRoot = doc.body ? doc.body : doc.documentElement; 786 787 xhr.responseText = docRoot ? docRoot.innerHTML : null; 788 xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc; 789 if (isXml) { 790 s.dataType = 'xml'; 791 } 792 xhr.getResponseHeader = function(header){ 793 var headers = {'content-type': s.dataType}; 794 795 return headers[header.toLowerCase()]; 796 }; 797 // support for XHR 'status' & 'statusText' emulation : 798 if (docRoot) { 799 xhr.status = Number(docRoot.getAttribute('status')) || xhr.status; 800 xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText; 801 } 802 803 var dt = (s.dataType || '').toLowerCase(); 804 var scr = /(json|script|text)/.test(dt); 805 806 if (scr || s.textarea) { 807 // see if user embedded response in textarea 808 var ta = doc.getElementsByTagName('textarea')[0]; 809 810 if (ta) { 811 xhr.responseText = ta.value; 812 // support for XHR 'status' & 'statusText' emulation : 813 xhr.status = Number(ta.getAttribute('status')) || xhr.status; 814 xhr.statusText = ta.getAttribute('statusText') || xhr.statusText; 815 816 } else if (scr) { 817 // account for browsers injecting pre around json response 818 var pre = doc.getElementsByTagName('pre')[0]; 819 var b = doc.getElementsByTagName('body')[0]; 820 821 if (pre) { 822 xhr.responseText = pre.textContent ? pre.textContent : pre.innerText; 823 } else if (b) { 824 xhr.responseText = b.textContent ? b.textContent : b.innerText; 825 } 826 } 827 828 } else if (dt === 'xml' && !xhr.responseXML && xhr.responseText) { 829 xhr.responseXML = toXml(xhr.responseText); // eslint-disable-line no-use-before-define 830 } 831 832 try { 833 data = httpData(xhr, dt, s); // eslint-disable-line no-use-before-define 834 835 } catch (err) { 836 status = 'parsererror'; 837 xhr.error = errMsg = (err || status); 838 } 839 840 } catch (err) { 841 log('error caught: ', err); 842 status = 'error'; 843 xhr.error = errMsg = (err || status); 844 } 845 846 if (xhr.aborted) { 847 log('upload aborted'); 848 status = null; 849 } 850 851 if (xhr.status) { // we've set xhr.status 852 status = ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) ? 'success' : 'error'; 853 } 854 855 // ordering of these callbacks/triggers is odd, but that's how $.ajax does it 856 if (status === 'success') { 857 if (s.success) { 858 s.success.call(s.context, data, 'success', xhr); 859 } 860 861 deferred.resolve(xhr.responseText, 'success', xhr); 862 863 if (g) {
864 $.event.trigger('ajaxSuccess', [xhr, s]); 865 } 866 867 } else if (status) { 868 if (typeof errMsg === 'undefined') { 869 errMsg = xhr.statusText; 870 } 871 if (s.error) { 872 s.error.call(s.context, xhr, status, errMsg); 873 } 874 deferred.reject(xhr, 'error', errMsg); 875 if (g) { 876 $.event.trigger('ajaxError', [xhr, s, errMsg]); 877 } 878 } 879 880 if (g) { 881 $.event.trigger('ajaxComplete', [xhr, s]); 882 } 883 884 if (g && !--$.active) { 885 $.event.trigger('ajaxStop'); 886 } 887 888 if (s.complete) { 889 s.complete.call(s.context, xhr, status); 890 } 891 892 callbackProcessed = true; 893 if (s.timeout) { 894 clearTimeout(timeoutHandle); 895 } 896 897 // clean up 898 setTimeout(function() { 899 if (!s.iframeTarget) { 900 $io.remove(); 901 } else { // adding else to clean up existing iframe response. 902 $io.attr('src', s.iframeSrc); 903 } 904 xhr.responseXML = null; 905 }, 100); 906 } 907 908 var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+) 909 if (window.ActiveXObject) { 910 doc = new ActiveXObject('Microsoft.XMLDOM'); 911 doc.async = 'false'; 912 doc.loadXML(s); 913 914 } else { 915 doc = (new DOMParser()).parseFromString(s, 'text/xml'); 916 } 917 918 return (doc && doc.documentElement && doc.documentElement.nodeName !== 'parsererror') ? doc : null; 919 }; 920 var parseJSON = $.parseJSON || function(s) { 921 /* jslint evil:true */ 922 return window['eval']('(' + s + ')'); // eslint-disable-line dot-notation 923 }; 924 925 var httpData = function(xhr, type, s) { // mostly lifted from jq1.4.4 926 927 var ct = xhr.getResponseHeader('content-type') || '', 928 xml = ((type === 'xml' || !type) && ct.indexOf('xml') >= 0), 929 data = xml ? xhr.responseXML : xhr.responseText; 930 931 if (xml && data.documentElement.nodeName === 'parsererror') { 932 if ($.error) { 933 $.error('parsererror'); 934 } 935 } 936 if (s && s.dataFilter) { 937 data = s.dataFilter(data, type); 938 } 939 if (typeof data === 'string') { 940 if ((type === 'json' || !type) && ct.indexOf('json') >= 0) { 941 data = parseJSON(data); 942 } else if ((type === 'script' || !type) && ct.indexOf('javascript') >= 0) { 943 $.globalEval(data); 944 } 945 } 946 947 return data; 948 }; 949 950 return deferred; 951 } 952 }; 953 954 /** 955 * ajaxForm() provides a mechanism for fully automating form submission. 956 * 957 * The advantages of using this method instead of ajaxSubmit() are: 958 * 959 * 1: This method will include coordinates for <input type="image"> elements (if the element 960 * is used to submit the form). 961 * 2. This method will include the submit element's name/value data (for the element that was 962 * used to submit the form). 963 * 3. This method binds the submit() method to the form for you. 964 * 965 * The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely 966 * passes the options argument along after properly binding events for submit elements and 967 * the form itself. 968 */ 969 $.fn.ajaxForm = function(options, data, dataType, onSuccess) { 970 if (typeof options === 'string' || (options === false && arguments.length > 0)) { 971 options = { 972 'url' : options, 973 'data' : data, 974 'dataType' : dataType 975 }; 976 977 if (typeof onSuccess === 'function') { 978 options.success = onSuccess; 979 } 980 } 981 982 options = options || {}; 983 options.delegation = options.delegation && $.isFunction($.fn.on); 984 985 // in jQuery 1.3+ we can fix mistakes with the ready state 986 if (!options.delegation && this.length === 0) { 987 var o = {s: this.selector, c: this.context}; 988 989 if (!$.isReady && o.s) { 990 log('DOM not ready, queuing ajaxForm'); 991 $(function() { 992 $(o.s, o.c).ajaxForm(options); 993 }); 994 995 return this; 996 } 997 998 // is your DOM ready? http://docs.jquery.com/Tutorials:Introducing_$(document).ready() 999 log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)')); 1000 1001 return this; 1002 } 1003 1004 if (options.delegation) { 1005 $(document) 1006 .off('submit.form-plugin', this.selector, doAjaxSubmit) 1007 .off('click.form-plugin', this.selector, captureSubmittingElement) 1008 .on('submit.form-plugin', this.selector, options, doAjaxSubmit) 1009 .on('click.form-plugin', this.selector, options, captureSubmittingElement); 1010 1011 return this; 1012 } 1013 1014 return this.ajaxFormUnbind() 1015 .on('submit.form-plugin', options, doAjaxSubmit) 1016 .on('click.form-plugin', options, captureSubmittingElement); 1017 }; 1018 1019 // private event handlers 1020 function doAjaxSubmit(e) { 1021 /* jshint validthis:true */ 1022 var options = e.data; 1023 1024 if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed 1025 e.preventDefault(); 1026 $(e.target).closest('form').ajaxSubmit(options); // #365 1027 } 1028 } 1029 1030 function captureSubmittingElement(e) { 1031 /* jshint validthis:true */ 1032 var target = e.target; 1033 var $el = $(target); 1034 1035 if (!$el.is('[type=submit],[type=image]')) { 1036 // is this a child element of the submit el? (ex: a span within a button) 1037 var t = $el.closest('[type=submit]'); 1038 1039 if (t.length === 0) { 1040 return; 1041 } 1042 target = t[0]; 1043 } 1044 1045 var form = target.form; 1046 1047 form.clk = target; 1048 1049 if (target.type === 'image') { 1050 if (typeof e.offsetX !== 'undefined') { 1051 form.clk_x = e.offsetX; 1052 form.clk_y = e.offsetY; 1053 1054 } else if (typeof $.fn.offset === 'function') { 1055 var offset = $el.offset(); 1056 1057 form.clk_x = e.pageX - offset.left; 1058 form.clk_y = e.pageY - offset.top; 1059 1060 } else { 1061 form.clk_x = e.pageX - target.offsetLeft; 1062 form.clk_y = e.pageY - target.offsetTop; 1063 } 1064 } 1065 // clear form vars 1066 setTimeout(function() { 1067 form.clk = form.clk_x = form.clk_y = null; 1068 }, 100); 1069 } 1070 1071 1072 // ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm 1073 $.fn.ajaxFormUnbind = function() { 1074 return this.off('submit.form-plugin click.form-plugin'); 1075 }; 1076 1077 /** 1078 * formToArray() gathers form element data into an array of objects that can 1079 * be passed to any of the following ajax functions: $.get, $.post, or load. 1080 * Each object in the array has both a 'name' and 'value' property. An example of 1081 * an array for a simple login form might be: 1082 * 1083 * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ] 1084 * 1085 * It is this array that is passed to pre-submit callback functions provided to the 1086 * ajaxSubmit() and ajaxForm() methods. 1087 */ 1088 $.fn.formToArray = function(semantic, elements, filtering) { 1089 var a = []; 1090 1091 if (this.length === 0) { 1092 return a; 1093 } 1094 1095 var form = this[0]; 1096 var formId = this.attr('id'); 1097 var els = (semantic || typeof form.elements === 'undefined') ? form.getElementsByTagName('*') : form.elements; 1098 var els2; 1099 1100 if (els) { 1101 els = $.makeArray(els); // convert to standard array 1102 } 1103 1104 // #386; account for inputs outside the form which use the 'form' attribute 1105 // FinesseRus: in non-IE browsers outside fields are already included in form.elements. 1106 if (formId && (semantic || /(Edge|Trident)\//.test(navigator.userAgent))) { 1107 els2 = $(':input[form="' + formId + '"]').get(); // hat tip @thet 1108 if (els2.length) { 1109 els = (els || []).concat(els2); 1110 } 1111 } 1112 1113 if (!els || !els.length) { 1114 return a; 1115 } 1116
1117 if ($.isFunction(filtering)) { 1118 els = $.map(els, filtering); 1119 } 1120 1121 var i, j, n, v, el, max, jmax; 1122 1123 for (i = 0, max = els.length; i < max; i++) { 1124 el = els[i]; 1125 n = el.name; 1126 if (!n || el.disabled) { 1127 continue; 1128 } 1129 1130 if (semantic && form.clk && el.type === 'image') { 1131 // handle image inputs on the fly when semantic == true 1132 if (form.clk === el) { 1133 a.push({name: n, value: $(el).val(), type: el.type}); 1134 a.push({name: n + '.x', value: form.clk_x}, {name: n + '.y', value: form.clk_y}); 1135 } 1136 continue; 1137 } 1138 1139 v = $.fieldValue(el, true); 1140 if (v && v.constructor === Array) { 1141 if (elements) { 1142 elements.push(el); 1143 } 1144 for (j = 0, jmax = v.length; j < jmax; j++) { 1145 a.push({name: n, value: v[j]}); 1146 } 1147 1148 } else if (feature.fileapi && el.type === 'file') { 1149 if (elements) { 1150 elements.push(el); 1151 } 1152 1153 var files = el.files; 1154 1155 if (files.length) { 1156 for (j = 0; j < files.length; j++) { 1157 a.push({name: n, value: files[j], type: el.type}); 1158 } 1159 } else { 1160 // #180 1161 a.push({name: n, value: '', type: el.type}); 1162 } 1163 1164 } else if (v !== null && typeof v !== 'undefined') { 1165 if (elements) { 1166 elements.push(el); 1167 } 1168 a.push({name: n, value: v, type: el.type, required: el.required}); 1169 } 1170 } 1171 1172 if (!semantic && form.clk) { 1173 // input type=='image' are not found in elements array! handle it here 1174 var $input = $(form.clk), input = $input[0]; 1175 1176 n = input.name; 1177 1178 if (n && !input.disabled && input.type === 'image') { 1179 a.push({name: n, value: $input.val()}); 1180 a.push({name: n + '.x', value: form.clk_x}, {name: n + '.y', value: form.clk_y}); 1181 } 1182 } 1183 1184 return a; 1185 }; 1186 1187 /** 1188 * Serializes form data into a 'submittable' string. This method will return a string 1189 * in the format: name1=value1&name2=value2 1190 */ 1191 $.fn.formSerialize = function(semantic) { 1192 // hand off to jQuery.param for proper encoding 1193 return $.param(this.formToArray(semantic)); 1194 }; 1195 1196 /** 1197 * Serializes all field elements in the jQuery object into a query string. 1198 * This method will return a string in the format: name1=value1&name2=value2 1199 */ 1200 $.fn.fieldSerialize = function(successful) { 1201 var a = []; 1202 1203 this.each(function() { 1204 var n = this.name; 1205 1206 if (!n) { 1207 return; 1208 } 1209 1210 var v = $.fieldValue(this, successful); 1211 1212 if (v && v.constructor === Array) { 1213 for (var i = 0, max = v.length; i < max; i++) { 1214 a.push({name: n, value: v[i]}); 1215 } 1216 1217 } else if (v !== null && typeof v !== 'undefined') { 1218 a.push({name: this.name, value: v}); 1219 } 1220 }); 1221 1222 // hand off to jQuery.param for proper encoding 1223 return $.param(a); 1224 }; 1225 1226 /** 1227 * Returns the value(s) of the element in the matched set. For example, consider the following form: 1228 * 1229 * <form><fieldset> 1230 * <input name="A" type="text"> 1231 * <input name="A" type="text"> 1232 * <input name="B" type="checkbox" value="B1"> 1233 * <input name="B" type="checkbox" value="B2"> 1234 * <input name="C" type="radio" value="C1"> 1235 * <input name="C" type="radio" value="C2"> 1236 * </fieldset></form> 1237 * 1238 * var v = $('input[type=text]').fieldValue(); 1239 * // if no values are entered into the text inputs 1240 * v === ['',''] 1241 * // if values entered into the text inputs are 'foo' and 'bar' 1242 * v === ['foo','bar'] 1243 * 1244 * var v = $('input[type=checkbox]').fieldValue(); 1245 * // if neither checkbox is checked 1246 * v === undefined 1247 * // if both checkboxes are checked 1248 * v === ['B1', 'B2'] 1249 * 1250 * var v = $('input[type=radio]').fieldValue(); 1251 * // if neither radio is checked 1252 * v === undefined 1253 * // if first radio is checked 1254 * v === ['C1'] 1255 * 1256 * The successful argument controls whether or not the field element must be 'successful' 1257 * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls). 1258 * The default value of the successful argument is true. If this value is false the value(s) 1259 * for each element is returned. 1260 * 1261 * Note: This method *always* returns an array. If no valid value can be determined the 1262 * array will be empty, otherwise it will contain one or more values. 1263 */ 1264 $.fn.fieldValue = function(successful) { 1265 for (var val = [], i = 0, max = this.length; i < max; i++) { 1266 var el = this[i]; 1267 var v = $.fieldValue(el, successful); 1268 1269 if (v === null || typeof v === 'undefined' || (v.constructor === Array && !v.length)) { 1270 continue; 1271 } 1272 1273 if (v.constructor === Array) { 1274 $.merge(val, v); 1275 } else { 1276 val.push(v); 1277 } 1278 } 1279 1280 return val; 1281 }; 1282 1283 /** 1284 * Returns the value of the field element. 1285 */ 1286 $.fieldValue = function(el, successful) { 1287 var n = el.name, t = el.type, tag = el.tagName.toLowerCase(); 1288 1289 if (typeof successful === 'undefined') { 1290 successful = true; 1291 } 1292 1293 /* eslint-disable no-mixed-operators */ 1294 if (successful && (!n || el.disabled || t === 'reset' || t === 'button' || 1295 (t === 'checkbox' || t === 'radio') && !el.checked || 1296 (t === 'submit' || t === 'image') && el.form && el.form.clk !== el || 1297 tag === 'select' && el.selectedIndex === -1)) { 1298 /* eslint-enable no-mixed-operators */ 1299 return null; 1300 } 1301 1302 if (tag === 'select') { 1303 var index = el.selectedIndex; 1304 1305 if (index < 0) { 1306 return null; 1307 } 1308 1309 var a = [], ops = el.options; 1310 var one = (t === 'select-one'); 1311 var max = (one ? index + 1 : ops.length); 1312 1313 for (var i = (one ? index : 0); i < max; i++) { 1314 var op = ops[i]; 1315 1316 if (op.selected && !op.disabled) { 1317 var v = op.value; 1318 1319 if (!v) { // extra pain for IE... 1320 v = (op.attributes && op.attributes.value && !(op.attributes.value.specified)) ? op.text : op.value; 1321 } 1322 1323 if (one) { 1324 return v; 1325 } 1326 1327 a.push(v); 1328 } 1329 } 1330 1331 return a; 1332 } 1333 1334 return $(el).val().replace(rCRLF, '\r\n'); 1335 }; 1336 1337 /** 1338 * Clears the form data. Takes the following actions on the form's input fields: 1339 * - input text fields will have their 'value' property set to the empty string 1340 * - select elements will have their 'selectedIndex' property set to -1 1341 * - checkbox and radio inputs will have their 'checked' property set to false 1342 * - inputs of type submit, button, reset, and hidden will *not* be effected 1343 * - button elements will *not* be effected 1344 */ 1345 $.fn.clearForm = function(includeHidden) { 1346 return this.each(function() { 1347 $('input,select,textarea', this).clearFields(includeHidden); 1348 }); 1349 }; 1350 1351 /** 1352 * Clears the selected form elements. 1353 */ 1354 $.fn.clearFields = $.fn.clearInputs = function(includeHidden) { 1355 var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list 1356 1357 return this.each(function() { 1358 var t = this.type, tag = this.tagName.toLowerCase(); 1359 1360 if (re.test(t) || tag === 'textarea') { 1361 this.value = ''; 1362 1363 } else if (t === 'checkbox' || t === 'radio') { 1364 this.checked = false;
1365 1366 } else if (tag === 'select') { 1367 this.selectedIndex = -1; 1368 1369 } else if (t === 'file') { 1370 if (/MSIE/.test(navigator.userAgent)) { 1371 $(this).replaceWith($(this).clone(true)); 1372 } else { 1373 $(this).val(''); 1374 } 1375 1376 } else if (includeHidden) { 1377 // includeHidden can be the value true, or it can be a selector string 1378 // indicating a special test; for example: 1379 // $('#myForm').clearForm('.special:hidden') 1380 // the above would clean hidden inputs that have the class of 'special' 1381 if ((includeHidden === true && /hidden/.test(t)) || 1382 (typeof includeHidden === 'string' && $(this).is(includeHidden))) { 1383 this.value = ''; 1384 } 1385 } 1386 }); 1387 }; 1388 1389 1390 /** 1391 * Resets the form data or individual elements. Takes the following actions 1392 * on the selected tags: 1393 * - all fields within form elements will be reset to their original value 1394 * - input / textarea / select fields will be reset to their original value 1395 * - option / optgroup fields (for multi-selects) will defaulted individually 1396 * - non-multiple options will find the right select to default 1397 * - label elements will be searched against its 'for' attribute 1398 * - all others will be searched for appropriate children to default 1399 */ 1400 $.fn.resetForm = function() { 1401 return this.each(function() { 1402 var el = $(this); 1403 var tag = this.tagName.toLowerCase(); 1404 1405 switch (tag) { 1406 case 'input': 1407 this.checked = this.defaultChecked; 1408 // fall through 1409 1410 case 'textarea': 1411 this.value = this.defaultValue; 1412 1413 return true; 1414 1415 case 'option': 1416 case 'optgroup': 1417 var select = el.parents('select'); 1418 1419 if (select.length && select[0].multiple) { 1420 if (tag === 'option') { 1421 this.selected = this.defaultSelected; 1422 } else { 1423 el.find('option').resetForm(); 1424 } 1425 } else { 1426 select.resetForm(); 1427 } 1428 1429 return true; 1430 1431 case 'select': 1432 el.find('option').each(function(i) { // eslint-disable-line consistent-return 1433 this.selected = this.defaultSelected; 1434 if (this.defaultSelected && !el[0].multiple) { 1435 el[0].selectedIndex = i; 1436 1437 return false; 1438 } 1439 }); 1440 1441 return true; 1442 1443 case 'label': 1444 var forEl = $(el.attr('for')); 1445 var list = el.find('input,select,textarea'); 1446 1447 if (forEl[0]) { 1448 list.unshift(forEl[0]); 1449 } 1450 1451 list.resetForm(); 1452 1453 return true; 1454 1455 case 'form': 1456 // guard against an input with the name of 'reset' 1457 // note that IE reports the reset function as an 'object' 1458 if (typeof this.reset === 'function' || (typeof this.reset === 'object' && !this.reset.nodeType)) { 1459 this.reset(); 1460 } 1461 1462 return true; 1463 1464 default: 1465 el.find('form,input,label,select,textarea').resetForm(); 1466 1467 return true; 1468 } 1469 }); 1470 }; 1471 1472 /** 1473 * Enables or disables any matching elements. 1474 */ 1475 $.fn.enable = function(b) { 1476 if (typeof b === 'undefined') { 1477 b = true; 1478 } 1479 1480 return this.each(function() { 1481 this.disabled = !b; 1482 }); 1483 }; 1484 1485 /** 1486 * Checks/unchecks any matching checkboxes or radio buttons and 1487 * selects/deselects and matching option elements. 1488 */ 1489 $.fn.selected = function(select) { 1490 if (typeof select === 'undefined') { 1491 select = true; 1492 } 1493 1494 return this.each(function() { 1495 var t = this.type; 1496 1497 if (t === 'checkbox' || t === 'radio') { 1498 this.checked = select; 1499 1500 } else if (this.tagName.toLowerCase() === 'option') { 1501 var $sel = $(this).parent('select'); 1502 1503 if (select && $sel[0] && $sel[0].type === 'select-one') { 1504 // deselect all other options 1505 $sel.find('option').selected(false); 1506 } 1507 1508 this.selected = select; 1509 } 1510 }); 1511 }; 1512 1513 // expose debug var 1514 $.fn.ajaxSubmit.debug = false; 1515 1516 // helper fn for console logging 1517 function log() { 1518 if (!$.fn.ajaxSubmit.debug) { 1519 return; 1520 } 1521 1522 var msg = '[jquery.form] ' + Array.prototype.join.call(arguments, ''); 1523 1524 if (window.console && window.console.log) { 1525 window.console.log(msg); 1526 1527 } else if (window.opera && window.opera.postError) { 1528 window.opera.postError(msg); 1529 } 1530 } 1531}));
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.