@@ -59,6 +59,7 @@ const kStop = Symbol('kStop');
59
59
const kTarget = Symbol ( 'kTarget' ) ;
60
60
const kHandlers = Symbol ( 'kHandlers' ) ;
61
61
const kWeakHandler = Symbol ( 'kWeak' ) ;
62
+ const kResistStopPropagation = Symbol ( 'kResistStopPropagation' ) ;
62
63
63
64
const kHybridDispatch = SymbolFor ( 'nodejs.internal.kHybridDispatch' ) ;
64
65
const kCreateEvent = Symbol ( 'kCreateEvent' ) ;
@@ -421,6 +422,7 @@ const kFlagPassive = 1 << 2;
421
422
const kFlagNodeStyle = 1 << 3 ;
422
423
const kFlagWeak = 1 << 4 ;
423
424
const kFlagRemoved = 1 << 5 ;
425
+ const kFlagResistStopPropagation = 1 << 6 ;
424
426
425
427
// The listeners for an EventTarget are maintained as a linked list.
426
428
// Unfortunately, the way EventTarget is defined, listeners are accounted
@@ -431,7 +433,7 @@ const kFlagRemoved = 1 << 5;
431
433
// slower.
432
434
class Listener {
433
435
constructor ( previous , listener , once , capture , passive ,
434
- isNodeStyleListener , weak ) {
436
+ isNodeStyleListener , weak , resistStopPropagation ) {
435
437
this . next = undefined ;
436
438
if ( previous !== undefined )
437
439
previous . next = this ;
@@ -449,6 +451,8 @@ class Listener {
449
451
flags |= kFlagNodeStyle ;
450
452
if ( weak )
451
453
flags |= kFlagWeak ;
454
+ if ( resistStopPropagation )
455
+ flags |= kFlagResistStopPropagation ;
452
456
this . flags = flags ;
453
457
454
458
this . removed = false ;
@@ -486,6 +490,9 @@ class Listener {
486
490
get weak ( ) {
487
491
return Boolean ( this . flags & kFlagWeak ) ;
488
492
}
493
+ get resistStopPropagation ( ) {
494
+ return Boolean ( this . flags & kFlagResistStopPropagation ) ;
495
+ }
489
496
get removed ( ) {
490
497
return Boolean ( this . flags & kFlagRemoved ) ;
491
498
}
@@ -583,6 +590,7 @@ class EventTarget {
583
590
signal,
584
591
isNodeStyleListener,
585
592
weak,
593
+ resistStopPropagation,
586
594
} = validateEventListenerOptions ( options ) ;
587
595
588
596
validateAbortSignal ( signal , 'options.signal' ) ;
@@ -609,16 +617,16 @@ class EventTarget {
609
617
// not prevent the event target from GC.
610
618
signal . addEventListener ( 'abort' , ( ) => {
611
619
this . removeEventListener ( type , listener , options ) ;
612
- } , { once : true , [ kWeakHandler ] : this } ) ;
620
+ } , { __proto__ : null , once : true , [ kWeakHandler ] : this , [ kResistStopPropagation ] : true } ) ;
613
621
}
614
622
615
623
let root = this [ kEvents ] . get ( type ) ;
616
624
617
625
if ( root === undefined ) {
618
- root = { size : 1 , next : undefined } ;
626
+ root = { size : 1 , next : undefined , resistStopPropagation : Boolean ( resistStopPropagation ) } ;
619
627
// This is the first handler in our linked list.
620
628
new Listener ( root , listener , once , capture , passive ,
621
- isNodeStyleListener , weak ) ;
629
+ isNodeStyleListener , weak , resistStopPropagation ) ;
622
630
this [ kNewListener ] (
623
631
root . size ,
624
632
type ,
@@ -645,8 +653,9 @@ class EventTarget {
645
653
}
646
654
647
655
new Listener ( previous , listener , once , capture , passive ,
648
- isNodeStyleListener , weak ) ;
656
+ isNodeStyleListener , weak , resistStopPropagation ) ;
649
657
root . size ++ ;
658
+ root . resistStopPropagation ||= Boolean ( resistStopPropagation ) ;
650
659
this [ kNewListener ] ( root . size , type , listener , once , capture , passive , weak ) ;
651
660
}
652
661
@@ -730,14 +739,21 @@ class EventTarget {
730
739
let handler = root . next ;
731
740
let next ;
732
741
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 ( ) ) {
735
749
// Cache the next item in case this iteration removes the current one
736
750
next = handler . next ;
737
751
738
- if ( handler . removed ) {
752
+ if ( handler . removed || ( event ?. [ kStop ] === true && ! handler . resistStopPropagation ) ) {
739
753
// Deal with the case an event is removed while event handlers are
740
754
// Being processed (removeEventListener called from a listener)
755
+ // And the case of event.stopImmediatePropagation() being called
756
+ // For events not flagged as resistStopPropagation
741
757
handler = next ;
742
758
continue ;
743
759
}
@@ -1005,6 +1021,7 @@ function validateEventListenerOptions(options) {
1005
1021
passive : Boolean ( options . passive ) ,
1006
1022
signal : options . signal ,
1007
1023
weak : options [ kWeakHandler ] ,
1024
+ resistStopPropagation : options [ kResistStopPropagation ] ?? false ,
1008
1025
isNodeStyleListener : Boolean ( options [ kIsNodeStyleListener ] ) ,
1009
1026
} ;
1010
1027
}
@@ -1132,5 +1149,6 @@ module.exports = {
1132
1149
kRemoveListener,
1133
1150
kEvents,
1134
1151
kWeakHandler,
1152
+ kResistStopPropagation,
1135
1153
isEventTarget,
1136
1154
} ;
0 commit comments