[ Index ] |
PHP Cross Reference of WordPress |
[Summary view] [Print] [Text view]
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 >83 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 /* jslint evil:true */ 927 return window['eval']('(' + s + ')'); // eslint-disable-line dot-notation 928 }; 929 930 var httpData = function(xhr, type, s) { // mostly lifted from jq1.4.4 931 932 var ct = xhr.getResponseHeader('content-type') || '', 933 xml = ((type === 'xml' || !type) && ct.indexOf('xml') >= 0), 934 data = xml ? xhr.responseXML : xhr.responseText; 935 936 if (xml && data.documentElement.nodeName === 'parsererror') { 937 if ($.error) { 938 $.error('parsererror'); 939 } 940 } 941 if (s && s.dataFilter) { 942 data = s.dataFilter(data, type); 943 } 944 if (typeof data === 'string') { 945 if ((type === 'json' || !type) && ct.indexOf('json') >= 0) { 946 data = parseJSON(data); 947 } else if ((type === 'script' || !type) && ct.indexOf('javascript') >= 0) { 948 $.globalEval(data); 949 } 950 } 951 952 return data; 953 }; 954 955 return deferred; 956 } 957 }; 958 959 /** 960 * ajaxForm() provides a mechanism for fully automating form submission. 961 * 962 * The advantages of using this method instead of ajaxSubmit() are: 963 * 964 * 1: This method will include coordinates for <input type="image"> elements (if the element 965 * is used to submit the form). 966 * 2. This method will include the submit element's name/value data (for the element that was 967 * used to submit the form). 968 * 3. This method binds the submit() method to the form for you. 969 * 970 * The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely 971 * passes the options argument along after properly binding events for submit elements and 972 * the form itself. 973 */ 974 $.fn.ajaxForm = function(options, data, dataType, onSuccess) { 975 if (typeof options === 'string' || (options === false && arguments.length > 0)) { 976 options = { 977 'url' : options, 978 'data' : data, 979 'dataType' : dataType 980 }; 981 982 if (typeof onSuccess === 'function') { 983 options.success = onSuccess; 984 } 985 } 986 987 options = options || {}; 988 options.delegation = options.delegation && $.isFunction($.fn.on); 989 990 // in jQuery 1.3+ we can fix mistakes with the ready state 991 if (!options.delegation && this.length === 0) { 992 var o = {s: this.selector, c: this.context}; 993 994 if (!$.isReady && o.s) { 995 log('DOM not ready, queuing ajaxForm'); 996 $(function() { 997 $(o.s, o.c).ajaxForm(options); 998 }); 999 1000 return this; 1001 } 1002 1003 // is your DOM ready? http://docs.jquery.com/Tutorials:Introducing_$(document).ready() 1004 log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)')); 1005 1006 return this; 1007 } 1008 1009 if (options.delegation) { 1010 $(document) 1011 .off('submit.form-plugin', this.selector, doAjaxSubmit) 1012 .off('click.form-plugin', this.selector, captureSubmittingElement) 1013 .on('submit.form-plugin', this.selector, options, doAjaxSubmit) 1014 .on('click.form-plugin', this.selector, options, captureSubmittingElement); 1015 1016 return this; 1017 } 1018 1019 if (options.beforeFormUnbind) { 1020 options.beforeFormUnbind(this, options); 1021 } 1022 1023 return this.ajaxFormUnbind() 1024 .on('submit.form-plugin', options, doAjaxSubmit) 1025 .on('click.form-plugin', options, captureSubmittingElement); 1026 }; 1027 1028 // private event handlers 1029 function doAjaxSubmit(e) { 1030 /* jshint validthis:true */ 1031 var options = e.data; 1032 1033 if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed 1034 e.preventDefault(); 1035 $(e.target).closest('form').ajaxSubmit(options); // #365 1036 } 1037 } 1038 1039 function captureSubmittingElement(e) { 1040 /* jshint validthis:true */ 1041 var target = e.target; 1042 var $el = $(target); 1043 1044 if (!$el.is('[type=submit],[type=image]')) { 1045 // is this a child element of the submit el? (ex: a span within a button) 1046 var t = $el.closest('[type=submit]'); 1047 1048 if (t.length === 0) { 1049 return; 1050 } 1051 target = t[0]; 1052 } 1053 1054 var form = target.form; 1055 1056 form.clk = target; 1057 1058 if (target.type === 'image') { 1059 if (typeof e.offsetX !== 'undefined') { 1060 form.clk_x = e.offsetX; 1061 form.clk_y = e.offsetY; 1062 1063 } else if (typeof $.fn.offset === 'function') { 1064 var offset = $el.offset(); 1065 1066 form.clk_x = e.pageX - offset.left; 1067 form.clk_y = e.pageY - offset.top; 1068 1069 } else { 1070 form.clk_x = e.pageX - target.offsetLeft; 1071 form.clk_y = e.pageY - target.offsetTop; 1072 } 1073 } 1074 // clear form vars 1075 setTimeout(function() { 1076 form.clk = form.clk_x = form.clk_y = null; 1077 }, 100); 1078 } 1079 1080 1081 // ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm 1082 $.fn.ajaxFormUnbind = function() { 1083 return this.off('submit.form-plugin click.form-plugin'); 1084 }; 1085 1086 /** 1087 * formToArray() gathers form element data into an array of objects that can 1088 * be passed to any of the following ajax functions: $.get, $.post, or load. 1089 * Each object in the array has both a 'name' and 'value' property. An example of 1090 * an array for a simple login form might be: 1091 * 1092 * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ] 1093 * 1094 * It is this array that is passed to pre-submit callback functions provided to the 1095 * ajaxSubmit() and ajaxForm() methods. 1096 */ 1097 $.fn.formToArray = function(semantic, elements, filtering) { 1098 var a = []; 1099 1100 if (this.length === 0) { 1101 return a; 1102 } 1103 1104 var form = this[0]; 1105 var formId = this.attr('id'); 1106 var els = (semantic || typeof form.elements === 'undefined') ? form.getElementsByTagName('*') : form.elements; 1107 var els2; 1108 1109 if (els) { 1110 els = $.makeArray(els); // convert to standard array 1111 } 1112 1113 // #386; account for inputs outside the form which use the 'form' attribute 1114 // FinesseRus: in non-IE browsers outside fields are already included in form.elements. 1115 if (formId && (semantic || /(Edge|Trident)\//.test(navigator.userAgent))) { 1116 els2 = $(':input[form="' + formId + '"]').get(); // hat tip @thet 1117 if (els2.length) { 1118 els = (els || []).concat(els2); 1119 } 1120 } 1121 1122 if (!els || !els.length) { 1123 return a; 1124 } 1125 1126 if ($.isFunction(filtering)) { 1127 els = $.map(els, filtering); 1128 } 1129 1130 var i, j, n, v, el, max, jmax; 1131 1132 for (i = 0, max = els.length; i < max; i++) { 1133 el = els[i]; 1134 n = el.name; 1135 if (!n || el.disabled) { 1136 continue; 1137 } 1138 1139 if (semantic && form.clk && el.type === 'image') { 1140 // handle image inputs on the fly when semantic == true 1141 if (form.clk === el) { 1142 a.push({name: n, value: $(el).val(), type: el.type}); 1143 a.push({name: n + '.x', value: form.clk_x}, {name: n + '.y', value: form.clk_y}); 1144 } 1145 continue; 1146 } 1147 1148 v = $.fieldValue(el, true); 1149 if (v && v.constructor === Array) { 1150 if (elements) { 1151 elements.push(el); 1152 } 1153 for (j = 0, jmax = v.length; j < jmax; j++) { 1154 a.push({name: n, value: v[j]}); 1155 } 1156 1157 } else if (feature.fileapi && el.type === 'file') { 1158 if (elements) { 1159 elements.push(el); 1160 } 1161 1162 var files = el.files; 1163 1164 if (files.length) { 1165 for (j = 0; j < files.length; j++) { 1166 a.push({name: n, value: files[j], type: el.type}); 1167 } 1168 } else { 1169 // #180 1170 a.push({name: n, value: '', type: el.type}); 1171 } 1172 1173 } else if (v !== null && typeof v !== 'undefined') { 1174 if (elements) { 1175 elements.push(el); 1176 } 1177 a.push({name: n, value: v, type: el.type, required: el.required}); 1178 } 1179 } 1180 1181 if (!semantic && form.clk) { 1182 // input type=='image' are not found in elements array! handle it here 1183 var $input = $(form.clk), input = $input[0]; 1184 1185 n = input.name; 1186 1187 if (n && !input.disabled && input.type === 'image') { 1188 a.push({name: n, value: $input.val()}); 1189 a.push({name: n + '.x', value: form.clk_x}, {name: n + '.y', value: form.clk_y}); 1190 } 1191 } 1192 1193 return a; 1194 }; 1195 1196 /** 1197 * Serializes form data into a 'submittable' string. This method will return a string 1198 * in the format: name1=value1&name2=value2 1199 */ 1200 $.fn.formSerialize = function(semantic) { 1201 // hand off to jQuery.param for proper encoding 1202 return $.param(this.formToArray(semantic)); 1203 }; 1204 1205 /** 1206 * Serializes all field elements in the jQuery object into a query string. 1207 * This method will return a string in the format: name1=value1&name2=value2 1208 */ 1209 $.fn.fieldSerialize = function(successful) { 1210 var a = []; 1211 1212 this.each(function() { 1213 var n = this.name; 1214 1215 if (!n) { 1216 return; 1217 } 1218 1219 var v = $.fieldValue(this, successful); 1220 1221 if (v && v.constructor === Array) { 1222 for (var i = 0, max = v.length; i < max; i++) { 1223 a.push({name: n, value: v[i]}); 1224 } 1225 1226 } else if (v !== null && typeof v !== 'undefined') { 1227 a.push({name: this.name, value: v}); 1228 } 1229 }); 1230 1231 // hand off to jQuery.param for proper encoding 1232 return $.param(a); 1233 }; 1234 1235 /** 1236 * Returns the value(s) of the element in the matched set. For example, consider the following form: 1237 * 1238 * <form><fieldset> 1239 * <input name="A" type="text"> 1240 * <input name="A" type="text"> 1241 * <input name="B" type="checkbox" value="B1"> 1242 * <input name="B" type="checkbox" value="B2"> 1243 * <input name="C" type="radio" value="C1"> 1244 * <input name="C" type="radio" value="C2"> 1245 * </fieldset></form> 1246 * 1247 * var v = $('input[type=text]').fieldValue(); 1248 * // if no values are entered into the text inputs 1249 * v === ['',''] 1250 * // if values entered into the text inputs are 'foo' and 'bar' 1251 * v === ['foo','bar'] 1252 * 1253 * var v = $('input[type=checkbox]').fieldValue(); 1254 * // if neither checkbox is checked 1255 * v === undefined 1256 * // if both checkboxes are checked 1257 * v === ['B1', 'B2'] 1258 * 1259 * var v = $('input[type=radio]').fieldValue(); 1260 * // if neither radio is checked 1261 * v === undefined 1262 * // if first radio is checked 1263 * v === ['C1'] 1264 * 1265 * The successful argument controls whether or not the field element must be 'successful' 1266 * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls). 1267 * The default value of the successful argument is true. If this value is false the value(s) 1268 * for each element is returned. 1269 * 1270 * Note: This method *always* returns an array. If no valid value can be determined the 1271 * array will be empty, otherwise it will contain one or more values. 1272 */ 1273 $.fn.fieldValue = function(successful) { 1274 for (var val = [], i = 0, max = this.length; i < max; i++) { 1275 var el = this[i]; 1276 var v = $.fieldValue(el, successful); 1277 1278 if (v === null || typeof v === 'undefined' || (v.constructor === Array && !v.length)) { 1279 continue; 1280 } 1281 1282 if (v.constructor === Array) { 1283 $.merge(val, v); 1284 } else { 1285 val.push(v); 1286 } 1287 } 1288 1289 return val; 1290 }; 1291 1292 /** 1293 * Returns the value of the field element. 1294 */ 1295 $.fieldValue = function(el, successful) { 1296 var n = el.name, t = el.type, tag = el.tagName.toLowerCase(); 1297 1298 if (typeof successful === 'undefined') { 1299 successful = true; 1300 } 1301 1302 /* eslint-disable no-mixed-operators */ 1303 if (successful && (!n || el.disabled || t === 'reset' || t === 'button' || 1304 (t === 'checkbox' || t === 'radio') && !el.checked || 1305 (t === 'submit' || t === 'image') && el.form && el.form.clk !== el || 1306 tag === 'select' && el.selectedIndex === -1)) { 1307 /* eslint-enable no-mixed-operators */ 1308 return null; 1309 } 1310 1311 if (tag === 'select') { 1312 var index = el.selectedIndex; 1313 1314 if (index < 0) { 1315 return null; 1316 } 1317 1318 var a = [], ops = el.options; 1319 var one = (t === 'select-one'); 1320 var max = (one ? index + 1 : ops.length); 1321 1322 for (var i = (one ? index : 0); i < max; i++) { 1323 var op = ops[i]; 1324 1325 if (op.selected && !op.disabled) { 1326 var v = op.value; 1327 1328 if (!v) { // extra pain for IE... 1329 v = (op.attributes && op.attributes.value && !(op.attributes.value.specified)) ? op.text : op.value; 1330 } 1331 1332 if (one) { 1333 return v; 1334 } 1335 1336 a.push(v); 1337 } 1338 } 1339 1340 return a; 1341 } 1342 1343 return $(el).val().replace(rCRLF, '\r\n'); 1344 }; 1345 1346 /** 1347 * Clears the form data. Takes the following actions on the form's input fields: 1348 * - input text fields will have their 'value' property set to the empty string 1349 * - select elements will have their 'selectedIndex' property set to -1 1350 * - checkbox and radio inputs will have their 'checked' property set to false 1351 * - inputs of type submit, button, reset, and hidden will *not* be effected 1352 * - button elements will *not* be effected 1353 */ 1354 $.fn.clearForm = function(includeHidden) { 1355 return this.each(function() { 1356 $('input,select,textarea', this).clearFields(includeHidden); 1357 }); 1358 }; 1359 1360 /** 1361 * Clears the selected form elements. 1362 */ 1363 $.fn.clearFields = $.fn.clearInputs = function(includeHidden) { 1364 var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list 1365 1366 return this.each(function() { 1367 var t = this.type, tag = this.tagName.toLowerCase(); 1368 1369 if (re.test(t) || tag === 'textarea') { 1370 this.value = ''; 1371 1372 } else if (t === 'checkbox' || t === 'radio') { 1373 this.checked = false; 1374 1375 } else if (tag === 'select') { 1376 this.selectedIndex = -1; 1377 1378 } else if (t === 'file') { 1379 if (/MSIE/.test(navigator.userAgent)) { 1380 $(this).replaceWith($(this).clone(true)); 1381 } else { 1382 $(this).val(''); 1383 } 1384 1385 } else if (includeHidden) { 1386 // includeHidden can be the value true, or it can be a selector string 1387 // indicating a special test; for example: 1388 // $('#myForm').clearForm('.special:hidden') 1389 // the above would clean hidden inputs that have the class of 'special' 1390 if ((includeHidden === true && /hidden/.test(t)) || 1391 (typeof includeHidden === 'string' && $(this).is(includeHidden))) { 1392 this.value = ''; 1393 } 1394 } 1395 }); 1396 }; 1397 1398 1399 /** 1400 * Resets the form data or individual elements. Takes the following actions 1401 * on the selected tags: 1402 * - all fields within form elements will be reset to their original value 1403 * - input / textarea / select fields will be reset to their original value 1404 * - option / optgroup fields (for multi-selects) will defaulted individually 1405 * - non-multiple options will find the right select to default 1406 * - label elements will be searched against its 'for' attribute 1407 * - all others will be searched for appropriate children to default 1408 */ 1409 $.fn.resetForm = function() { 1410 return this.each(function() { 1411 var el = $(this); 1412 var tag = this.tagName.toLowerCase(); 1413 1414 switch (tag) { 1415 case 'input': 1416 this.checked = this.defaultChecked; 1417 // fall through 1418 1419 case 'textarea': 1420 this.value = this.defaultValue; 1421 1422 return true; 1423 1424 case 'option': 1425 case 'optgroup': 1426 var select = el.parents('select'); 1427 1428 if (select.length && select[0].multiple) { 1429 if (tag === 'option') { 1430 this.selected = this.defaultSelected; 1431 } else { 1432 el.find('option').resetForm(); 1433 } 1434 } else { 1435 select.resetForm(); 1436 } 1437 1438 return true; 1439 1440 case 'select': 1441 el.find('option').each(function(i) { // eslint-disable-line consistent-return 1442 this.selected = this.defaultSelected; 1443 if (this.defaultSelected && !el[0].multiple) { 1444 el[0].selectedIndex = i; 1445 1446 return false; 1447 } 1448 }); 1449 1450 return true; 1451 1452 case 'label': 1453 var forEl = $(el.attr('for')); 1454 var list = el.find('input,select,textarea'); 1455 1456 if (forEl[0]) { 1457 list.unshift(forEl[0]); 1458 } 1459 1460 list.resetForm(); 1461 1462 return true; 1463 1464 case 'form': 1465 // guard against an input with the name of 'reset' 1466 // note that IE reports the reset function as an 'object' 1467 if (typeof this.reset === 'function' || (typeof this.reset === 'object' && !this.reset.nodeType)) { 1468 this.reset(); 1469 } 1470 1471 return true; 1472 1473 default: 1474 el.find('form,input,label,select,textarea').resetForm(); 1475 1476 return true; 1477 } 1478 }); 1479 }; 1480 1481 /** 1482 * Enables or disables any matching elements. 1483 */ 1484 $.fn.enable = function(b) { 1485 if (typeof b === 'undefined') { 1486 b = true; 1487 } 1488 1489 return this.each(function() { 1490 this.disabled = !b; 1491 }); 1492 }; 1493 1494 /** 1495 * Checks/unchecks any matching checkboxes or radio buttons and 1496 * selects/deselects and matching option elements. 1497 */ 1498 $.fn.selected = function(select) { 1499 if (typeof select === 'undefined') { 1500 select = true; 1501 } 1502 1503 return this.each(function() { 1504 var t = this.type; 1505 1506 if (t === 'checkbox' || t === 'radio') { 1507 this.checked = select; 1508 1509 } else if (this.tagName.toLowerCase() === 'option') { 1510 var $sel = $(this).parent('select'); 1511 1512 if (select && $sel[0] && $sel[0].type === 'select-one') { 1513 // deselect all other options 1514 $sel.find('option').selected(false); 1515 } 1516 1517 this.selected = select; 1518 } 1519 }); 1520 }; 1521 1522 // expose debug var 1523 $.fn.ajaxSubmit.debug = false; 1524 1525 // helper fn for console logging 1526 function log() { 1527 if (!$.fn.ajaxSubmit.debug) { 1528 return; 1529 } 1530 1531 var msg = '[jquery.form] ' + Array.prototype.join.call(arguments, ''); 1532 1533 if (window.console && window.console.log) { 1534 window.console.log(msg); 1535 1536 } else if (window.opera && window.opera.postError) { 1537 window.opera.postError(msg); 1538 } 1539 } 1540 }));
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Nov 21 01:00:03 2024 | Cross-referenced by PHPXref 0.7.1 |