1/*! 2 * jQuery Form Plugin 3 * version: 3.32.0-2013.04.09 4 * @requires jQuery v1.5 or later 5 * Copyright (c) 2013 M. Alsup 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 * https://github.com/malsup/form#copyright-and-license 10 */ 11/*global ActiveXObject */ 12;(function($) { 13"use strict"; 14 15/* 16 Usage Note: 17 ----------- 18 Do not use both ajaxSubmit and ajaxForm on the same form. These 19 functions are mutually exclusive. Use ajaxSubmit if you want 20 to bind your own submit handler to the form. For example, 21 22 $(document).ready(function() { 23 $('#myForm').on('submit', function(e) { 24 e.preventDefault(); // <-- important 25 $(this).ajaxSubmit({ 26 target: '#output' 27 }); 28 }); 29 }); 30 31 Use ajaxForm when you want the plugin to manage all the event binding 32 for you. For example, 33 34 $(document).ready(function() { 35 $('#myForm').ajaxForm({ 36 target: '#output' 37 }); 38 }); 39 40 You can also use ajaxForm with delegation (requires jQuery v1.7+), so the 41 form does not have to exist when you invoke ajaxForm: 42 43 $('#myForm').ajaxForm({ 44 delegation: true, 45 target: '#output' 46 }); 47 48 When using ajaxForm, the ajaxSubmit function will be invoked for you 49 at the appropriate time. 50*/ 51 52/** 53 * Feature detection 54 */ 55var feature = {}; 56feature.fileapi = $("<input type='file'/>").get(0).files !== undefined; 57feature.formdata = window.FormData !== undefined; 58 59var hasProp = !!$.fn.prop; 60 61// attr2 uses prop when it can but checks the return type for 62// an expected string. this accounts for the case where a form 63// contains inputs with names like "action" or "method"; in those 64// cases "prop" returns the element 65$.fn.attr2 = function() { 66 if ( ! hasProp ) 67 return this.attr.apply(this, arguments); 68 var val = this.prop.apply(this, arguments); 69 if ( ( val && val.jquery ) || typeof val === 'string' ) 70 return val; 71 return this.attr.apply(this, arguments); 72}; 73 74/** 75 * ajaxSubmit() provides a mechanism for immediately submitting 76 * an HTML form using AJAX. 77 */ 78$.fn.ajaxSubmit = function(options) { 79 /*jshint scripturl:true */ 80 81 // fast fail if nothing selected (http://dev.jquery.com/ticket/2752) 82 if (!this.length) { 83 log('ajaxSubmit: skipping submit process - no element selected'); 84 return this; 85 } 86 87 var method, action, url, $form = this; 88 89 if (typeof options == 'function') { 90 options = { success: options }; 91 } 92 93 method = this.attr2('method'); 94 action = this.attr2('action'); 95 96 url = (typeof action === 'string') ? $.trim(action) : ''; 97 url = url || window.location.href || ''; 98 if (url) { 99 // clean url (don't include hash vaue) 100 url = (url.match(/^([^#]+)/)||[])[1]; 101 } 102 103 options = $.extend(true, { 104 url: url, 105 success: $.ajaxSettings.success, 106 type: method || 'GET', 107 iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank' 108 }, options); 109 110 // hook for manipulating the form data before it is extracted; 111 // convenient for use with rich editors like tinyMCE or FCKEditor 112 var veto = {}; 113 this.trigger('form-pre-serialize', [this, options, veto]); 114 if (veto.veto) { 115 log('ajaxSubmit: submit vetoed via form-pre-serialize trigger'); 116 return this; 117 } 118 119 // provide opportunity to alter form data before it is serialized 120 if (options.beforeSerialize && options.beforeSerialize(this, options) === false) { 121 log('ajaxSubmit: submit aborted via beforeSerialize callback'); 122 return this; 123 } 124 125 var traditional = options.traditional; 126 if ( traditional === undefined ) { 127 traditional = $.ajaxSettings.traditional; 128 } 129 130 var elements = []; 131 var qx, a = this.formToArray(options.semantic, elements); 132 if (options.data) { 133 options.extraData = options.data; 134 qx = $.param(options.data, traditional); 135 } 136 137 // give pre-submit callback an opportunity to abort the submit 138 if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) { 139 log('ajaxSubmit: submit aborted via beforeSubmit callback'); 140 return this; 141 } 142 143 // fire vetoable 'validate' event 144 this.trigger('form-submit-validate', [a, this, options, veto]); 145 if (veto.veto) { 146 log('ajaxSubmit: submit vetoed via form-submit-validate trigger'); 147 return this; 148 } 149 150 var q = $.param(a, traditional); 151 if (qx) { 152 q = ( q ? (q + '&' + qx) : qx ); 153 } 154 if (options.type.toUpperCase() == 'GET') { 155 options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q; 156 options.data = null; // data is null for 'get' 157 } 158 else { 159 options.data = q; // data is the query string for 'post' 160 } 161 162 var callbacks = []; 163 if (options.resetForm) { 164 callbacks.push(function() { $form.resetForm(); }); 165 } 166 if (options.clearForm) { 167 callbacks.push(function() { $form.clearForm(options.includeHidden); }); 168 } 169 170 // perform a load on the target only if dataType is not provided 171 if (!options.dataType && options.target) { 172 var oldSuccess = options.success || function(){}; 173 callbacks.push(function(data) { 174 var fn = options.replaceTarget ? 'replaceWith' : 'html'; 175 $(options.target)[fn](data).each(oldSuccess, arguments); 176 }); 177 } 178 else if (options.success) { 179 callbacks.push(options.success); 180 } 181 182 options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg 183 var context = options.context || this ; // jQuery 1.4+ supports scope context 184 for (var i=0, max=callbacks.length; i < max; i++) { 185 callbacks[i].apply(context, [data, status, xhr || $form, $form]); 186 } 187 }; 188 189 // are there files to upload? 190 191 // [value] (issue #113), also see comment: 192 // https://github.com/malsup/form/commit/588306aedba1de01388032d5f42a60159eea9228#commitcomment-2180219 193 var fileInputs = $('input[type=file]:enabled[value!=""]', this); 194 195 var hasFileInputs = fileInputs.length > 0; 196 var mp = 'multipart/form-data'; 197 var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp); 198 199 var fileAPI = feature.fileapi && feature.formdata; 200 log("fileAPI :" + fileAPI); 201 var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI; 202 203 var jqxhr; 204 205 // options.iframe allows user to force iframe mode 206 // 06-NOV-09: now defaulting to iframe mode if file input is detected 207 if (options.iframe !== false && (options.iframe || shouldUseFrame)) { 208 // hack to fix Safari hang (thanks to Tim Molendijk for this) 209 // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d 210 if (options.closeKeepAlive) { 211 $.get(options.closeKeepAlive, function() { 212 jqxhr = fileUploadIframe(a); 213 }); 214 } 215 else { 216 jqxhr = fileUploadIframe(a); 217 } 218 } 219 else if ((hasFileInputs || multipart) && fileAPI) { 220 jqxhr = fileUploadXhr(a); 221 } 222 else { 223 jqxhr = $.ajax(options); 224 } 225 226 $form.removeData('jqxhr').data('jqxhr', jqxhr); 227 228 // clear element array 229 for (var k=0; k < elements.length; k++) 230 elements[k] = null; 231 232 // fire 'notify' event 233 this.trigger('form-submit-notify', [this, options]); 234 return this; 235 236 // utility fn for deep serialization 237 function deepSerialize(extraData){ 238 var serialized = $.param(extraData).split('&'); 239 var len = serialized.length; 240 var result = []; 241 var i, part; 242 for (i=0; i < len; i++) { 243 // #252; undo param space replacement 244 serialized[i] = serialized[i].replace(/\+/g,' '); 245 part = serialized[i].split('='); 246 // #278; use array instead of object storage, favoring array serializations 247 result.push([decodeURIComponent(part[0]), decodeURIComponent(part[1])]); 248 } 249 return result; 250 } 251 252 // XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz) 253 function fileUploadXhr(a) { 254 var formdata = new FormData(); 255 256 for (var i=0; i < a.length; i++) { 257 formdata.append(a[i].name, a[i].value); 258 } 259 260 if (options.extraData) { 261 var serializedData = deepSerialize(options.extraData); 262 for (i=0; i < serializedData.length; i++) 263 if (serializedData[i]) 264 formdata.append(serializedData[i][0], serializedData[i][1]); 265 } 266 267 options.data = null; 268 269 var s = $.extend(true, {}, $.ajaxSettings, options, { 270 contentType: false, 271 processData: false, 272 cache: false, 273 type: method || 'POST' 274 }); 275 276 if (options.uploadProgress) { 277 // workaround because jqXHR does not expose upload property 278 s.xhr = function() { 279 var xhr = jQuery.ajaxSettings.xhr(); 280 if (xhr.upload) { 281 xhr.upload.addEventListener('progress', function(event) { 282 var percent = 0; 283 var position = event.loaded || event.position; /*event.position is deprecated*/ 284 var total = event.total; 285 if (event.lengthComputable) {
286 percent = Math.ceil(position / total * 100); 287 } 288 options.uploadProgress(event, position, total, percent); 289 }, false); 290 } 291 return xhr; 292 }; 293 } 294 295 s.data = null; 296 var beforeSend = s.beforeSend; 297 s.beforeSend = function(xhr, o) { 298 o.data = formdata; 299 if(beforeSend) 300 beforeSend.call(this, xhr, o); 301 }; 302 return $.ajax(s); 303 } 304 305 // private function for handling file uploads (hat tip to YAHOO!) 306 function fileUploadIframe(a) { 307 var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle; 308 var deferred = $.Deferred(); 309 310 if (a) { 311 // ensure that every serialized input is still enabled 312 for (i=0; i < elements.length; i++) { 313 el = $(elements[i]); 314 if ( hasProp ) 315 el.prop('disabled', false); 316 else 317 el.removeAttr('disabled'); 318 } 319 } 320 321 s = $.extend(true, {}, $.ajaxSettings, options); 322 s.context = s.context || s; 323 id = 'jqFormIO' + (new Date().getTime()); 324 if (s.iframeTarget) { 325 $io = $(s.iframeTarget); 326 n = $io.attr2('name'); 327 if (!n) 328 $io.attr2('name', id); 329 else 330 id = n; 331 } 332 else { 333 $io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />'); 334 $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' }); 335 } 336 io = $io[0]; 337 338 339 xhr = { // mock object 340 aborted: 0, 341 responseText: null, 342 responseXML: null, 343 status: 0, 344 statusText: 'n/a', 345 getAllResponseHeaders: function() {}, 346 getResponseHeader: function() {}, 347 setRequestHeader: function() {}, 348 abort: function(status) { 349 var e = (status === 'timeout' ? 'timeout' : 'aborted'); 350 log('aborting upload... ' + e); 351 this.aborted = 1; 352 353 try { // #214, #257 354 if (io.contentWindow.document.execCommand) { 355 io.contentWindow.document.execCommand('Stop'); 356 } 357 } 358 catch(ignore) {} 359 360 $io.attr('src', s.iframeSrc); // abort op in progress 361 xhr.error = e; 362 if (s.error) 363 s.error.call(s.context, xhr, e, status); 364 if (g) 365 $.event.trigger("ajaxError", [xhr, s, e]); 366 if (s.complete) 367 s.complete.call(s.context, xhr, e); 368 } 369 }; 370 371 g = s.global; 372 // trigger ajax global events so that activity/block indicators work like normal 373 if (g && 0 === $.active++) { 374 $.event.trigger("ajaxStart"); 375 } 376 if (g) { 377 $.event.trigger("ajaxSend", [xhr, s]); 378 } 379 380 if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) { 381 if (s.global) { 382 $.active--; 383 } 384 deferred.reject(); 385 return deferred; 386 } 387 if (xhr.aborted) { 388 deferred.reject(); 389 return deferred; 390 } 391 392 // add submitting element to data if we know it 393 sub = form.clk; 394 if (sub) { 395 n = sub.name; 396 if (n && !sub.disabled) { 397 s.extraData = s.extraData || {}; 398 s.extraData[n] = sub.value; 399 if (sub.type == "image") { 400 s.extraData[n+'.x'] = form.clk_x; 401 s.extraData[n+'.y'] = form.clk_y; 402 } 403 } 404 } 405 406 var CLIENT_TIMEOUT_ABORT = 1; 407 var SERVER_ABORT = 2; 408 409 function getDoc(frame) { 410 /* it looks like contentWindow or contentDocument do not 411 * carry the protocol property in ie8, when running under ssl 412 * frame.document is the only valid response document, since 413 * the protocol is know but not on the other two objects. strange? 414 * "Same origin policy" http://en.wikipedia.org/wiki/Same_origin_policy 415 */ 416 417 var doc = null; 418 419 // IE8 cascading access check 420 try { 421 if (frame.contentWindow) { 422 doc = frame.contentWindow.document; 423 } 424 } catch(err) { 425 // IE8 access denied under ssl & missing protocol 426 log('cannot get iframe.contentWindow document: ' + err); 427 } 428 429 if (doc) { // successful getting content 430 return doc; 431 } 432 433 try { // simply checking may throw in ie8 under ssl or mismatched protocol 434 doc = frame.contentDocument ? frame.contentDocument : frame.document; 435 } catch(err) { 436 // last attempt 437 log('cannot get iframe.contentDocument: ' + err); 438 doc = frame.document; 439 } 440 return doc; 441 } 442 443 // Rails CSRF hack (thanks to Yvan Barthelemy) 444 var csrf_token = $('meta[name=csrf-token]').attr('content'); 445 var csrf_param = $('meta[name=csrf-param]').attr('content'); 446 if (csrf_param && csrf_token) { 447 s.extraData = s.extraData || {}; 448 s.extraData[csrf_param] = csrf_token; 449 } 450 451 // take a breath so that pending repaints get some cpu time before the upload starts 452 function doSubmit() { 453 // make sure form attrs are set 454 var t = $form.attr2('target'), a = $form.attr2('action'); 455 456 // update form attrs in IE friendly way 457 form.setAttribute('target',id);
458 if (!method) { 459 form.setAttribute('method', 'POST'); 460 } 461 if (a != s.url) { 462 form.setAttribute('action', s.url); 463 } 464 465 // ie borks in some cases when setting encoding 466 if (! s.skipEncodingOverride && (!method || /post/i.test(method))) { 467 $form.attr({ 468 encoding: 'multipart/form-data', 469 enctype: 'multipart/form-data' 470 }); 471 } 472 473 // support timout 474 if (s.timeout) { 475 timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout); 476 } 477 478 // look for server aborts 479 function checkState() { 480 try { 481 var state = getDoc(io).readyState; 482 log('state = ' + state); 483 if (state && state.toLowerCase() == 'uninitialized') 484 setTimeout(checkState,50); 485 } 486 catch(e) { 487 log('Server abort: ' , e, ' (', e.name, ')'); 488 cb(SERVER_ABORT); 489 if (timeoutHandle) 490 clearTimeout(timeoutHandle); 491 timeoutHandle = undefined; 492 } 493 } 494 495 // add "extra" data to form if provided in options 496 var extraInputs = []; 497 try { 498 if (s.extraData) { 499 for (var n in s.extraData) { 500 if (s.extraData.hasOwnProperty(n)) { 501 // if using the $.param format that allows for multiple values with the same name 502 if($.isPlainObject(s.extraData[n]) && s.extraData[n].hasOwnProperty('name') && s.extraData[n].hasOwnProperty('value')) { 503 extraInputs.push( 504 $('<input type="hidden" name="'+s.extraData[n].name+'">').val(s.extraData[n].value) 505 .appendTo(form)[0]); 506 } else { 507 extraInputs.push( 508 $('<input type="hidden" name="'+n+'">').val(s.extraData[n]) 509 .appendTo(form)[0]); 510 } 511 } 512 } 513 } 514 515 if (!s.iframeTarget) { 516 // add iframe to doc and submit the form 517 $io.appendTo('body'); 518 if (io.attachEvent) 519 io.attachEvent('onload', cb); 520 else 521 io.addEventListener('load', cb, false); 522 } 523 setTimeout(checkState,15); 524 525 try { 526 form.submit(); 527 } catch(err) { 528 // just in case form has element with name/id of 'submit' 529 var submitFn = document.createElement('form').submit; 530 submitFn.apply(form); 531 } 532 } 533 finally { 534 // reset attrs and remove "extra" input elements 535 form.setAttribute('action',a); 536 if(t) { 537 form.setAttribute('target', t); 538 } else { 539 $form.removeAttr('target'); 540 } 541 $(extraInputs).remove(); 542 } 543 } 544 545 if (s.forceSync) { 546 doSubmit(); 547 } 548 else { 549 setTimeout(doSubmit, 10); // this lets dom updates render 550 } 551 552 var data, doc, domCheckCount = 50, callbackProcessed; 553 554 function cb(e) { 555 if (xhr.aborted || callbackProcessed) { 556 return; 557 } 558 559 doc = getDoc(io); 560 if(!doc) { 561 log('cannot access response document'); 562 e = SERVER_ABORT; 563 } 564 if (e === CLIENT_TIMEOUT_ABORT && xhr) { 565 xhr.abort('timeout'); 566 deferred.reject(xhr, 'timeout'); 567 return; 568 } 569 else if (e == SERVER_ABORT && xhr) { 570 xhr.abort('server abort'); 571 deferred.reject(xhr, 'error', 'server abort'); 572 return; 573 } 574 575 if (!doc || doc.location.href == s.iframeSrc) { 576 // response not received yet 577 if (!timedOut) 578 return; 579 } 580 if (io.detachEvent) 581 io.detachEvent('onload', cb); 582 else 583 io.removeEventListener('load', cb, false); 584 585 var status = 'success', errMsg; 586 try { 587 if (timedOut) { 588 throw 'timeout'; 589 } 590 591 var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc); 592 log('isXml='+isXml); 593 if (!isXml && window.opera && (doc.body === null || !doc.body.innerHTML)) { 594 if (--domCheckCount) { 595 // in some browsers (Opera) the iframe DOM is not always traversable when 596 // the onload callback fires, so we loop a bit to accommodate 597 log('requeing onLoad callback, DOM not available'); 598 setTimeout(cb, 250); 599 return; 600 } 601 // let this fall through because server response could be an empty document 602 //log('Could not access iframe DOM after mutiple tries.'); 603 //throw 'DOMException: not available'; 604 } 605 606 //log('response detected'); 607 var docRoot = doc.body ? doc.body : doc.documentElement; 608 xhr.responseText = docRoot ? docRoot.innerHTML : null; 609 xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc; 610 if (isXml) 611 s.dataType = 'xml'; 612 xhr.getResponseHeader = function(header){ 613 var headers = {'content-type': s.dataType}; 614 return headers[header]; 615 }; 616 // support for XHR 'status' & 'statusText' emulation : 617 if (docRoot) { 618 xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status; 619 xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText; 620 } 621 622 var dt = (s.dataType || '').toLowerCase(); 623 var scr = /(json|script|text)/.test(dt); 624 if (scr || s.textarea) { 625 // see if user embedded response in textarea 626 var ta = doc.getElementsByTagName('textarea')[0]; 627 if (ta) { 628 xhr.responseText = ta.value; 629 // support for XHR 'status' & 'statusText' emulation : 630 xhr.status = Number( ta.getAttribute('status') ) || xhr.status; 631 xhr.statusText = ta.getAttribute('statusText') || xhr.statusText; 632 } 633 else if (scr) { 634 // account for browsers injecting pre around json response 635 var pre = doc.getElementsByTagName('pre')[0]; 636 var b = doc.getElementsByTagName('body')[0]; 637 if (pre) { 638 xhr.responseText = pre.textContent ? pre.textContent : pre.innerText; 639 } 640 else if (b) { 641 xhr.responseText = b.textContent ? b.textContent : b.innerText; 642 } 643 } 644 } 645 else if (dt == 'xml' && !xhr.responseXML && xhr.responseText) { 646 xhr.responseXML = toXml(xhr.responseText); 647 } 648 649 try { 650 data = httpData(xhr, dt, s); 651 } 652 catch (err) { 653 status = 'parsererror'; 654 xhr.error = errMsg = (err || status); 655 } 656 } 657 catch (err) { 658 log('error caught: ',err); 659 status = 'error'; 660 xhr.error = errMsg = (err || status); 661 } 662 663 if (xhr.aborted) { 664 log('upload aborted'); 665 status = null; 666 } 667 668 if (xhr.status) { // we've set xhr.status 669 status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error'; 670 } 671 672 // ordering of these callbacks/triggers is odd, but that's how $.ajax does it 673 if (status === 'success') { 674 if (s.success) 675 s.success.call(s.context, data, 'success', xhr); 676 deferred.resolve(xhr.responseText, 'success', xhr); 677 if (g) 678 $.event.trigger("ajaxSuccess", [xhr, s]); 679 } 680 else if (status) { 681 if (errMsg === undefined) 682 errMsg = xhr.statusText; 683 if (s.error) 684 s.error.call(s.context, xhr, status, errMsg); 685 deferred.reject(xhr, 'error', errMsg); 686 if (g) 687 $.event.trigger("ajaxError", [xhr, s, errMsg]); 688 } 689 690 if (g)
691 $.event.trigger("ajaxComplete", [xhr, s]); 692 693 if (g && ! --$.active) { 694 $.event.trigger("ajaxStop"); 695 } 696 697 if (s.complete) 698 s.complete.call(s.context, xhr, status); 699 700 callbackProcessed = true; 701 if (s.timeout) 702 clearTimeout(timeoutHandle); 703 704 // clean up 705 setTimeout(function() { 706 if (!s.iframeTarget) 707 $io.remove(); 708 xhr.responseXML = null; 709 }, 100); 710 } 711 712 var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+) 713 if (window.ActiveXObject) { 714 doc = new ActiveXObject('Microsoft.XMLDOM'); 715 doc.async = 'false'; 716 doc.loadXML(s); 717 } 718 else { 719 doc = (new DOMParser()).parseFromString(s, 'text/xml'); 720 } 721 return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null; 722 }; 723 var parseJSON = $.parseJSON || function(s) { 724 /*jslint evil:true */ 725 return window['eval']('(' + s + ')'); 726 }; 727 728 var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4 729 730 var ct = xhr.getResponseHeader('content-type') || '', 731 xml = type === 'xml' || !type && ct.indexOf('xml') >= 0, 732 data = xml ? xhr.responseXML : xhr.responseText; 733 734 if (xml && data.documentElement.nodeName === 'parsererror') { 735 if ($.error) 736 $.error('parsererror'); 737 } 738 if (s && s.dataFilter) { 739 data = s.dataFilter(data, type); 740 } 741 if (typeof data === 'string') { 742 if (type === 'json' || !type && ct.indexOf('json') >= 0) { 743 data = parseJSON(data); 744 } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) { 745 $.globalEval(data); 746 } 747 } 748 return data; 749 }; 750 751 return deferred; 752 } 753}; 754 755/** 756 * ajaxForm() provides a mechanism for fully automating form submission. 757 * 758 * The advantages of using this method instead of ajaxSubmit() are: 759 * 760 * 1: This method will include coordinates for <input type="image" /> elements (if the element 761 * is used to submit the form). 762 * 2. This method will include the submit element's name/value data (for the element that was 763 * used to submit the form). 764 * 3. This method binds the submit() method to the form for you. 765 * 766 * The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely 767 * passes the options argument along after properly binding events for submit elements and 768 * the form itself. 769 */ 770$.fn.ajaxForm = function(options) { 771 options = options || {}; 772 options.delegation = options.delegation && $.isFunction($.fn.on); 773 774 // in jQuery 1.3+ we can fix mistakes with the ready state 775 if (!options.delegation && this.length === 0) { 776 var o = { s: this.selector, c: this.context }; 777 if (!$.isReady && o.s) { 778 log('DOM not ready, queuing ajaxForm'); 779 $(function() { 780 $(o.s,o.c).ajaxForm(options); 781 }); 782 return this; 783 } 784 // is your DOM ready? http://docs.jquery.com/Tutorials:Introducing_$(document).ready() 785 log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)')); 786 return this; 787 } 788 789 if ( options.delegation ) { 790 $(document) 791 .off('submit.form-plugin', this.selector, doAjaxSubmit) 792 .off('click.form-plugin', this.selector, captureSubmittingElement) 793 .on('submit.form-plugin', this.selector, options, doAjaxSubmit) 794 .on('click.form-plugin', this.selector, options, captureSubmittingElement); 795 return this; 796 } 797 798 return this.ajaxFormUnbind() 799 .bind('submit.form-plugin', options, doAjaxSubmit) 800 .bind('click.form-plugin', options, captureSubmittingElement); 801}; 802 803// private event handlers 804function doAjaxSubmit(e) { 805 /*jshint validthis:true */ 806 var options = e.data; 807 if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed 808 e.preventDefault(); 809 $(this).ajaxSubmit(options); 810 } 811} 812 813function captureSubmittingElement(e) { 814 /*jshint validthis:true */ 815 var target = e.target; 816 var $el = $(target); 817 if (!($el.is("[type=submit],[type=image]"))) { 818 // is this a child element of the submit el? (ex: a span within a button) 819 var t = $el.closest('[type=submit]'); 820 if (t.length === 0) { 821 return; 822 } 823 target = t[0]; 824 } 825 var form = this; 826 form.clk = target; 827 if (target.type == 'image') { 828 if (e.offsetX !== undefined) { 829 form.clk_x = e.offsetX; 830 form.clk_y = e.offsetY; 831 } else if (typeof $.fn.offset == 'function') { 832 var offset = $el.offset(); 833 form.clk_x = e.pageX - offset.left; 834 form.clk_y = e.pageY - offset.top; 835 } else { 836 form.clk_x = e.pageX - target.offsetLeft; 837 form.clk_y = e.pageY - target.offsetTop; 838 } 839 } 840 // clear form vars 841 setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100); 842} 843 844 845// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm 846$.fn.ajaxFormUnbind = function() { 847 return this.unbind('submit.form-plugin click.form-plugin'); 848}; 849 850/** 851 * formToArray() gathers form element data into an array of objects that can 852 * be passed to any of the following ajax functions: $.get, $.post, or load. 853 * Each object in the array has both a 'name' and 'value' property. An example of 854 * an array for a simple login form might be: 855 * 856 * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ] 857 * 858 * It is this array that is passed to pre-submit callback functions provided to the 859 * ajaxSubmit() and ajaxForm() methods. 860 */ 861$.fn.formToArray = function(semantic, elements) { 862 var a = []; 863 if (this.length === 0) { 864 return a; 865 } 866 867 var form = this[0]; 868 var els = semantic ? form.getElementsByTagName('*') : form.elements; 869 if (!els) { 870 return a; 871 } 872 873 var i,j,n,v,el,max,jmax; 874 for(i=0, max=els.length; i < max; i++) { 875 el = els[i]; 876 n = el.name; 877 if (!n || el.disabled) { 878 continue; 879 } 880 881 if (semantic && form.clk && el.type == "image") { 882 // handle image inputs on the fly when semantic == true 883 if(form.clk == el) { 884 a.push({name: n, value: $(el).val(), type: el.type }); 885 a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y}); 886 } 887 continue; 888 } 889 890 v = $.fieldValue(el, true); 891 if (v && v.constructor == Array) { 892 if (elements) 893 elements.push(el); 894 for(j=0, jmax=v.length; j < jmax; j++) { 895 a.push({name: n, value: v[j]}); 896 } 897 } 898 else if (feature.fileapi && el.type == 'file') { 899 if (elements) 900 elements.push(el); 901 var files = el.files; 902 if (files.length) { 903 for (j=0; j < files.length; j++) { 904 a.push({name: n, value: files[j], type: el.type}); 905 } 906 } 907 else { 908 // #180 909 a.push({ name: n, value: '', type: el.type }); 910 } 911 } 912 else if (v !== null && typeof v != 'undefined') { 913 if (elements) 914 elements.push(el); 915 a.push({name: n, value: v, type: el.type, required: el.required}); 916 } 917 } 918 919 if (!semantic && form.clk) { 920 // input type=='image' are not found in elements array! handle it here 921 var $input = $(form.clk), input = $input[0]; 922 n = input.name; 923 if (n && !input.disabled && input.type == 'image') { 924 a.push({name: n, value: $input.val()}); 925 a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y}); 926 } 927 } 928 return a; 929}; 930 931/** 932 * Serializes form data into a 'submittable' string. This method will return a string 933 * in the format: name1=value1&name2=value2 934 */
935$.fn.formSerialize = function(semantic) { 936 //hand off to jQuery.param for proper encoding 937 return $.param(this.formToArray(semantic)); 938}; 939 940/** 941 * Serializes all field elements in the jQuery object into a query string. 942 * This method will return a string in the format: name1=value1&name2=value2 943 */ 944$.fn.fieldSerialize = function(successful) { 945 var a = []; 946 this.each(function() { 947 var n = this.name; 948 if (!n) { 949 return; 950 } 951 var v = $.fieldValue(this, successful); 952 if (v && v.constructor == Array) { 953 for (var i=0,max=v.length; i < max; i++) { 954 a.push({name: n, value: v[i]}); 955 } 956 } 957 else if (v !== null && typeof v != 'undefined') { 958 a.push({name: this.name, value: v}); 959 } 960 }); 961 //hand off to jQuery.param for proper encoding 962 return $.param(a); 963}; 964 965/** 966 * Returns the value(s) of the element in the matched set. For example, consider the following form: 967 * 968 * <form><fieldset> 969 * <input name="A" type="text" /> 970 * <input name="A" type="text" /> 971 * <input name="B" type="checkbox" value="B1" /> 972 * <input name="B" type="checkbox" value="B2"/> 973 * <input name="C" type="radio" value="C1" /> 974 * <input name="C" type="radio" value="C2" /> 975 * </fieldset></form> 976 * 977 * var v = $('input[type=text]').fieldValue(); 978 * // if no values are entered into the text inputs 979 * v == ['',''] 980 * // if values entered into the text inputs are 'foo' and 'bar' 981 * v == ['foo','bar'] 982 * 983 * var v = $('input[type=checkbox]').fieldValue(); 984 * // if neither checkbox is checked 985 * v === undefined 986 * // if both checkboxes are checked 987 * v == ['B1', 'B2'] 988 * 989 * var v = $('input[type=radio]').fieldValue(); 990 * // if neither radio is checked 991 * v === undefined 992 * // if first radio is checked 993 * v == ['C1'] 994 * 995 * The successful argument controls whether or not the field element must be 'successful' 996 * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls). 997 * The default value of the successful argument is true. If this value is false the value(s) 998 * for each element is returned. 999 * 1000 * Note: This method *always* returns an array. If no valid value can be determined the 1001 * array will be empty, otherwise it will contain one or more values. 1002 */ 1003$.fn.fieldValue = function(successful) { 1004 for (var val=[], i=0, max=this.length; i < max; i++) { 1005 var el = this[i]; 1006 var v = $.fieldValue(el, successful); 1007 if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) { 1008 continue; 1009 } 1010 if (v.constructor == Array) 1011 $.merge(val, v); 1012 else 1013 val.push(v); 1014 } 1015 return val; 1016}; 1017 1018/** 1019 * Returns the value of the field element. 1020 */ 1021$.fieldValue = function(el, successful) { 1022 var n = el.name, t = el.type, tag = el.tagName.toLowerCase(); 1023 if (successful === undefined) { 1024 successful = true; 1025 } 1026 1027 if (successful && (!n || el.disabled || t == 'reset' || t == 'button' || 1028 (t == 'checkbox' || t == 'radio') && !el.checked || 1029 (t == 'submit' || t == 'image') && el.form && el.form.clk != el || 1030 tag == 'select' && el.selectedIndex == -1)) { 1031 return null; 1032 } 1033 1034 if (tag == 'select') { 1035 var index = el.selectedIndex; 1036 if (index < 0) { 1037 return null; 1038 } 1039 var a = [], ops = el.options; 1040 var one = (t == 'select-one'); 1041 var max = (one ? index+1 : ops.length); 1042 for(var i=(one ? index : 0); i < max; i++) { 1043 var op = ops[i]; 1044 if (op.selected) { 1045 var v = op.value; 1046 if (!v) { // extra pain for IE... 1047 v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value; 1048 } 1049 if (one) { 1050 return v; 1051 } 1052 a.push(v); 1053 } 1054 } 1055 return a; 1056 } 1057 return $(el).val(); 1058}; 1059 1060/** 1061 * Clears the form data. Takes the following actions on the form's input fields: 1062 * - input text fields will have their 'value' property set to the empty string 1063 * - select elements will have their 'selectedIndex' property set to -1 1064 * - checkbox and radio inputs will have their 'checked' property set to false 1065 * - inputs of type submit, button, reset, and hidden will *not* be effected 1066 * - button elements will *not* be effected 1067 */ 1068$.fn.clearForm = function(includeHidden) { 1069 return this.each(function() { 1070 $('input,select,textarea', this).clearFields(includeHidden); 1071 }); 1072}; 1073 1074/** 1075 * Clears the selected form elements. 1076 */ 1077$.fn.clearFields = $.fn.clearInputs = function(includeHidden) { 1078 var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list 1079 return this.each(function() { 1080 var t = this.type, tag = this.tagName.toLowerCase(); 1081 if (re.test(t) || tag == 'textarea') { 1082 this.value = ''; 1083 } 1084 else if (t == 'checkbox' || t == 'radio') { 1085 this.checked = false;
1086 } 1087 else if (tag == 'select') { 1088 this.selectedIndex = -1; 1089 } 1090 else if (t == "file") { 1091 if (/MSIE/.test(navigator.userAgent)) { 1092 $(this).replaceWith($(this).clone(true)); 1093 } else { 1094 $(this).val(''); 1095 } 1096 } 1097 else if (includeHidden) { 1098 // includeHidden can be the value true, or it can be a selector string 1099 // indicating a special test; for example: 1100 // $('#myForm').clearForm('.special:hidden') 1101 // the above would clean hidden inputs that have the class of 'special' 1102 if ( (includeHidden === true && /hidden/.test(t)) || 1103 (typeof includeHidden == 'string' && $(this).is(includeHidden)) ) 1104 this.value = ''; 1105 } 1106 }); 1107}; 1108 1109/** 1110 * Resets the form data. Causes all form elements to be reset to their original value. 1111 */ 1112$.fn.resetForm = function() { 1113 return this.each(function() { 1114 // guard against an input with the name of 'reset' 1115 // note that IE reports the reset function as an 'object' 1116 if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) { 1117 this.reset(); 1118 } 1119 }); 1120}; 1121 1122/** 1123 * Enables or disables any matching elements. 1124 */ 1125$.fn.enable = function(b) { 1126 if (b === undefined) { 1127 b = true; 1128 } 1129 return this.each(function() { 1130 this.disabled = !b; 1131 }); 1132}; 1133 1134/** 1135 * Checks/unchecks any matching checkboxes or radio buttons and 1136 * selects/deselects and matching option elements. 1137 */ 1138$.fn.selected = function(select) { 1139 if (select === undefined) { 1140 select = true; 1141 } 1142 return this.each(function() { 1143 var t = this.type; 1144 if (t == 'checkbox' || t == 'radio') { 1145 this.checked = select; 1146 } 1147 else if (this.tagName.toLowerCase() == 'option') { 1148 var $sel = $(this).parent('select'); 1149 if (select && $sel[0] && $sel[0].type == 'select-one') { 1150 // deselect all other options 1151 $sel.find('option').selected(false); 1152 } 1153 this.selected = select; 1154 } 1155 }); 1156}; 1157 1158// expose debug var 1159$.fn.ajaxSubmit.debug = false; 1160 1161// helper fn for console logging 1162function log() { 1163 if (!$.fn.ajaxSubmit.debug) 1164 return; 1165 var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,''); 1166 if (window.console && window.console.log) { 1167 window.console.log(msg); 1168 } 1169 else if (window.opera && window.opera.postError) { 1170 window.opera.postError(msg); 1171 } 1172} 1173 1174})(jQuery); 1175 1176 1177 1178 1179/*! 1180 * jQuery Validation Plugin v1.12.0 1181 * 1182 * http://jqueryvalidation.org/ 1183 * 1184 * Copyright (c) 2014 Jörn Zaefferer 1185 * Released under the MIT license 1186 */ 1187(function($) { 1188 1189$.extend($.fn, { 1190 // http://jqueryvalidation.org/validate/ 1191 validate: function( options ) { 1192 1193 // if nothing is selected, return nothing; can't chain anyway 1194 if ( !this.length ) { 1195 if ( options && options.debug && window.console ) { 1196 console.warn( "Nothing selected, can't validate, returning nothing." ); 1197 } 1198 return; 1199 } 1200 1201 // check if a validator for this form was already created 1202 var validator = $.data( this[0], "validator" ); 1203 if ( validator ) { 1204 return validator; 1205 } 1206 1207 // Add novalidate tag if HTML5. 1208 this.attr( "novalidate", "novalidate" ); 1209 1210 validator = new $.validator( options, this[0] ); 1211 $.data( this[0], "validator", validator ); 1212 1213 if ( validator.settings.onsubmit ) { 1214 1215 this.validateDelegate( ":submit", "click", function( event ) { 1216 if ( validator.settings.submitHandler ) { 1217 validator.submitButton = event.target; 1218 } 1219 // allow suppressing validation by adding a cancel class to the submit button 1220 if ( $(event.target).hasClass("cancel") ) { 1221 validator.cancelSubmit = true; 1222 } 1223 1224 // allow suppressing validation by adding the html5 formnovalidate attribute to the submit button 1225 if ( $(event.target).attr("formnovalidate") !== undefined ) { 1226 validator.cancelSubmit = true; 1227 } 1228 }); 1229 1230 // validate the form on submit 1231 this.submit( function( event ) { 1232 if ( validator.settings.debug ) { 1233 // prevent form submit to be able to see console output 1234 event.preventDefault(); 1235 } 1236 function handle() { 1237 var hidden; 1238 if ( validator.settings.submitHandler ) { 1239 if ( validator.submitButton ) { 1240 // insert a hidden input as a replacement for the missing submit button 1241 hidden = $("<input type='hidden'/>").attr("name", validator.submitButton.name).val( $(validator.submitButton).val() ).appendTo(validator.currentForm); 1242 } 1243 validator.settings.submitHandler.call( validator, validator.currentForm, event ); 1244 if ( validator.submitButton ) { 1245 // and clean up afterwards; thanks to no-block-scope, hidden can be referenced 1246 hidden.remove(); 1247 } 1248 return false;
1249 } 1250 return true; 1251 } 1252 1253 // prevent submit for invalid forms or custom submit handlers 1254 if ( validator.cancelSubmit ) { 1255 validator.cancelSubmit = false; 1256 return handle(); 1257 } 1258 if ( validator.form() ) { 1259 if ( validator.pendingRequest ) { 1260 validator.formSubmitted = true; 1261 return false; 1262 } 1263 return handle(); 1264 } else { 1265 validator.focusInvalid(); 1266 return false; 1267 } 1268 }); 1269 } 1270 1271 return validator; 1272 }, 1273 // http://jqueryvalidation.org/valid/ 1274 valid: function() { 1275 var valid, validator; 1276 1277 if ( $(this[0]).is("form")) { 1278 valid = this.validate().form(); 1279 } else { 1280 valid = true; 1281 validator = $(this[0].form).validate(); 1282 this.each(function() { 1283 valid = validator.element(this) && valid; 1284 }); 1285 } 1286 return valid; 1287 }, 1288 // attributes: space separated list of attributes to retrieve and remove 1289 removeAttrs: function( attributes ) { 1290 var result = {}, 1291 $element = this; 1292 $.each(attributes.split(/\s/), function( index, value ) { 1293 result[value] = $element.attr(value); 1294 $element.removeAttr(value); 1295 }); 1296 return result; 1297 }, 1298 // http://jqueryvalidation.org/rules/ 1299 rules: function( command, argument ) { 1300 var element = this[0], 1301 settings, staticRules, existingRules, data, param, filtered; 1302 1303 if ( command ) { 1304 settings = $.data(element.form, "validator").settings; 1305 staticRules = settings.rules; 1306 existingRules = $.validator.staticRules(element); 1307 switch (command) { 1308 case "add": 1309 $.extend(existingRules, $.validator.normalizeRule(argument)); 1310 // remove messages from rules, but allow them to be set separately 1311 delete existingRules.messages; 1312 staticRules[element.name] = existingRules; 1313 if ( argument.messages ) { 1314 settings.messages[element.name] = $.extend( settings.messages[element.name], argument.messages ); 1315 } 1316 break; 1317 case "remove": 1318 if ( !argument ) { 1319 delete staticRules[element.name]; 1320 return existingRules; 1321 } 1322 filtered = {}; 1323 $.each(argument.split(/\s/), function( index, method ) { 1324 filtered[method] = existingRules[method]; 1325 delete existingRules[method]; 1326 if ( method === "required" ) { 1327 $(element).removeAttr("aria-required"); 1328 } 1329 }); 1330 return filtered; 1331 } 1332 } 1333 1334 data = $.validator.normalizeRules( 1335 $.extend( 1336 {}, 1337 $.validator.classRules(element), 1338 $.validator.attributeRules(element), 1339 $.validator.dataRules(element), 1340 $.validator.staticRules(element) 1341 ), element); 1342 1343 // make sure required is at front 1344 if ( data.required ) { 1345 param = data.required; 1346 delete data.required; 1347 data = $.extend({ required: param }, data ); 1348 $(element).attr( "aria-required", "true" ); 1349 } 1350 1351 // make sure remote is at back 1352 if ( data.remote ) { 1353 param = data.remote; 1354 delete data.remote; 1355 data = $.extend( data, { remote: param }); 1356 } 1357 1358 return data; 1359 } 1360}); 1361 1362// Custom selectors 1363$.extend($.expr[":"], { 1364 // http://jqueryvalidation.org/blank-selector/ 1365 blank: function( a ) { return !$.trim("" + $(a).val()); }, 1366 // http://jqueryvalidation.org/filled-selector/ 1367 filled: function( a ) { return !!$.trim("" + $(a).val()); }, 1368 // http://jqueryvalidation.org/unchecked-selector/ 1369 unchecked: function( a ) { return !$(a).prop("checked"); } 1370}); 1371 1372// constructor for validator 1373$.validator = function( options, form ) { 1374 this.settings = $.extend( true, {}, $.validator.defaults, options ); 1375 this.currentForm = form; 1376 this.init(); 1377}; 1378 1379// http://jqueryvalidation.org/jQuery.validator.format/ 1380$.validator.format = function( source, params ) { 1381 if ( arguments.length === 1 ) { 1382 return function() { 1383 var args = $.makeArray(arguments); 1384 args.unshift(source); 1385 return $.validator.format.apply( this, args ); 1386 }; 1387 } 1388 if ( arguments.length > 2 && params.constructor !== Array ) { 1389 params = $.makeArray(arguments).slice(1); 1390 } 1391 if ( params.constructor !== Array ) { 1392 params = [ params ]; 1393 } 1394 $.each(params, function( i, n ) { 1395 source = source.replace( new RegExp("\\{" + i + "\\}", "g"), function() { 1396 return n; 1397 }); 1398 }); 1399 return source; 1400}; 1401 1402$.extend($.validator, { 1403 1404 defaults: { 1405 messages: {}, 1406 groups: {}, 1407 rules: {}, 1408 errorClass: "error", 1409 validClass: "valid", 1410 errorElement: "label", 1411 focusInvalid: true, 1412 errorContainer: $([]), 1413 errorLabelContainer: $([]), 1414 onsubmit: true, 1415 ignore: ":hidden", 1416 ignoreTitle: false, 1417 onfocusin: function( element ) { 1418 this.lastActive = element; 1419 1420 // hide error label and remove error class on focus if enabled 1421 if ( this.settings.focusCleanup && !this.blockFocusCleanup ) { 1422 if ( this.settings.unhighlight ) { 1423 this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.val
1423idClass ); 1424 } 1425 this.addWrapper(this.errorsFor(element)).hide(); 1426 } 1427 }, 1428 onfocusout: function( element ) { 1429 if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) { 1430 this.element(element); 1431 } 1432 }, 1433 onkeyup: function( element, event ) { 1434 if ( event.which === 9 && this.elementValue(element) === "" ) { 1435 return; 1436 } else if ( element.name in this.submitted || element === this.lastElement ) { 1437 this.element(element); 1438 } 1439 }, 1440 onclick: function( element ) { 1441 // click on selects, radiobuttons and checkboxes 1442 if ( element.name in this.submitted ) { 1443 this.element(element); 1444 1445 // or option elements, check parent select in that case 1446 } else if ( element.parentNode.name in this.submitted ) { 1447 this.element(element.parentNode); 1448 } 1449 }, 1450 highlight: function( element, errorClass, validClass ) { 1451 if ( element.type === "radio" ) { 1452 this.findByName(element.name).addClass(errorClass).removeClass(validClass); 1453 } else { 1454 $(element).addClass(errorClass).removeClass(validClass); 1455 } 1456 }, 1457 unhighlight: function( element, errorClass, validClass ) { 1458 if ( element.type === "radio" ) { 1459 this.findByName(element.name).removeClass(errorClass).addClass(validClass); 1460 } else { 1461 $(element).removeClass(errorClass).addClass(validClass); 1462 } 1463 } 1464 }, 1465 1466 // http://jqueryvalidation.org/jQuery.validator.setDefaults/ 1467 setDefaults: function( settings ) { 1468 $.extend( $.validator.defaults, settings ); 1469 }, 1470 1471 messages: { 1472 required: "This field is required.", 1473 remote: "Please fix this field.", 1474 email: "Please enter a valid email address.", 1475 url: "Please enter a valid URL.", 1476 date: "Please enter a valid date.", 1477 dateISO: "Please enter a valid date (ISO).", 1478 number: "Please enter a valid number.", 1479 digits: "Please enter only digits.", 1480 creditcard: "Please enter a valid credit card number.", 1481 equalTo: "Please enter the same value again.", 1482 maxlength: $.validator.format("Please enter no more than {0} characters."), 1483 minlength: $.validator.format("Please enter at least {0} characters."), 1484 rangelength: $.validator.format("Please enter a value between {0} and {1} characters long."), 1485 range: $.validator.format("Please enter a value between {0} and {1}."), 1486 max: $.validator.format("Please enter a value less than or equal to {0}."), 1487 min: $.validator.format("Please enter a value greater than or equal to {0}.") 1488 }, 1489 1490 autoCreateRanges: false, 1491 1492 prototype: { 1493 1494 init: function() { 1495 this.labelContainer = $(this.settings.errorLabelContainer); 1496 this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm); 1497 this.containers = $(this.settings.errorContainer).add( this.settings.errorLabelContainer ); 1498 this.submitted = {}; 1499 this.valueCache = {}; 1500 this.pendingRequest = 0; 1501 this.pending = {}; 1502 this.invalid = {}; 1503 this.reset(); 1504 1505 var groups = (this.groups = {}), 1506 rules; 1507 $.each(this.settings.groups, function( key, value ) { 1508 if ( typeof value === "string" ) { 1509 value = value.split(/\s/); 1510 } 1511 $.each(value, function( index, name ) { 1512 groups[name] = key; 1513 }); 1514 }); 1515 rules = this.settings.rules; 1516 $.each(rules, function( key, value ) { 1517 rules[key] = $.validator.normalizeRule(value); 1518 }); 1519 1520 function delegate(event) { 1521 var validator = $.data(this[0].form, "validator"), 1522 eventType = "on" + event.type.replace(/^validate/, ""), 1523 settings = validator.settings; 1524 if ( settings[eventType] && !this.is( settings.ignore ) ) { 1525 settings[eventType].call(validator, this[0], event); 1526 } 1527 } 1528 $(this.currentForm) 1529 .validateDelegate(":text, [type='password'], [type='file'], select, textarea, " + 1530 "[type='number'], [type='search'] ,[type='tel'], [type='url'], " + 1531 "[type='email'], [type='datetime'], [type='date'], [type='month'], " + 1532 "[type='week'], [type='time'], [type='datetime-local'], " + 1533 "[type='range'], [type='color'] ", 1534 "focusin focusout keyup", delegate) 1535 .validateDelegate("[type='radio'], [type='checkbox'], select, option", "click", delegate); 1536 1537 if ( this.settings.invalidHandler ) { 1538 $(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler); 1539 } 1540 1541 // Add aria-required to any Static/Data/Class required fields before first validation 1542 // Screen readers require this attribute to be present before the initial submission http://www.w3.org/TR/WCAG-TECHS/ARIA2.html 1543 $(this.currentForm).find("[required], [data-rule-required], .required").attr("aria-required", "true"); 1544 }, 1545 1546 // http://jqueryvalidation.org/Validator.form/ 1547 form: function() { 1548 this.checkForm(); 1549 $.extend(this.submitted, this.errorMap); 1550 this.invalid = $.extend({}, this.errorMap); 1551 if ( !this.valid() ) { 1552 $(this.currentForm).triggerHandler("invalid-form", [ this ]); 1553 } 1554 this.showErrors(); 1555 return this.valid(); 1556 }, 1557 1558 checkForm: function() { 1559 this.prepareForm(); 1560 for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) { 1561 this.check( elements[i] ); 1562 } 1563 return this.valid(); 1564 }, 1565 1566 // http://jqueryvalidation.org/Validator.element/ 1567 element: function( element ) { 1568 var cleanElement = this.clean( element ), 1569 checkElement = this.validationTargetFor( cleanElement ), 1570 result = true; 1571 1572 this.lastElement = checkElement; 1573 1574 if ( checkElement === undefined ) { 1575 delete this.invalid[ cleanElement.name ]; 1576 } else { 1577 this.prepareElement( checkElement ); 1578 this.currentElements = $( checkElement ); 1579 1580 result = this.check( checkElement ) !== false; 1581 if (result) { 1582 delete this.invalid[checkElement.name]; 1583 } else { 1584 this.invalid[checkElement.name] = true; 1585 } 1586 } 1587 // Add aria-invalid status for screen readers 1588 $( element ).attr( "aria-invalid", !result ); 1589 1590 if ( !this.numberOfInvalids() ) { 1591 // Hide error containers on last error 1592 this.toHide = this.toHide.add( this.containers ); 1593 } 1594 this.showErrors(); 1595 return result; 1596 }, 1597 1598 // http://jqueryvalidation.org/Validator.showErrors/ 1599 showErrors: function( errors ) { 1600 if ( errors ) { 1601 // add items to error list and map 1602 $.extend( this.errorMap, errors ); 1603 this.errorList = []; 1604 for ( var name in errors ) { 1605 this.errorList.push({ 1606 message: errors[name], 1607 element: this.findByName(name)[0] 1608 }); 1609 } 1610 // remove items from success list 1611 this.successList = $.grep( this.successList, function( element ) { 1612 return !(element.name in errors); 1613 }); 1614 } 1615 if ( this.settings.showErrors ) { 1616 this.settings.showErrors.call( this, this.errorMap, this.errorList ); 1617 } else { 1618 this.defaultShowErrors(); 1619 } 1620 }, 1621 1622 // http://jqueryvalidation.org/Validator.resetForm/ 1623 resetForm: function() { 1624 if ( $.fn.resetForm ) { 1625 $(this.currentForm).resetForm(); 1626 } 1627 this.submitted = {}; 1628 this.lastElement = null; 1629 this.prepareForm(); 1630 this.hideErrors(); 1631 this.elements() 1632 .removeClass( this.settings.errorClass ) 1633 .removeData( "previousValue" ) 1634 .removeAttr( "aria-invalid" ); 1635 }, 1636 1637 numberOfInvalids: function() { 1638 return this.objectLength(this.invalid); 1639 }, 1640 1641 objectLength: function( obj ) { 1642 /* jshint unused: false */ 1643 var count = 0, 1644 i; 1645 for ( i in obj ) { 1646 count++; 1647 } 1648 return count; 1649 }, 1650 1651 hideErrors: function() { 1652 this.addWrapper( this.toHide ).hide(); 1653 }, 1654 1655 valid: function() { 1656 return this.size() === 0; 1657 }, 1658 1659 size: function() { 1660 return this.errorList.length; 1661 }, 1662 1663 focusInvalid: function() { 1664 if ( this.settings.focusInvalid ) { 1665 try { 1666 $(this.findLastActive() || this.errorList.length && this.errorList[0].element || []) 1667 .filter(":visible") 1668 .focus() 1669 // manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find 1670 .trigger("focusin"); 1671 } catch(e) {
1672 // ignore IE throwing errors when focusing hidden elements 1673 } 1674 } 1675 }, 1676 1677 findLastActive: function() { 1678 var lastActive = this.lastActive; 1679 return lastActive && $.grep(this.errorList, function( n ) { 1680 return n.element.name === lastActive.name; 1681 }).length === 1 && lastActive; 1682 }, 1683 1684 elements: function() { 1685 var validator = this, 1686 rulesCache = {}; 1687 1688 // select all valid inputs inside the form (no submit or reset buttons) 1689 return $(this.currentForm) 1690 .find("input, select, textarea") 1691 .not(":submit, :reset, :image, [disabled]") 1692 .not( this.settings.ignore ) 1693 .filter(function() { 1694 if ( !this.name && validator.settings.debug && window.console ) { 1695 console.error( "%o has no name assigned", this); 1696 } 1697 1698 // select only the first element for each name, and only those with rules specified 1699 if ( this.name in rulesCache || !validator.objectLength($(this).rules()) ) { 1700 return false; 1701 } 1702 1703 rulesCache[this.name] = true; 1704 return true; 1705 }); 1706 }, 1707 1708 clean: function( selector ) { 1709 return $(selector)[0]; 1710 }, 1711 1712 errors: function() { 1713 var errorClass = this.settings.errorClass.split(" ").join("."); 1714 return $(this.settings.errorElement + "." + errorClass, this.errorContext); 1715 }, 1716 1717 reset: function() { 1718 this.successList = []; 1719 this.errorList = []; 1720 this.errorMap = {}; 1721 this.toShow = $([]); 1722 this.toHide = $([]); 1723 this.currentElements = $([]); 1724 }, 1725 1726 prepareForm: function() { 1727 this.reset(); 1728 this.toHide = this.errors().add( this.containers ); 1729 }, 1730 1731 prepareElement: function( element ) { 1732 this.reset(); 1733 this.toHide = this.errorsFor(element); 1734 }, 1735 1736 elementValue: function( element ) { 1737 var val, 1738 $element = $(element), 1739 type = $element.attr("type"); 1740 1741 if ( type === "radio" || type === "checkbox" ) { 1742 return $("input[name='" + $element.attr("name") + "']:checked").val(); 1743 } 1744 1745 val = $element.val(); 1746 if ( typeof val === "string" ) { 1747 return val.replace(/\r/g, ""); 1748 } 1749 return val; 1750 }, 1751 1752 check: function( element ) { 1753 element = this.validationTargetFor( this.clean( element ) ); 1754 1755 var rules = $(element).rules(), 1756 rulesCount = $.map( rules, function(n, i) { 1757 return i; 1758 }).length, 1759 dependencyMismatch = false, 1760 val = this.elementValue(element), 1761 result, method, rule; 1762 1763 for (method in rules ) { 1764 rule = { method: method, parameters: rules[method] }; 1765 try { 1766 1767 result = $.validator.methods[method].call( this, val, element, rule.parameters ); 1768 1769 // if a method indicates that the field is optional and therefore valid, 1770 // don't mark it as valid when there are no other rules 1771 if ( result === "dependency-mismatch" && rulesCount === 1 ) { 1772 dependencyMismatch = true; 1773 continue; 1774 } 1775 dependencyMismatch = false; 1776 1777 if ( result === "pending" ) { 1778 this.toHide = this.toHide.not( this.errorsFor(element) ); 1779 return; 1780 } 1781 1782 if ( !result ) { 1783 this.formatAndAdd( element, rule ); 1784 return false; 1785 } 1786 } catch(e) { 1787 if ( this.settings.debug && window.console ) { 1788 console.log( "Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.", e ); 1789 } 1790 throw e; 1791 } 1792 } 1793 if ( dependencyMismatch ) { 1794 return; 1795 } 1796 if ( this.objectLength(rules) ) { 1797 this.successList.push(element); 1798 } 1799 return true; 1800 }, 1801 1802 // return the custom message for the given element and validation method 1803 // specified in the element's HTML5 data attribute 1804 // return the generic message if present and no method specific message is present 1805 customDataMessage: function( element, method ) { 1806 return $( element ).data( "msg" + method[ 0 ].toUpperCase() + 1807 method.substring( 1 ).toLowerCase() ) || $( element ).data("msg"); 1808 }, 1809 1810 // return the custom message for the given element name and validation method 1811 customMessage: function( name, method ) { 1812 var m = this.settings.messages[name]; 1813 return m && (m.constructor === String ? m : m[method]); 1814 }, 1815 1816 // return the first defined argument, allowing empty strings 1817 findDefined: function() { 1818 for (var i = 0; i < arguments.length; i++) { 1819 if ( arguments[i] !== undefined ) { 1820 return arguments[i]; 1821 } 1822 } 1823 return undefined; 1824 }, 1825 1826 defaultMessage: function( element, method ) { 1827 return this.findDefined( 1828 this.customMessage( element.name, method ), 1829 this.customDataMessage( element, method ), 1830 // title is never undefined, so handle empty string as undefined 1831 !this.settings.ignoreTitle && element.title || undefined, 1832 $.validator.messages[method], 1833 "<strong>Warning: No message defined for " + element.name + "</strong>" 1834 ); 1835 }, 1836 1837 formatAndAdd: function( element, rule ) { 1838 var message = this.defaultMessage( element, rule.method ), 1839 theregex = /\$?\{(\d+)\}/g; 1840 if ( typeof message === "function" ) { 1841 message = message.call(this, rule.parameters, element); 1842 } else if (theregex.test(message)) { 1843 message = $.validator.format(message.replace(theregex, "{$1}"), rule.parameters); 1844 } 1845 this.errorList.push({ 1846 message: message, 1847 element: element, 1848 method: rule.method 1849 }); 1850 1851 this.errorMap[element.name] = message; 1852 this.submitted[element.name] = message; 1853 }, 1854 1855 addWrapper: function( toToggle ) { 1856 if ( this.settings.wrapper ) { 1857 toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) ); 1858 } 1859 return toToggle; 1860 }, 1861 1862 defaultShowErrors: function() { 1863 var i, elements, error; 1864 for ( i = 0; this.errorList[i]; i++ ) { 1865 error = this.errorList[i]; 1866 if ( this.settings.highlight ) { 1867 this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.val
1867idClass ); 1868 } 1869 this.showLabel( error.element, error.message ); 1870 } 1871 if ( this.errorList.length ) { 1872 this.toShow = this.toShow.add( this.containers ); 1873 } 1874 if ( this.settings.success ) { 1875 for ( i = 0; this.successList[i]; i++ ) { 1876 this.showLabel( this.successList[i] ); 1877 } 1878 } 1879 if ( this.settings.unhighlight ) { 1880 for ( i = 0, elements = this.validElements(); elements[i]; i++ ) { 1881 this.settings.unhighlight.call( this, elements[i], this.settings.errorClass, this.settings.validClass ); 1882 } 1883 } 1884 this.toHide = this.toHide.not( this.toShow ); 1885 this.hideErrors(); 1886 this.addWrapper( this.toShow ).show(); 1887 }, 1888 1889 validElements: function() { 1890 return this.currentElements.not(this.invalidElements()); 1891 }, 1892 1893 invalidElements: function() { 1894 return $(this.errorList).map(function() { 1895 return this.element; 1896 }); 1897 }, 1898 1899 showLabel: function( element, message ) { 1900 var label = this.errorsFor( element ); 1901 if ( label.length ) { 1902 // refresh error/success class 1903 label.removeClass( this.settings.validClass ).addClass( this.settings.errorClass ); 1904 // replace message on existing label 1905 label.html(message); 1906 } else { 1907 // create label 1908 label = $("<" + this.settings.errorElement + ">") 1909 .attr("for", this.idOrName(element)) 1910 .addClass(this.settings.errorClass) 1911 .html(message || ""); 1912 if ( this.settings.wrapper ) { 1913 // make sure the element is visible, even in IE 1914 // actually showing the wrapped element is handled elsewhere 1915 label = label.hide().show().wrap("<" + this.settings.wrapper + "/>").parent(); 1916 } 1917 if ( !this.labelContainer.append(label).length ) { 1918 if ( this.settings.errorPlacement ) { 1919 this.settings.errorPlacement(label, $(element) ); 1920 } else { 1921 label.insertAfter(element); 1922 } 1923 } 1924 } 1925 if ( !message && this.settings.success ) { 1926 label.text(""); 1927 if ( typeof this.settings.success === "string" ) { 1928 label.addClass( this.settings.success ); 1929 } else { 1930 this.settings.success( label, element ); 1931 } 1932 } 1933 this.toShow = this.toShow.add(label); 1934 }, 1935 1936 errorsFor: function( element ) { 1937 var name = this.idOrName(element); 1938 return this.errors().filter(function() { 1939 return $(this).attr("for") === name; 1940 }); 1941 }, 1942 1943 idOrName: function( element ) { 1944 return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name); 1945 }, 1946 1947 validationTargetFor: function( element ) { 1948 // if radio/checkbox, validate first element in group instead 1949 if ( this.checkable(element) ) { 1950 element = this.findByName( element.name ).not(this.settings.ignore)[0]; 1951 } 1952 return element; 1953 }, 1954 1955 checkable: function( element ) { 1956 return (/radio|checkbox/i).test(element.type); 1957 }, 1958 1959 findByName: function( name ) { 1960 return $(this.currentForm).find("[name='" + name + "']"); 1961 }, 1962 1963 getLength: function( value, element ) { 1964 switch ( element.nodeName.toLowerCase() ) { 1965 case "select": 1966 return $("option:selected", element).length; 1967 case "input": 1968 if ( this.checkable( element) ) { 1969 return this.findByName(element.name).filter(":checked").length; 1970 } 1971 } 1972 return value.length; 1973 }, 1974 1975 depend: function( param, element ) { 1976 return this.dependTypes[typeof param] ? this.dependTypes[typeof param](param, element) : true; 1977 }, 1978 1979 dependTypes: { 1980 "boolean": function( param ) { 1981 return param; 1982 }, 1983 "string": function( param, element ) { 1984 return !!$(param, element.form).length; 1985 }, 1986 "function": function( param, element ) { 1987 return param(element); 1988 } 1989 }, 1990 1991 optional: function( element ) { 1992 var val = this.elementValue(element); 1993 return !$.validator.methods.required.call(this, val, element) && "dependency-mismatch"; 1994 }, 1995 1996 startRequest: function( element ) { 1997 if ( !this.pending[element.name] ) { 1998 this.pendingRequest++; 1999 this.pending[element.name] = true; 2000 } 2001 }, 2002 2003 stopRequest: function( element, valid ) { 2004 this.pendingRequest--; 2005 // sometimes synchronization fails, make sure pendingRequest is never < 0 2006 if ( this.pendingRequest < 0 ) { 2007 this.pendingRequest = 0; 2008 } 2009 delete this.pending[element.name]; 2010 if ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() ) { 2011 $(this.currentForm).submit(); 2012 this.formSubmitted = false;
vendor: 9,086 bytes, lines 2013-2278
2013 } else if (!valid && this.pendingRequest === 0 && this.formSubmitted) { 2014 $(this.currentForm).triggerHandler("invalid-form", [ this ]); 2015 this.formSubmitted = false; 2016 } 2017 }, 2018 2019 previousValue: function( element ) { 2020 return $.data(element, "previousValue") || $.data(element, "previousValue", { 2021 old: null, 2022 valid: true, 2023 message: this.defaultMessage( element, "remote" ) 2024 }); 2025 } 2026 2027 }, 2028 2029 classRuleSettings: { 2030 required: { required: true }, 2031 email: { email: true }, 2032 url: { url: true }, 2033 date: { date: true }, 2034 dateISO: { dateISO: true }, 2035 number: { number: true }, 2036 digits: { digits: true }, 2037 creditcard: { creditcard: true } 2038 }, 2039 2040 addClassRules: function( className, rules ) { 2041 if ( className.constructor === String ) { 2042 this.classRuleSettings[className] = rules; 2043 } else { 2044 $.extend(this.classRuleSettings, className); 2045 } 2046 }, 2047 2048 classRules: function( element ) { 2049 var rules = {}, 2050 classes = $(element).attr("class"); 2051 2052 if ( classes ) { 2053 $.each(classes.split(" "), function() { 2054 if ( this in $.validator.classRuleSettings ) { 2055 $.extend(rules, $.validator.classRuleSettings[this]); 2056 } 2057 }); 2058 } 2059 return rules; 2060 }, 2061 2062 attributeRules: function( element ) { 2063 var rules = {}, 2064 $element = $(element), 2065 type = element.getAttribute("type"), 2066 method, value; 2067 2068 for (method in $.validator.methods) { 2069 2070 // support for <input required> in both html5 and older browsers 2071 if ( method === "required" ) { 2072 value = element.getAttribute(method); 2073 // Some browsers return an empty string for the required attribute 2074 // and non-HTML5 browsers might have required="" markup 2075 if ( value === "" ) { 2076 value = true; 2077 } 2078 // force non-HTML5 browsers to return bool 2079 value = !!value; 2080 } else { 2081 value = $element.attr(method); 2082 } 2083 2084 // convert the value to a number for number inputs, and for text for backwards compability 2085 // allows type="date" and others to be compared as strings 2086 if ( /min|max/.test( method ) && ( type === null || /number|range|text/.test( type ) ) ) { 2087 value = Number(value); 2088 } 2089 2090 if ( value || value === 0 ) { 2091 rules[method] = value; 2092 } else if ( type === method && type !== "range" ) { 2093 // exception: the jquery validate 'range' method 2094 // does not test for the html5 'range' type 2095 rules[method] = true; 2096 } 2097 } 2098 2099 // maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs 2100 if ( rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength) ) { 2101 delete rules.maxlength; 2102 } 2103 2104 return rules; 2105 }, 2106 2107 dataRules: function( element ) { 2108 var method, value, 2109 rules = {}, $element = $( element ); 2110 for ( method in $.validator.methods ) { 2111 value = $element.data( "rule" + method[ 0 ].toUpperCase() + method.substring( 1 ).toLowerCase() ); 2112 if ( value !== undefined ) { 2113 rules[ method ] = value; 2114 } 2115 } 2116 return rules; 2117 }, 2118 2119 staticRules: function( element ) { 2120 var rules = {}, 2121 validator = $.data(element.form, "validator"); 2122 2123 if ( validator.settings.rules ) { 2124 rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {}; 2125 } 2126 return rules; 2127 }, 2128 2129 normalizeRules: function( rules, element ) { 2130 // handle dependency check 2131 $.each(rules, function( prop, val ) { 2132 // ignore rule when param is explicitly false, eg. required:false 2133 if ( val === false ) { 2134 delete rules[prop]; 2135 return; 2136 } 2137 if ( val.param || val.depends ) { 2138 var keepRule = true; 2139 switch (typeof val.depends) { 2140 case "string": 2141 keepRule = !!$(val.depends, element.form).length; 2142 break; 2143 case "function": 2144 keepRule = val.depends.call(element, element); 2145 break; 2146 } 2147 if ( keepRule ) { 2148 rules[prop] = val.param !== undefined ? val.param : true; 2149 } else { 2150 delete rules[prop]; 2151 } 2152 } 2153 }); 2154 2155 // evaluate parameters 2156 $.each(rules, function( rule, parameter ) { 2157 rules[rule] = $.isFunction(parameter) ? parameter(element) : parameter; 2158 }); 2159 2160 // clean number parameters 2161 $.each([ "minlength", "maxlength" ], function() { 2162 if ( rules[this] ) { 2163 rules[this] = Number(rules[this]); 2164 } 2165 }); 2166 $.each([ "rangelength", "range" ], function() { 2167 var parts; 2168 if ( rules[this] ) { 2169 if ( $.isArray(rules[this]) ) { 2170 rules[this] = [ Number(rules[this][0]), Number(rules[this][1]) ]; 2171 } else if ( typeof rules[this] === "string" ) { 2172 parts = rules[this].split(/[\s,]+/); 2173 rules[this] = [ Number(parts[0]), Number(parts[1]) ]; 2174 } 2175 } 2176 }); 2177 2178 if ( $.validator.autoCreateRanges ) { 2179 // auto-create ranges 2180 if ( rules.min && rules.max ) { 2181 rules.range = [ rules.min, rules.max ]; 2182 delete rules.min; 2183 delete rules.max; 2184 } 2185 if ( rules.minlength && rules.maxlength ) { 2186 rules.rangelength = [ rules.minlength, rules.maxlength ]; 2187 delete rules.minlength; 2188 delete rules.maxlength; 2189 } 2190 } 2191 2192 return rules; 2193 }, 2194 2195 // Converts a simple string to a {string: true} rule, e.g., "required" to {required:true} 2196 normalizeRule: function( data ) { 2197 if ( typeof data === "string" ) { 2198 var transformed = {}; 2199 $.each(data.split(/\s/), function() { 2200 transformed[this] = true; 2201 }); 2202 data = transformed; 2203 } 2204 return data; 2205 }, 2206 2207 // http://jqueryvalidation.org/jQuery.validator.addMethod/ 2208 addMethod: function( name, method, message ) { 2209 $.validator.methods[name] = method; 2210 $.validator.messages[name] = message !== undefined ? message : $.validator.messages[name]; 2211 if ( method.length < 3 ) { 2212 $.validator.addClassRules(name, $.validator.normalizeRule(name)); 2213 } 2214 }, 2215 2216 methods: { 2217 2218 // http://jqueryvalidation.org/required-method/ 2219 required: function( value, element, param ) { 2220 // check if dependency is met 2221 if ( !this.depend(param, element) ) { 2222 return "dependency-mismatch"; 2223 } 2224 if ( element.nodeName.toLowerCase() === "select" ) { 2225 // could be an array for select-multiple or a string, both are fine this way 2226 var val = $(element).val(); 2227 return val && val.length > 0; 2228 } 2229 if ( this.checkable(element) ) { 2230 return this.getLength(value, element) > 0; 2231 } 2232 return $.trim(value).length > 0; 2233 }, 2234 2235 // http://jqueryvalidation.org/email-method/ 2236 email: function( value, element ) { 2237 // From http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#e-mail-state-%28type=email%29 2238 // Retrieved 2014-01-14 2239 // If you have a problem with this implementation, report a bug against the above spec 2240 // Or use custom methods to implement your own email validation 2241 return this.optional(element) || /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(value); 2242 }, 2243 2244 // http://jqueryvalidation.org/url-method/ 2245 url: function( value, element ) { 2246 // contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/ 2247 return this.optional(element) || /^(https?|s?ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value); 2248 }, 2249 2250 // http://jqueryvalidation.org/date-method/ 2251 date: function( value, element ) { 2252 return this.optional(element) || !/Invalid|NaN/.test(new Date(value).toString()); 2253 }, 2254 2255 // http://jqueryvalidation.org/dateISO-method/ 2256 dateISO: function( value, element ) { 2257 return this.optional(element) || /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/.test(value); 2258 }, 2259 2260 // http://jqueryvalidation.org/number-method/ 2261 number: function( value, element ) { 2262 return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value); 2263 }, 2264 2265 // http://jqueryvalidation.org/digits-method/ 2266 digits: function( value, element ) { 2267 return this.optional(element) || /^\d+$/.test(value); 2268 }, 2269 2270 // http://jqueryvalidation.org/creditcard-method/ 2271 // based on http://en.wikipedia.org/wiki/Luhn/ 2272 creditcard: function( value, element ) { 2273 if ( this.optional(element) ) { 2274 return "dependency-mismatch"; 2275 } 2276 // accept only spaces, digits and dashes 2277 if ( /[^0-9 \-]+/.test(value) ) { 2278 return false;
2279 } 2280 var nCheck = 0, 2281 nDigit = 0, 2282 bEven = false, 2283 n, cDigit; 2284 2285 value = value.replace(/\D/g, ""); 2286 2287 // Basing min and max length on 2288 // http://developer.ean.com/general_info/Valid_Credit_Card_Types 2289 if ( value.length < 13 || value.length > 19 ) { 2290 return false; 2291 } 2292 2293 for ( n = value.length - 1; n >= 0; n--) { 2294 cDigit = value.charAt(n); 2295 nDigit = parseInt(cDigit, 10); 2296 if ( bEven ) { 2297 if ( (nDigit *= 2) > 9 ) { 2298 nDigit -= 9; 2299 } 2300 } 2301 nCheck += nDigit; 2302 bEven = !bEven; 2303 } 2304 2305 return (nCheck % 10) === 0; 2306 }, 2307 2308 // http://jqueryvalidation.org/minlength-method/ 2309 minlength: function( value, element, param ) { 2310 var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element); 2311 return this.optional(element) || length >= param; 2312 }, 2313 2314 // http://jqueryvalidation.org/maxlength-method/ 2315 maxlength: function( value, element, param ) { 2316 var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element); 2317 return this.optional(element) || length <= param; 2318 }, 2319 2320 // http://jqueryvalidation.org/rangelength-method/ 2321 rangelength: function( value, element, param ) { 2322 var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element); 2323 return this.optional(element) || ( length >= param[0] && length <= param[1] ); 2324 }, 2325 2326 // http://jqueryvalidation.org/min-method/ 2327 min: function( value, element, param ) { 2328 return this.optional(element) || value >= param; 2329 }, 2330 2331 // http://jqueryvalidation.org/max-method/ 2332 max: function( value, element, param ) { 2333 return this.optional(element) || value <= param; 2334 }, 2335 2336 // http://jqueryvalidation.org/range-method/ 2337 range: function( value, element, param ) { 2338 return this.optional(element) || ( value >= param[0] && value <= param[1] ); 2339 }, 2340 2341 // http://jqueryvalidation.org/equalTo-method/ 2342 equalTo: function( value, element, param ) {
2343 // bind to the blur event of the target in order to revalidate whenever the target field is updated 2344 // TODO find a way to bind the event just once, avoiding the unbind-rebind overhead 2345 var target = $(param); 2346 if ( this.settings.onfocusout ) { 2347 target.unbind(".validate-equalTo").bind("blur.validate-equalTo", function() { 2348 $(element).valid(); 2349 }); 2350 } 2351 return value === target.val(); 2352 }, 2353 2354 // http://jqueryvalidation.org/remote-method/ 2355 remote: function( value, element, param ) { 2356 if ( this.optional(element) ) { 2357 return "dependency-mismatch"; 2358 } 2359 2360 var previous = this.previousValue(element), 2361 validator, data; 2362 2363 if (!this.settings.messages[element.name] ) { 2364 this.settings.messages[element.name] = {}; 2365 } 2366 previous.originalMessage = this.settings.messages[element.name].remote; 2367 this.settings.messages[element.name].remote = previous.message; 2368 2369 param = typeof param === "string" && { url: param } || param; 2370 2371 if ( previous.old === value ) { 2372 return previous.valid; 2373 } 2374 2375 previous.old = value; 2376 validator = this; 2377 this.startRequest(element); 2378 data = {}; 2379 data[element.name] = value; 2380 $.ajax($.extend(true, { 2381 url: param, 2382 mode: "abort", 2383 port: "validate" + element.name, 2384 dataType: "json", 2385 data: data, 2386 context: validator.currentForm, 2387 success: function( response ) { 2388 var valid = response === true || response === "true", 2389 errors, message, submitted; 2390 2391 validator.settings.messages[element.name].remote = previous.originalMessage; 2392 if ( valid ) { 2393 submitted = validator.formSubmitted; 2394 validator.prepareElement(element); 2395 validator.formSubmitted = submitted; 2396 validator.successList.push(element); 2397 delete validator.invalid[element.name]; 2398 validator.showErrors(); 2399 } else { 2400 errors = {}; 2401 message = response || validator.defaultMessage( element, "remote" ); 2402 errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message; 2403 validator.invalid[element.name] = true; 2404 validator.showErrors(errors); 2405 } 2406 previous.valid = valid; 2407 validator.stopRequest(element, valid); 2408 } 2409 }, param)); 2410 return "pending"; 2411 } 2412 2413 } 2414 2415}); 2416 2417$.format = function deprecated() { 2418 throw "$.format has been deprecated. Please use $.validator.format instead."; 2419}; 2420 2421}(jQuery)); 2422 2423// ajax mode: abort 2424// usage: $.ajax({ mode: "abort"[, port: "uniqueport"]}); 2425// if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort() 2426(function($) { 2427 var pendingRequests = {}, 2428 ajax; 2429 // Use a prefilter if available (1.5+) 2430 if ( $.ajaxPrefilter ) { 2431 $.ajaxPrefilter(function( settings, _, xhr ) { 2432 var port = settings.port; 2433 if ( settings.mode === "abort" ) { 2434 if ( pendingRequests[port] ) { 2435 pendingRequests[port].abort(); 2436 } 2437 pendingRequests[port] = xhr; 2438 } 2439 }); 2440 } else { 2441 // Proxy ajax 2442 ajax = $.ajax; 2443 $.ajax = function( settings ) { 2444 var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode, 2445 port = ( "port" in settings ? settings : $.ajaxSettings ).port; 2446 if ( mode === "abort" ) { 2447 if ( pendingRequests[port] ) { 2448 pendingRequests[port].abort(); 2449 } 2450 pendingRequests[port] = ajax.apply(this, arguments); 2451 return pendingRequests[port]; 2452 } 2453 return ajax.apply(this, arguments); 2454 }; 2455 } 2456}(jQuery)); 2457 2458// provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation 2459// handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target 2460(function($) { 2461 $.extend($.fn, { 2462 validateDelegate: function( delegate, type, handler ) { 2463 return this.bind(type, function( event ) { 2464 var target = $(event.target); 2465 if ( target.is(delegate) ) { 2466 return handler.apply(target, arguments); 2467 } 2468 }); 2469 } 2470 }); 2471}(jQuery)); 2472 2473 2474 2475 2476 2477(function($) { 2478 $('#contact').validate({ 2479 rules: { 2480 name: { 2481 required: true, 2482 minlength: 2 2483 }, 2484 email: { 2485 required: true, 2486 email: true 2487 }, 2488 message: { 2489 required: true 2490 } 2491 }, 2492 messages: { 2493 name: { 2494 required: "Please, add your name.", 2495 minlength: "Your name must consist of at least 2 characters" 2496 }, 2497 email: { 2498 required: "Please, add your e-mail address." 2499 }, 2500 message: { 2501 required: "Please, add your message.", 2502 minlength: "Your message is too short." 2503 } 2504 }, 2505 submitHandler: function(form) {
2506 $(form).ajaxSubmit({ 2507 type:"POST", 2508 data: $(form).serialize(), 2509 url:"process.php", 2510 success: function() { 2511 $('#contact :input').attr('disabled', 'disabled'); 2512 $('#contact').fadeTo( "slow", 0.15, function() { 2513 $(this).find(':input').attr('disabled', 'disabled'); 2514 $(this).find('label').css('cursor','default'); 2515 $('#success').fadeIn(); 2516 }); 2517 }, 2518 error: function() { 2519 $('#contact').fadeTo( "slow", 0.15, function() { 2520 $('#error').fadeIn(); 2521 }); 2522 } 2523 }); 2524 } 2525 }); 2526})(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.