Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 1 | espaco | 1 | /*! |
| 2 | * jQuery Validation Plugin v1.13.0 |
||
| 3 | * |
||
| 4 | * http://jqueryvalidation.org/ |
||
| 5 | * |
||
| 6 | * Copyright (c) 2014 Jörn Zaefferer |
||
| 7 | * Released under the MIT license |
||
| 8 | */ |
||
| 9 | (function( factory ) { |
||
| 10 | if ( typeof define === "function" && define.amd ) { |
||
| 11 | define( ["jquery"], factory ); |
||
| 12 | } else { |
||
| 13 | factory( jQuery ); |
||
| 14 | } |
||
| 15 | }(function( $ ) { |
||
| 16 | |||
| 17 | $.extend($.fn, { |
||
| 18 | // http://jqueryvalidation.org/validate/ |
||
| 19 | validate: function( options ) { |
||
| 20 | |||
| 21 | // if nothing is selected, return nothing; can't chain anyway |
||
| 22 | if ( !this.length ) { |
||
| 23 | if ( options && options.debug && window.console ) { |
||
| 24 | console.warn( "Nothing selected, can't validate, returning nothing." ); |
||
| 25 | } |
||
| 26 | return; |
||
| 27 | } |
||
| 28 | |||
| 29 | // check if a validator for this form was already created |
||
| 30 | var validator = $.data( this[ 0 ], "validator" ); |
||
| 31 | if ( validator ) { |
||
| 32 | return validator; |
||
| 33 | } |
||
| 34 | |||
| 35 | // Add novalidate tag if HTML5. |
||
| 36 | this.attr( "novalidate", "novalidate" ); |
||
| 37 | |||
| 38 | validator = new $.validator( options, this[ 0 ] ); |
||
| 39 | $.data( this[ 0 ], "validator", validator ); |
||
| 40 | |||
| 41 | if ( validator.settings.onsubmit ) { |
||
| 42 | |||
| 43 | this.validateDelegate( ":submit", "click", function( event ) { |
||
| 44 | if ( validator.settings.submitHandler ) { |
||
| 45 | validator.submitButton = event.target; |
||
| 46 | } |
||
| 47 | // allow suppressing validation by adding a cancel class to the submit button |
||
| 48 | if ( $( event.target ).hasClass( "cancel" ) ) { |
||
| 49 | validator.cancelSubmit = true; |
||
| 50 | } |
||
| 51 | |||
| 52 | // allow suppressing validation by adding the html5 formnovalidate attribute to the submit button |
||
| 53 | if ( $( event.target ).attr( "formnovalidate" ) !== undefined ) { |
||
| 54 | validator.cancelSubmit = true; |
||
| 55 | } |
||
| 56 | }); |
||
| 57 | |||
| 58 | // validate the form on submit |
||
| 59 | this.submit( function( event ) { |
||
| 60 | if ( validator.settings.debug ) { |
||
| 61 | // prevent form submit to be able to see console output |
||
| 62 | event.preventDefault(); |
||
| 63 | } |
||
| 64 | function handle() { |
||
| 65 | var hidden; |
||
| 66 | if ( validator.settings.submitHandler ) { |
||
| 67 | if ( validator.submitButton ) { |
||
| 68 | // insert a hidden input as a replacement for the missing submit button |
||
| 69 | hidden = $( "<input type='hidden'/>" ) |
||
| 70 | .attr( "name", validator.submitButton.name ) |
||
| 71 | .val( $( validator.submitButton ).val() ) |
||
| 72 | .appendTo( validator.currentForm ); |
||
| 73 | } |
||
| 74 | validator.settings.submitHandler.call( validator, validator.currentForm, event ); |
||
| 75 | if ( validator.submitButton ) { |
||
| 76 | // and clean up afterwards; thanks to no-block-scope, hidden can be referenced |
||
| 77 | hidden.remove(); |
||
| 78 | } |
||
| 79 | return false; |
||
| 80 | } |
||
| 81 | return true; |
||
| 82 | } |
||
| 83 | |||
| 84 | // prevent submit for invalid forms or custom submit handlers |
||
| 85 | if ( validator.cancelSubmit ) { |
||
| 86 | validator.cancelSubmit = false; |
||
| 87 | return handle(); |
||
| 88 | } |
||
| 89 | if ( validator.form() ) { |
||
| 90 | if ( validator.pendingRequest ) { |
||
| 91 | validator.formSubmitted = true; |
||
| 92 | return false; |
||
| 93 | } |
||
| 94 | return handle(); |
||
| 95 | } else { |
||
| 96 | validator.focusInvalid(); |
||
| 97 | return false; |
||
| 98 | } |
||
| 99 | }); |
||
| 100 | } |
||
| 101 | |||
| 102 | return validator; |
||
| 103 | }, |
||
| 104 | // http://jqueryvalidation.org/valid/ |
||
| 105 | valid: function() { |
||
| 106 | var valid, validator; |
||
| 107 | |||
| 108 | if ( $( this[ 0 ] ).is( "form" ) ) { |
||
| 109 | valid = this.validate().form(); |
||
| 110 | } else { |
||
| 111 | valid = true; |
||
| 112 | validator = $( this[ 0 ].form ).validate(); |
||
| 113 | this.each( function() { |
||
| 114 | valid = validator.element( this ) && valid; |
||
| 115 | }); |
||
| 116 | } |
||
| 117 | return valid; |
||
| 118 | }, |
||
| 119 | // attributes: space separated list of attributes to retrieve and remove |
||
| 120 | removeAttrs: function( attributes ) { |
||
| 121 | var result = {}, |
||
| 122 | $element = this; |
||
| 123 | $.each( attributes.split( /\s/ ), function( index, value ) { |
||
| 124 | result[ value ] = $element.attr( value ); |
||
| 125 | $element.removeAttr( value ); |
||
| 126 | }); |
||
| 127 | return result; |
||
| 128 | }, |
||
| 129 | // http://jqueryvalidation.org/rules/ |
||
| 130 | rules: function( command, argument ) { |
||
| 131 | var element = this[ 0 ], |
||
| 132 | settings, staticRules, existingRules, data, param, filtered; |
||
| 133 | |||
| 134 | if ( command ) { |
||
| 135 | settings = $.data( element.form, "validator" ).settings; |
||
| 136 | staticRules = settings.rules; |
||
| 137 | existingRules = $.validator.staticRules( element ); |
||
| 138 | switch ( command ) { |
||
| 139 | case "add": |
||
| 140 | $.extend( existingRules, $.validator.normalizeRule( argument ) ); |
||
| 141 | // remove messages from rules, but allow them to be set separately |
||
| 142 | delete existingRules.messages; |
||
| 143 | staticRules[ element.name ] = existingRules; |
||
| 144 | if ( argument.messages ) { |
||
| 145 | settings.messages[ element.name ] = $.extend( settings.messages[ element.name ], argument.messages ); |
||
| 146 | } |
||
| 147 | break; |
||
| 148 | case "remove": |
||
| 149 | if ( !argument ) { |
||
| 150 | delete staticRules[ element.name ]; |
||
| 151 | return existingRules; |
||
| 152 | } |
||
| 153 | filtered = {}; |
||
| 154 | $.each( argument.split( /\s/ ), function( index, method ) { |
||
| 155 | filtered[ method ] = existingRules[ method ]; |
||
| 156 | delete existingRules[ method ]; |
||
| 157 | if ( method === "required" ) { |
||
| 158 | $( element ).removeAttr( "aria-required" ); |
||
| 159 | } |
||
| 160 | }); |
||
| 161 | return filtered; |
||
| 162 | } |
||
| 163 | } |
||
| 164 | |||
| 165 | data = $.validator.normalizeRules( |
||
| 166 | $.extend( |
||
| 167 | {}, |
||
| 168 | $.validator.classRules( element ), |
||
| 169 | $.validator.attributeRules( element ), |
||
| 170 | $.validator.dataRules( element ), |
||
| 171 | $.validator.staticRules( element ) |
||
| 172 | ), element ); |
||
| 173 | |||
| 174 | // make sure required is at front |
||
| 175 | if ( data.required ) { |
||
| 176 | param = data.required; |
||
| 177 | delete data.required; |
||
| 178 | data = $.extend( { required: param }, data ); |
||
| 179 | $( element ).attr( "aria-required", "true" ); |
||
| 180 | } |
||
| 181 | |||
| 182 | // make sure remote is at back |
||
| 183 | if ( data.remote ) { |
||
| 184 | param = data.remote; |
||
| 185 | delete data.remote; |
||
| 186 | data = $.extend( data, { remote: param }); |
||
| 187 | } |
||
| 188 | |||
| 189 | return data; |
||
| 190 | } |
||
| 191 | }); |
||
| 192 | |||
| 193 | // Custom selectors |
||
| 194 | $.extend( $.expr[ ":" ], { |
||
| 195 | // http://jqueryvalidation.org/blank-selector/ |
||
| 196 | blank: function( a ) { |
||
| 197 | return !$.trim( "" + $( a ).val() ); |
||
| 198 | }, |
||
| 199 | // http://jqueryvalidation.org/filled-selector/ |
||
| 200 | filled: function( a ) { |
||
| 201 | return !!$.trim( "" + $( a ).val() ); |
||
| 202 | }, |
||
| 203 | // http://jqueryvalidation.org/unchecked-selector/ |
||
| 204 | unchecked: function( a ) { |
||
| 205 | return !$( a ).prop( "checked" ); |
||
| 206 | } |
||
| 207 | }); |
||
| 208 | |||
| 209 | // constructor for validator |
||
| 210 | $.validator = function( options, form ) { |
||
| 211 | this.settings = $.extend( true, {}, $.validator.defaults, options ); |
||
| 212 | this.currentForm = form; |
||
| 213 | this.init(); |
||
| 214 | }; |
||
| 215 | |||
| 216 | // http://jqueryvalidation.org/jQuery.validator.format/ |
||
| 217 | $.validator.format = function( source, params ) { |
||
| 218 | if ( arguments.length === 1 ) { |
||
| 219 | return function() { |
||
| 220 | var args = $.makeArray( arguments ); |
||
| 221 | args.unshift( source ); |
||
| 222 | return $.validator.format.apply( this, args ); |
||
| 223 | }; |
||
| 224 | } |
||
| 225 | if ( arguments.length > 2 && params.constructor !== Array ) { |
||
| 226 | params = $.makeArray( arguments ).slice( 1 ); |
||
| 227 | } |
||
| 228 | if ( params.constructor !== Array ) { |
||
| 229 | params = [ params ]; |
||
| 230 | } |
||
| 231 | $.each( params, function( i, n ) { |
||
| 232 | source = source.replace( new RegExp( "\\{" + i + "\\}", "g" ), function() { |
||
| 233 | return n; |
||
| 234 | }); |
||
| 235 | }); |
||
| 236 | return source; |
||
| 237 | }; |
||
| 238 | |||
| 239 | $.extend( $.validator, { |
||
| 240 | |||
| 241 | defaults: { |
||
| 242 | messages: {}, |
||
| 243 | groups: {}, |
||
| 244 | rules: {}, |
||
| 245 | errorClass: "error", |
||
| 246 | validClass: "valid", |
||
| 247 | errorElement: "label", |
||
| 248 | focusInvalid: true, |
||
| 249 | errorContainer: $( [] ), |
||
| 250 | errorLabelContainer: $( [] ), |
||
| 251 | onsubmit: true, |
||
| 252 | ignore: ":hidden", |
||
| 253 | ignoreTitle: false, |
||
| 254 | onfocusin: function( element ) { |
||
| 255 | this.lastActive = element; |
||
| 256 | |||
| 257 | // hide error label and remove error class on focus if enabled |
||
| 258 | if ( this.settings.focusCleanup && !this.blockFocusCleanup ) { |
||
| 259 | if ( this.settings.unhighlight ) { |
||
| 260 | this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass ); |
||
| 261 | } |
||
| 262 | this.hideThese( this.errorsFor( element ) ); |
||
| 263 | } |
||
| 264 | }, |
||
| 265 | onfocusout: function( element ) { |
||
| 266 | if ( !this.checkable( element ) && ( element.name in this.submitted || !this.optional( element ) ) ) { |
||
| 267 | this.element( element ); |
||
| 268 | } |
||
| 269 | }, |
||
| 270 | onkeyup: function( element, event ) { |
||
| 271 | if ( event.which === 9 && this.elementValue( element ) === "" ) { |
||
| 272 | return; |
||
| 273 | } else if ( element.name in this.submitted || element === this.lastElement ) { |
||
| 274 | this.element( element ); |
||
| 275 | } |
||
| 276 | }, |
||
| 277 | onclick: function( element ) { |
||
| 278 | // click on selects, radiobuttons and checkboxes |
||
| 279 | if ( element.name in this.submitted ) { |
||
| 280 | this.element( element ); |
||
| 281 | |||
| 282 | // or option elements, check parent select in that case |
||
| 283 | } else if ( element.parentNode.name in this.submitted ) { |
||
| 284 | this.element( element.parentNode ); |
||
| 285 | } |
||
| 286 | }, |
||
| 287 | highlight: function( element, errorClass, validClass ) { |
||
| 288 | if ( element.type === "radio" ) { |
||
| 289 | this.findByName( element.name ).addClass( errorClass ).removeClass( validClass ); |
||
| 290 | } else { |
||
| 291 | $( element ).addClass( errorClass ).removeClass( validClass ); |
||
| 292 | } |
||
| 293 | }, |
||
| 294 | unhighlight: function( element, errorClass, validClass ) { |
||
| 295 | if ( element.type === "radio" ) { |
||
| 296 | this.findByName( element.name ).removeClass( errorClass ).addClass( validClass ); |
||
| 297 | } else { |
||
| 298 | $( element ).removeClass( errorClass ).addClass( validClass ); |
||
| 299 | } |
||
| 300 | } |
||
| 301 | }, |
||
| 302 | |||
| 303 | // http://jqueryvalidation.org/jQuery.validator.setDefaults/ |
||
| 304 | setDefaults: function( settings ) { |
||
| 305 | $.extend( $.validator.defaults, settings ); |
||
| 306 | }, |
||
| 307 | |||
| 308 | messages: { |
||
| 309 | required: "This field is required.", |
||
| 310 | remote: "Please fix this field.", |
||
| 311 | email: "Please enter a valid email address.", |
||
| 312 | url: "Please enter a valid URL.", |
||
| 313 | date: "Please enter a valid date.", |
||
| 314 | dateISO: "Please enter a valid date ( ISO ).", |
||
| 315 | number: "Please enter a valid number.", |
||
| 316 | digits: "Please enter only digits.", |
||
| 317 | creditcard: "Please enter a valid credit card number.", |
||
| 318 | equalTo: "Please enter the same value again.", |
||
| 319 | maxlength: $.validator.format( "Please enter no more than {0} characters." ), |
||
| 320 | minlength: $.validator.format( "Please enter at least {0} characters." ), |
||
| 321 | rangelength: $.validator.format( "Please enter a value between {0} and {1} characters long." ), |
||
| 322 | range: $.validator.format( "Please enter a value between {0} and {1}." ), |
||
| 323 | max: $.validator.format( "Please enter a value less than or equal to {0}." ), |
||
| 324 | min: $.validator.format( "Please enter a value greater than or equal to {0}." ) |
||
| 325 | }, |
||
| 326 | |||
| 327 | autoCreateRanges: false, |
||
| 328 | |||
| 329 | prototype: { |
||
| 330 | |||
| 331 | init: function() { |
||
| 332 | this.labelContainer = $( this.settings.errorLabelContainer ); |
||
| 333 | this.errorContext = this.labelContainer.length && this.labelContainer || $( this.currentForm ); |
||
| 334 | this.containers = $( this.settings.errorContainer ).add( this.settings.errorLabelContainer ); |
||
| 335 | this.submitted = {}; |
||
| 336 | this.valueCache = {}; |
||
| 337 | this.pendingRequest = 0; |
||
| 338 | this.pending = {}; |
||
| 339 | this.invalid = {}; |
||
| 340 | this.reset(); |
||
| 341 | |||
| 342 | var groups = ( this.groups = {} ), |
||
| 343 | rules; |
||
| 344 | $.each( this.settings.groups, function( key, value ) { |
||
| 345 | if ( typeof value === "string" ) { |
||
| 346 | value = value.split( /\s/ ); |
||
| 347 | } |
||
| 348 | $.each( value, function( index, name ) { |
||
| 349 | groups[ name ] = key; |
||
| 350 | }); |
||
| 351 | }); |
||
| 352 | rules = this.settings.rules; |
||
| 353 | $.each( rules, function( key, value ) { |
||
| 354 | rules[ key ] = $.validator.normalizeRule( value ); |
||
| 355 | }); |
||
| 356 | |||
| 357 | function delegate( event ) { |
||
| 358 | var validator = $.data( this[ 0 ].form, "validator" ), |
||
| 359 | eventType = "on" + event.type.replace( /^validate/, "" ), |
||
| 360 | settings = validator.settings; |
||
| 361 | if ( settings[ eventType ] && !this.is( settings.ignore ) ) { |
||
| 362 | settings[ eventType ].call( validator, this[ 0 ], event ); |
||
| 363 | } |
||
| 364 | } |
||
| 365 | $( this.currentForm ) |
||
| 366 | .validateDelegate( ":text, [type='password'], [type='file'], select, textarea, " + |
||
| 367 | "[type='number'], [type='search'] ,[type='tel'], [type='url'], " + |
||
| 368 | "[type='email'], [type='datetime'], [type='date'], [type='month'], " + |
||
| 369 | "[type='week'], [type='time'], [type='datetime-local'], " + |
||
| 370 | "[type='range'], [type='color'], [type='radio'], [type='checkbox']", |
||
| 371 | "focusin focusout keyup", delegate) |
||
| 372 | // Support: Chrome, oldIE |
||
| 373 | // "select" is provided as event.target when clicking a option |
||
| 374 | .validateDelegate("select, option, [type='radio'], [type='checkbox']", "click", delegate); |
||
| 375 | |||
| 376 | if ( this.settings.invalidHandler ) { |
||
| 377 | $( this.currentForm ).bind( "invalid-form.validate", this.settings.invalidHandler ); |
||
| 378 | } |
||
| 379 | |||
| 380 | // Add aria-required to any Static/Data/Class required fields before first validation |
||
| 381 | // Screen readers require this attribute to be present before the initial submission http://www.w3.org/TR/WCAG-TECHS/ARIA2.html |
||
| 382 | $( this.currentForm ).find( "[required], [data-rule-required], .required" ).attr( "aria-required", "true" ); |
||
| 383 | }, |
||
| 384 | |||
| 385 | // http://jqueryvalidation.org/Validator.form/ |
||
| 386 | form: function() { |
||
| 387 | this.checkForm(); |
||
| 388 | $.extend( this.submitted, this.errorMap ); |
||
| 389 | this.invalid = $.extend({}, this.errorMap ); |
||
| 390 | if ( !this.valid() ) { |
||
| 391 | $( this.currentForm ).triggerHandler( "invalid-form", [ this ]); |
||
| 392 | } |
||
| 393 | this.showErrors(); |
||
| 394 | return this.valid(); |
||
| 395 | }, |
||
| 396 | |||
| 397 | checkForm: function() { |
||
| 398 | this.prepareForm(); |
||
| 399 | for ( var i = 0, elements = ( this.currentElements = this.elements() ); elements[ i ]; i++ ) { |
||
| 400 | this.check( elements[ i ] ); |
||
| 401 | } |
||
| 402 | return this.valid(); |
||
| 403 | }, |
||
| 404 | |||
| 405 | // http://jqueryvalidation.org/Validator.element/ |
||
| 406 | element: function( element ) { |
||
| 407 | var cleanElement = this.clean( element ), |
||
| 408 | checkElement = this.validationTargetFor( cleanElement ), |
||
| 409 | result = true; |
||
| 410 | |||
| 411 | this.lastElement = checkElement; |
||
| 412 | |||
| 413 | if ( checkElement === undefined ) { |
||
| 414 | delete this.invalid[ cleanElement.name ]; |
||
| 415 | } else { |
||
| 416 | this.prepareElement( checkElement ); |
||
| 417 | this.currentElements = $( checkElement ); |
||
| 418 | |||
| 419 | result = this.check( checkElement ) !== false; |
||
| 420 | if ( result ) { |
||
| 421 | delete this.invalid[ checkElement.name ]; |
||
| 422 | } else { |
||
| 423 | this.invalid[ checkElement.name ] = true; |
||
| 424 | } |
||
| 425 | } |
||
| 426 | // Add aria-invalid status for screen readers |
||
| 427 | $( element ).attr( "aria-invalid", !result ); |
||
| 428 | |||
| 429 | if ( !this.numberOfInvalids() ) { |
||
| 430 | // Hide error containers on last error |
||
| 431 | this.toHide = this.toHide.add( this.containers ); |
||
| 432 | } |
||
| 433 | this.showErrors(); |
||
| 434 | return result; |
||
| 435 | }, |
||
| 436 | |||
| 437 | // http://jqueryvalidation.org/Validator.showErrors/ |
||
| 438 | showErrors: function( errors ) { |
||
| 439 | if ( errors ) { |
||
| 440 | // add items to error list and map |
||
| 441 | $.extend( this.errorMap, errors ); |
||
| 442 | this.errorList = []; |
||
| 443 | for ( var name in errors ) { |
||
| 444 | this.errorList.push({ |
||
| 445 | message: errors[ name ], |
||
| 446 | element: this.findByName( name )[ 0 ] |
||
| 447 | }); |
||
| 448 | } |
||
| 449 | // remove items from success list |
||
| 450 | this.successList = $.grep( this.successList, function( element ) { |
||
| 451 | return !( element.name in errors ); |
||
| 452 | }); |
||
| 453 | } |
||
| 454 | if ( this.settings.showErrors ) { |
||
| 455 | this.settings.showErrors.call( this, this.errorMap, this.errorList ); |
||
| 456 | } else { |
||
| 457 | this.defaultShowErrors(); |
||
| 458 | } |
||
| 459 | }, |
||
| 460 | |||
| 461 | // http://jqueryvalidation.org/Validator.resetForm/ |
||
| 462 | resetForm: function() { |
||
| 463 | if ( $.fn.resetForm ) { |
||
| 464 | $( this.currentForm ).resetForm(); |
||
| 465 | } |
||
| 466 | this.submitted = {}; |
||
| 467 | this.lastElement = null; |
||
| 468 | this.prepareForm(); |
||
| 469 | this.hideErrors(); |
||
| 470 | this.elements() |
||
| 471 | .removeClass( this.settings.errorClass ) |
||
| 472 | .removeData( "previousValue" ) |
||
| 473 | .removeAttr( "aria-invalid" ); |
||
| 474 | }, |
||
| 475 | |||
| 476 | numberOfInvalids: function() { |
||
| 477 | return this.objectLength( this.invalid ); |
||
| 478 | }, |
||
| 479 | |||
| 480 | objectLength: function( obj ) { |
||
| 481 | /* jshint unused: false */ |
||
| 482 | var count = 0, |
||
| 483 | i; |
||
| 484 | for ( i in obj ) { |
||
| 485 | count++; |
||
| 486 | } |
||
| 487 | return count; |
||
| 488 | }, |
||
| 489 | |||
| 490 | hideErrors: function() { |
||
| 491 | this.hideThese( this.toHide ); |
||
| 492 | }, |
||
| 493 | |||
| 494 | hideThese: function( errors ) { |
||
| 495 | errors.not( this.containers ).text( "" ); |
||
| 496 | this.addWrapper( errors ).hide(); |
||
| 497 | }, |
||
| 498 | |||
| 499 | valid: function() { |
||
| 500 | return this.size() === 0; |
||
| 501 | }, |
||
| 502 | |||
| 503 | size: function() { |
||
| 504 | return this.errorList.length; |
||
| 505 | }, |
||
| 506 | |||
| 507 | focusInvalid: function() { |
||
| 508 | if ( this.settings.focusInvalid ) { |
||
| 509 | try { |
||
| 510 | $( this.findLastActive() || this.errorList.length && this.errorList[ 0 ].element || []) |
||
| 511 | .filter( ":visible" ) |
||
| 512 | .focus() |
||
| 513 | // manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find |
||
| 514 | .trigger( "focusin" ); |
||
| 515 | } catch ( e ) { |
||
| 516 | // ignore IE throwing errors when focusing hidden elements |
||
| 517 | } |
||
| 518 | } |
||
| 519 | }, |
||
| 520 | |||
| 521 | findLastActive: function() { |
||
| 522 | var lastActive = this.lastActive; |
||
| 523 | return lastActive && $.grep( this.errorList, function( n ) { |
||
| 524 | return n.element.name === lastActive.name; |
||
| 525 | }).length === 1 && lastActive; |
||
| 526 | }, |
||
| 527 | |||
| 528 | elements: function() { |
||
| 529 | var validator = this, |
||
| 530 | rulesCache = {}; |
||
| 531 | |||
| 532 | // select all valid inputs inside the form (no submit or reset buttons) |
||
| 533 | return $( this.currentForm ) |
||
| 534 | .find( "input, select, textarea" ) |
||
| 535 | .not( ":submit, :reset, :image, [disabled]" ) |
||
| 536 | .not( this.settings.ignore ) |
||
| 537 | .filter( function() { |
||
| 538 | if ( !this.name && validator.settings.debug && window.console ) { |
||
| 539 | console.error( "%o has no name assigned", this ); |
||
| 540 | } |
||
| 541 | |||
| 542 | // select only the first element for each name, and only those with rules specified |
||
| 543 | if ( this.name in rulesCache || !validator.objectLength( $( this ).rules() ) ) { |
||
| 544 | return false; |
||
| 545 | } |
||
| 546 | |||
| 547 | rulesCache[ this.name ] = true; |
||
| 548 | return true; |
||
| 549 | }); |
||
| 550 | }, |
||
| 551 | |||
| 552 | clean: function( selector ) { |
||
| 553 | return $( selector )[ 0 ]; |
||
| 554 | }, |
||
| 555 | |||
| 556 | errors: function() { |
||
| 557 | var errorClass = this.settings.errorClass.split( " " ).join( "." ); |
||
| 558 | return $( this.settings.errorElement + "." + errorClass, this.errorContext ); |
||
| 559 | }, |
||
| 560 | |||
| 561 | reset: function() { |
||
| 562 | this.successList = []; |
||
| 563 | this.errorList = []; |
||
| 564 | this.errorMap = {}; |
||
| 565 | this.toShow = $( [] ); |
||
| 566 | this.toHide = $( [] ); |
||
| 567 | this.currentElements = $( [] ); |
||
| 568 | }, |
||
| 569 | |||
| 570 | prepareForm: function() { |
||
| 571 | this.reset(); |
||
| 572 | this.toHide = this.errors().add( this.containers ); |
||
| 573 | }, |
||
| 574 | |||
| 575 | prepareElement: function( element ) { |
||
| 576 | this.reset(); |
||
| 577 | this.toHide = this.errorsFor( element ); |
||
| 578 | }, |
||
| 579 | |||
| 580 | elementValue: function( element ) { |
||
| 581 | var val, |
||
| 582 | $element = $( element ), |
||
| 583 | type = element.type; |
||
| 584 | |||
| 585 | if ( type === "radio" || type === "checkbox" ) { |
||
| 586 | return $( "input[name='" + element.name + "']:checked" ).val(); |
||
| 587 | } else if ( type === "number" && typeof element.validity !== "undefined" ) { |
||
| 588 | return element.validity.badInput ? false : $element.val(); |
||
| 589 | } |
||
| 590 | |||
| 591 | val = $element.val(); |
||
| 592 | if ( typeof val === "string" ) { |
||
| 593 | return val.replace(/\r/g, "" ); |
||
| 594 | } |
||
| 595 | return val; |
||
| 596 | }, |
||
| 597 | |||
| 598 | check: function( element ) { |
||
| 599 | element = this.validationTargetFor( this.clean( element ) ); |
||
| 600 | |||
| 601 | var rules = $( element ).rules(), |
||
| 602 | rulesCount = $.map( rules, function( n, i ) { |
||
| 603 | return i; |
||
| 604 | }).length, |
||
| 605 | dependencyMismatch = false, |
||
| 606 | val = this.elementValue( element ), |
||
| 607 | result, method, rule; |
||
| 608 | |||
| 609 | for ( method in rules ) { |
||
| 610 | rule = { method: method, parameters: rules[ method ] }; |
||
| 611 | try { |
||
| 612 | |||
| 613 | result = $.validator.methods[ method ].call( this, val, element, rule.parameters ); |
||
| 614 | |||
| 615 | // if a method indicates that the field is optional and therefore valid, |
||
| 616 | // don't mark it as valid when there are no other rules |
||
| 617 | if ( result === "dependency-mismatch" && rulesCount === 1 ) { |
||
| 618 | dependencyMismatch = true; |
||
| 619 | continue; |
||
| 620 | } |
||
| 621 | dependencyMismatch = false; |
||
| 622 | |||
| 623 | if ( result === "pending" ) { |
||
| 624 | this.toHide = this.toHide.not( this.errorsFor( element ) ); |
||
| 625 | return; |
||
| 626 | } |
||
| 627 | |||
| 628 | if ( !result ) { |
||
| 629 | this.formatAndAdd( element, rule ); |
||
| 630 | return false; |
||
| 631 | } |
||
| 632 | } catch ( e ) { |
||
| 633 | if ( this.settings.debug && window.console ) { |
||
| 634 | console.log( "Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.", e ); |
||
| 635 | } |
||
| 636 | throw e; |
||
| 637 | } |
||
| 638 | } |
||
| 639 | if ( dependencyMismatch ) { |
||
| 640 | return; |
||
| 641 | } |
||
| 642 | if ( this.objectLength( rules ) ) { |
||
| 643 | this.successList.push( element ); |
||
| 644 | } |
||
| 645 | return true; |
||
| 646 | }, |
||
| 647 | |||
| 648 | // return the custom message for the given element and validation method |
||
| 649 | // specified in the element's HTML5 data attribute |
||
| 650 | // return the generic message if present and no method specific message is present |
||
| 651 | customDataMessage: function( element, method ) { |
||
| 652 | return $( element ).data( "msg" + method.charAt( 0 ).toUpperCase() + |
||
| 653 | method.substring( 1 ).toLowerCase() ) || $( element ).data( "msg" ); |
||
| 654 | }, |
||
| 655 | |||
| 656 | // return the custom message for the given element name and validation method |
||
| 657 | customMessage: function( name, method ) { |
||
| 658 | var m = this.settings.messages[ name ]; |
||
| 659 | return m && ( m.constructor === String ? m : m[ method ]); |
||
| 660 | }, |
||
| 661 | |||
| 662 | // return the first defined argument, allowing empty strings |
||
| 663 | findDefined: function() { |
||
| 664 | for ( var i = 0; i < arguments.length; i++) { |
||
| 665 | if ( arguments[ i ] !== undefined ) { |
||
| 666 | return arguments[ i ]; |
||
| 667 | } |
||
| 668 | } |
||
| 669 | return undefined; |
||
| 670 | }, |
||
| 671 | |||
| 672 | defaultMessage: function( element, method ) { |
||
| 673 | return this.findDefined( |
||
| 674 | this.customMessage( element.name, method ), |
||
| 675 | this.customDataMessage( element, method ), |
||
| 676 | // title is never undefined, so handle empty string as undefined |
||
| 677 | !this.settings.ignoreTitle && element.title || undefined, |
||
| 678 | $.validator.messages[ method ], |
||
| 679 | "<strong>Warning: No message defined for " + element.name + "</strong>" |
||
| 680 | ); |
||
| 681 | }, |
||
| 682 | |||
| 683 | formatAndAdd: function( element, rule ) { |
||
| 684 | var message = this.defaultMessage( element, rule.method ), |
||
| 685 | theregex = /\$?\{(\d+)\}/g; |
||
| 686 | if ( typeof message === "function" ) { |
||
| 687 | message = message.call( this, rule.parameters, element ); |
||
| 688 | } else if ( theregex.test( message ) ) { |
||
| 689 | message = $.validator.format( message.replace( theregex, "{$1}" ), rule.parameters ); |
||
| 690 | } |
||
| 691 | this.errorList.push({ |
||
| 692 | message: message, |
||
| 693 | element: element, |
||
| 694 | method: rule.method |
||
| 695 | }); |
||
| 696 | |||
| 697 | this.errorMap[ element.name ] = message; |
||
| 698 | this.submitted[ element.name ] = message; |
||
| 699 | }, |
||
| 700 | |||
| 701 | addWrapper: function( toToggle ) { |
||
| 702 | if ( this.settings.wrapper ) { |
||
| 703 | toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) ); |
||
| 704 | } |
||
| 705 | return toToggle; |
||
| 706 | }, |
||
| 707 | |||
| 708 | defaultShowErrors: function() { |
||
| 709 | var i, elements, error; |
||
| 710 | for ( i = 0; this.errorList[ i ]; i++ ) { |
||
| 711 | error = this.errorList[ i ]; |
||
| 712 | if ( this.settings.highlight ) { |
||
| 713 | this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass ); |
||
| 714 | } |
||
| 715 | this.showLabel( error.element, error.message ); |
||
| 716 | } |
||
| 717 | if ( this.errorList.length ) { |
||
| 718 | this.toShow = this.toShow.add( this.containers ); |
||
| 719 | } |
||
| 720 | if ( this.settings.success ) { |
||
| 721 | for ( i = 0; this.successList[ i ]; i++ ) { |
||
| 722 | this.showLabel( this.successList[ i ] ); |
||
| 723 | } |
||
| 724 | } |
||
| 725 | if ( this.settings.unhighlight ) { |
||
| 726 | for ( i = 0, elements = this.validElements(); elements[ i ]; i++ ) { |
||
| 727 | this.settings.unhighlight.call( this, elements[ i ], this.settings.errorClass, this.settings.validClass ); |
||
| 728 | } |
||
| 729 | } |
||
| 730 | this.toHide = this.toHide.not( this.toShow ); |
||
| 731 | this.hideErrors(); |
||
| 732 | this.addWrapper( this.toShow ).show(); |
||
| 733 | }, |
||
| 734 | |||
| 735 | validElements: function() { |
||
| 736 | return this.currentElements.not( this.invalidElements() ); |
||
| 737 | }, |
||
| 738 | |||
| 739 | invalidElements: function() { |
||
| 740 | return $( this.errorList ).map(function() { |
||
| 741 | return this.element; |
||
| 742 | }); |
||
| 743 | }, |
||
| 744 | |||
| 745 | showLabel: function( element, message ) { |
||
| 746 | var place, group, errorID, |
||
| 747 | error = this.errorsFor( element ), |
||
| 748 | elementID = this.idOrName( element ), |
||
| 749 | describedBy = $( element ).attr( "aria-describedby" ); |
||
| 750 | if ( error.length ) { |
||
| 751 | // refresh error/success class |
||
| 752 | error.removeClass( this.settings.validClass ).addClass( this.settings.errorClass ); |
||
| 753 | // replace message on existing label |
||
| 754 | error.html( message ); |
||
| 755 | } else { |
||
| 756 | // create error element |
||
| 757 | error = $( "<" + this.settings.errorElement + ">" ) |
||
| 758 | .attr( "id", elementID + "-error" ) |
||
| 759 | .addClass( this.settings.errorClass ) |
||
| 760 | .html( message || "" ); |
||
| 761 | |||
| 762 | // Maintain reference to the element to be placed into the DOM |
||
| 763 | place = error; |
||
| 764 | if ( this.settings.wrapper ) { |
||
| 765 | // make sure the element is visible, even in IE |
||
| 766 | // actually showing the wrapped element is handled elsewhere |
||
| 767 | place = error.hide().show().wrap( "<" + this.settings.wrapper + "/>" ).parent(); |
||
| 768 | } |
||
| 769 | if ( this.labelContainer.length ) { |
||
| 770 | this.labelContainer.append( place ); |
||
| 771 | } else if ( this.settings.errorPlacement ) { |
||
| 772 | this.settings.errorPlacement( place, $( element ) ); |
||
| 773 | } else { |
||
| 774 | place.insertAfter( element ); |
||
| 775 | } |
||
| 776 | |||
| 777 | // Link error back to the element |
||
| 778 | if ( error.is( "label" ) ) { |
||
| 779 | // If the error is a label, then associate using 'for' |
||
| 780 | error.attr( "for", elementID ); |
||
| 781 | } else if ( error.parents( "label[for='" + elementID + "']" ).length === 0 ) { |
||
| 782 | // If the element is not a child of an associated label, then it's necessary |
||
| 783 | // to explicitly apply aria-describedby |
||
| 784 | |||
| 785 | errorID = error.attr( "id" ); |
||
| 786 | // Respect existing non-error aria-describedby |
||
| 787 | if ( !describedBy ) { |
||
| 788 | describedBy = errorID; |
||
| 789 | } else if ( !describedBy.match( new RegExp( "\b" + errorID + "\b" ) ) ) { |
||
| 790 | // Add to end of list if not already present |
||
| 791 | describedBy += " " + errorID; |
||
| 792 | } |
||
| 793 | $( element ).attr( "aria-describedby", describedBy ); |
||
| 794 | |||
| 795 | // If this element is grouped, then assign to all elements in the same group |
||
| 796 | group = this.groups[ element.name ]; |
||
| 797 | if ( group ) { |
||
| 798 | $.each( this.groups, function( name, testgroup ) { |
||
| 799 | if ( testgroup === group ) { |
||
| 800 | $( "[name='" + name + "']", this.currentForm ) |
||
| 801 | .attr( "aria-describedby", error.attr( "id" ) ); |
||
| 802 | } |
||
| 803 | }); |
||
| 804 | } |
||
| 805 | } |
||
| 806 | } |
||
| 807 | if ( !message && this.settings.success ) { |
||
| 808 | error.text( "" ); |
||
| 809 | if ( typeof this.settings.success === "string" ) { |
||
| 810 | error.addClass( this.settings.success ); |
||
| 811 | } else { |
||
| 812 | this.settings.success( error, element ); |
||
| 813 | } |
||
| 814 | } |
||
| 815 | this.toShow = this.toShow.add( error ); |
||
| 816 | }, |
||
| 817 | |||
| 818 | errorsFor: function( element ) { |
||
| 819 | var name = this.idOrName( element ), |
||
| 820 | describer = $( element ).attr( "aria-describedby" ), |
||
| 821 | selector = "label[for='" + name + "'], label[for='" + name + "'] *"; |
||
| 822 | // aria-describedby should directly reference the error element |
||
| 823 | if ( describer ) { |
||
| 824 | selector = selector + ", #" + describer.replace( /\s+/g, ", #" ); |
||
| 825 | } |
||
| 826 | return this |
||
| 827 | .errors() |
||
| 828 | .filter( selector ); |
||
| 829 | }, |
||
| 830 | |||
| 831 | idOrName: function( element ) { |
||
| 832 | return this.groups[ element.name ] || ( this.checkable( element ) ? element.name : element.id || element.name ); |
||
| 833 | }, |
||
| 834 | |||
| 835 | validationTargetFor: function( element ) { |
||
| 836 | // if radio/checkbox, validate first element in group instead |
||
| 837 | if ( this.checkable( element ) ) { |
||
| 838 | element = this.findByName( element.name ).not( this.settings.ignore )[ 0 ]; |
||
| 839 | } |
||
| 840 | return element; |
||
| 841 | }, |
||
| 842 | |||
| 843 | checkable: function( element ) { |
||
| 844 | return ( /radio|checkbox/i ).test( element.type ); |
||
| 845 | }, |
||
| 846 | |||
| 847 | findByName: function( name ) { |
||
| 848 | return $( this.currentForm ).find( "[name='" + name + "']" ); |
||
| 849 | }, |
||
| 850 | |||
| 851 | getLength: function( value, element ) { |
||
| 852 | switch ( element.nodeName.toLowerCase() ) { |
||
| 853 | case "select": |
||
| 854 | return $( "option:selected", element ).length; |
||
| 855 | case "input": |
||
| 856 | if ( this.checkable( element ) ) { |
||
| 857 | return this.findByName( element.name ).filter( ":checked" ).length; |
||
| 858 | } |
||
| 859 | } |
||
| 860 | return value.length; |
||
| 861 | }, |
||
| 862 | |||
| 863 | depend: function( param, element ) { |
||
| 864 | return this.dependTypes[typeof param] ? this.dependTypes[typeof param]( param, element ) : true; |
||
| 865 | }, |
||
| 866 | |||
| 867 | dependTypes: { |
||
| 868 | "boolean": function( param ) { |
||
| 869 | return param; |
||
| 870 | }, |
||
| 871 | "string": function( param, element ) { |
||
| 872 | return !!$( param, element.form ).length; |
||
| 873 | }, |
||
| 874 | "function": function( param, element ) { |
||
| 875 | return param( element ); |
||
| 876 | } |
||
| 877 | }, |
||
| 878 | |||
| 879 | optional: function( element ) { |
||
| 880 | var val = this.elementValue( element ); |
||
| 881 | return !$.validator.methods.required.call( this, val, element ) && "dependency-mismatch"; |
||
| 882 | }, |
||
| 883 | |||
| 884 | startRequest: function( element ) { |
||
| 885 | if ( !this.pending[ element.name ] ) { |
||
| 886 | this.pendingRequest++; |
||
| 887 | this.pending[ element.name ] = true; |
||
| 888 | } |
||
| 889 | }, |
||
| 890 | |||
| 891 | stopRequest: function( element, valid ) { |
||
| 892 | this.pendingRequest--; |
||
| 893 | // sometimes synchronization fails, make sure pendingRequest is never < 0 |
||
| 894 | if ( this.pendingRequest < 0 ) { |
||
| 895 | this.pendingRequest = 0; |
||
| 896 | } |
||
| 897 | delete this.pending[ element.name ]; |
||
| 898 | if ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() ) { |
||
| 899 | $( this.currentForm ).submit(); |
||
| 900 | this.formSubmitted = false; |
||
| 901 | } else if (!valid && this.pendingRequest === 0 && this.formSubmitted ) { |
||
| 902 | $( this.currentForm ).triggerHandler( "invalid-form", [ this ]); |
||
| 903 | this.formSubmitted = false; |
||
| 904 | } |
||
| 905 | }, |
||
| 906 | |||
| 907 | previousValue: function( element ) { |
||
| 908 | return $.data( element, "previousValue" ) || $.data( element, "previousValue", { |
||
| 909 | old: null, |
||
| 910 | valid: true, |
||
| 911 | message: this.defaultMessage( element, "remote" ) |
||
| 912 | }); |
||
| 913 | } |
||
| 914 | |||
| 915 | }, |
||
| 916 | |||
| 917 | classRuleSettings: { |
||
| 918 | required: { required: true }, |
||
| 919 | email: { email: true }, |
||
| 920 | url: { url: true }, |
||
| 921 | date: { date: true }, |
||
| 922 | dateISO: { dateISO: true }, |
||
| 923 | number: { number: true }, |
||
| 924 | digits: { digits: true }, |
||
| 925 | creditcard: { creditcard: true } |
||
| 926 | }, |
||
| 927 | |||
| 928 | addClassRules: function( className, rules ) { |
||
| 929 | if ( className.constructor === String ) { |
||
| 930 | this.classRuleSettings[ className ] = rules; |
||
| 931 | } else { |
||
| 932 | $.extend( this.classRuleSettings, className ); |
||
| 933 | } |
||
| 934 | }, |
||
| 935 | |||
| 936 | classRules: function( element ) { |
||
| 937 | var rules = {}, |
||
| 938 | classes = $( element ).attr( "class" ); |
||
| 939 | |||
| 940 | if ( classes ) { |
||
| 941 | $.each( classes.split( " " ), function() { |
||
| 942 | if ( this in $.validator.classRuleSettings ) { |
||
| 943 | $.extend( rules, $.validator.classRuleSettings[ this ]); |
||
| 944 | } |
||
| 945 | }); |
||
| 946 | } |
||
| 947 | return rules; |
||
| 948 | }, |
||
| 949 | |||
| 950 | attributeRules: function( element ) { |
||
| 951 | var rules = {}, |
||
| 952 | $element = $( element ), |
||
| 953 | type = element.getAttribute( "type" ), |
||
| 954 | method, value; |
||
| 955 | |||
| 956 | for ( method in $.validator.methods ) { |
||
| 957 | |||
| 958 | // support for <input required> in both html5 and older browsers |
||
| 959 | if ( method === "required" ) { |
||
| 960 | value = element.getAttribute( method ); |
||
| 961 | // Some browsers return an empty string for the required attribute |
||
| 962 | // and non-HTML5 browsers might have required="" markup |
||
| 963 | if ( value === "" ) { |
||
| 964 | value = true; |
||
| 965 | } |
||
| 966 | // force non-HTML5 browsers to return bool |
||
| 967 | value = !!value; |
||
| 968 | } else { |
||
| 969 | value = $element.attr( method ); |
||
| 970 | } |
||
| 971 | |||
| 972 | // convert the value to a number for number inputs, and for text for backwards compability |
||
| 973 | // allows type="date" and others to be compared as strings |
||
| 974 | if ( /min|max/.test( method ) && ( type === null || /number|range|text/.test( type ) ) ) { |
||
| 975 | value = Number( value ); |
||
| 976 | } |
||
| 977 | |||
| 978 | if ( value || value === 0 ) { |
||
| 979 | rules[ method ] = value; |
||
| 980 | } else if ( type === method && type !== "range" ) { |
||
| 981 | // exception: the jquery validate 'range' method |
||
| 982 | // does not test for the html5 'range' type |
||
| 983 | rules[ method ] = true; |
||
| 984 | } |
||
| 985 | } |
||
| 986 | |||
| 987 | // maxlength may be returned as -1, 2147483647 ( IE ) and 524288 ( safari ) for text inputs |
||
| 988 | if ( rules.maxlength && /-1|2147483647|524288/.test( rules.maxlength ) ) { |
||
| 989 | delete rules.maxlength; |
||
| 990 | } |
||
| 991 | |||
| 992 | return rules; |
||
| 993 | }, |
||
| 994 | |||
| 995 | dataRules: function( element ) { |
||
| 996 | var method, value, |
||
| 997 | rules = {}, $element = $( element ); |
||
| 998 | for ( method in $.validator.methods ) { |
||
| 999 | value = $element.data( "rule" + method.charAt( 0 ).toUpperCase() + method.substring( 1 ).toLowerCase() ); |
||
| 1000 | if ( value !== undefined ) { |
||
| 1001 | rules[ method ] = value; |
||
| 1002 | } |
||
| 1003 | } |
||
| 1004 | return rules; |
||
| 1005 | }, |
||
| 1006 | |||
| 1007 | staticRules: function( element ) { |
||
| 1008 | var rules = {}, |
||
| 1009 | validator = $.data( element.form, "validator" ); |
||
| 1010 | |||
| 1011 | if ( validator.settings.rules ) { |
||
| 1012 | rules = $.validator.normalizeRule( validator.settings.rules[ element.name ] ) || {}; |
||
| 1013 | } |
||
| 1014 | return rules; |
||
| 1015 | }, |
||
| 1016 | |||
| 1017 | normalizeRules: function( rules, element ) { |
||
| 1018 | // handle dependency check |
||
| 1019 | $.each( rules, function( prop, val ) { |
||
| 1020 | // ignore rule when param is explicitly false, eg. required:false |
||
| 1021 | if ( val === false ) { |
||
| 1022 | delete rules[ prop ]; |
||
| 1023 | return; |
||
| 1024 | } |
||
| 1025 | if ( val.param || val.depends ) { |
||
| 1026 | var keepRule = true; |
||
| 1027 | switch ( typeof val.depends ) { |
||
| 1028 | case "string": |
||
| 1029 | keepRule = !!$( val.depends, element.form ).length; |
||
| 1030 | break; |
||
| 1031 | case "function": |
||
| 1032 | keepRule = val.depends.call( element, element ); |
||
| 1033 | break; |
||
| 1034 | } |
||
| 1035 | if ( keepRule ) { |
||
| 1036 | rules[ prop ] = val.param !== undefined ? val.param : true; |
||
| 1037 | } else { |
||
| 1038 | delete rules[ prop ]; |
||
| 1039 | } |
||
| 1040 | } |
||
| 1041 | }); |
||
| 1042 | |||
| 1043 | // evaluate parameters |
||
| 1044 | $.each( rules, function( rule, parameter ) { |
||
| 1045 | rules[ rule ] = $.isFunction( parameter ) ? parameter( element ) : parameter; |
||
| 1046 | }); |
||
| 1047 | |||
| 1048 | // clean number parameters |
||
| 1049 | $.each([ "minlength", "maxlength" ], function() { |
||
| 1050 | if ( rules[ this ] ) { |
||
| 1051 | rules[ this ] = Number( rules[ this ] ); |
||
| 1052 | } |
||
| 1053 | }); |
||
| 1054 | $.each([ "rangelength", "range" ], function() { |
||
| 1055 | var parts; |
||
| 1056 | if ( rules[ this ] ) { |
||
| 1057 | if ( $.isArray( rules[ this ] ) ) { |
||
| 1058 | rules[ this ] = [ Number( rules[ this ][ 0 ]), Number( rules[ this ][ 1 ] ) ]; |
||
| 1059 | } else if ( typeof rules[ this ] === "string" ) { |
||
| 1060 | parts = rules[ this ].replace(/[\[\]]/g, "" ).split( /[\s,]+/ ); |
||
| 1061 | rules[ this ] = [ Number( parts[ 0 ]), Number( parts[ 1 ] ) ]; |
||
| 1062 | } |
||
| 1063 | } |
||
| 1064 | }); |
||
| 1065 | |||
| 1066 | if ( $.validator.autoCreateRanges ) { |
||
| 1067 | // auto-create ranges |
||
| 1068 | if ( rules.min && rules.max ) { |
||
| 1069 | rules.range = [ rules.min, rules.max ]; |
||
| 1070 | delete rules.min; |
||
| 1071 | delete rules.max; |
||
| 1072 | } |
||
| 1073 | if ( rules.minlength && rules.maxlength ) { |
||
| 1074 | rules.rangelength = [ rules.minlength, rules.maxlength ]; |
||
| 1075 | delete rules.minlength; |
||
| 1076 | delete rules.maxlength; |
||
| 1077 | } |
||
| 1078 | } |
||
| 1079 | |||
| 1080 | return rules; |
||
| 1081 | }, |
||
| 1082 | |||
| 1083 | // Converts a simple string to a {string: true} rule, e.g., "required" to {required:true} |
||
| 1084 | normalizeRule: function( data ) { |
||
| 1085 | if ( typeof data === "string" ) { |
||
| 1086 | var transformed = {}; |
||
| 1087 | $.each( data.split( /\s/ ), function() { |
||
| 1088 | transformed[ this ] = true; |
||
| 1089 | }); |
||
| 1090 | data = transformed; |
||
| 1091 | } |
||
| 1092 | return data; |
||
| 1093 | }, |
||
| 1094 | |||
| 1095 | // http://jqueryvalidation.org/jQuery.validator.addMethod/ |
||
| 1096 | addMethod: function( name, method, message ) { |
||
| 1097 | $.validator.methods[ name ] = method; |
||
| 1098 | $.validator.messages[ name ] = message !== undefined ? message : $.validator.messages[ name ]; |
||
| 1099 | if ( method.length < 3 ) { |
||
| 1100 | $.validator.addClassRules( name, $.validator.normalizeRule( name ) ); |
||
| 1101 | } |
||
| 1102 | }, |
||
| 1103 | |||
| 1104 | methods: { |
||
| 1105 | |||
| 1106 | // http://jqueryvalidation.org/required-method/ |
||
| 1107 | required: function( value, element, param ) { |
||
| 1108 | // check if dependency is met |
||
| 1109 | if ( !this.depend( param, element ) ) { |
||
| 1110 | return "dependency-mismatch"; |
||
| 1111 | } |
||
| 1112 | if ( element.nodeName.toLowerCase() === "select" ) { |
||
| 1113 | // could be an array for select-multiple or a string, both are fine this way |
||
| 1114 | var val = $( element ).val(); |
||
| 1115 | return val && val.length > 0; |
||
| 1116 | } |
||
| 1117 | if ( this.checkable( element ) ) { |
||
| 1118 | return this.getLength( value, element ) > 0; |
||
| 1119 | } |
||
| 1120 | return $.trim( value ).length > 0; |
||
| 1121 | }, |
||
| 1122 | |||
| 1123 | // http://jqueryvalidation.org/email-method/ |
||
| 1124 | email: function( value, element ) { |
||
| 1125 | // From http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#e-mail-state-%28type=email%29 |
||
| 1126 | // Retrieved 2014-01-14 |
||
| 1127 | // If you have a problem with this implementation, report a bug against the above spec |
||
| 1128 | // Or use custom methods to implement your own email validation |
||
| 1129 | 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 ); |
||
| 1130 | }, |
||
| 1131 | |||
| 1132 | // http://jqueryvalidation.org/url-method/ |
||
| 1133 | url: function( value, element ) { |
||
| 1134 | // contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/ |
||
| 1135 | 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 ); |
||
| 1136 | }, |
||
| 1137 | |||
| 1138 | // http://jqueryvalidation.org/date-method/ |
||
| 1139 | date: function( value, element ) { |
||
| 1140 | return this.optional( element ) || !/Invalid|NaN/.test( new Date( value ).toString() ); |
||
| 1141 | }, |
||
| 1142 | |||
| 1143 | // http://jqueryvalidation.org/dateISO-method/ |
||
| 1144 | dateISO: function( value, element ) { |
||
| 1145 | return this.optional( element ) || /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test( value ); |
||
| 1146 | }, |
||
| 1147 | |||
| 1148 | // http://jqueryvalidation.org/number-method/ |
||
| 1149 | number: function( value, element ) { |
||
| 1150 | return this.optional( element ) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test( value ); |
||
| 1151 | }, |
||
| 1152 | |||
| 1153 | // http://jqueryvalidation.org/digits-method/ |
||
| 1154 | digits: function( value, element ) { |
||
| 1155 | return this.optional( element ) || /^\d+$/.test( value ); |
||
| 1156 | }, |
||
| 1157 | |||
| 1158 | // http://jqueryvalidation.org/creditcard-method/ |
||
| 1159 | // based on http://en.wikipedia.org/wiki/Luhn/ |
||
| 1160 | creditcard: function( value, element ) { |
||
| 1161 | if ( this.optional( element ) ) { |
||
| 1162 | return "dependency-mismatch"; |
||
| 1163 | } |
||
| 1164 | // accept only spaces, digits and dashes |
||
| 1165 | if ( /[^0-9 \-]+/.test( value ) ) { |
||
| 1166 | return false; |
||
| 1167 | } |
||
| 1168 | var nCheck = 0, |
||
| 1169 | nDigit = 0, |
||
| 1170 | bEven = false, |
||
| 1171 | n, cDigit; |
||
| 1172 | |||
| 1173 | value = value.replace( /\D/g, "" ); |
||
| 1174 | |||
| 1175 | // Basing min and max length on |
||
| 1176 | // http://developer.ean.com/general_info/Valid_Credit_Card_Types |
||
| 1177 | if ( value.length < 13 || value.length > 19 ) { |
||
| 1178 | return false; |
||
| 1179 | } |
||
| 1180 | |||
| 1181 | for ( n = value.length - 1; n >= 0; n--) { |
||
| 1182 | cDigit = value.charAt( n ); |
||
| 1183 | nDigit = parseInt( cDigit, 10 ); |
||
| 1184 | if ( bEven ) { |
||
| 1185 | if ( ( nDigit *= 2 ) > 9 ) { |
||
| 1186 | nDigit -= 9; |
||
| 1187 | } |
||
| 1188 | } |
||
| 1189 | nCheck += nDigit; |
||
| 1190 | bEven = !bEven; |
||
| 1191 | } |
||
| 1192 | |||
| 1193 | return ( nCheck % 10 ) === 0; |
||
| 1194 | }, |
||
| 1195 | |||
| 1196 | // http://jqueryvalidation.org/minlength-method/ |
||
| 1197 | minlength: function( value, element, param ) { |
||
| 1198 | var length = $.isArray( value ) ? value.length : this.getLength( $.trim( value ), element ); |
||
| 1199 | return this.optional( element ) || length >= param; |
||
| 1200 | }, |
||
| 1201 | |||
| 1202 | // http://jqueryvalidation.org/maxlength-method/ |
||
| 1203 | maxlength: function( value, element, param ) { |
||
| 1204 | var length = $.isArray( value ) ? value.length : this.getLength( $.trim( value ), element ); |
||
| 1205 | return this.optional( element ) || length <= param; |
||
| 1206 | }, |
||
| 1207 | |||
| 1208 | // http://jqueryvalidation.org/rangelength-method/ |
||
| 1209 | rangelength: function( value, element, param ) { |
||
| 1210 | var length = $.isArray( value ) ? value.length : this.getLength( $.trim( value ), element ); |
||
| 1211 | return this.optional( element ) || ( length >= param[ 0 ] && length <= param[ 1 ] ); |
||
| 1212 | }, |
||
| 1213 | |||
| 1214 | // http://jqueryvalidation.org/min-method/ |
||
| 1215 | min: function( value, element, param ) { |
||
| 1216 | return this.optional( element ) || value >= param; |
||
| 1217 | }, |
||
| 1218 | |||
| 1219 | // http://jqueryvalidation.org/max-method/ |
||
| 1220 | max: function( value, element, param ) { |
||
| 1221 | return this.optional( element ) || value <= param; |
||
| 1222 | }, |
||
| 1223 | |||
| 1224 | // http://jqueryvalidation.org/range-method/ |
||
| 1225 | range: function( value, element, param ) { |
||
| 1226 | return this.optional( element ) || ( value >= param[ 0 ] && value <= param[ 1 ] ); |
||
| 1227 | }, |
||
| 1228 | |||
| 1229 | // http://jqueryvalidation.org/equalTo-method/ |
||
| 1230 | equalTo: function( value, element, param ) { |
||
| 1231 | // bind to the blur event of the target in order to revalidate whenever the target field is updated |
||
| 1232 | // TODO find a way to bind the event just once, avoiding the unbind-rebind overhead |
||
| 1233 | var target = $( param ); |
||
| 1234 | if ( this.settings.onfocusout ) { |
||
| 1235 | target.unbind( ".validate-equalTo" ).bind( "blur.validate-equalTo", function() { |
||
| 1236 | $( element ).valid(); |
||
| 1237 | }); |
||
| 1238 | } |
||
| 1239 | return value === target.val(); |
||
| 1240 | }, |
||
| 1241 | |||
| 1242 | // http://jqueryvalidation.org/remote-method/ |
||
| 1243 | remote: function( value, element, param ) { |
||
| 1244 | if ( this.optional( element ) ) { |
||
| 1245 | return "dependency-mismatch"; |
||
| 1246 | } |
||
| 1247 | |||
| 1248 | var previous = this.previousValue( element ), |
||
| 1249 | validator, data; |
||
| 1250 | |||
| 1251 | if (!this.settings.messages[ element.name ] ) { |
||
| 1252 | this.settings.messages[ element.name ] = {}; |
||
| 1253 | } |
||
| 1254 | previous.originalMessage = this.settings.messages[ element.name ].remote; |
||
| 1255 | this.settings.messages[ element.name ].remote = previous.message; |
||
| 1256 | |||
| 1257 | param = typeof param === "string" && { url: param } || param; |
||
| 1258 | |||
| 1259 | if ( previous.old === value ) { |
||
| 1260 | return previous.valid; |
||
| 1261 | } |
||
| 1262 | |||
| 1263 | previous.old = value; |
||
| 1264 | validator = this; |
||
| 1265 | this.startRequest( element ); |
||
| 1266 | data = {}; |
||
| 1267 | data[ element.name ] = value; |
||
| 1268 | $.ajax( $.extend( true, { |
||
| 1269 | url: param, |
||
| 1270 | mode: "abort", |
||
| 1271 | port: "validate" + element.name, |
||
| 1272 | dataType: "json", |
||
| 1273 | data: data, |
||
| 1274 | context: validator.currentForm, |
||
| 1275 | success: function( response ) { |
||
| 1276 | var valid = response === true || response === "true", |
||
| 1277 | errors, message, submitted; |
||
| 1278 | |||
| 1279 | validator.settings.messages[ element.name ].remote = previous.originalMessage; |
||
| 1280 | if ( valid ) { |
||
| 1281 | submitted = validator.formSubmitted; |
||
| 1282 | validator.prepareElement( element ); |
||
| 1283 | validator.formSubmitted = submitted; |
||
| 1284 | validator.successList.push( element ); |
||
| 1285 | delete validator.invalid[ element.name ]; |
||
| 1286 | validator.showErrors(); |
||
| 1287 | } else { |
||
| 1288 | errors = {}; |
||
| 1289 | message = response || validator.defaultMessage( element, "remote" ); |
||
| 1290 | errors[ element.name ] = previous.message = $.isFunction( message ) ? message( value ) : message; |
||
| 1291 | validator.invalid[ element.name ] = true; |
||
| 1292 | validator.showErrors( errors ); |
||
| 1293 | } |
||
| 1294 | previous.valid = valid; |
||
| 1295 | validator.stopRequest( element, valid ); |
||
| 1296 | } |
||
| 1297 | }, param ) ); |
||
| 1298 | return "pending"; |
||
| 1299 | } |
||
| 1300 | |||
| 1301 | } |
||
| 1302 | |||
| 1303 | }); |
||
| 1304 | |||
| 1305 | $.format = function deprecated() { |
||
| 1306 | throw "$.format has been deprecated. Please use $.validator.format instead."; |
||
| 1307 | }; |
||
| 1308 | |||
| 1309 | // ajax mode: abort |
||
| 1310 | // usage: $.ajax({ mode: "abort"[, port: "uniqueport"]}); |
||
| 1311 | // if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort() |
||
| 1312 | |||
| 1313 | var pendingRequests = {}, |
||
| 1314 | ajax; |
||
| 1315 | // Use a prefilter if available (1.5+) |
||
| 1316 | if ( $.ajaxPrefilter ) { |
||
| 1317 | $.ajaxPrefilter(function( settings, _, xhr ) { |
||
| 1318 | var port = settings.port; |
||
| 1319 | if ( settings.mode === "abort" ) { |
||
| 1320 | if ( pendingRequests[port] ) { |
||
| 1321 | pendingRequests[port].abort(); |
||
| 1322 | } |
||
| 1323 | pendingRequests[port] = xhr; |
||
| 1324 | } |
||
| 1325 | }); |
||
| 1326 | } else { |
||
| 1327 | // Proxy ajax |
||
| 1328 | ajax = $.ajax; |
||
| 1329 | $.ajax = function( settings ) { |
||
| 1330 | var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode, |
||
| 1331 | port = ( "port" in settings ? settings : $.ajaxSettings ).port; |
||
| 1332 | if ( mode === "abort" ) { |
||
| 1333 | if ( pendingRequests[port] ) { |
||
| 1334 | pendingRequests[port].abort(); |
||
| 1335 | } |
||
| 1336 | pendingRequests[port] = ajax.apply(this, arguments); |
||
| 1337 | return pendingRequests[port]; |
||
| 1338 | } |
||
| 1339 | return ajax.apply(this, arguments); |
||
| 1340 | }; |
||
| 1341 | } |
||
| 1342 | |||
| 1343 | // provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation |
||
| 1344 | // handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target |
||
| 1345 | |||
| 1346 | $.extend($.fn, { |
||
| 1347 | validateDelegate: function( delegate, type, handler ) { |
||
| 1348 | return this.bind(type, function( event ) { |
||
| 1349 | var target = $(event.target); |
||
| 1350 | if ( target.is(delegate) ) { |
||
| 1351 | return handler.apply(target, arguments); |
||
| 1352 | } |
||
| 1353 | }); |
||
| 1354 | } |
||
| 1355 | }); |
||
| 1356 | |||
| 1357 | })); |