@@ -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 {
433435constructor ( previous , listener , once , capture , passive ,
434- isNodeStyleListener , weak ) {
436+ isNodeStyleListener , weak , resistStopPropagation ) {
435437this . next = undefined ;
436438if ( previous !== undefined )
437439previous . next = this ;
@@ -449,6 +451,8 @@ class Listener{
449451flags |= kFlagNodeStyle ;
450452if ( weak )
451453flags |= kFlagWeak ;
454+ if ( resistStopPropagation )
455+ flags |= kFlagResistStopPropagation ;
452456this . flags = flags ;
453457
454458this . removed = false ;
@@ -486,6 +490,9 @@ class Listener{
486490get weak ( ) {
487491return Boolean ( this . flags & kFlagWeak ) ;
488492}
493+ get resistStopPropagation ( ) {
494+ return Boolean ( this . flags & kFlagResistStopPropagation ) ;
495+ }
489496get removed ( ) {
490497return Boolean ( this . flags & kFlagRemoved ) ;
491498}
@@ -583,6 +590,7 @@ class EventTarget{
583590 signal,
584591 isNodeStyleListener,
585592 weak,
593+ resistStopPropagation,
586594} = validateEventListenerOptions ( options ) ;
587595
588596validateAbortSignal ( signal , 'options.signal' ) ;
@@ -609,16 +617,16 @@ class EventTarget{
609617// not prevent the event target from GC.
610618signal . addEventListener ( 'abort' , ( ) => {
611619this . removeEventListener ( type , listener , options ) ;
612- } , { once : true , [ kWeakHandler ] : this } ) ;
620+ } , { __proto__ : null , once : true , [ kWeakHandler ] : this , [ kResistStopPropagation ] : true } ) ;
613621}
614622
615623let root = this [ kEvents ] . get ( type ) ;
616624
617625if ( 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.
620628new Listener ( root , listener , once , capture , passive ,
621- isNodeStyleListener , weak ) ;
629+ isNodeStyleListener , weak , resistStopPropagation ) ;
622630this [ kNewListener ] (
623631root . size ,
624632type ,
@@ -645,8 +653,9 @@ class EventTarget{
645653}
646654
647655new Listener ( previous , listener , once , capture , passive ,
648- isNodeStyleListener , weak ) ;
656+ isNodeStyleListener , weak , resistStopPropagation ) ;
649657root . size ++ ;
658+ root . resistStopPropagation ||= Boolean ( resistStopPropagation ) ;
650659this [ kNewListener ] ( root . size , type , listener , once , capture , passive , weak ) ;
651660}
652661
@@ -730,14 +739,21 @@ class EventTarget{
730739let handler = root . next ;
731740let next ;
732741
733- while ( handler !== undefined &&
734- ( handler . passive || event ?. [ kStop ] !== true ) ) {
742+ const iterationCondition = ( ) => {
743+ if ( root . resistStopPropagation ) {
744+ return handler !== undefined ;
745+ }
746+ return handler !== undefined && ( handler . passive || event ?. [ kStop ] !== true ) ;
747+ } ;
748+ while ( iterationCondition ( ) ) {
735749// Cache the next item in case this iteration removes the current one
736750next = 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
741757handler = next ;
742758continue ;
743759}
@@ -1005,6 +1021,7 @@ function validateEventListenerOptions(options){
10051021passive : Boolean ( options . passive ) ,
10061022signal : options . signal ,
10071023weak : options [ kWeakHandler ] ,
1024+ resistStopPropagation : options [ kResistStopPropagation ] ?? false ,
10081025isNodeStyleListener : 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