mirror of
https://github.com/jquery/jquery.git
synced 2024-11-23 02:54:22 +00:00
Event: Make trigger(focus/blur/click) work with native handlers
In `leverageNative`, instead of calling `event.stopImmediatePropagation()` which would abort both native & jQuery handlers, set the wrapper's `isImmediatePropagationStopped` property to a function returning `true`. Since for each element + type pair jQuery attaches only one native handler, there is also only one wrapper jQuery event so this achieves the goal: on the target element jQuery handlers don't fire but native ones do. Unfortunately, this workaround doesn't work for handlers on ancestors - since the native event is re-wrapped by a jQuery one on each level of the propagation, the only way to stop it for jQuery was to stop it for everyone via native `stopPropagation()`. This is not a problem for `focus`/`blur` which don't bubble, but it does also stop `click` on checkboxes and radios. We accept this limitation. Fixes gh-5015 Closes gh-5228
This commit is contained in:
parent
ce60d31893
commit
6ad3651dbf
16
src/event.js
16
src/event.js
@ -545,8 +545,8 @@ function leverageNative( el, type, isSetup ) {
|
||||
}
|
||||
|
||||
// If this is an inner synthetic event for an event with a bubbling surrogate
|
||||
// (focus or blur), assume that the surrogate already propagated from triggering the
|
||||
// native event and prevent that from happening again here.
|
||||
// (focus or blur), assume that the surrogate already propagated from triggering
|
||||
// the native event and prevent that from happening again here.
|
||||
// This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the
|
||||
// bubbling surrogate propagates *after* the non-bubbling base), but that seems
|
||||
// less bad than duplication.
|
||||
@ -565,8 +565,16 @@ function leverageNative( el, type, isSetup ) {
|
||||
this
|
||||
) );
|
||||
|
||||
// Abort handling of the native event
|
||||
event.stopImmediatePropagation();
|
||||
// Abort handling of the native event by all jQuery handlers while allowing
|
||||
// native handlers on the same element to run. On target, this is achieved
|
||||
// by stopping immediate propagation just on the jQuery event. However,
|
||||
// the native event is re-wrapped by a jQuery one on each level of the
|
||||
// propagation so the only way to stop it for jQuery is to stop it for
|
||||
// everyone via native `stopPropagation()`. This is not a problem for
|
||||
// focus/blur which don't bubble, but it does also stop click on checkboxes
|
||||
// and radios. We accept this limitation.
|
||||
event.stopPropagation();
|
||||
event.isImmediatePropagationStopped = returnTrue;
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
@ -3423,6 +3423,36 @@ QUnit.test( "trigger(focus) works after focusing when hidden (gh-4950)", functio
|
||||
assert.equal( document.activeElement, input[ 0 ], "input has focus" );
|
||||
} );
|
||||
|
||||
QUnit.test( "trigger(focus) fires native & jQuery handlers (gh-5015)", function( assert ) {
|
||||
assert.expect( 3 );
|
||||
|
||||
var input = jQuery( "<input />" ),
|
||||
|
||||
// Support: IE 9 - 11+
|
||||
// focus is async in IE; we now emulate it via sync focusin in jQuery
|
||||
// but this test also attaches native handlers.
|
||||
done = assert.async( 3 );
|
||||
|
||||
input.appendTo( "#qunit-fixture" );
|
||||
|
||||
input[ 0 ].addEventListener( "focus", function() {
|
||||
assert.ok( true, "1st native handler fired" );
|
||||
done();
|
||||
} );
|
||||
|
||||
input.on( "focus", function() {
|
||||
assert.ok( true, "jQuery handler fired" );
|
||||
done();
|
||||
} );
|
||||
|
||||
input[ 0 ].addEventListener( "focus", function() {
|
||||
assert.ok( true, "2nd native handler fired" );
|
||||
done();
|
||||
} );
|
||||
|
||||
input.trigger( "focus" );
|
||||
} );
|
||||
|
||||
// TODO replace with an adaptation of
|
||||
// https://github.com/jquery/jquery/pull/1367/files#diff-a215316abbaabdf71857809e8673ea28R2464
|
||||
( function() {
|
||||
@ -3431,10 +3461,13 @@ QUnit.test( "trigger(focus) works after focusing when hidden (gh-4950)", functio
|
||||
checkbox: "<input type='checkbox'>",
|
||||
radio: "<input type='radio'>"
|
||||
},
|
||||
makeTestFor3751
|
||||
function( type, html ) {
|
||||
makeTestForGh3751( type, html );
|
||||
makeTestForGh5015( type, html );
|
||||
}
|
||||
);
|
||||
|
||||
function makeTestFor3751( type, html ) {
|
||||
function makeTestForGh3751( type, html ) {
|
||||
var testName = "native-backed namespaced clicks are handled correctly (gh-3751) - " + type;
|
||||
QUnit.test( testName, function( assert ) {
|
||||
assert.expect( 2 );
|
||||
@ -3461,4 +3494,30 @@ QUnit.test( "trigger(focus) works after focusing when hidden (gh-4950)", functio
|
||||
target.trigger( "click.fired" );
|
||||
} );
|
||||
}
|
||||
|
||||
function makeTestForGh5015( type, html ) {
|
||||
var testName = "trigger(click) fires native & jQuery handlers (gh-5015) - " + type;
|
||||
QUnit.test( testName, function( assert ) {
|
||||
assert.expect( 3 );
|
||||
|
||||
var parent = supportjQuery( "<div class='parent'>" + html + "</div>" ),
|
||||
input = jQuery( parent[ 0 ].firstChild );
|
||||
|
||||
parent.appendTo( "#qunit-fixture" );
|
||||
|
||||
input[ 0 ].addEventListener( "click", function() {
|
||||
assert.ok( true, "1st native handler fired" );
|
||||
} );
|
||||
|
||||
input.on( "click", function() {
|
||||
assert.ok( true, "jQuery handler fired" );
|
||||
} );
|
||||
|
||||
input[ 0 ].addEventListener( "click", function() {
|
||||
assert.ok( true, "2nd native handler fired" );
|
||||
} );
|
||||
|
||||
input.trigger( "click" );
|
||||
} );
|
||||
}
|
||||
} )();
|
||||
|
Loading…
Reference in New Issue
Block a user