🌐 AI搜索 & 代理 主页
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 56 additions & 46 deletions src/event.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import jQuery from "./core.js";
import document from "./var/document.js";
import documentElement from "./var/documentElement.js";
import rnothtmlwhite from "./var/rnothtmlwhite.js";
import rcheckableType from "./var/rcheckableType.js";
import slice from "./var/slice.js";
import isIE from "./var/isIE.js";
import acceptData from "./data/var/acceptData.js";
import dataPriv from "./data/var/dataPriv.js";
import nodeName from "./core/nodeName.js";
Expand All @@ -21,16 +21,6 @@ function returnFalse() {
return false;
}

// Support: IE <=9 - 11+
// focus() and blur() are asynchronous, except when they are no-op.
// So expect focus to be synchronous when the element is already active,
// and blur to be synchronous when the element is not already active.
// (focus and blur are always synchronous in other supported browsers,
// this just defines when we can count on it).
function expectSync( elem, type ) {
return ( elem === document.activeElement ) === ( type === "focus" );
}

function on( elem, types, selector, data, fn, one ) {
var origFn, type;

Expand Down Expand Up @@ -459,7 +449,7 @@ jQuery.event = {
el.click && nodeName( el, "input" ) ) {

// dataPriv.set( el, "click", ... )
leverageNative( el, "click", returnTrue );
leverageNative( el, "click", true );
}

// Return false to allow normal processing in the caller
Expand Down Expand Up @@ -511,10 +501,10 @@ jQuery.event = {
// synthetic events by interrupting progress until reinvoked in response to
// *native* events that it fires directly, ensuring that state changes have
// already occurred before other listeners are invoked.
function leverageNative( el, type, expectSync ) {
function leverageNative( el, type, isSetup ) {

// Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add
if ( !expectSync ) {
// Missing `isSetup` indicates a trigger call, which must force setup through jQuery.event.add
if ( !isSetup ) {
if ( dataPriv.get( el, type ) === undefined ) {
jQuery.event.add( el, type, returnTrue );
}
Expand All @@ -526,15 +516,13 @@ function leverageNative( el, type, expectSync ) {
jQuery.event.add( el, type, {
namespace: false,
handler: function( event ) {
var notAsync, result,
var result,
saved = dataPriv.get( this, type );

if ( ( event.isTrigger & 1 ) && this[ type ] ) {

// Interrupt processing of the outer synthetic .trigger()ed event
// Saved data should be false in such cases, but might be a leftover capture object
// from an async native handler (gh-4350)
if ( !saved.length ) {
if ( !saved ) {

// Store arguments for use when handling the inner native event
// There will always be at least one argument (an event object), so this array
Expand All @@ -543,28 +531,17 @@ function leverageNative( el, type, expectSync ) {
dataPriv.set( this, type, saved );

// Trigger the native event and capture its result
// Support: IE <=9 - 11+
// focus() and blur() are asynchronous
notAsync = expectSync( this, type );
this[ type ]();
result = dataPriv.get( this, type );
if ( saved !== result || notAsync ) {
dataPriv.set( this, type, false );
} else {
result = {};
}
dataPriv.set( this, type, false );

if ( saved !== result ) {

// Cancel the outer synthetic event
event.stopImmediatePropagation();
event.preventDefault();

// Support: Chrome 86+
// In Chrome, if an element having a focusout handler is blurred by
// clicking outside of it, it invokes the handler synchronously. If
// that handler calls `.remove()` on the element, the data is cleared,
// leaving `result` undefined. We need to guard against this.
return result && result.value;
return result;
}

// If this is an inner synthetic event for an event with a bubbling surrogate
Expand All @@ -582,16 +559,11 @@ function leverageNative( el, type, expectSync ) {
} else if ( saved.length ) {

// ...and capture the result
dataPriv.set( this, type, {
value: jQuery.event.trigger(

// Support: IE <=9 - 11+
// Extend with the prototype to reset the above stopImmediatePropagation()
jQuery.extend( saved[ 0 ], jQuery.Event.prototype ),
saved.slice( 1 ),
this
)
} );
dataPriv.set( this, type, jQuery.event.trigger(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gibson042 One thing to note - while #4350 which added this wrapping was mainly aimed at IE with its async focus handlers, there has been a report about this also affecting Chrome somehow:
#4350 (comment)

I'm not sure if we can do anything about it due to the lack of data, though.

saved[ 0 ],
saved.slice( 1 ),
this
) );

// Abort handling of the native event
event.stopImmediatePropagation();
Expand Down Expand Up @@ -724,6 +696,29 @@ jQuery.each( {
}, jQuery.event.addProp );

jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) {

// Support: IE 11+
// Attach a single focusin/focusout handler on the document while someone wants focus/blur.
// This is because the former are synchronous in IE while the latter are async. In other
// browsers, all those handlers are invoked synchronously.
function focusMappedHandler( nativeEvent ) {

// `eventHandle` would already wrap the event, but we need to change the `type` here.
var event = jQuery.event.fix( nativeEvent );
event.type = nativeEvent.type === "focusin" ? "focus" : "blur";
event.isSimulated = true;

// focus/blur don't bubble while focusin/focusout do; simulate the former by only
// invoking the handler at the lower level.
if ( event.target === event.currentTarget ) {

// The setup part calls `leverageNative`, which, in turn, calls
// `jQuery.event.add`, so event handle will already have been set
// by this point.
dataPriv.get( this, "handle" )( event );
}
}

jQuery.event.special[ type ] = {

// Utilize native event if possible so blur/focus sequence is correct
Expand All @@ -732,10 +727,15 @@ jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateTyp
// Claim the first handler
// dataPriv.set( this, "focus", ... )
// dataPriv.set( this, "blur", ... )
leverageNative( this, type, expectSync );
leverageNative( this, type, true );

if ( isIE ) {
this.addEventListener( delegateType, focusMappedHandler );
} else {

// Return false to allow normal processing in the caller
return false;
// Return false to allow normal processing in the caller
return false;
}
},
trigger: function() {

Expand All @@ -746,6 +746,16 @@ jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateTyp
return true;
},

teardown: function() {
if ( isIE ) {
this.removeEventListener( delegateType, focusMappedHandler );
} else {

// Return false to indicate standard teardown should be applied
return false;
}
},

// Suppress native focus or blur if we're currently inside
// a leveraged native-event stack
_default: function( event ) {
Expand Down
Loading