@@ -612,65 +612,101 @@ jQuery.event.special.submit = {
612612// change delegation, happens here so we have bind.
613613if ( ! jQuery . support . changeBubbles ) {
614614
615- jQuery . event . special . change = {
616- filters : {
617- click : function ( e ) {
618- var elem = e . target ;
615+ var formElems = / t e x t a r e a | i n p u t | s e l e c t / i;
619616
620- if ( elem . nodeName . toLowerCase ( ) === "input" && elem . type === "checkbox" ) {
621- return trigger ( "change" , this , arguments ) ;
622- }
617+ function getVal ( elem ) {
618+ var type = elem . type , val = elem . value ;
623619
624- return changeFilters . keyup . call ( this , e ) ;
625- } ,
626- keyup : function ( e ) {
627- var elem = e . target , data , index = elem . selectedIndex + "" ;
620+ if ( type === "radio" || type === "checkbox" ) {
621+ val = elem . checked ;
628622
629- if ( elem . nodeName . toLowerCase ( ) === "select" ) {
630- data = jQuery . data ( elem , "_change_data" ) ;
631- jQuery . data ( elem , "_change_data" , index ) ;
623+ } else if ( type === "select-multiple" ) {
624+ val = elem . selectedIndex > - 1 ?
625+ jQuery . map ( elem . options , function ( elem ) {
626+ return elem . selected ;
627+ } ) . join ( "-" ) :
628+ "" ;
632629
633- if ( ( elem . type === "select-multiple" || data != null ) && data !== index ) {
634- return trigger ( "change" , this , arguments ) ;
635- }
636- }
637- } ,
638- beforeactivate : function ( e ) {
639- var elem = e . target ;
630+ } else if ( elem . nodeName . toLowerCase ( ) === "select" ) {
631+ val = elem . selectedIndex ;
632+ }
633+
634+ return val ;
635+ }
636+
637+ function testChange ( e ) {
638+ var elem = e . target , data , val ;
639+
640+ if ( ! formElems . test ( elem . nodeName ) || elem . readOnly ) {
641+ return ;
642+ }
643+
644+ data = jQuery . data ( elem , "_change_data" ) ;
645+ val = getVal ( elem ) ;
640646
641- if ( elem . nodeName . toLowerCase ( ) === "input" && elem . type === "radio" && ! elem . checked ) {
642- return trigger ( "change" , this , arguments ) ;
647+ if ( val === data ) {
648+ return ;
649+ }
650+
651+ // the current data will be also retrieved by beforeactivate
652+ if ( e . type !== "focusout" || elem . type !== "radio" ) {
653+ jQuery . data ( elem , "_change_data" , val ) ;
654+ }
655+
656+ if ( elem . type !== "select" && ( data != null || val ) ) {
657+ e . type = "change" ;
658+ return jQuery . event . trigger ( e , arguments [ 1 ] , this ) ;
659+ }
660+ }
661+
662+ jQuery . event . special . change = {
663+ filters : {
664+ focusout : testChange ,
665+
666+ click : function ( e ) {
667+ var elem = e . target , type = elem . type ;
668+
669+ if ( type === "radio" || type === "checkbox" || elem . nodeName . toLowerCase ( ) === "select" ) {
670+ return testChange . call ( this , e ) ;
643671 }
644672 } ,
645- blur : function ( e ) {
646- var elem = e . target , nodeName = elem . nodeName . toLowerCase ( ) ;
647673
648- if ( ( nodeName === "textarea" || ( nodeName === "input" && ( elem . type === "text" || elem . type === "password" ) ) )
649- && jQuery . data ( elem , "_change_data" ) !== elem . value ) {
674+ // Change has to be called before submit
675+ // Keydown will be called before keypress, wich is used in submit-event delegation
676+ keydown : function ( e ) {
677+ var elem = e . target , type = elem . type ;
650678
651- return trigger ( "change" , this , arguments ) ;
679+ if ( ( e . keyCode === 13 && elem . nodeName . toLowerCase ( ) !== "textarea" ) ||
680+ ( e . keyCode === 32 && ( type === "checkbox" || type === "radio" ) ) ||
681+ type === "select-multiple" ) {
682+ return testChange . call ( this , e ) ;
652683 }
653684 } ,
654- focus : function ( e ) {
655- var elem = e . target , nodeName = elem . nodeName . toLowerCase ( ) ;
656685
657- if ( nodeName === "textarea" || ( nodeName === "input" && ( elem . type === "text" || elem . type === "password" ) ) ) {
658- jQuery . data ( elem , "_change_data" , elem . value ) ;
686+ // Beforeactivate happens also before the previous element is blurred
687+ // with this event you can't trigger a change event, but you can store
688+ // information/focus[in] is not needed anymore
689+ beforeactivate : function ( e ) {
690+ var elem = e . target ;
691+
692+ if ( elem . nodeName . toLowerCase ( ) === "input" && elem . type === "radio" ) {
693+ return jQuery . data ( elem , "_change_data" , getVal ( elem ) ) ;
659694 }
660695 }
661696 } ,
662697 setup : function ( data , namespaces , fn ) {
663698 for ( var type in changeFilters ) {
664699 jQuery . event . add ( this , type + ".specialChange." + fn . guid , changeFilters [ type ] ) ;
665700 }
666-
667- // always want to listen for change for trigger
668- return false ;
701+
702+ return formElems . test ( this . nodeName ) ;
669703 } ,
670704 remove : function ( namespaces , fn ) {
671705 for ( var type in changeFilters ) {
672706 jQuery . event . remove ( this , type + ".specialChange" + ( fn ? "." + fn . guid : "" ) , changeFilters [ type ] ) ;
673707 }
708+
709+ return formElems . test ( this . nodeName ) ;
674710 }
675711} ;
676712
0 commit comments