@@ -59,6 +59,7 @@ const kStop = Symbol('kStop');
5959const kTarget = Symbol ( 'kTarget' ) ;
6060const kHandlers = Symbol ( 'kHandlers' ) ;
6161const kWeakHandler = Symbol ( 'kWeak' ) ;
62+ const kResistStopPropagation = Symbol ( 'kResistStopPropagation' ) ;
6263
6364const kHybridDispatch = SymbolFor ( 'nodejs.internal.kHybridDispatch' ) ;
6465const kCreateEvent = Symbol ( 'kCreateEvent' ) ;
@@ -403,6 +404,7 @@ const kFlagPassive = 1 << 2;
403404const kFlagNodeStyle = 1 << 3 ;
404405const kFlagWeak = 1 << 4 ;
405406const kFlagRemoved = 1 << 5 ;
407+ const kFlagResistStopPropagation = 1 << 6 ;
406408
407409// The listeners for an EventTarget are maintained as a linked list.
408410// Unfortunately, the way EventTarget is defined, listeners are accounted
@@ -413,7 +415,7 @@ const kFlagRemoved = 1 << 5;
413415// slower.
414416class Listener {
415417 constructor ( previous , listener , once , capture , passive ,
416- isNodeStyleListener , weak ) {
418+ isNodeStyleListener , weak , resistStopPropagation ) {
417419 this . next = undefined ;
418420 if ( previous !== undefined )
419421 previous . next = this ;
@@ -431,6 +433,8 @@ class Listener {
431433 flags |= kFlagNodeStyle ;
432434 if ( weak )
433435 flags |= kFlagWeak ;
436+ if ( resistStopPropagation )
437+ flags |= kFlagResistStopPropagation ;
434438 this . flags = flags ;
435439
436440 this . removed = false ;
@@ -468,6 +472,9 @@ class Listener {
468472 get weak ( ) {
469473 return Boolean ( this . flags & kFlagWeak ) ;
470474 }
475+ get resistStopPropagation ( ) {
476+ return Boolean ( this . flags & kFlagResistStopPropagation ) ;
477+ }
471478 get removed ( ) {
472479 return Boolean ( this . flags & kFlagRemoved ) ;
473480 }
@@ -564,6 +571,7 @@ class EventTarget {
564571 signal,
565572 isNodeStyleListener,
566573 weak,
574+ resistStopPropagation,
567575 } = validateEventListenerOptions ( options ) ;
568576
569577 if ( ! validateEventListener ( listener ) ) {
@@ -588,16 +596,16 @@ class EventTarget {
588596 // not prevent the event target from GC.
589597 signal . addEventListener ( 'abort' , ( ) => {
590598 this . removeEventListener ( type , listener , options ) ;
591- } , { once : true , [ kWeakHandler ] : this } ) ;
599+ } , { __proto__ : null , once : true , [ kWeakHandler ] : this , [ kResistStopPropagation ] : true } ) ;
592600 }
593601
594602 let root = this [ kEvents ] . get ( type ) ;
595603
596604 if ( root === undefined ) {
597- root = { size : 1 , next : undefined } ;
605+ root = { size : 1 , next : undefined , resistStopPropagation : Boolean ( resistStopPropagation ) } ;
598606 // This is the first handler in our linked list.
599607 new Listener ( root , listener , once , capture , passive ,
600- isNodeStyleListener , weak ) ;
608+ isNodeStyleListener , weak , resistStopPropagation ) ;
601609 this [ kNewListener ] (
602610 root . size ,
603611 type ,
@@ -624,8 +632,9 @@ class EventTarget {
624632 }
625633
626634 new Listener ( previous , listener , once , capture , passive ,
627- isNodeStyleListener , weak ) ;
635+ isNodeStyleListener , weak , resistStopPropagation ) ;
628636 root . size ++ ;
637+ root . resistStopPropagation ||= Boolean ( resistStopPropagation ) ;
629638 this [ kNewListener ] ( root . size , type , listener , once , capture , passive , weak ) ;
630639 }
631640
@@ -709,14 +718,21 @@ class EventTarget {
709718 let handler = root . next ;
710719 let next ;
711720
712- while ( handler !== undefined &&
713- ( handler . passive || event ?. [ kStop ] !== true ) ) {
721+ const iterationCondition = ( ) => {
722+ if ( handler === undefined ) {
723+ return false ;
724+ }
725+ return root . resistStopPropagation || handler . passive || event ?. [ kStop ] !== true ;
726+ } ;
727+ while ( iterationCondition ( ) ) {
714728 // Cache the next item in case this iteration removes the current one
715729 next = handler . next ;
716730
717- if ( handler . removed ) {
731+ if ( handler . removed || ( event ?. [ kStop ] === true && ! handler . resistStopPropagation ) ) {
718732 // Deal with the case an event is removed while event handlers are
719733 // Being processed (removeEventListener called from a listener)
734+ // And the case of event.stopImmediatePropagation() being called
735+ // For events not flagged as resistStopPropagation
720736 handler = next ;
721737 continue ;
722738 }
@@ -984,6 +1000,7 @@ function validateEventListenerOptions(options) {
9841000 passive : Boolean ( options . passive ) ,
9851001 signal : options . signal ,
9861002 weak : options [ kWeakHandler ] ,
1003+ resistStopPropagation : options [ kResistStopPropagation ] ?? false ,
9871004 isNodeStyleListener : Boolean ( options [ kIsNodeStyleListener ] ) ,
9881005 } ;
9891006}
@@ -1099,5 +1116,6 @@ module.exports = {
10991116 kRemoveListener,
11001117 kEvents,
11011118 kWeakHandler,
1119+ kResistStopPropagation,
11021120 isEventTarget,
11031121} ;
0 commit comments