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