Event: Optimize delegated event processing

Closes gh-3255
This commit is contained in:
Richard Gibson 2016-08-01 14:20:38 -04:00
parent 6acf4a7946
commit 76c5237cc4

View File

@ -355,51 +355,58 @@ jQuery.event = {
}, },
handlers: function( event, handlers ) { handlers: function( event, handlers ) {
var i, matches, sel, handleObj, var i, handleObj, sel, matchedHandlers, matchedSelectors,
handlerQueue = [], handlerQueue = [],
delegateCount = handlers.delegateCount, delegateCount = handlers.delegateCount,
cur = event.target; cur = event.target;
// Support: IE <=9
// Find delegate handlers // Find delegate handlers
// Black-hole SVG <use> instance trees (#13180) if ( delegateCount &&
//
// Support: Firefox <=42 // Support: IE <=9
// Avoid non-left-click in FF but don't block IE radio events (#3861, gh-2343) // Black-hole SVG <use> instance trees (trac-13180)
if ( delegateCount && cur.nodeType && cur.nodeType &&
( event.type !== "click" || isNaN( event.button ) || event.button < 1 ) ) {
// Support: Firefox <=42
// Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)
// https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click
// Support: IE 11 only
// ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343)
!( event.type === "click" && event.button >= 1 ) ) {
for ( ; cur !== this; cur = cur.parentNode || this ) { for ( ; cur !== this; cur = cur.parentNode || this ) {
// Don't check non-elements (#13208) // Don't check non-elements (#13208)
// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
if ( cur.nodeType === 1 && ( cur.disabled !== true || event.type !== "click" ) ) { if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) {
matches = []; matchedHandlers = [];
matchedSelectors = {};
for ( i = 0; i < delegateCount; i++ ) { for ( i = 0; i < delegateCount; i++ ) {
handleObj = handlers[ i ]; handleObj = handlers[ i ];
// Don't conflict with Object.prototype properties (#13203) // Don't conflict with Object.prototype properties (#13203)
sel = handleObj.selector + " "; sel = handleObj.selector + " ";
if ( matches[ sel ] === undefined ) { if ( matchedSelectors[ sel ] === undefined ) {
matches[ sel ] = handleObj.needsContext ? matchedSelectors[ sel ] = handleObj.needsContext ?
jQuery( sel, this ).index( cur ) > -1 : jQuery( sel, this ).index( cur ) > -1 :
jQuery.find( sel, this, null, [ cur ] ).length; jQuery.find( sel, this, null, [ cur ] ).length;
} }
if ( matches[ sel ] ) { if ( matchedSelectors[ sel ] ) {
matches.push( handleObj ); matchedHandlers.push( handleObj );
} }
} }
if ( matches.length ) { if ( matchedHandlers.length ) {
handlerQueue.push( { elem: cur, handlers: matches } ); handlerQueue.push( { elem: cur, handlers: matchedHandlers } );
} }
} }
} }
} }
// Add the remaining (directly-bound) handlers // Add the remaining (directly-bound) handlers
cur = this;
if ( delegateCount < handlers.length ) { if ( delegateCount < handlers.length ) {
handlerQueue.push( { elem: this, handlers: handlers.slice( delegateCount ) } ); handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );
} }
return handlerQueue; return handlerQueue;