@@ -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' ) ;
@@ -421,6 +422,7 @@ const kFlagPassive = 1 << 2;
421422const kFlagNodeStyle = 1 << 3 ;
422423const kFlagWeak = 1 << 4 ;
423424const kFlagRemoved = 1 << 5 ;
425+ const kFlagResistStopPropagation = 1 << 6 ;
424426
425427// The listeners for an EventTarget are maintained as a linked list.
426428// Unfortunately, the way EventTarget is defined, listeners are accounted
@@ -431,7 +433,7 @@ const kFlagRemoved = 1 << 5;
431433// slower.
432434class Listener {
433435 constructor ( previous , listener , once , capture , passive ,
434- isNodeStyleListener , weak ) {
436+ isNodeStyleListener , weak , resistStopPropagation ) {
435437 this . next = undefined ;
436438 if ( previous !== undefined )
437439 previous . next = this ;
@@ -449,6 +451,8 @@ class Listener {
449451 flags |= kFlagNodeStyle ;
450452 if ( weak )
451453 flags |= kFlagWeak ;
454+ if ( resistStopPropagation )
455+ flags |= kFlagResistStopPropagation ;
452456 this . flags = flags ;
453457
454458 this . removed = false ;
@@ -486,6 +490,9 @@ class Listener {
486490 get weak ( ) {
487491 return Boolean ( this . flags & kFlagWeak ) ;
488492 }
493+ get resistStopPropagation ( ) {
494+ return Boolean ( this . flags & kFlagResistStopPropagation ) ;
495+ }
489496 get removed ( ) {
490497 return Boolean ( this . flags & kFlagRemoved ) ;
491498 }
@@ -583,6 +590,7 @@ class EventTarget {
583590 signal,
584591 isNodeStyleListener,
585592 weak,
593+ resistStopPropagation,
586594 } = validateEventListenerOptions ( options ) ;
587595
588596 validateAbortSignal ( signal , 'options.signal' ) ;
@@ -609,16 +617,16 @@ class EventTarget {
609617 // not prevent the event target from GC.
610618 signal . addEventListener ( 'abort' , ( ) => {
611619 this . removeEventListener ( type , listener , options ) ;
612- } , { once : true , [ kWeakHandler ] : this } ) ;
620+ } , { __proto__ : null , once : true , [ kWeakHandler ] : this , [ kResistStopPropagation ] : true } ) ;
613621 }
614622
615623 let root = this [ kEvents ] . get ( type ) ;
616624
617625 if ( root === undefined ) {
618- root = { size : 1 , next : undefined } ;
626+ root = { size : 1 , next : undefined , resistStopPropagation : Boolean ( resistStopPropagation ) } ;
619627 // This is the first handler in our linked list.
620628 new Listener ( root , listener , once , capture , passive ,
621- isNodeStyleListener , weak ) ;
629+ isNodeStyleListener , weak , resistStopPropagation ) ;
622630 this [ kNewListener ] (
623631 root . size ,
624632 type ,
@@ -645,8 +653,9 @@ class EventTarget {
645653 }
646654
647655 new Listener ( previous , listener , once , capture , passive ,
648- isNodeStyleListener , weak ) ;
656+ isNodeStyleListener , weak , resistStopPropagation ) ;
649657 root . size ++ ;
658+ root . resistStopPropagation ||= Boolean ( resistStopPropagation ) ;
650659 this [ kNewListener ] ( root . size , type , listener , once , capture , passive , weak ) ;
651660 }
652661
@@ -730,14 +739,21 @@ class EventTarget {
730739 let handler = root . next ;
731740 let next ;
732741
733- while ( handler !== undefined &&
734- ( handler . passive || event ?. [ kStop ] !== true ) ) {
742+ const iterationCondition = ( ) => {
743+ if ( handler === undefined ) {
744+ return false ;
745+ }
746+ return root . resistStopPropagation || handler . passive || event ?. [ kStop ] !== true ;
747+ } ;
748+ while ( iterationCondition ( ) ) {
735749 // Cache the next item in case this iteration removes the current one
736750 next = handler . next ;
737751
738- if ( handler . removed ) {
752+ if ( handler . removed || ( event ?. [ kStop ] === true && ! handler . resistStopPropagation ) ) {
739753 // Deal with the case an event is removed while event handlers are
740754 // Being processed (removeEventListener called from a listener)
755+ // And the case of event.stopImmediatePropagation() being called
756+ // For events not flagged as resistStopPropagation
741757 handler = next ;
742758 continue ;
743759 }
@@ -1005,6 +1021,7 @@ function validateEventListenerOptions(options) {
10051021 passive : Boolean ( options . passive ) ,
10061022 signal : options . signal ,
10071023 weak : options [ kWeakHandler ] ,
1024+ resistStopPropagation : options [ kResistStopPropagation ] ?? false ,
10081025 isNodeStyleListener : Boolean ( options [ kIsNodeStyleListener ] ) ,
10091026 } ;
10101027}
@@ -1132,5 +1149,6 @@ module.exports = {
11321149 kRemoveListener,
11331150 kEvents,
11341151 kWeakHandler,
1152+ kResistStopPropagation,
11351153 isEventTarget,
11361154} ;
0 commit comments