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