[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
1 /*! 2 * jQuery Form Plugin 3 * version: 3.14 (30-JUL-2012) 4 * @requires jQuery v1.3.2 or later 5 * 6 * Examples and documentation at: http://malsup.com/jquery/form/ 7 * Project repository: https://github.com/malsup/form 8 * Dual licensed under the MIT and GPL licenses: 9 * http://malsup.github.com/mit-license.txt 10 * http://malsup.github.com/gpl-license-v2.txt 11 */ 12 /*global ActiveXObject alert */ 13 ;(function($) { 14 "use strict"; 15 16 /* 17 Usage Note: 18 ----------- 19 Do not use both ajaxSubmit and ajaxForm on the same form. These 20 functions are mutually exclusive. Use ajaxSubmit if you want 21 to bind your own submit handler to the form. For example, 22 23 $(document).ready(function() { 24 $('#myForm').on('submit', function(e) { 25 e.preventDefault(); // <-- important 26 $(this).ajaxSubmit({ 27 target: '#output' 28 }); 29 }); 30 }); 31 32 Use ajaxForm when you want the plugin to manage all the event binding 33 for you. For example, 34 35 $(document).ready(function() { 36 $('#myForm').ajaxForm({ 37 target: '#output' 38 }); 39 }); 40 41 You can also use ajaxForm with delegation (requires jQuery v1.7+), so the 42 form does not have to exist when you invoke ajaxForm: 43 44 $('#myForm').ajaxForm({ 45 delegation: true, 46 target: '#output' 47 }); 48 49 When using ajaxForm, the ajaxSubmit function will be invoked for you 50 at the appropriate time. 51 */ 52 53 /** 54 * Feature detection 55 */ 56 var feature = {}; 57 feature.fileapi = $("<input type='file'/>").get(0).files !== undefined; 58 feature.formdata = window.FormData !== undefined; 59 60 /** 61 * ajaxSubmit() provides a mechanism for immediately submitting 62 * an HTML form using AJAX. 63 */ 64 $.fn.ajaxSubmit = function(options) { 65 /*jshint scripturl:true */ 66 67 // fast fail if nothing selected (http://dev.jquery.com/ticket/2752) 68 if (!this.length) { 69 log('ajaxSubmit: skipping submit process - no element selected'); 70 return this; 71 } 72 73 var method, action, url, $form = this; 74 75 if (typeof options == 'function') { 76 options = { success: options }; 77 } 78 79 method = this.attr('method'); 80 action = this.attr('action'); 81 url = (typeof action === 'string') ? $.trim(action) : ''; 82 url = url || window.location.href || ''; 83 if (url) { 84 // clean url (don't include hash vaue) 85 url = (url.match(/^([^#]+)/)||[])[1]; 86 } 87 88 options = $.extend(true, { 89 url: url, 90 success: $.ajaxSettings.success, 91 type: method || 'GET', 92 iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank' 93 }, options); 94 95 // hook for manipulating the form data before it is extracted; 96 // convenient for use with rich editors like tinyMCE or FCKEditor 97 var veto = {}; 98 this.trigger('form-pre-serialize', [this, options, veto]); 99 if (veto.veto) { 100 log('ajaxSubmit: submit vetoed via form-pre-serialize trigger'); 101 return this; 102 } 103 104 // provide opportunity to alter form data before it is serialized 105 if (options.beforeSerialize && options.beforeSerialize(this, options) === false) { 106 log('ajaxSubmit: submit aborted via beforeSerialize callback'); 107 return this; 108 } 109 110 var traditional = options.traditional; 111 if ( traditional === undefined ) { 112 traditional = $.ajaxSettings.traditional; 113 } 114 115 var elements = []; 116 var qx, a = this.formToArray(options.semantic, elements); 117 if (options.data) { 118 options.extraData = options.data; 119 qx = $.param(options.data, traditional); 120 } 121 122 // give pre-submit callback an opportunity to abort the submit 123 if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) { 124 log('ajaxSubmit: submit aborted via beforeSubmit callback'); 125 return this; 126 } 127 128 // fire vetoable 'validate' event 129 this.trigger('form-submit-validate', [a, this, options, veto]); 130 if (veto.veto) { 131 log('ajaxSubmit: submit vetoed via form-submit-validate trigger'); 132 return this; 133 } 134 135 var q = $.param(a, traditional); 136 if (qx) { 137 q = ( q ? (q + '&' + qx) : qx ); 138 } 139 if (options.type.toUpperCase() == 'GET') { 140 options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q; 141 options.data = null; // data is null for 'get' 142 } 143 else { 144 options.data = q; // data is the query string for 'post' 145 } 146 147 var callbacks = []; 148 if (options.resetForm) { 149 callbacks.push(function() { $form.resetForm(); }); 150 } 151 if (options.clearForm) { 152 callbacks.push(function() { $form.clearForm(options.includeHidden); }); 153 } 154 155 // perform a load on the target only if dataType is not provided 156 if (!options.dataType && options.target) { 157 var oldSuccess = options.success || function(){}; 158 callbacks.push(function(data) { 159 var fn = options.replaceTarget ? 'replaceWith' : 'html'; 160 $(options.target)[fn](data).each(oldSuccess, arguments); 161 }); 162 } 163 else if (options.success) { 164 callbacks.push(options.success); 165 } 166 167 options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg 168 var context = options.context || this ; // jQuery 1.4+ supports scope context 169 for (var i=0, max=callbacks.length; i < max; i++) { 170 callbacks[i].apply(context, [data, status, xhr || $form, $form]); 171 } 172 }; 173 174 // are there files to upload? 175 var fileInputs = $('input:file:enabled[value]', this); // [value] (issue #113) 176 var hasFileInputs = fileInputs.length > 0; 177 var mp = 'multipart/form-data'; 178 var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp); 179 180 var fileAPI = feature.fileapi && feature.formdata; 181 log("fileAPI :" + fileAPI); 182 var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI; 183 184 // options.iframe allows user to force iframe mode 185 // 06-NOV-09: now defaulting to iframe mode if file input is detected 186 if (options.iframe !== false && (options.iframe || shouldUseFrame)) { 187 // hack to fix Safari hang (thanks to Tim Molendijk for this) 188 // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d 189 if (options.closeKeepAlive) { 190 $.get(options.closeKeepAlive, function() { 191 fileUploadIframe(a); 192 }); 193 } 194 else { 195 fileUploadIframe(a); 196 } 197 } 198 else if ((hasFileInputs || multipart) && fileAPI) { 199 fileUploadXhr(a); 200 } 201 else { 202 $.ajax(options); 203 } 204 205 // clear element array 206 for (var k=0; k < elements.length; k++) 207 elements[k] = null; 208 209 // fire 'notify' event 210 this.trigger('form-submit-notify', [this, options]); 211 return this; 212 213 // XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz) 214 function fileUploadXhr(a) { 215 var formdata = new FormData(); 216 217 for (var i=0; i < a.length; i++) { 218 formdata.append(a[i].name, a[i].value); 219 } 220 221 if (options.extraData) { 222 for (var p in options.extraData) 223 if (options.extraData.hasOwnProperty(p)) 224 formdata.append(p, options.extraData[p]); 225 } 226 227 options.data = null; 228 229 var s = $.extend(true, {}, $.ajaxSettings, options, { 230 contentType: false, 231 processData: false, 232 cache: false, 233 type: 'POST' 234 }); 235 236 if (options.uploadProgress) { 237 // workaround because jqXHR does not expose upload property 238 s.xhr = function() { 239 var xhr = jQuery.ajaxSettings.xhr(); 240 if (xhr.upload) { 241 xhr.upload.onprogress = function(event) { 242 var percent = 0; 243 var position = event.loaded || event.position; /*event.position is deprecated*/ 244 var total = event.total; 245 if (event.lengthComputable) { 246 percent = Math.ceil(position / total * 100); 247 } 248 options.uploadProgress(event, position, total, percent); 249 }; 250 } 251 return xhr; 252 }; 253 } 254 255 s.data = null; 256 var beforeSend = s.beforeSend; 257 s.beforeSend = function(xhr, o) { 258 o.data = formdata; 259 if(beforeSend) 260 beforeSend.call(this, xhr, o); 261 }; 262 $.ajax(s); 263 } 264 265 // private function for handling file uploads (hat tip to YAHOO!) 266 function fileUploadIframe(a) { 267 var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle; 268 var useProp = !!$.fn.prop; 269 270 if ($(':input[name=submit],:input[id=submit]', form).length) { 271 // if there is an input with a name or id of 'submit' then we won't be 272 // able to invoke the submit fn on the form (at least not x-browser) 273 alert('Error: Form elements must not have name or id of "submit".'); 274 return; 275 } 276 277 if (a) { 278 // ensure that every serialized input is still enabled 279 for (i=0; i < elements.length; i++) { 280 el = $(elements[i]); 281 if ( useProp ) 282 el.prop('disabled', false); 283 else 284 el.removeAttr('disabled'); 285 } 286 } 287 288 s = $.extend(true, {}, $.ajaxSettings, options); 289 s.context = s.context || s; 290 id = 'jqFormIO' + (new Date().getTime()); 291 if (s.iframeTarget) { 292 $io = $(s.iframeTarget); 293 n = $io.attr('name'); 294 if (!n) 295 $io.attr('name', id); 296 else 297 id = n; 298 } 299 else { 300 $io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />'); 301 $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' }); 302 } 303 io = $io[0]; 304 305 306 xhr = { // mock object 307 aborted: 0, 308 responseText: null, 309 responseXML: null, 310 status: 0, 311 statusText: 'n/a', 312 getAllResponseHeaders: function() {}, 313 getResponseHeader: function() {}, 314 setRequestHeader: function() {}, 315 abort: function(status) { 316 var e = (status === 'timeout' ? 'timeout' : 'aborted'); 317 log('aborting upload... ' + e); 318 this.aborted = 1; 319 // #214 320 if (io.contentWindow.document.execCommand) { 321 try { // #214 322 io.contentWindow.document.execCommand('Stop'); 323 } catch(ignore) {} 324 } 325 $io.attr('src', s.iframeSrc); // abort op in progress 326 xhr.error = e; 327 if (s.error) 328 s.error.call(s.context, xhr, e, status); 329 if (g) 330 $.event.trigger("ajaxError", [xhr, s, e]); 331 if (s.complete) 332 s.complete.call(s.context, xhr, e); 333 } 334 }; 335 336 g = s.global; 337 // trigger ajax global events so that activity/block indicators work like normal 338 if (g && 0 === $.active++) { 339 $.event.trigger("ajaxStart"); 340 } 341 if (g) { 342 $.event.trigger("ajaxSend", [xhr, s]); 343 } 344 345 if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) { 346 if (s.global) { 347 $.active--; 348 } 349 return; 350 } 351 if (xhr.aborted) { 352 return; 353 } 354 355 // add submitting element to data if we know it 356 sub = form.clk; 357 if (sub) { 358 n = sub.name; 359 if (n && !sub.disabled) { 360 s.extraData = s.extraData || {}; 361 s.extraData[n] = sub.value; 362 if (sub.type == "image") { 363 s.extraData[n+'.x'] = form.clk_x; 364 s.extraData[n+'.y'] = form.clk_y; 365 } 366 } 367 } 368 369 var CLIENT_TIMEOUT_ABORT = 1; 370 var SERVER_ABORT = 2; 371 372 function getDoc(frame) { 373 var doc = frame.contentWindow ? frame.contentWindow.document : frame.contentDocument ? frame.contentDocument : frame.document; 374 return doc; 375 } 376 377 // Rails CSRF hack (thanks to Yvan Barthelemy) 378 var csrf_token = $('meta[name=csrf-token]').attr('content'); 379 var csrf_param = $('meta[name=csrf-param]').attr('content'); 380 if (csrf_param && csrf_token) { 381 s.extraData = s.extraData || {}; 382 s.extraData[csrf_param] = csrf_token; 383 } 384 385 // take a breath so that pending repaints get some cpu time before the upload starts 386 function doSubmit() { 387 // make sure form attrs are set 388 var t = $form.attr('target'), a = $form.attr('action'); 389 390 // update form attrs in IE friendly way 391 form.setAttribute('target',id); 392 if (!method) { 393 form.setAttribute('method', 'POST'); 394 } 395 if (a != s.url) { 396 form.setAttribute('action', s.url); 397 } 398 399 // ie borks in some cases when setting encoding 400 if (! s.skipEncodingOverride && (!method || /post/i.test(method))) { 401 $form.attr({ 402 encoding: 'multipart/form-data', 403 enctype: 'multipart/form-data' 404 }); 405 } 406 407 // support timout 408 if (s.timeout) { 409 timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout); 410 } 411 412 // look for server aborts 413 function checkState() { 414 try { 415 var state = getDoc(io).readyState; 416 log('state = ' + state); 417 if (state && state.toLowerCase() == 'uninitialized') 418 setTimeout(checkState,50); 419 } 420 catch(e) { 421 log('Server abort: ' , e, ' (', e.name, ')'); 422 cb(SERVER_ABORT); 423 if (timeoutHandle) 424 clearTimeout(timeoutHandle); 425 timeoutHandle = undefined; 426 } 427 } 428 429 // add "extra" data to form if provided in options 430 var extraInputs = []; 431 try { 432 if (s.extraData) { 433 for (var n in s.extraData) { 434 if (s.extraData.hasOwnProperty(n)) { 435 // if using the $.param format that allows for multiple values with the same name 436 if($.isPlainObject(s.extraData[n]) && s.extraData[n].hasOwnProperty('name') && s.extraData[n].hasOwnProperty('value')) { 437 extraInputs.push( 438 $('<input type="hidden" name="'+s.extraData[n].name+'">').attr('value',s.extraData[n].value) 439 .appendTo(form)[0]); 440 } else { 441 extraInputs.push( 442 $('<input type="hidden" name="'+n+'">').attr('value',s.extraData[n]) 443 .appendTo(form)[0]); 444 } 445 } 446 } 447 } 448 449 if (!s.iframeTarget) { 450 // add iframe to doc and submit the form 451 $io.appendTo('body'); 452 if (io.attachEvent) 453 io.attachEvent('onload', cb); 454 else 455 io.addEventListener('load', cb, false); 456 } 457 setTimeout(checkState,15); 458 form.submit(); 459 } 460 finally { 461 // reset attrs and remove "extra" input elements 462 form.setAttribute('action',a); 463 if(t) { 464 form.setAttribute('target', t); 465 } else { 466 $form.removeAttr('target'); 467 } 468 $(extraInputs).remove(); 469 } 470 } 471 472 if (s.forceSync) { 473 doSubmit(); 474 } 475 else { 476 setTimeout(doSubmit, 10); // this lets dom updates render 477 } 478 479 var data, doc, domCheckCount = 50, callbackProcessed; 480 481 function cb(e) { 482 if (xhr.aborted || callbackProcessed) { 483 return; 484 } 485 try { 486 doc = getDoc(io); 487 } 488 catch(ex) { 489 log('cannot access response document: ', ex); 490 e = SERVER_ABORT; 491 } 492 if (e === CLIENT_TIMEOUT_ABORT && xhr) { 493 xhr.abort('timeout'); 494 return; 495 } 496 else if (e == SERVER_ABORT && xhr) { 497 xhr.abort('server abort'); 498 return; 499 } 500 501 if (!doc || doc.location.href == s.iframeSrc) { 502 // response not received yet 503 if (!timedOut) 504 return; 505 } 506 if (io.detachEvent) 507 io.detachEvent('onload', cb); 508 else 509 io.removeEventListener('load', cb, false); 510 511 var status = 'success', errMsg; 512 try { 513 if (timedOut) { 514 throw 'timeout'; 515 } 516 517 var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc); 518 log('isXml='+isXml); 519 if (!isXml && window.opera && (doc.body === null || !doc.body.innerHTML)) { 520 if (--domCheckCount) { 521 // in some browsers (Opera) the iframe DOM is not always traversable when 522 // the onload callback fires, so we loop a bit to accommodate 523 log('requeing onLoad callback, DOM not available'); 524 setTimeout(cb, 250); 525 return; 526 } 527 // let this fall through because server response could be an empty document 528 //log('Could not access iframe DOM after mutiple tries.'); 529 //throw 'DOMException: not available'; 530 } 531 532 //log('response detected'); 533 var docRoot = doc.body ? doc.body : doc.documentElement; 534 xhr.responseText = docRoot ? docRoot.innerHTML : null; 535 xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc; 536 if (isXml) 537 s.dataType = 'xml'; 538 xhr.getResponseHeader = function(header){ 539 var headers = {'content-type': s.dataType}; 540 return headers[header]; 541 }; 542 // support for XHR 'status' & 'statusText' emulation : 543 if (docRoot) { 544 xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status; 545 xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText; 546 } 547 548 var dt = (s.dataType || '').toLowerCase(); 549 var scr = /(json|script|text)/.test(dt); 550 if (scr || s.textarea) { 551 // see if user embedded response in textarea 552 var ta = doc.getElementsByTagName('textarea')[0]; 553 if (ta) { 554 xhr.responseText = ta.value; 555 // support for XHR 'status' & 'statusText' emulation : 556 xhr.status = Number( ta.getAttribute('status') ) || xhr.status; 557 xhr.statusText = ta.getAttribute('statusText') || xhr.statusText; 558 } 559 else if (scr) { 560 // account for browsers injecting pre around json response 561 var pre = doc.getElementsByTagName('pre')[0]; 562 var b = doc.getElementsByTagName('body')[0]; 563 if (pre) { 564 xhr.responseText = pre.textContent ? pre.textContent : pre.innerText; 565 } 566 else if (b) { 567 xhr.responseText = b.textContent ? b.textContent : b.innerText; 568 } 569 } 570 } 571 else if (dt == 'xml' && !xhr.responseXML && xhr.responseText) { 572 xhr.responseXML = toXml(xhr.responseText); 573 } 574 575 try { 576 data = httpData(xhr, dt, s); 577 } 578 catch (e) { 579 status = 'parsererror'; 580 xhr.error = errMsg = (e || status); 581 } 582 } 583 catch (e) { 584 log('error caught: ',e); 585 status = 'error'; 586 xhr.error = errMsg = (e || status); 587 } 588 589 if (xhr.aborted) { 590 log('upload aborted'); 591 status = null; 592 } 593 594 if (xhr.status) { // we've set xhr.status 595 status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error'; 596 } 597 598 // ordering of these callbacks/triggers is odd, but that's how $.ajax does it 599 if (status === 'success') { 600 if (s.success) 601 s.success.call(s.context, data, 'success', xhr); 602 if (g) 603 $.event.trigger("ajaxSuccess", [xhr, s]); 604 } 605 else if (status) { 606 if (errMsg === undefined) 607 errMsg = xhr.statusText; 608 if (s.error) 609 s.error.call(s.context, xhr, status, errMsg); 610 if (g) 611 $.event.trigger("ajaxError", [xhr, s, errMsg]); 612 } 613 614 if (g) 615 $.event.trigger("ajaxComplete", [xhr, s]); 616 617 if (g && ! --$.active) { 618 $.event.trigger("ajaxStop"); 619 } 620 621 if (s.complete) 622 s.complete.call(s.context, xhr, status); 623 624 callbackProcessed = true; 625 if (s.timeout) 626 clearTimeout(timeoutHandle); 627 628 // clean up 629 setTimeout(function() { 630 if (!s.iframeTarget) 631 $io.remove(); 632 xhr.responseXML = null; 633 }, 100); 634 } 635 636 var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+) 637 if (window.ActiveXObject) { 638 doc = new ActiveXObject('Microsoft.XMLDOM'); 639 doc.async = 'false'; 640 doc.loadXML(s); 641 } 642 else { 643 doc = (new DOMParser()).parseFromString(s, 'text/xml'); 644 } 645 return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null; 646 }; 647 var parseJSON = $.parseJSON || function(s) { 648 /*jslint evil:true */ 649 return window['eval']('(' + s + ')'); 650 }; 651 652 var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4 653 654 var ct = xhr.getResponseHeader('content-type') || '', 655 xml = type === 'xml' || !type && ct.indexOf('xml') >= 0, 656 data = xml ? xhr.responseXML : xhr.responseText; 657 658 if (xml && data.documentElement.nodeName === 'parsererror') { 659 if ($.error) 660 $.error('parsererror'); 661 } 662 if (s && s.dataFilter) { 663 data = s.dataFilter(data, type); 664 } 665 if (typeof data === 'string') { 666 if (type === 'json' || !type && ct.indexOf('json') >= 0) { 667 data = parseJSON(data); 668 } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) { 669 $.globalEval(data); 670 } 671 } 672 return data; 673 }; 674 } 675 }; 676 677 /** 678 * ajaxForm() provides a mechanism for fully automating form submission. 679 * 680 * The advantages of using this method instead of ajaxSubmit() are: 681 * 682 * 1: This method will include coordinates for <input type="image" /> elements (if the element 683 * is used to submit the form). 684 * 2. This method will include the submit element's name/value data (for the element that was 685 * used to submit the form). 686 * 3. This method binds the submit() method to the form for you. 687 * 688 * The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely 689 * passes the options argument along after properly binding events for submit elements and 690 * the form itself. 691 */ 692 $.fn.ajaxForm = function(options) { 693 options = options || {}; 694 options.delegation = options.delegation && $.isFunction($.fn.on); 695 696 // in jQuery 1.3+ we can fix mistakes with the ready state 697 if (!options.delegation && this.length === 0) { 698 var o = { s: this.selector, c: this.context }; 699 if (!$.isReady && o.s) { 700 log('DOM not ready, queuing ajaxForm'); 701 $(function() { 702 $(o.s,o.c).ajaxForm(options); 703 }); 704 return this; 705 } 706 // is your DOM ready? http://docs.jquery.com/Tutorials:Introducing_$(document).ready() 707 log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)')); 708 return this; 709 } 710 711 if ( options.delegation ) { 712 $(document) 713 .off('submit.form-plugin', this.selector, doAjaxSubmit) 714 .off('click.form-plugin', this.selector, captureSubmittingElement) 715 .on('submit.form-plugin', this.selector, options, doAjaxSubmit) 716 .on('click.form-plugin', this.selector, options, captureSubmittingElement); 717 return this; 718 } 719 720 return this.ajaxFormUnbind() 721 .bind('submit.form-plugin', options, doAjaxSubmit) 722 .bind('click.form-plugin', options, captureSubmittingElement); 723 }; 724 725 // private event handlers 726 function doAjaxSubmit(e) { 727 /*jshint validthis:true */ 728 var options = e.data; 729 if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed 730 e.preventDefault(); 731 $(this).ajaxSubmit(options); 732 } 733 } 734 735 function captureSubmittingElement(e) { 736 /*jshint validthis:true */ 737 var target = e.target; 738 var $el = $(target); 739 if (!($el.is(":submit,input:image"))) { 740 // is this a child element of the submit el? (ex: a span within a button) 741 var t = $el.closest(':submit'); 742 if (t.length === 0) { 743 return; 744 } 745 target = t[0]; 746 } 747 var form = this; 748 form.clk = target; 749 if (target.type == 'image') { 750 if (e.offsetX !== undefined) { 751 form.clk_x = e.offsetX; 752 form.clk_y = e.offsetY; 753 } else if (typeof $.fn.offset == 'function') { 754 var offset = $el.offset(); 755 form.clk_x = e.pageX - offset.left; 756 form.clk_y = e.pageY - offset.top; 757 } else { 758 form.clk_x = e.pageX - target.offsetLeft; 759 form.clk_y = e.pageY - target.offsetTop; 760 } 761 } 762 // clear form vars 763 setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100); 764 } 765 766 767 // ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm 768 $.fn.ajaxFormUnbind = function() { 769 return this.unbind('submit.form-plugin click.form-plugin'); 770 }; 771 772 /** 773 * formToArray() gathers form element data into an array of objects that can 774 * be passed to any of the following ajax functions: $.get, $.post, or load. 775 * Each object in the array has both a 'name' and 'value' property. An example of 776 * an array for a simple login form might be: 777 * 778 * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ] 779 * 780 * It is this array that is passed to pre-submit callback functions provided to the 781 * ajaxSubmit() and ajaxForm() methods. 782 */ 783 $.fn.formToArray = function(semantic, elements) { 784 var a = []; 785 if (this.length === 0) { 786 return a; 787 } 788 789 var form = this[0]; 790 var els = semantic ? form.getElementsByTagName('*') : form.elements; 791 if (!els) { 792 return a; 793 } 794 795 var i,j,n,v,el,max,jmax; 796 for(i=0, max=els.length; i < max; i++) { 797 el = els[i]; 798 n = el.name; 799 if (!n) { 800 continue; 801 } 802 803 if (semantic && form.clk && el.type == "image") { 804 // handle image inputs on the fly when semantic == true 805 if(!el.disabled && form.clk == el) { 806 a.push({name: n, value: $(el).val(), type: el.type }); 807 a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y}); 808 } 809 continue; 810 } 811 812 v = $.fieldValue(el, true); 813 if (v && v.constructor == Array) { 814 if (elements) 815 elements.push(el); 816 for(j=0, jmax=v.length; j < jmax; j++) { 817 a.push({name: n, value: v[j]}); 818 } 819 } 820 else if (feature.fileapi && el.type == 'file' && !el.disabled) { 821 if (elements) 822 elements.push(el); 823 var files = el.files; 824 if (files.length) { 825 for (j=0; j < files.length; j++) { 826 a.push({name: n, value: files[j], type: el.type}); 827 } 828 } 829 else { 830 // #180 831 a.push({ name: n, value: '', type: el.type }); 832 } 833 } 834 else if (v !== null && typeof v != 'undefined') { 835 if (elements) 836 elements.push(el); 837 a.push({name: n, value: v, type: el.type, required: el.required}); 838 } 839 } 840 841 if (!semantic && form.clk) { 842 // input type=='image' are not found in elements array! handle it here 843 var $input = $(form.clk), input = $input[0]; 844 n = input.name; 845 if (n && !input.disabled && input.type == 'image') { 846 a.push({name: n, value: $input.val()}); 847 a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y}); 848 } 849 } 850 return a; 851 }; 852 853 /** 854 * Serializes form data into a 'submittable' string. This method will return a string 855 * in the format: name1=value1&name2=value2 856 */ 857 $.fn.formSerialize = function(semantic) { 858 //hand off to jQuery.param for proper encoding 859 return $.param(this.formToArray(semantic)); 860 }; 861 862 /** 863 * Serializes all field elements in the jQuery object into a query string. 864 * This method will return a string in the format: name1=value1&name2=value2 865 */ 866 $.fn.fieldSerialize = function(successful) { 867 var a = []; 868 this.each(function() { 869 var n = this.name; 870 if (!n) { 871 return; 872 } 873 var v = $.fieldValue(this, successful); 874 if (v && v.constructor == Array) { 875 for (var i=0,max=v.length; i < max; i++) { 876 a.push({name: n, value: v[i]}); 877 } 878 } 879 else if (v !== null && typeof v != 'undefined') { 880 a.push({name: this.name, value: v}); 881 } 882 }); 883 //hand off to jQuery.param for proper encoding 884 return $.param(a); 885 }; 886 887 /** 888 * Returns the value(s) of the element in the matched set. For example, consider the following form: 889 * 890 * <form><fieldset> 891 * <input name="A" type="text" /> 892 * <input name="A" type="text" /> 893 * <input name="B" type="checkbox" value="B1" /> 894 * <input name="B" type="checkbox" value="B2"/> 895 * <input name="C" type="radio" value="C1" /> 896 * <input name="C" type="radio" value="C2" /> 897 * </fieldset></form> 898 * 899 * var v = $(':text').fieldValue(); 900 * // if no values are entered into the text inputs 901 * v == ['',''] 902 * // if values entered into the text inputs are 'foo' and 'bar' 903 * v == ['foo','bar'] 904 * 905 * var v = $(':checkbox').fieldValue(); 906 * // if neither checkbox is checked 907 * v === undefined 908 * // if both checkboxes are checked 909 * v == ['B1', 'B2'] 910 * 911 * var v = $(':radio').fieldValue(); 912 * // if neither radio is checked 913 * v === undefined 914 * // if first radio is checked 915 * v == ['C1'] 916 * 917 * The successful argument controls whether or not the field element must be 'successful' 918 * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls). 919 * The default value of the successful argument is true. If this value is false the value(s) 920 * for each element is returned. 921 * 922 * Note: This method *always* returns an array. If no valid value can be determined the 923 * array will be empty, otherwise it will contain one or more values. 924 */ 925 $.fn.fieldValue = function(successful) { 926 for (var val=[], i=0, max=this.length; i < max; i++) { 927 var el = this[i]; 928 var v = $.fieldValue(el, successful); 929 if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) { 930 continue; 931 } 932 if (v.constructor == Array) 933 $.merge(val, v); 934 else 935 val.push(v); 936 } 937 return val; 938 }; 939 940 /** 941 * Returns the value of the field element. 942 */ 943 $.fieldValue = function(el, successful) { 944 var n = el.name, t = el.type, tag = el.tagName.toLowerCase(); 945 if (successful === undefined) { 946 successful = true; 947 } 948 949 if (successful && (!n || el.disabled || t == 'reset' || t == 'button' || 950 (t == 'checkbox' || t == 'radio') && !el.checked || 951 (t == 'submit' || t == 'image') && el.form && el.form.clk != el || 952 tag == 'select' && el.selectedIndex == -1)) { 953 return null; 954 } 955 956 if (tag == 'select') { 957 var index = el.selectedIndex; 958 if (index < 0) { 959 return null; 960 } 961 var a = [], ops = el.options; 962 var one = (t == 'select-one'); 963 var max = (one ? index+1 : ops.length); 964 for(var i=(one ? index : 0); i < max; i++) { 965 var op = ops[i]; 966 if (op.selected) { 967 var v = op.value; 968 if (!v) { // extra pain for IE... 969 v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value; 970 } 971 if (one) { 972 return v; 973 } 974 a.push(v); 975 } 976 } 977 return a; 978 } 979 return $(el).val(); 980 }; 981 982 /** 983 * Clears the form data. Takes the following actions on the form's input fields: 984 * - input text fields will have their 'value' property set to the empty string 985 * - select elements will have their 'selectedIndex' property set to -1 986 * - checkbox and radio inputs will have their 'checked' property set to false 987 * - inputs of type submit, button, reset, and hidden will *not* be effected 988 * - button elements will *not* be effected 989 */ 990 $.fn.clearForm = function(includeHidden) { 991 return this.each(function() { 992 $('input,select,textarea', this).clearFields(includeHidden); 993 }); 994 }; 995 996 /** 997 * Clears the selected form elements. 998 */ 999 $.fn.clearFields = $.fn.clearInputs = function(includeHidden) { 1000 var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list 1001 return this.each(function() { 1002 var t = this.type, tag = this.tagName.toLowerCase(); 1003 if (re.test(t) || tag == 'textarea') { 1004 this.value = ''; 1005 } 1006 else if (t == 'checkbox' || t == 'radio') { 1007 this.checked = false; 1008 } 1009 else if (tag == 'select') { 1010 this.selectedIndex = -1; 1011 } 1012 else if (includeHidden) { 1013 // includeHidden can be the value true, or it can be a selector string 1014 // indicating a special test; for example: 1015 // $('#myForm').clearForm('.special:hidden') 1016 // the above would clean hidden inputs that have the class of 'special' 1017 if ( (includeHidden === true && /hidden/.test(t)) || 1018 (typeof includeHidden == 'string' && $(this).is(includeHidden)) ) 1019 this.value = ''; 1020 } 1021 }); 1022 }; 1023 1024 /** 1025 * Resets the form data. Causes all form elements to be reset to their original value. 1026 */ 1027 $.fn.resetForm = function() { 1028 return this.each(function() { 1029 // guard against an input with the name of 'reset' 1030 // note that IE reports the reset function as an 'object' 1031 if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) { 1032 this.reset(); 1033 } 1034 }); 1035 }; 1036 1037 /** 1038 * Enables or disables any matching elements. 1039 */ 1040 $.fn.enable = function(b) { 1041 if (b === undefined) { 1042 b = true; 1043 } 1044 return this.each(function() { 1045 this.disabled = !b; 1046 }); 1047 }; 1048 1049 /** 1050 * Checks/unchecks any matching checkboxes or radio buttons and 1051 * selects/deselects and matching option elements. 1052 */ 1053 $.fn.selected = function(select) { 1054 if (select === undefined) { 1055 select = true; 1056 } 1057 return this.each(function() { 1058 var t = this.type; 1059 if (t == 'checkbox' || t == 'radio') { 1060 this.checked = select; 1061 } 1062 else if (this.tagName.toLowerCase() == 'option') { 1063 var $sel = $(this).parent('select'); 1064 if (select && $sel[0] && $sel[0].type == 'select-one') { 1065 // deselect all other options 1066 $sel.find('option').selected(false); 1067 } 1068 this.selected = select; 1069 } 1070 }); 1071 }; 1072 1073 // expose debug var 1074 $.fn.ajaxSubmit.debug = false; 1075 1076 // helper fn for console logging 1077 function log() { 1078 if (!$.fn.ajaxSubmit.debug) 1079 return; 1080 var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,''); 1081 if (window.console && window.console.log) { 1082 window.console.log(msg); 1083 } 1084 else if (window.opera && window.opera.postError) { 1085 window.opera.postError(msg); 1086 } 1087 } 1088 1089 })(jQuery);
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 14:03:12 2014 | Cross-referenced by PHPXref 0.7.1 |