1/*! 2 * jQuery Form Plugin 3 * version: 2.43 (12-MAR-2010) 4 * @requires jQuery v1.3.2 or later 5 * 6 * Examples and documentation at: http://malsup.com/jquery/form/ 7 * Dual licensed under the MIT and GPL licenses: 8 * http://www.opensource.org/licenses/mit-license.php 9 * http://www.gnu.org/licenses/gpl.html 10 */ 11;(function($) { 12 13/* 14 Usage Note: 15 ----------- 16 Do not use both ajaxSubmit and ajaxForm on the same form. These 17 functions are intended to be exclusive. Use ajaxSubmit if you want 18 to bind your own submit handler to the form. For example, 19 20 $(document).ready(function() { 21 $('#myForm').bind('submit', function() { 22 $(this).ajaxSubmit({ 23 target: '#output' 24 }); 25 return false; // <-- important! 26 }); 27 }); 28 29 Use ajaxForm when you want the plugin to manage all the event binding 30 for you. For example, 31 32 $(document).ready(function() { 33 $('#myForm').ajaxForm({ 34 target: '#output' 35 }); 36 }); 37 38 When using ajaxForm, the ajaxSubmit function will be invoked for you 39 at the appropriate time. 40*/ 41 42/** 43 * ajaxSubmit() provides a mechanism for immediately submitting 44 * an HTML form using AJAX. 45 */ 46 $.httpData=function( xhr, type, s ) {Â 47 48var ct = xhr.getResponseHeader( 'content-type'), xml = type == 'xml' || !type && ct && ct.indexOf( 'xml' ) >=0, data = xml ? xhr.responseXML: xhr.responseText; if ( xml && data.documentElement.tagName == 'parsererror' ) 49 50throw 'parsererror' ; if ( s && s.dataFilter ) data = s.dataFilter( data, type );if ( typeof data === 'string' ){if ( type == 'script' ) jQuery.globalEval( data ); if ( type == 'json' ) 51 52data = window[ "eval" ]( '(' + data + ')' ); } return data; }; 53 54$.handleError= function (s, xhr, status, e) {Â 55 56if (s.error) {Â 57 58s.error.call(s.context || s, xhr, status, e); } 59 60if (s.global) { 61 62(s.context ? jQuery(s.context) : jQuery.event).trigger('ajaxError', [xhr, s, e]); }Â 63 64} 65 66$.fn.ajaxSubmit = function(options) { 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 if (typeof options == 'function') 74 options = { success: options }; 75 76 var url = $.trim(this.attr('action')); 77 if (url) { 78 // clean url (don't include hash vaue) 79 url = (url.match(/^([^#]+)/)||[])[1]; 80 } 81 url = url || window.location.href || ''; 82 83 options = $.extend({ 84 url: url, 85 type: this.attr('method') || 'GET', 86 iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank' 87 }, options || {}); 88 89 // hook for manipulating the form data before it is extracted; 90 // convenient for use with rich editors like tinyMCE or FCKEditor 91 var veto = {}; 92 this.trigger('form-pre-serialize', [this, options, veto]); 93 if (veto.veto) { 94 log('ajaxSubmit: submit vetoed via form-pre-serialize trigger'); 95 return this; 96 } 97 98 // provide opportunity to alter form data before it is serialized 99 if (options.beforeSerialize && options.beforeSerialize(this, options) === false) { 100 log('ajaxSubmit: submit aborted via beforeSerialize callback'); 101 return this; 102 } 103 104 var a = this.formToArray(options.semantic); 105 if (options.data) { 106 options.extraData = options.data; 107 for (var n in options.data) { 108 if(options.data[n] instanceof Array) { 109 for (var k in options.data[n]) 110 a.push( { name: n, value: options.data[n][k] } ); 111 } 112 else 113 a.push( { name: n, value: options.data[n] } ); 114 } 115 } 116 117 // give pre-submit callback an opportunity to abort the submit 118 if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) { 119 log('ajaxSubmit: submit aborted via beforeSubmit callback'); 120 return this; 121 } 122 123 // fire vetoable 'validate' event 124 this.trigger('form-submit-validate', [a, this, options, veto]); 125 if (veto.veto) { 126 log('ajaxSubmit: submit vetoed via form-submit-validate trigger'); 127 return this; 128 } 129 130 var q = $.param(a); 131 132 if (options.type.toUpperCase() == 'GET') { 133 options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q; 134 options.data = null; // data is null for 'get' 135 } 136 else 137 options.data = q; // data is the query string for 'post' 138 139 var $form = this, callbacks = []; 140 if (options.resetForm) callbacks.push(function() { $form.resetForm(); }); 141 if (options.clearForm) callbacks.push(function() { $form.clearForm(); }); 142 143 // perform a load on the target only if dataType is not provided 144 if (!options.dataType && options.target) { 145 var oldSuccess = options.success || function(){}; 146 callbacks.push(function(data) { 147 var fn = options.replaceTarget ? 'replaceWith' : 'html'; 148 $(options.target)[fn](data).each(oldSuccess, arguments); 149 }); 150 } 151 else if (options.success) 152 callbacks.push(options.success); 153 154 options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg 155 for (var i=0, max=callbacks.length; i < max; i++) 156 callbacks[i].apply(options, [data, status, xhr || $form, $form]); 157 }; 158 159 // are there files to upload? 160 var files = $('input:file', this).fieldValue(); 161 var found = false;
162 for (var j=0; j < files.length; j++) 163 if (files[j]) 164 found = true; 165 166 var multipart = false; 167// var mp = 'multipart/form-data'; 168// multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp); 169 170 // options.iframe allows user to force iframe mode 171 // 06-NOV-09: now defaulting to iframe mode if file input is detected 172 if ((files.length && options.iframe !== false) || options.iframe || found || multipart) { 173 // hack to fix Safari hang (thanks to Tim Molendijk for this) 174 // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d 175 if (options.closeKeepAlive) 176 $.get(options.closeKeepAlive, fileUpload); 177 else 178 fileUpload(); 179 } 180 else 181 $.ajax(options); 182 183 // fire 'notify' event 184 this.trigger('form-submit-notify', [this, options]); 185 return this; 186 187 188 // private function for handling file uploads (hat tip to YAHOO!) 189 function fileUpload() { 190 var form = $form[0]; 191 192 if ($(':input[name=submit]', form).length) { 193 alert('Error: Form elements must not be named "submit".'); 194 return; 195 } 196 197 var opts = $.extend({}, $.ajaxSettings, options); 198 var s = $.extend(true, {}, $.extend(true, {}, $.ajaxSettings), opts); 199 200 var id = 'jqFormIO' + (new Date().getTime()); 201 var $io = $('<iframe id="' + id + '" name="' + id + '" src="'+ opts.iframeSrc +'" onload="(jQuery(this).data(\'form-plugin-onload\'))()" />'); 202 var io = $io[0]; 203 204 $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' }); 205 206 var xhr = { // mock object 207 aborted: 0, 208 responseText: null, 209 responseXML: null, 210 status: 0, 211 statusText: 'n/a', 212 getAllResponseHeaders: function() {}, 213 getResponseHeader: function() {}, 214 setRequestHeader: function() {}, 215 abort: function() { 216 this.aborted = 1; 217 $io.attr('src', opts.iframeSrc); // abort op in progress 218 } 219 }; 220 221 var g = opts.global; 222 // trigger ajax global events so that activity/block indicators work like normal 223 if (g && ! $.active++) $.event.trigger("ajaxStart"); 224 if (g) $.event.trigger("ajaxSend", [xhr, opts]); 225 226 if (s.beforeSend && s.beforeSend(xhr, s) === false) { 227 s.global && $.active--; 228 return; 229 } 230 if (xhr.aborted) 231 return; 232 233 var cbInvoked = false; 234 var timedOut = 0; 235 236 // add submitting element to data if we know it 237 var sub = form.clk; 238 if (sub) { 239 var n = sub.name; 240 if (n && !sub.disabled) { 241 opts.extraData = opts.extraData || {}; 242 opts.extraData[n] = sub.value; 243 if (sub.type == "image") { 244 opts.extraData[n+'.x'] = form.clk_x; 245 opts.extraData[n+'.y'] = form.clk_y; 246 } 247 } 248 } 249 250 // take a breath so that pending repaints get some cpu time before the upload starts 251 function doSubmit() { 252 // make sure form attrs are set 253 var t = $form.attr('target'), a = $form.attr('action'); 254 255 // update form attrs in IE friendly way 256 form.setAttribute('target',id); 257 if (form.getAttribute('method') != 'POST') 258 form.setAttribute('method', 'POST'); 259 if (form.getAttribute('action') != opts.url) 260 form.setAttribute('action', opts.url); 261 262 // ie borks in some cases when setting encoding 263 if (! opts.skipEncodingOverride) { 264 $form.attr({ 265 encoding: 'multipart/form-data', 266 enctype: 'multipart/form-data' 267 }); 268 } 269 270 // support timout 271 if (opts.timeout) 272 setTimeout(function() { timedOut = true; cb(); }, opts.timeout); 273 274 // add "extra" data to form if provided in options 275 var extraInputs = []; 276 try { 277 if (opts.extraData) 278 for (var n in opts.extraData) 279 extraInputs.push( 280 $('<input type="hidden" name="'+n+'" value="'+opts.extraData[n]+'" />') 281 .appendTo(form)[0]); 282 283 // add iframe to doc and submit the form 284 $io.appendTo('body'); 285 $io.data('form-plugin-onload', cb); 286 form.submit(); 287 } 288 finally { 289 // reset attrs and remove "extra" input elements 290 form.setAttribute('action',a); 291 t ? form.setAttribute('target', t) : $form.removeAttr('target'); 292 $(extraInputs).remove(); 293 } 294 }; 295 296 if (opts.forceSync) 297 doSubmit(); 298 else 299 setTimeout(doSubmit, 10); // this lets dom updates render 300 301 var domCheckCount = 100; 302 303 function cb() { 304 if (cbInvoked) 305 return; 306 307 var ok = true; 308 try { 309 if (timedOut) throw 'timeout'; 310 // extract the server response from the iframe 311 var data, doc; 312 313 doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document; 314 315 var isXml = opts.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc); 316 log('isXml='+isXml); 317 if (!isXml && (doc.body == null || doc.body.innerHTML == '')) { 318 if (--domCheckCount) { 319 // in some browsers (Opera) the iframe DOM is not always traversable when 320 // the onload callback fires, so we loop a bit to accommodate 321 log('requeing onLoad callback, DOM not available'); 322 setTimeout(cb, 250); 323 return; 324 } 325 log('Could not access iframe DOM after 100 tries.'); 326 return; 327 } 328 329 log('response detected'); 330 cbInvoked = true; 331 xhr.responseText = doc.body ? doc.body.innerHTML : null; 332 xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc; 333 xhr.getResponseHeader = function(header){ 334 var headers = {'content-type': opts.dataType}; 335 return headers[header]; 336 }; 337 338 if (opts.dataType == 'json' || opts.dataType == 'script') { 339 // see if user embedded response in textarea 340 var ta = doc.getElementsByTagName('textarea')[0]; 341 if (ta) 342 xhr.responseText = ta.value; 343 else { 344 // account for browsers injecting pre around json response 345 var pre = doc.getElementsByTagName('pre')[0]; 346 if (pre) 347 xhr.responseText = pre.innerHTML; 348 } 349 } 350 else if (opts.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) { 351 xhr.responseXML = toXml(xhr.responseText); 352 } 353 data = $.httpData(xhr, opts.dataType); 354 } 355 catch(e){ 356 log('error caught:',e); 357 ok = false;
358 xhr.error = e; 359 360 $.handleError(opts, xhr, 'error', e); 361 362 } 363 364 // ordering of these callbacks/triggers is odd, but that's how $.ajax does it 365 if (ok) { 366 opts.success(data, 'success'); 367 if (g) $.event.trigger("ajaxSuccess", [xhr, opts]); 368 } 369 if (g) $.event.trigger("ajaxComplete", [xhr, opts]); 370 if (g && ! --$.active) $.event.trigger("ajaxStop"); 371 if (opts.complete) opts.complete(xhr, ok ? 'success' : 'error'); 372 373 // clean up 374 setTimeout(function() { 375 $io.removeData('form-plugin-onload'); 376 $io.remove(); 377 xhr.responseXML = null; 378 }, 100); 379 }; 380 381 function toXml(s, doc) { 382 if (window.ActiveXObject) { 383 doc = new ActiveXObject('Microsoft.XMLDOM'); 384 doc.async = 'false'; 385 doc.loadXML(s); 386 } 387 else 388 doc = (new DOMParser()).parseFromString(s, 'text/xml'); 389 return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null; 390 }; 391 }; 392}; 393 394/** 395 * ajaxForm() provides a mechanism for fully automating form submission. 396 * 397 * The advantages of using this method instead of ajaxSubmit() are: 398 * 399 * 1: This method will include coordinates for <input type="image" /> elements (if the element 400 * is used to submit the form). 401 * 2. This method will include the submit element's name/value data (for the element that was 402 * used to submit the form). 403 * 3. This method binds the submit() method to the form for you. 404 * 405 * The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely 406 * passes the options argument along after properly binding events for submit elements and 407 * the form itself. 408 */ 409$.fn.ajaxForm = function(options) { 410 return this.ajaxFormUnbind().bind('submit.form-plugin', function(e) { 411 e.preventDefault(); 412 $(this).ajaxSubmit(options); 413 }).bind('click.form-plugin', function(e) { 414 var target = e.target; 415 var $el = $(target); 416 if (!($el.is(":submit,input:image"))) { 417 // is this a child element of the submit el? (ex: a span within a button) 418 var t = $el.closest(':submit'); 419 if (t.length == 0) 420 return; 421 target = t[0]; 422 } 423 var form = this; 424 form.clk = target; 425 if (target.type == 'image') { 426 if (e.offsetX != undefined) { 427 form.clk_x = e.offsetX; 428 form.clk_y = e.offsetY; 429 } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin 430 var offset = $el.offset(); 431 form.clk_x = e.pageX - offset.left; 432 form.clk_y = e.pageY - offset.top; 433 } else { 434 form.clk_x = e.pageX - target.offsetLeft; 435 form.clk_y = e.pageY - target.offsetTop; 436 } 437 } 438 // clear form vars 439 setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100); 440 }); 441}; 442 443// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm 444$.fn.ajaxFormUnbind = function() { 445 return this.unbind('submit.form-plugin click.form-plugin'); 446}; 447 448/** 449 * formToArray() gathers form element data into an array of objects that can 450 * be passed to any of the following ajax functions: $.get, $.post, or load. 451 * Each object in the array has both a 'name' and 'value' property. An example of 452 * an array for a simple login form might be: 453 * 454 * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ] 455 * 456 * It is this array that is passed to pre-submit callback functions provided to the 457 * ajaxSubmit() and ajaxForm() methods. 458 */ 459$.fn.formToArray = function(semantic) { 460 var a = []; 461 if (this.length == 0) return a; 462 463 var form = this[0]; 464 var els = semantic ? form.getElementsByTagName('*') : form.elements; 465 if (!els) return a; 466 for(var i=0, max=els.length; i < max; i++) { 467 var el = els[i]; 468 var n = el.name; 469 if (!n) continue; 470 471 if (semantic && form.clk && el.type == "image") { 472 // handle image inputs on the fly when semantic == true 473 if(!el.disabled && form.clk == el) { 474 a.push({name: n, value: $(el).val()}); 475 a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y}); 476 } 477 continue; 478 } 479 480 var v = $.fieldValue(el, true); 481 if (v && v.constructor == Array) { 482 for(var j=0, jmax=v.length; j < jmax; j++) 483 a.push({name: n, value: v[j]}); 484 } 485 else if (v !== null && typeof v != 'undefined') 486 a.push({name: n, value: v}); 487 } 488 489 if (!semantic && form.clk) { 490 // input type=='image' are not found in elements array! handle it here 491 var $input = $(form.clk), input = $input[0], n = input.name; 492 if (n && !input.disabled && input.type == 'image') { 493 a.push({name: n, value: $input.val()}); 494 a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y}); 495 } 496 } 497 return a; 498}; 499 500/** 501 * Serializes form data into a 'submittable' string. This method will return a string 502 * in the format: name1=value1&name2=value2 503 */
504$.fn.formSerialize = function(semantic) { 505 //hand off to jQuery.param for proper encoding 506 return $.param(this.formToArray(semantic)); 507}; 508 509/** 510 * Serializes all field elements in the jQuery object into a query string. 511 * This method will return a string in the format: name1=value1&name2=value2 512 */ 513$.fn.fieldSerialize = function(successful) { 514 var a = []; 515 this.each(function() { 516 var n = this.name; 517 if (!n) return; 518 var v = $.fieldValue(this, successful); 519 if (v && v.constructor == Array) { 520 for (var i=0,max=v.length; i < max; i++) 521 a.push({name: n, value: v[i]}); 522 } 523 else if (v !== null && typeof v != 'undefined') 524 a.push({name: this.name, value: v}); 525 }); 526 //hand off to jQuery.param for proper encoding 527 return $.param(a); 528}; 529 530/** 531 * Returns the value(s) of the element in the matched set. For example, consider the following form: 532 * 533 * <form><fieldset> 534 * <input name="A" type="text" /> 535 * <input name="A" type="text" /> 536 * <input name="B" type="checkbox" value="B1" /> 537 * <input name="B" type="checkbox" value="B2"/> 538 * <input name="C" type="radio" value="C1" /> 539 * <input name="C" type="radio" value="C2" /> 540 * </fieldset></form> 541 * 542 * var v = $(':text').fieldValue(); 543 * // if no values are entered into the text inputs 544 * v == ['',''] 545 * // if values entered into the text inputs are 'foo' and 'bar' 546 * v == ['foo','bar'] 547 * 548 * var v = $(':checkbox').fieldValue(); 549 * // if neither checkbox is checked 550 * v === undefined 551 * // if both checkboxes are checked 552 * v == ['B1', 'B2'] 553 * 554 * var v = $(':radio').fieldValue(); 555 * // if neither radio is checked 556 * v === undefined 557 * // if first radio is checked 558 * v == ['C1'] 559 * 560 * The successful argument controls whether or not the field element must be 'successful' 561 * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls). 562 * The default value of the successful argument is true. If this value is false the value(s) 563 * for each element is returned. 564 * 565 * Note: This method *always* returns an array. If no valid value can be determined the 566 * array will be empty, otherwise it will contain one or more values. 567 */ 568$.fn.fieldValue = function(successful) { 569 for (var val=[], i=0, max=this.length; i < max; i++) { 570 var el = this[i]; 571 var v = $.fieldValue(el, successful); 572 if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) 573 continue; 574 v.constructor == Array ? $.merge(val, v) : val.push(v); 575 } 576 return val; 577}; 578 579/** 580 * Returns the value of the field element. 581 */ 582$.fieldValue = function(el, successful) { 583 var n = el.name, t = el.type, tag = el.tagName.toLowerCase(); 584 if (typeof successful == 'undefined') successful = true; 585 586 if (successful && (!n || el.disabled || t == 'reset' || t == 'button' || 587 (t == 'checkbox' || t == 'radio') && !el.checked || 588 (t == 'submit' || t == 'image') && el.form && el.form.clk != el || 589 tag == 'select' && el.selectedIndex == -1)) 590 return null; 591 592 if (tag == 'select') { 593 var index = el.selectedIndex; 594 if (index < 0) return null; 595 var a = [], ops = el.options; 596 var one = (t == 'select-one'); 597 var max = (one ? index+1 : ops.length); 598 for(var i=(one ? index : 0); i < max; i++) { 599 var op = ops[i]; 600 if (op.selected) { 601 var v = op.value; 602 if (!v) // extra pain for IE... 603 v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value; 604 if (one) return v; 605 a.push(v); 606 } 607 } 608 return a; 609 } 610 return el.value; 611}; 612 613/** 614 * Clears the form data. Takes the following actions on the form's input fields: 615 * - input text fields will have their 'value' property set to the empty string 616 * - select elements will have their 'selectedIndex' property set to -1 617 * - checkbox and radio inputs will have their 'checked' property set to false 618 * - inputs of type submit, button, reset, and hidden will *not* be effected 619 * - button elements will *not* be effected 620 */ 621$.fn.clearForm = function() { 622 return this.each(function() { 623 $('input,select,textarea', this).clearFields(); 624 }); 625}; 626 627/** 628 * Clears the selected form elements. 629 */ 630$.fn.clearFields = $.fn.clearInputs = function() { 631 return this.each(function() { 632 var t = this.type, tag = this.tagName.toLowerCase(); 633 if (t == 'text' || t == 'password' || tag == 'textarea') 634 this.value = ''; 635 else if (t == 'checkbox' || t == 'radio') 636 this.checked = false;
637 else if (tag == 'select') 638 this.selectedIndex = -1; 639 }); 640}; 641 642/** 643 * Resets the form data. Causes all form elements to be reset to their original value. 644 */ 645$.fn.resetForm = function() { 646 return this.each(function() { 647 // guard against an input with the name of 'reset' 648 // note that IE reports the reset function as an 'object' 649 if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) 650 this.reset(); 651 }); 652}; 653 654/** 655 * Enables or disables any matching elements. 656 */ 657$.fn.enable = function(b) { 658 if (b == undefined) b = true; 659 return this.each(function() { 660 this.disabled = !b; 661 }); 662}; 663 664/** 665 * Checks/unchecks any matching checkboxes or radio buttons and 666 * selects/deselects and matching option elements. 667 */ 668$.fn.selected = function(select) { 669 if (select == undefined) select = true; 670 return this.each(function() { 671 var t = this.type; 672 if (t == 'checkbox' || t == 'radio') 673 this.checked = select; 674 else if (this.tagName.toLowerCase() == 'option') { 675 var $sel = $(this).parent('select'); 676 if (select && $sel[0] && $sel[0].type == 'select-one') { 677 // deselect all other options 678 $sel.find('option').selected(false); 679 } 680 this.selected = select; 681 } 682 }); 683}; 684 685// helper fn for console logging 686// set $.fn.ajaxSubmit.debug to true to enable debug logging 687function log() { 688 if ($.fn.ajaxSubmit.debug) { 689 var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,''); 690 if (window.console && window.console.log) 691 window.console.log(msg); 692 else if (window.opera && window.opera.postError) 693 window.opera.postError(msg); 694 } 695}; 696 697})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.