Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit527fb3d

Browse files
authored
Event: Increase robustness of an inner native event in leverageNative
In Firefox, alert displayed just before blurring an element dispatchesthe native blur event twice which tripped the jQuery logic if a jQuery blurhandler was not attached before the trigger call.This was because the `leverageNative` logic part for triggering first checked ifsetup was done before (which, for example, is done if a jQuery handler wasregistered before for this element+event pair) and - if it was not - addeda dummy handler that just returned `true`. The `leverageNative` logic made that`true` then saved into private data, replacing the previous `saved` array. Since`true` passed the truthy check, the second native inner handler treated `true`as an array, crashing on the `slice` call.The same issue could happen if a handler returning `true` is attached beforetriggering. A bare `length` check would not be enough as the user handler mayreturn an array-like as well. To remove this potential data shape clash, capturethe inner result in an object with a `value` property instead of saving itdirectly.Since it's impossible to call `alert()` in unit tests, simulate the issue byreplacing the `addEventListener` method on a test button with a version thatcalls attached blur handlers twice.Fixesgh-5459Closesgh-5466Refgh-5236
1 parent5880e02 commit527fb3d

File tree

2 files changed

+97
-18
lines changed

2 files changed

+97
-18
lines changed

‎src/event.js

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -519,14 +519,29 @@ function leverageNative( el, type, isSetup ) {
519519
varresult,
520520
saved=dataPriv.get(this,type);
521521

522+
// This controller function is invoked under multiple circumstances,
523+
// differentiated by the stored value in `saved`:
524+
// 1. For an outer synthetic `.trigger()`ed event (detected by
525+
// `event.isTrigger & 1` and non-array `saved`), it records arguments
526+
// as an array and fires an [inner] native event to prompt state
527+
// changes that should be observed by registered listeners (such as
528+
// checkbox toggling and focus updating), then clears the stored value.
529+
// 2. For an [inner] native event (detected by `saved` being
530+
// an array), it triggers an inner synthetic event, records the
531+
// result, and preempts propagation to further jQuery listeners.
532+
// 3. For an inner synthetic event (detected by `event.isTrigger & 1` and
533+
// array `saved`), it prevents double-propagation of surrogate events
534+
// but otherwise allows everything to proceed (particularly including
535+
// further listeners).
536+
// Possible `saved` data shapes: `[...], `{ value }`, `false`.
522537
if((event.isTrigger&1)&&this[type]){
523538

524539
// Interrupt processing of the outer synthetic .trigger()ed event
525-
if(!saved){
540+
if(!saved.length){
526541

527542
// Store arguments for use when handling the inner native event
528-
// There will always be at least one argument (an event object), so this array
529-
// will not be confused with a leftover capture object.
543+
// There will always be at least one argument (an event object),
544+
//so this arraywill not be confused with a leftover capture object.
530545
saved=slice.call(arguments);
531546
dataPriv.set(this,type,saved);
532547

@@ -541,29 +556,35 @@ function leverageNative( el, type, isSetup ) {
541556
event.stopImmediatePropagation();
542557
event.preventDefault();
543558

544-
returnresult;
559+
// Support: Chrome 86+
560+
// In Chrome, if an element having a focusout handler is
561+
// blurred by clicking outside of it, it invokes the handler
562+
// synchronously. If that handler calls `.remove()` on
563+
// the element, the data is cleared, leaving `result`
564+
// undefined. We need to guard against this.
565+
returnresult&&result.value;
545566
}
546567

547-
// If this is an inner synthetic event for an event with a bubbling surrogate
548-
// (focus or blur), assume that the surrogate already propagated from triggering
549-
// the native event and prevent that from happening again here.
550-
// This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the
551-
// bubbling surrogate propagates *after* the non-bubbling base), but that seems
552-
// less bad than duplication.
568+
// If this is an inner synthetic event for an event with a bubbling
569+
// surrogate (focus or blur), assume that the surrogate already
570+
// propagated from triggering the native event and prevent that
571+
// from happening again here.
553572
}elseif((jQuery.event.special[type]||{}).delegateType){
554573
event.stopPropagation();
555574
}
556575

557-
// If this is a native event triggered above, everything is now in order
558-
// Fire an inner synthetic event with the original arguments
559-
}elseif(saved){
576+
// If this is a native event triggered above, everything is now in order.
577+
// Fire an inner synthetic event with the original arguments.
578+
}elseif(saved.length){
560579

561580
// ...and capture the result
562-
dataPriv.set(this,type,jQuery.event.trigger(
563-
saved[0],
564-
saved.slice(1),
565-
this
566-
));
581+
dataPriv.set(this,type,{
582+
value:jQuery.event.trigger(
583+
saved[0],
584+
saved.slice(1),
585+
this
586+
)
587+
});
567588

568589
// Abort handling of the native event by all jQuery handlers while allowing
569590
// native handlers on the same element to run. On target, this is achieved

‎test/unit/event.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3502,6 +3502,64 @@ QUnit.test( "trigger(focus) fires native & jQuery handlers (gh-5015)", function(
35023502
input.trigger("focus");
35033503
});
35043504

3505+
QUnit.test("duplicate native blur doesn't crash (gh-5459)",function(assert){
3506+
assert.expect(4);
3507+
3508+
functionpatchAddEventListener(elem){
3509+
varnativeAddEvent=elem[0].addEventListener;
3510+
3511+
// Support: Firefox 124+
3512+
// In Firefox, alert displayed just before blurring an element
3513+
// dispatches the native blur event twice which tripped the jQuery
3514+
// logic. We cannot call `alert()` in unit tests; simulate the
3515+
// behavior by overwriting the native `addEventListener` with
3516+
// a version that calls blur handlers twice.
3517+
//
3518+
// Such a simulation allows us to test whether `leverageNative`
3519+
// logic correctly differentiates between data saved by outer/inner
3520+
// handlers, so it's useful even without the Firefox bug.
3521+
elem[0].addEventListener=function(eventName,handler){
3522+
varfinalHandler;
3523+
if(eventName==="blur"){
3524+
finalHandler=functionwrappedHandler(){
3525+
handler.apply(this,arguments);
3526+
returnhandler.apply(this,arguments);
3527+
};
3528+
}else{
3529+
finalHandler=handler;
3530+
}
3531+
returnnativeAddEvent.call(this,eventName,finalHandler);
3532+
};
3533+
}
3534+
3535+
functionrunTest(handler,message){
3536+
varbutton=jQuery("<button></button>");
3537+
3538+
patchAddEventListener(button);
3539+
button.appendTo("#qunit-fixture");
3540+
3541+
if(handler){
3542+
button.on("blur",handler);
3543+
}
3544+
button.on("focus",function(){
3545+
button.trigger("blur");
3546+
assert.ok(true,"Did not crash ("+message+")");
3547+
});
3548+
button.trigger("focus");
3549+
}
3550+
3551+
runTest(undefined,"no prior handler");
3552+
runTest(function(){
3553+
returntrue;
3554+
},"prior handler returning true");
3555+
runTest(function(){
3556+
return{length:42};
3557+
},"prior handler returning an array-like");
3558+
runTest(function(){
3559+
return{value:42};
3560+
},"prior handler returning `{ value }`");
3561+
});
3562+
35053563
// TODO replace with an adaptation of
35063564
// https://github.com/jquery/jquery/pull/1367/files#diff-a215316abbaabdf71857809e8673ea28R2464
35073565
(function(){

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp