9595 } ;
9696
9797 /* calculate error message position relative to the input */
98- function getPosition ( trigger , el , conf ) {
98+ function getPosition ( trigger , el , conf ) {
99+
100+ // Get the first element in the selector set
101+ el = $ ( el ) . first ( ) || el ;
99102
100103 // get origin top/left position
101- var top = trigger . offset ( ) . top ,
102- left = trigger . offset ( ) . left ,
103- pos = conf . position . split ( / , ? \s + / ) ,
104- y = pos [ 0 ] ,
105- x = pos [ 1 ] ;
104+ var top = trigger . offset ( ) . top ,
105+ left = trigger . offset ( ) . left ,
106+ pos = conf . position . split ( / , ? \s + / ) ,
107+ y = pos [ 0 ] ,
108+ x = pos [ 1 ] ;
106109
107110 top -= el . outerHeight ( ) - conf . offset [ 0 ] ;
108111 left += trigger . outerWidth ( ) + conf . offset [ 1 ] ;
256259 return p . test ( el . val ( ) ) ;
257260 } ) ;
258261
262+ v . fn ( ":radio" , "Please select an option." , function ( el ) {
263+ var checked = false ;
264+ var els = $ ( "[name=" + el . attr ( "name" ) + "]" ) . each ( function ( i , el ) {
265+ if ( $ ( el ) . is ( ":checked" ) ) {
266+ checked = true ;
267+ }
268+ } ) ;
269+ return ( checked ) ? true : false ;
270+ } ) ;
259271
260272 function Validator ( inputs , form , conf ) {
261273
262274 // private variables
263275 var self = this ,
264- fire = form . add ( self ) ;
276+ fire = form . add ( self ) ;
265277
266278 // make sure there are input fields available
267279 inputs = inputs . not ( ":button, :image, :reset, :submit" ) ;
388400
389401 els = els || inputs ;
390402 els = els . not ( ":disabled" ) ;
403+
404+ // filter duplicate elements by name
405+ var names = { } ;
406+ els = els . filter ( function ( ) {
407+ var name = $ ( this ) . attr ( "name" ) ;
408+ if ( ! names [ name ] ) {
409+ names [ name ] = true ;
410+ return $ ( this ) ;
411+ }
412+ } ) ;
413+
391414 if ( ! els . length ) { return true ; }
392415
393416 e = e || $ . Event ( ) ;
401424 var errs = [ ] ;
402425
403426 // loop trough the inputs
404- els . not ( ":radio:not(:checked)" ) . each ( function ( ) {
427+ els . each ( function ( ) {
405428
406429 // field and it's error message container
407430 var msgs = [ ] ,
545568 } ) ;
546569 }
547570
548- // checkboxes, selects and radios are checked separately
571+ // checkboxes and selects are checked separately
549572 inputs . filter ( ":checkbox, select" ) . filter ( "[required]" ) . bind ( "change.V" , function ( e ) {
550573 var el = $ ( this ) ;
551574 if ( this . checked || ( el . is ( "select" ) && $ ( this ) . val ( ) ) ) {
552575 effects [ conf . effect ] [ 1 ] . call ( self , el , e ) ;
553576 }
554- } ) ;
555-
556- var radios = inputs . filter ( ":radio" ) . change ( function ( e ) {
557- self . checkValidity ( radios , e ) ;
577+ } ) ;
578+
579+ // get radio groups by name
580+ inputs . filter ( ":radio[required]" ) . bind ( "change.V" , function ( e ) {
581+ var els = $ ( "[name=" + $ ( e . srcElement ) . attr ( "name" ) + "]" ) ;
582+ if ( ( els != null ) && ( els . length != 0 ) ) {
583+ self . checkValidity ( els , e ) ;
584+ }
558585 } ) ;
559586
560587 // reposition tooltips when window is resized
561588 $ ( window ) . resize ( function ( ) {
562589 self . reflow ( ) ;
563590 } ) ;
591+
564592 }
565593
566594
593621
594622 } ;
595623
596- } ) ( jQuery ) ;
597-
598-
624+ } ) ( jQuery ) ;
0 commit comments