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