Skip to content

Commit 55ec6a7

Browse files
committed
Fixes #7340. Use a single capturing handler to simulate bubbling focusin/focusout event on non-IE browsers. Allow native DOM methods to fire events other than the currently active one back into jQuery.
1 parent 2d0bc7c commit 55ec6a7

File tree

2 files changed

+48
-9
lines changed

2 files changed

+48
-9
lines changed

src/event.js

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,10 @@ jQuery.event = {
7070
}
7171

7272
if ( !eventHandle ) {
73-
elemData.handle = eventHandle = function() {
73+
elemData.handle = eventHandle = function( e ) {
7474
// Handle the second event of a trigger and when
7575
// an event is called after a page has unloaded
76-
return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
76+
return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ?
7777
jQuery.event.handle.apply( eventHandle.elem, arguments ) :
7878
undefined;
7979
};
@@ -380,7 +380,7 @@ jQuery.event = {
380380
target[ "on" + targetType ] = null;
381381
}
382382

383-
jQuery.event.triggered = true;
383+
jQuery.event.triggered = event.type;
384384
target[ targetType ]();
385385
}
386386

@@ -391,7 +391,7 @@ jQuery.event = {
391391
target[ "on" + targetType ] = old;
392392
}
393393

394-
jQuery.event.triggered = false;
394+
jQuery.event.triggered = undefined;
395395
}
396396
}
397397
},
@@ -868,19 +868,33 @@ function trigger( type, elem, args ) {
868868
// Create "bubbling" focus and blur events
869869
if ( document.addEventListener ) {
870870
jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
871+
872+
// Attach a single capturing handler while someone wants focusin/focusout
873+
var attaches = 0;
874+
871875
jQuery.event.special[ fix ] = {
872876
setup: function() {
873-
this.addEventListener( orig, handler, true );
877+
if ( attaches++ === 0 ) {
878+
document.addEventListener( orig, handler, true );
879+
}
874880
},
875881
teardown: function() {
876-
this.removeEventListener( orig, handler, true );
882+
if ( --attaches === 0 ) {
883+
document.removeEventListener( orig, handler, true );
884+
}
877885
}
878886
};
879887

880-
function handler( e ) {
881-
e = jQuery.event.fix( e );
888+
function handler( donor ) {
889+
// Donor event is always a native one; fix it and switch its type.
890+
// Let focusin/out handler cancel the donor focus/blur event.
891+
var e = jQuery.event.fix( donor );
882892
e.type = fix;
883-
return jQuery.event.handle.call( this, e );
893+
e.originalEvent = {};
894+
jQuery.event.trigger( e, null, e.target );
895+
if ( e.isDefaultPrevented() ) {
896+
donor.preventDefault();
897+
}
884898
}
885899
});
886900
}

test/unit/event.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1966,6 +1966,31 @@ test("window resize", function() {
19661966
ok( !jQuery._data(window, "__events__"), "Make sure all the events are gone." );
19671967
});
19681968

1969+
test("focusin bubbles", function() {
1970+
expect(4);
1971+
1972+
var input = jQuery( '<input type="text" />' ).prependTo( "body" ),
1973+
order = 0;
1974+
1975+
jQuery( "body" ).bind( "focusin.focusinBubblesTest", function(){
1976+
equals( 1, order++, "focusin on the body second" );
1977+
});
1978+
1979+
input.bind( "focusin.focusinBubblesTest", function(){
1980+
equals( 0, order++, "focusin on the element first" );
1981+
});
1982+
1983+
// DOM focus method
1984+
input[0].focus();
1985+
// jQuery trigger, which calls DOM focus
1986+
order = 0;
1987+
input[0].blur();
1988+
input.trigger( "focus" );
1989+
1990+
input.remove();
1991+
jQuery( "body" ).unbind( "focusin.focusinBubblesTest" );
1992+
});
1993+
19691994
/*
19701995
test("jQuery(function($) {})", function() {
19711996
stop();

0 commit comments

Comments
 (0)