2  * Copyright 2016 2015-2016 ZTE, Inc. and others. All rights reserved.
 
   4  * Licensed under the Apache License, Version 2.0 (the "License");
 
   5  * you may not use this file except in compliance with the License.
 
   6  * You may obtain a copy of the License at
 
   8  *     http://www.apache.org/licenses/LICENSE-2.0
 
  10  * Unless required by applicable law or agreed to in writing, software
 
  11  * distributed under the License is distributed on an "AS IS" BASIS,
 
  12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
  13  * See the License for the specific language governing permissions and
 
  14  * limitations under the License.
 
  16  *     Author: Zhaoxing Meng
 
  17  *     email: meng.zhaoxing1@zte.com.cn
 
  19 (function( factory ) {
 
  20         if ( typeof define === "function" && define.amd ) {
 
  21                 define( ["jquery"], factory );
 
  28         // http://jqueryvalidation.org/validate/
 
  29         validate: function( options ) {
 
  31                 // if nothing is selected, return nothing; can't chain anyway
 
  33                         if ( options && options.debug && window.console ) {
 
  34                                 console.warn( "Nothing selected, can't validate, returning nothing." );
 
  39                 // check if a validator for this form was already created
 
  40                 var validator = $.data( this[ 0 ], "validator" );
 
  45                 // Add novalidate tag if HTML5.
 
  46                 this.attr( "novalidate", "novalidate" );
 
  48                 validator = new $.validator( options, this[ 0 ] );
 
  49                 $.data( this[ 0 ], "validator", validator );
 
  51                 if ( validator.settings.onsubmit ) {
 
  53                         this.validateDelegate( ":submit", "click", function( event ) {
 
  54                                 if ( validator.settings.submitHandler ) {
 
  55                                         validator.submitButton = event.target;
 
  57                                 // allow suppressing validation by adding a cancel class to the submit button
 
  58                                 if ( $( event.target ).hasClass( "cancel" ) ) {
 
  59                                         validator.cancelSubmit = true;
 
  62                                 // allow suppressing validation by adding the html5 formnovalidate attribute to the submit button
 
  63                                 if ( $( event.target ).attr( "formnovalidate" ) !== undefined ) {
 
  64                                         validator.cancelSubmit = true;
 
  68                         // validate the form on submit
 
  69                         this.submit( function( event ) {
 
  70                                 if ( validator.settings.debug ) {
 
  71                                         // prevent form submit to be able to see console output
 
  72                                         event.preventDefault();
 
  76                                         if ( validator.settings.submitHandler ) {
 
  77                                                 if ( validator.submitButton ) {
 
  78                                                         // insert a hidden input as a replacement for the missing submit button
 
  79                                                         hidden = $( "<input type='hidden'/>" )
 
  80                                                                 .attr( "name", validator.submitButton.name )
 
  81                                                                 .val( $( validator.submitButton ).val() )
 
  82                                                                 .appendTo( validator.currentForm );
 
  84                                                 validator.settings.submitHandler.call( validator, validator.currentForm, event );
 
  85                                                 if ( validator.submitButton ) {
 
  86                                                         // and clean up afterwards; thanks to no-block-scope, hidden can be referenced
 
  94                                 // prevent submit for invalid forms or custom submit handlers
 
  95                                 if ( validator.cancelSubmit ) {
 
  96                                         validator.cancelSubmit = false;
 
  99                                 if ( validator.form() ) {
 
 100                                         if ( validator.pendingRequest ) {
 
 101                                                 validator.formSubmitted = true;
 
 106                                         validator.focusInvalid();
 
 114         // http://jqueryvalidation.org/valid/
 
 116                 var valid, validator;
 
 118                 if ( $( this[ 0 ] ).is( "form" ) ) {
 
 119                         valid = this.validate().form();
 
 122                         validator = $( this[ 0 ].form ).validate();
 
 123                         this.each( function() {
 
 124                                 valid = validator.element( this ) && valid;
 
 129         // attributes: space separated list of attributes to retrieve and remove
 
 130         removeAttrs: function( attributes ) {
 
 133                 $.each( attributes.split( /\s/ ), function( index, value ) {
 
 134                         result[ value ] = $element.attr( value );
 
 135                         $element.removeAttr( value );
 
 139         // http://jqueryvalidation.org/rules/
 
 140         rules: function( command, argument ) {
 
 141                 var element = this[ 0 ],
 
 142                         settings, staticRules, existingRules, data, param, filtered;
 
 145                         settings = $.data( element.form, "validator" ).settings;
 
 146                         staticRules = settings.rules;
 
 147                         existingRules = $.validator.staticRules( element );
 
 150                                 $.extend( existingRules, $.validator.normalizeRule( argument ) );
 
 151                                 // remove messages from rules, but allow them to be set separately
 
 152                                 delete existingRules.messages;
 
 153                                 staticRules[ element.name ] = existingRules;
 
 154                                 if ( argument.messages ) {
 
 155                                         settings.messages[ element.name ] = $.extend( settings.messages[ element.name ], argument.messages );
 
 160                                         delete staticRules[ element.name ];
 
 161                                         return existingRules;
 
 164                                 $.each( argument.split( /\s/ ), function( index, method ) {
 
 165                                         filtered[ method ] = existingRules[ method ];
 
 166                                         delete existingRules[ method ];
 
 167                                         if ( method === "required" ) {
 
 168                                                 $( element ).removeAttr( "aria-required" );
 
 175                 data = $.validator.normalizeRules(
 
 178                         $.validator.classRules( element ),
 
 179                         $.validator.attributeRules( element ),
 
 180                         $.validator.dataRules( element ),
 
 181                         $.validator.staticRules( element )
 
 184                 // make sure required is at front
 
 185                 if ( data.required ) {
 
 186                         param = data.required;
 
 187                         delete data.required;
 
 188                         data = $.extend( { required: param }, data );
 
 189                         $( element ).attr( "aria-required", "true" );
 
 192                 // make sure remote is at back
 
 196                         data = $.extend( data, { remote: param });
 
 204 $.extend( $.expr[ ":" ], {
 
 205         // http://jqueryvalidation.org/blank-selector/
 
 206         blank: function( a ) {
 
 207                 return !$.trim( "" + $( a ).val() );
 
 209         // http://jqueryvalidation.org/filled-selector/
 
 210         filled: function( a ) {
 
 211                 return !!$.trim( "" + $( a ).val() );
 
 213         // http://jqueryvalidation.org/unchecked-selector/
 
 214         unchecked: function( a ) {
 
 215                 return !$( a ).prop( "checked" );
 
 219 // constructor for validator
 
 220 $.validator = function( options, form ) {
 
 221         this.settings = $.extend( true, {}, $.validator.defaults, options );
 
 222         this.currentForm = form;
 
 226 // http://jqueryvalidation.org/jQuery.validator.format/
 
 227 $.validator.format = function( source, params ) {
 
 228         if ( arguments.length === 1 ) {
 
 230                         var args = $.makeArray( arguments );
 
 231                         args.unshift( source );
 
 232                         return $.validator.format.apply( this, args );
 
 235         if ( arguments.length > 2 && params.constructor !== Array  ) {
 
 236                 params = $.makeArray( arguments ).slice( 1 );
 
 238         if ( params.constructor !== Array ) {
 
 241         $.each( params, function( i, n ) {
 
 242                 source = source.replace( new RegExp( "\\{" + i + "\\}", "g" ), function() {
 
 249 $.extend( $.validator, {
 
 257                 errorElement: "label",
 
 259                 errorContainer: $( [] ),
 
 260                 errorLabelContainer: $( [] ),
 
 264                 onfocusin: function( element ) {
 
 265                         this.lastActive = element;
 
 267                         // hide error label and remove error class on focus if enabled
 
 268                         if ( this.settings.focusCleanup && !this.blockFocusCleanup ) {
 
 269                                 if ( this.settings.unhighlight ) {
 
 270                                         this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );
 
 272                                 this.hideThese( this.errorsFor( element ) );
 
 275                 onfocusout: function( element ) {
 
 276                         if ( !this.checkable( element ) && ( element.name in this.submitted || !this.optional( element ) ) ) {
 
 277                                 this.element( element );
 
 280                 onkeyup: function( element, event ) {
 
 281                         if ( event.which === 9 && this.elementValue( element ) === "" ) {
 
 283                         } else if ( element.name in this.submitted || element === this.lastElement ) {
 
 284                                 this.element( element );
 
 287                 onclick: function( element ) {
 
 288                         // click on selects, radiobuttons and checkboxes
 
 289                         if ( element.name in this.submitted ) {
 
 290                                 this.element( element );
 
 292                         // or option elements, check parent select in that case
 
 293                         } else if ( element.parentNode.name in this.submitted ) {
 
 294                                 this.element( element.parentNode );
 
 297                 highlight: function( element, errorClass, validClass ) {
 
 298                         if ( element.type === "radio" ) {
 
 299                                 this.findByName( element.name ).addClass( errorClass ).removeClass( validClass );
 
 301                                 $( element ).addClass( errorClass ).removeClass( validClass );
 
 304                 unhighlight: function( element, errorClass, validClass ) {
 
 305                         if ( element.type === "radio" ) {
 
 306                                 this.findByName( element.name ).removeClass( errorClass ).addClass( validClass );
 
 308                                 $( element ).removeClass( errorClass ).addClass( validClass );
 
 313         // http://jqueryvalidation.org/jQuery.validator.setDefaults/
 
 314         setDefaults: function( settings ) {
 
 315                 $.extend( $.validator.defaults, settings );
 
 319                 required: "This field is required.",
 
 320                 remote: "Please fix this field.",
 
 321                 email: "Please enter a valid email address.",
 
 322                 url: "Please enter a valid URL.",
 
 323                 date: "Please enter a valid date.",
 
 324                 dateISO: "Please enter a valid date ( ISO ).",
 
 325                 number: "Please enter a valid number.",
 
 326                 digits: "Please enter only digits.",
 
 327                 creditcard: "Please enter a valid credit card number.",
 
 328                 equalTo: "Please enter the same value again.",
 
 329                 maxlength: $.validator.format( "Please enter no more than {0} characters." ),
 
 330                 minlength: $.validator.format( "Please enter at least {0} characters." ),
 
 331                 rangelength: $.validator.format( "Please enter a value between {0} and {1} characters long." ),
 
 332                 range: $.validator.format( "Please enter a value between {0} and {1}." ),
 
 333                 max: $.validator.format( "Please enter a value less than or equal to {0}." ),
 
 334                 min: $.validator.format( "Please enter a value greater than or equal to {0}." )
 
 337         autoCreateRanges: false,
 
 342                         this.labelContainer = $( this.settings.errorLabelContainer );
 
 343                         this.errorContext = this.labelContainer.length && this.labelContainer || $( this.currentForm );
 
 344                         this.containers = $( this.settings.errorContainer ).add( this.settings.errorLabelContainer );
 
 346                         this.valueCache = {};
 
 347                         this.pendingRequest = 0;
 
 352                         var groups = ( this.groups = {} ),
 
 354                         $.each( this.settings.groups, function( key, value ) {
 
 355                                 if ( typeof value === "string" ) {
 
 356                                         value = value.split( /\s/ );
 
 358                                 $.each( value, function( index, name ) {
 
 359                                         groups[ name ] = key;
 
 362                         rules = this.settings.rules;
 
 363                         $.each( rules, function( key, value ) {
 
 364                                 rules[ key ] = $.validator.normalizeRule( value );
 
 367                         function delegate( event ) {
 
 368                                 var validator = $.data( this[ 0 ].form, "validator" ),
 
 369                                         eventType = "on" + event.type.replace( /^validate/, "" ),
 
 370                                         settings = validator.settings;
 
 371                                 if ( settings[ eventType ] && !this.is( settings.ignore ) ) {
 
 372                                         settings[ eventType ].call( validator, this[ 0 ], event );
 
 375                         $( this.currentForm )
 
 376                                 .validateDelegate( ":text, [type='password'], [type='file'], select, textarea, " +
 
 377                                         "[type='number'], [type='search'] ,[type='tel'], [type='url'], " +
 
 378                                         "[type='email'], [type='datetime'], [type='date'], [type='month'], " +
 
 379                                         "[type='week'], [type='time'], [type='datetime-local'], " +
 
 380                                         "[type='range'], [type='color'], [type='radio'], [type='checkbox']",
 
 381                                         "focusin focusout keyup", delegate)
 
 382                                 // Support: Chrome, oldIE
 
 383                                 // "select" is provided as event.target when clicking a option
 
 384                                 .validateDelegate("select, option, [type='radio'], [type='checkbox']", "click", delegate);
 
 386                         if ( this.settings.invalidHandler ) {
 
 387                                 $( this.currentForm ).bind( "invalid-form.validate", this.settings.invalidHandler );
 
 390                         // Add aria-required to any Static/Data/Class required fields before first validation
 
 391                         // Screen readers require this attribute to be present before the initial submission http://www.w3.org/TR/WCAG-TECHS/ARIA2.html
 
 392                         $( this.currentForm ).find( "[required], [data-rule-required], .required" ).attr( "aria-required", "true" );
 
 395                 // http://jqueryvalidation.org/Validator.form/
 
 398                         $.extend( this.submitted, this.errorMap );
 
 399                         this.invalid = $.extend({}, this.errorMap );
 
 400                         if ( !this.valid() ) {
 
 401                                 $( this.currentForm ).triggerHandler( "invalid-form", [ this ]);
 
 407                 checkForm: function() {
 
 409                         for ( var i = 0, elements = ( this.currentElements = this.elements() ); elements[ i ]; i++ ) {
 
 410                                 this.check( elements[ i ] );
 
 415                 // http://jqueryvalidation.org/Validator.element/
 
 416                 element: function( element ) {
 
 417                         var cleanElement = this.clean( element ),
 
 418                                 checkElement = this.validationTargetFor( cleanElement ),
 
 421                         this.lastElement = checkElement;
 
 423                         if ( checkElement === undefined ) {
 
 424                                 delete this.invalid[ cleanElement.name ];
 
 426                                 this.prepareElement( checkElement );
 
 427                                 this.currentElements = $( checkElement );
 
 429                                 result = this.check( checkElement ) !== false;
 
 431                                         delete this.invalid[ checkElement.name ];
 
 433                                         this.invalid[ checkElement.name ] = true;
 
 436                         // Add aria-invalid status for screen readers
 
 437                         $( element ).attr( "aria-invalid", !result );
 
 439                         if ( !this.numberOfInvalids() ) {
 
 440                                 // Hide error containers on last error
 
 441                                 this.toHide = this.toHide.add( this.containers );
 
 447                 // http://jqueryvalidation.org/Validator.showErrors/
 
 448                 showErrors: function( errors ) {
 
 450                                 // add items to error list and map
 
 451                                 $.extend( this.errorMap, errors );
 
 453                                 for ( var name in errors ) {
 
 454                                         this.errorList.push({
 
 455                                                 message: errors[ name ],
 
 456                                                 element: this.findByName( name )[ 0 ]
 
 459                                 // remove items from success list
 
 460                                 this.successList = $.grep( this.successList, function( element ) {
 
 461                                         return !( element.name in errors );
 
 464                         if ( this.settings.showErrors ) {
 
 465                                 this.settings.showErrors.call( this, this.errorMap, this.errorList );
 
 467                                 this.defaultShowErrors();
 
 471                 // http://jqueryvalidation.org/Validator.resetForm/
 
 472                 resetForm: function() {
 
 473                         if ( $.fn.resetForm ) {
 
 474                                 $( this.currentForm ).resetForm();
 
 477                         this.lastElement = null;
 
 481                                         .removeClass( this.settings.errorClass )
 
 482                                         .removeData( "previousValue" )
 
 483                                         .removeAttr( "aria-invalid" );
 
 486                 numberOfInvalids: function() {
 
 487                         return this.objectLength( this.invalid );
 
 490                 objectLength: function( obj ) {
 
 491                         /* jshint unused: false */
 
 500                 hideErrors: function() {
 
 501                         this.hideThese( this.toHide );
 
 504                 hideThese: function( errors ) {
 
 505                         errors.not( this.containers ).text( "" );
 
 506                         this.addWrapper( errors ).hide();
 
 510                         return this.size() === 0;
 
 514                         return this.errorList.length;
 
 517                 focusInvalid: function() {
 
 518                         if ( this.settings.focusInvalid ) {
 
 520                                         $( this.findLastActive() || this.errorList.length && this.errorList[ 0 ].element || [])
 
 521                                         .filter( ":visible" )
 
 523                                         // manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find
 
 524                                         .trigger( "focusin" );
 
 526                                         // ignore IE throwing errors when focusing hidden elements
 
 531                 findLastActive: function() {
 
 532                         var lastActive = this.lastActive;
 
 533                         return lastActive && $.grep( this.errorList, function( n ) {
 
 534                                 return n.element.name === lastActive.name;
 
 535                         }).length === 1 && lastActive;
 
 538                 elements: function() {
 
 539                         var validator = this,
 
 542                         // select all valid inputs inside the form (no submit or reset buttons)
 
 543                         return $( this.currentForm )
 
 544                         .find( "input, select, textarea" )
 
 545                         .not( ":submit, :reset, :image, [disabled]" )
 
 546                         .not( this.settings.ignore )
 
 547                         .filter( function() {
 
 548                                 if ( !this.name && validator.settings.debug && window.console ) {
 
 549                                         console.error( "%o has no name assigned", this );
 
 552                                 // select only the first element for each name, and only those with rules specified
 
 553                                 if ( this.name in rulesCache || !validator.objectLength( $( this ).rules() ) ) {
 
 557                                 rulesCache[ this.name ] = true;
 
 562                 clean: function( selector ) {
 
 563                         return $( selector )[ 0 ];
 
 567                         var errorClass = this.settings.errorClass.split( " " ).join( "." );
 
 568                         return $( this.settings.errorElement + "." + errorClass, this.errorContext );
 
 572                         this.successList = [];
 
 575                         this.toShow = $( [] );
 
 576                         this.toHide = $( [] );
 
 577                         this.currentElements = $( [] );
 
 580                 prepareForm: function() {
 
 582                         this.toHide = this.errors().add( this.containers );
 
 585                 prepareElement: function( element ) {
 
 587                         this.toHide = this.errorsFor( element );
 
 590                 elementValue: function( element ) {
 
 592                                 $element = $( element ),
 
 595                         if ( type === "radio" || type === "checkbox" ) {
 
 596                                 return $( "input[name='" + element.name + "']:checked" ).val();
 
 597                         } else if ( type === "number" && typeof element.validity !== "undefined" ) {
 
 598                                 return element.validity.badInput ? false : $element.val();
 
 601                         val = $element.val();
 
 602                         if ( typeof val === "string" ) {
 
 603                                 return val.replace(/\r/g, "" );
 
 608                 check: function( element ) {
 
 609                         element = this.validationTargetFor( this.clean( element ) );
 
 611                         var rules = $( element ).rules(),
 
 612                                 rulesCount = $.map( rules, function( n, i ) {
 
 615                                 dependencyMismatch = false,
 
 616                                 val = this.elementValue( element ),
 
 617                                 result, method, rule;
 
 619                         for ( method in rules ) {
 
 620                                 rule = { method: method, parameters: rules[ method ] };
 
 623                                         result = $.validator.methods[ method ].call( this, val, element, rule.parameters );
 
 625                                         // if a method indicates that the field is optional and therefore valid,
 
 626                                         // don't mark it as valid when there are no other rules
 
 627                                         if ( result === "dependency-mismatch" && rulesCount === 1 ) {
 
 628                                                 dependencyMismatch = true;
 
 631                                         dependencyMismatch = false;
 
 633                                         if ( result === "pending" ) {
 
 634                                                 this.toHide = this.toHide.not( this.errorsFor( element ) );
 
 639                                                 this.formatAndAdd( element, rule );
 
 643                                         if ( this.settings.debug && window.console ) {
 
 644                                                 console.log( "Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.", e );
 
 649                         if ( dependencyMismatch ) {
 
 652                         if ( this.objectLength( rules ) ) {
 
 653                                 this.successList.push( element );
 
 658                 // return the custom message for the given element and validation method
 
 659                 // specified in the element's HTML5 data attribute
 
 660                 // return the generic message if present and no method specific message is present
 
 661                 customDataMessage: function( element, method ) {
 
 662                         return $( element ).data( "msg" + method.charAt( 0 ).toUpperCase() +
 
 663                                 method.substring( 1 ).toLowerCase() ) || $( element ).data( "msg" );
 
 666                 // return the custom message for the given element name and validation method
 
 667                 customMessage: function( name, method ) {
 
 668                         var m = this.settings.messages[ name ];
 
 669                         return m && ( m.constructor === String ? m : m[ method ]);
 
 672                 // return the first defined argument, allowing empty strings
 
 673                 findDefined: function() {
 
 674                         for ( var i = 0; i < arguments.length; i++) {
 
 675                                 if ( arguments[ i ] !== undefined ) {
 
 676                                         return arguments[ i ];
 
 682                 defaultMessage: function( element, method ) {
 
 683                         return this.findDefined(
 
 684                                 this.customMessage( element.name, method ),
 
 685                                 this.customDataMessage( element, method ),
 
 686                                 // title is never undefined, so handle empty string as undefined
 
 687                                 !this.settings.ignoreTitle && element.title || undefined,
 
 688                                 $.validator.messages[ method ],
 
 689                                 "<strong>Warning: No message defined for " + element.name + "</strong>"
 
 693                 formatAndAdd: function( element, rule ) {
 
 694                         var message = this.defaultMessage( element, rule.method ),
 
 695                                 theregex = /\$?\{(\d+)\}/g;
 
 696                         if ( typeof message === "function" ) {
 
 697                                 message = message.call( this, rule.parameters, element );
 
 698                         } else if ( theregex.test( message ) ) {
 
 699                                 message = $.validator.format( message.replace( theregex, "{$1}" ), rule.parameters );
 
 701                         this.errorList.push({
 
 707                         this.errorMap[ element.name ] = message;
 
 708                         this.submitted[ element.name ] = message;
 
 711                 addWrapper: function( toToggle ) {
 
 712                         if ( this.settings.wrapper ) {
 
 713                                 toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) );
 
 718                 defaultShowErrors: function() {
 
 719                         var i, elements, error;
 
 720                         for ( i = 0; this.errorList[ i ]; i++ ) {
 
 721                                 error = this.errorList[ i ];
 
 722                                 if ( this.settings.highlight ) {
 
 723                                         this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );
 
 725                                 this.showLabel( error.element, error.message );
 
 727                         if ( this.errorList.length ) {
 
 728                                 this.toShow = this.toShow.add( this.containers );
 
 730                         if ( this.settings.success ) {
 
 731                                 for ( i = 0; this.successList[ i ]; i++ ) {
 
 732                                         this.showLabel( this.successList[ i ] );
 
 735                         if ( this.settings.unhighlight ) {
 
 736                                 for ( i = 0, elements = this.validElements(); elements[ i ]; i++ ) {
 
 737                                         this.settings.unhighlight.call( this, elements[ i ], this.settings.errorClass, this.settings.validClass );
 
 740                         this.toHide = this.toHide.not( this.toShow );
 
 742                         this.addWrapper( this.toShow ).show();
 
 745                 validElements: function() {
 
 746                         return this.currentElements.not( this.invalidElements() );
 
 749                 invalidElements: function() {
 
 750                         return $( this.errorList ).map(function() {
 
 755                 showLabel: function( element, message ) {
 
 756                         var place, group, errorID,
 
 757                                 error = this.errorsFor( element ),
 
 758                                 elementID = this.idOrName( element ),
 
 759                                 describedBy = $( element ).attr( "aria-describedby" );
 
 760                         if ( error.length ) {
 
 761                                 // refresh error/success class
 
 762                                 error.removeClass( this.settings.validClass ).addClass( this.settings.errorClass );
 
 763                                 // replace message on existing label
 
 764                                 error.html( message );
 
 766                                 // create error element
 
 767                                 error = $( "<" + this.settings.errorElement + ">" )
 
 768                                         .attr( "id", elementID + "-error" )
 
 769                                         .addClass( this.settings.errorClass )
 
 770                                         .html( message || "" );
 
 772                                 // Maintain reference to the element to be placed into the DOM
 
 774                                 if ( this.settings.wrapper ) {
 
 775                                         // make sure the element is visible, even in IE
 
 776                                         // actually showing the wrapped element is handled elsewhere
 
 777                                         place = error.hide().show().wrap( "<" + this.settings.wrapper + "/>" ).parent();
 
 779                                 if ( this.labelContainer.length ) {
 
 780                                         this.labelContainer.append( place );
 
 781                                 } else if ( this.settings.errorPlacement ) {
 
 782                                         this.settings.errorPlacement( place, $( element ) );
 
 784                                         place.insertAfter( element );
 
 787                                 // Link error back to the element
 
 788                                 if ( error.is( "label" ) ) {
 
 789                                         // If the error is a label, then associate using 'for'
 
 790                                         error.attr( "for", elementID );
 
 791                                 } else if ( error.parents( "label[for='" + elementID + "']" ).length === 0 ) {
 
 792                                         // If the element is not a child of an associated label, then it's necessary
 
 793                                         // to explicitly apply aria-describedby
 
 795                                         errorID = error.attr( "id" );
 
 796                                         // Respect existing non-error aria-describedby
 
 797                                         if ( !describedBy ) {
 
 798                                                 describedBy = errorID;
 
 799                                         } else if ( !describedBy.match( new RegExp( "\b" + errorID + "\b" ) ) ) {
 
 800                                                 // Add to end of list if not already present
 
 801                                                 describedBy += " " + errorID;
 
 803                                         $( element ).attr( "aria-describedby", describedBy );
 
 805                                         // If this element is grouped, then assign to all elements in the same group
 
 806                                         group = this.groups[ element.name ];
 
 808                                                 $.each( this.groups, function( name, testgroup ) {
 
 809                                                         if ( testgroup === group ) {
 
 810                                                                 $( "[name='" + name + "']", this.currentForm )
 
 811                                                                         .attr( "aria-describedby", error.attr( "id" ) );
 
 817                         if ( !message && this.settings.success ) {
 
 819                                 if ( typeof this.settings.success === "string" ) {
 
 820                                         error.addClass( this.settings.success );
 
 822                                         this.settings.success( error, element );
 
 825                         this.toShow = this.toShow.add( error );
 
 828                 errorsFor: function( element ) {
 
 829                         var name = this.idOrName( element ),
 
 830                                 describer = $( element ).attr( "aria-describedby" ),
 
 831                                 selector = "label[for='" + name + "'], label[for='" + name + "'] *";
 
 832                         // aria-describedby should directly reference the error element
 
 834                                 selector = selector + ", #" + describer.replace( /\s+/g, ", #" );
 
 841                 idOrName: function( element ) {
 
 842                         return this.groups[ element.name ] || ( this.checkable( element ) ? element.name : element.id || element.name );
 
 845                 validationTargetFor: function( element ) {
 
 846                         // if radio/checkbox, validate first element in group instead
 
 847                         if ( this.checkable( element ) ) {
 
 848                                 element = this.findByName( element.name ).not( this.settings.ignore )[ 0 ];
 
 853                 checkable: function( element ) {
 
 854                         return ( /radio|checkbox/i ).test( element.type );
 
 857                 findByName: function( name ) {
 
 858                         return $( this.currentForm ).find( "[name='" + name + "']" );
 
 861                 getLength: function( value, element ) {
 
 862                         switch ( element.nodeName.toLowerCase() ) {
 
 864                                 return $( "option:selected", element ).length;
 
 866                                 if ( this.checkable( element ) ) {
 
 867                                         return this.findByName( element.name ).filter( ":checked" ).length;
 
 873                 depend: function( param, element ) {
 
 874                         return this.dependTypes[typeof param] ? this.dependTypes[typeof param]( param, element ) : true;
 
 878                         "boolean": function( param ) {
 
 881                         "string": function( param, element ) {
 
 882                                 return !!$( param, element.form ).length;
 
 884                         "function": function( param, element ) {
 
 885                                 return param( element );
 
 889                 optional: function( element ) {
 
 890                         var val = this.elementValue( element );
 
 891                         return !$.validator.methods.required.call( this, val, element ) && "dependency-mismatch";
 
 894                 startRequest: function( element ) {
 
 895                         if ( !this.pending[ element.name ] ) {
 
 896                                 this.pendingRequest++;
 
 897                                 this.pending[ element.name ] = true;
 
 901                 stopRequest: function( element, valid ) {
 
 902                         this.pendingRequest--;
 
 903                         // sometimes synchronization fails, make sure pendingRequest is never < 0
 
 904                         if ( this.pendingRequest < 0 ) {
 
 905                                 this.pendingRequest = 0;
 
 907                         delete this.pending[ element.name ];
 
 908                         if ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() ) {
 
 909                                 $( this.currentForm ).submit();
 
 910                                 this.formSubmitted = false;
 
 911                         } else if (!valid && this.pendingRequest === 0 && this.formSubmitted ) {
 
 912                                 $( this.currentForm ).triggerHandler( "invalid-form", [ this ]);
 
 913                                 this.formSubmitted = false;
 
 917                 previousValue: function( element ) {
 
 918                         return $.data( element, "previousValue" ) || $.data( element, "previousValue", {
 
 921                                 message: this.defaultMessage( element, "remote" )
 
 928                 required: { required: true },
 
 929                 email: { email: true },
 
 931                 date: { date: true },
 
 932                 dateISO: { dateISO: true },
 
 933                 number: { number: true },
 
 934                 digits: { digits: true },
 
 935                 creditcard: { creditcard: true }
 
 938         addClassRules: function( className, rules ) {
 
 939                 if ( className.constructor === String ) {
 
 940                         this.classRuleSettings[ className ] = rules;
 
 942                         $.extend( this.classRuleSettings, className );
 
 946         classRules: function( element ) {
 
 948                         classes = $( element ).attr( "class" );
 
 951                         $.each( classes.split( " " ), function() {
 
 952                                 if ( this in $.validator.classRuleSettings ) {
 
 953                                         $.extend( rules, $.validator.classRuleSettings[ this ]);
 
 960         attributeRules: function( element ) {
 
 962                         $element = $( element ),
 
 963                         type = element.getAttribute( "type" ),
 
 966                 for ( method in $.validator.methods ) {
 
 968                         // support for <input required> in both html5 and older browsers
 
 969                         if ( method === "required" ) {
 
 970                                 value = element.getAttribute( method );
 
 971                                 // Some browsers return an empty string for the required attribute
 
 972                                 // and non-HTML5 browsers might have required="" markup
 
 973                                 if ( value === "" ) {
 
 976                                 // force non-HTML5 browsers to return bool
 
 979                                 value = $element.attr( method );
 
 982                         // convert the value to a number for number inputs, and for text for backwards compability
 
 983                         // allows type="date" and others to be compared as strings
 
 984                         if ( /min|max/.test( method ) && ( type === null || /number|range|text/.test( type ) ) ) {
 
 985                                 value = Number( value );
 
 988                         if ( value || value === 0 ) {
 
 989                                 rules[ method ] = value;
 
 990                         } else if ( type === method && type !== "range" ) {
 
 991                                 // exception: the jquery validate 'range' method
 
 992                                 // does not test for the html5 'range' type
 
 993                                 rules[ method ] = true;
 
 997                 // maxlength may be returned as -1, 2147483647 ( IE ) and 524288 ( safari ) for text inputs
 
 998                 if ( rules.maxlength && /-1|2147483647|524288/.test( rules.maxlength ) ) {
 
 999                         delete rules.maxlength;
 
1005         dataRules: function( element ) {
 
1007                         rules = {}, $element = $( element );
 
1008                 for ( method in $.validator.methods ) {
 
1009                         value = $element.data( "rule" + method.charAt( 0 ).toUpperCase() + method.substring( 1 ).toLowerCase() );
 
1010                         if ( value !== undefined ) {
 
1011                                 rules[ method ] = value;
 
1017         staticRules: function( element ) {
 
1019                         validator = $.data( element.form, "validator" );
 
1021                 if ( validator.settings.rules ) {
 
1022                         rules = $.validator.normalizeRule( validator.settings.rules[ element.name ] ) || {};
 
1027         normalizeRules: function( rules, element ) {
 
1028                 // handle dependency check
 
1029                 $.each( rules, function( prop, val ) {
 
1030                         // ignore rule when param is explicitly false, eg. required:false
 
1031                         if ( val === false ) {
 
1032                                 delete rules[ prop ];
 
1035                         if ( val.param || val.depends ) {
 
1036                                 var keepRule = true;
 
1037                                 switch ( typeof val.depends ) {
 
1039                                         keepRule = !!$( val.depends, element.form ).length;
 
1042                                         keepRule = val.depends.call( element, element );
 
1046                                         rules[ prop ] = val.param !== undefined ? val.param : true;
 
1048                                         delete rules[ prop ];
 
1053                 // evaluate parameters
 
1054                 $.each( rules, function( rule, parameter ) {
 
1055                         rules[ rule ] = $.isFunction( parameter ) ? parameter( element ) : parameter;
 
1058                 // clean number parameters
 
1059                 $.each([ "minlength", "maxlength" ], function() {
 
1060                         if ( rules[ this ] ) {
 
1061                                 rules[ this ] = Number( rules[ this ] );
 
1064                 $.each([ "rangelength", "range" ], function() {
 
1066                         if ( rules[ this ] ) {
 
1067                                 if ( $.isArray( rules[ this ] ) ) {
 
1068                                         rules[ this ] = [ Number( rules[ this ][ 0 ]), Number( rules[ this ][ 1 ] ) ];
 
1069                                 } else if ( typeof rules[ this ] === "string" ) {
 
1070                                         parts = rules[ this ].replace(/[\[\]]/g, "" ).split( /[\s,]+/ );
 
1071                                         rules[ this ] = [ Number( parts[ 0 ]), Number( parts[ 1 ] ) ];
 
1076                 if ( $.validator.autoCreateRanges ) {
 
1077                         // auto-create ranges
 
1078                         if ( rules.min && rules.max ) {
 
1079                                 rules.range = [ rules.min, rules.max ];
 
1083                         if ( rules.minlength && rules.maxlength ) {
 
1084                                 rules.rangelength = [ rules.minlength, rules.maxlength ];
 
1085                                 delete rules.minlength;
 
1086                                 delete rules.maxlength;
 
1093         // Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
 
1094         normalizeRule: function( data ) {
 
1095                 if ( typeof data === "string" ) {
 
1096                         var transformed = {};
 
1097                         $.each( data.split( /\s/ ), function() {
 
1098                                 transformed[ this ] = true;
 
1105         // http://jqueryvalidation.org/jQuery.validator.addMethod/
 
1106         addMethod: function( name, method, message ) {
 
1107                 $.validator.methods[ name ] = method;
 
1108                 $.validator.messages[ name ] = message !== undefined ? message : $.validator.messages[ name ];
 
1109                 if ( method.length < 3 ) {
 
1110                         $.validator.addClassRules( name, $.validator.normalizeRule( name ) );
 
1116                 // http://jqueryvalidation.org/required-method/
 
1117                 required: function( value, element, param ) {
 
1118                         // check if dependency is met
 
1119                         if ( !this.depend( param, element ) ) {
 
1120                                 return "dependency-mismatch";
 
1122                         if ( element.nodeName.toLowerCase() === "select" ) {
 
1123                                 // could be an array for select-multiple or a string, both are fine this way
 
1124                                 var val = $( element ).val();
 
1125                                 return val && val.length > 0;
 
1127                         if ( this.checkable( element ) ) {
 
1128                                 return this.getLength( value, element ) > 0;
 
1130                         return $.trim( value ).length > 0;
 
1133                 // http://jqueryvalidation.org/email-method/
 
1134                 email: function( value, element ) {
 
1135                         // From http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#e-mail-state-%28type=email%29
 
1136                         // Retrieved 2014-01-14
 
1137                         // If you have a problem with this implementation, report a bug against the above spec
 
1138                         // Or use custom methods to implement your own email validation
 
1139                         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 );
 
1142                 // http://jqueryvalidation.org/url-method/
 
1143                 url: function( value, element ) {
 
1144                         // contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/
 
1145                         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 );
 
1148                 // http://jqueryvalidation.org/date-method/
 
1149                 date: function( value, element ) {
 
1150                         return this.optional( element ) || !/Invalid|NaN/.test( new Date( value ).toString() );
 
1153                 // http://jqueryvalidation.org/dateISO-method/
 
1154                 dateISO: function( value, element ) {
 
1155                         return this.optional( element ) || /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test( value );
 
1158                 // http://jqueryvalidation.org/number-method/
 
1159                 number: function( value, element ) {
 
1160                         return this.optional( element ) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test( value );
 
1163                 // http://jqueryvalidation.org/digits-method/
 
1164                 digits: function( value, element ) {
 
1165                         return this.optional( element ) || /^\d+$/.test( value );
 
1168                 // http://jqueryvalidation.org/creditcard-method/
 
1169                 // based on http://en.wikipedia.org/wiki/Luhn/
 
1170                 creditcard: function( value, element ) {
 
1171                         if ( this.optional( element ) ) {
 
1172                                 return "dependency-mismatch";
 
1174                         // accept only spaces, digits and dashes
 
1175                         if ( /[^0-9 \-]+/.test( value ) ) {
 
1183                         value = value.replace( /\D/g, "" );
 
1185                         // Basing min and max length on
 
1186                         // http://developer.ean.com/general_info/Valid_Credit_Card_Types
 
1187                         if ( value.length < 13 || value.length > 19 ) {
 
1191                         for ( n = value.length - 1; n >= 0; n--) {
 
1192                                 cDigit = value.charAt( n );
 
1193                                 nDigit = parseInt( cDigit, 10 );
 
1195                                         if ( ( nDigit *= 2 ) > 9 ) {
 
1203                         return ( nCheck % 10 ) === 0;
 
1206                 // http://jqueryvalidation.org/minlength-method/
 
1207                 minlength: function( value, element, param ) {
 
1208                         var length = $.isArray( value ) ? value.length : this.getLength( $.trim( value ), element );
 
1209                         return this.optional( element ) || length >= param;
 
1212                 // http://jqueryvalidation.org/maxlength-method/
 
1213                 maxlength: function( value, element, param ) {
 
1214                         var length = $.isArray( value ) ? value.length : this.getLength( $.trim( value ), element );
 
1215                         return this.optional( element ) || length <= param;
 
1218                 // http://jqueryvalidation.org/rangelength-method/
 
1219                 rangelength: function( value, element, param ) {
 
1220                         var length = $.isArray( value ) ? value.length : this.getLength( $.trim( value ), element );
 
1221                         return this.optional( element ) || ( length >= param[ 0 ] && length <= param[ 1 ] );
 
1224                 // http://jqueryvalidation.org/min-method/
 
1225                 min: function( value, element, param ) {
 
1226                         return this.optional( element ) || value >= param;
 
1229                 // http://jqueryvalidation.org/max-method/
 
1230                 max: function( value, element, param ) {
 
1231                         return this.optional( element ) || value <= param;
 
1234                 // http://jqueryvalidation.org/range-method/
 
1235                 range: function( value, element, param ) {
 
1236                         return this.optional( element ) || ( value >= param[ 0 ] && value <= param[ 1 ] );
 
1239                 // http://jqueryvalidation.org/equalTo-method/
 
1240                 equalTo: function( value, element, param ) {
 
1241                         // bind to the blur event of the target in order to revalidate whenever the target field is updated
 
1242                         // TODO find a way to bind the event just once, avoiding the unbind-rebind overhead
 
1243                         var target = $( param );
 
1244                         if ( this.settings.onfocusout ) {
 
1245                                 target.unbind( ".validate-equalTo" ).bind( "blur.validate-equalTo", function() {
 
1246                                         $( element ).valid();
 
1249                         return value === target.val();
 
1252                 // http://jqueryvalidation.org/remote-method/
 
1253                 remote: function( value, element, param ) {
 
1254                         if ( this.optional( element ) ) {
 
1255                                 return "dependency-mismatch";
 
1258                         var previous = this.previousValue( element ),
 
1261                         if (!this.settings.messages[ element.name ] ) {
 
1262                                 this.settings.messages[ element.name ] = {};
 
1264                         previous.originalMessage = this.settings.messages[ element.name ].remote;
 
1265                         this.settings.messages[ element.name ].remote = previous.message;
 
1267                         param = typeof param === "string" && { url: param } || param;
 
1269                         if ( previous.old === value ) {
 
1270                                 return previous.valid;
 
1273                         previous.old = value;
 
1275                         this.startRequest( element );
 
1277                         data[ element.name ] = value;
 
1278                         $.ajax( $.extend( true, {
 
1281                                 port: "validate" + element.name,
 
1284                                 context: validator.currentForm,
 
1285                                 success: function( response ) {
 
1286                                         var valid = response === true || response === "true",
 
1287                                                 errors, message, submitted;
 
1289                                         validator.settings.messages[ element.name ].remote = previous.originalMessage;
 
1291                                                 submitted = validator.formSubmitted;
 
1292                                                 validator.prepareElement( element );
 
1293                                                 validator.formSubmitted = submitted;
 
1294                                                 validator.successList.push( element );
 
1295                                                 delete validator.invalid[ element.name ];
 
1296                                                 validator.showErrors();
 
1299                                                 message = response || validator.defaultMessage( element, "remote" );
 
1300                                                 errors[ element.name ] = previous.message = $.isFunction( message ) ? message( value ) : message;
 
1301                                                 validator.invalid[ element.name ] = true;
 
1302                                                 validator.showErrors( errors );
 
1304                                         previous.valid = valid;
 
1305                                         validator.stopRequest( element, valid );
 
1315 $.format = function deprecated() {
 
1316         throw "$.format has been deprecated. Please use $.validator.format instead.";
 
1320 // usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
 
1321 // if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()
 
1323 var pendingRequests = {},
 
1325 // Use a prefilter if available (1.5+)
 
1326 if ( $.ajaxPrefilter ) {
 
1327         $.ajaxPrefilter(function( settings, _, xhr ) {
 
1328                 var port = settings.port;
 
1329                 if ( settings.mode === "abort" ) {
 
1330                         if ( pendingRequests[port] ) {
 
1331                                 pendingRequests[port].abort();
 
1333                         pendingRequests[port] = xhr;
 
1339         $.ajax = function( settings ) {
 
1340                 var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode,
 
1341                         port = ( "port" in settings ? settings : $.ajaxSettings ).port;
 
1342                 if ( mode === "abort" ) {
 
1343                         if ( pendingRequests[port] ) {
 
1344                                 pendingRequests[port].abort();
 
1346                         pendingRequests[port] = ajax.apply(this, arguments);
 
1347                         return pendingRequests[port];
 
1349                 return ajax.apply(this, arguments);
 
1353 // provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation
 
1354 // handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target
 
1357         validateDelegate: function( delegate, type, handler ) {
 
1358                 return this.bind(type, function( event ) {
 
1359                         var target = $(event.target);
 
1360                         if ( target.is(delegate) ) {
 
1361                                 return handler.apply(target, arguments);