@@ -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' ) ;
@@ -403,6 +404,7 @@ const kFlagPassive = 1 << 2;
403
404
const kFlagNodeStyle = 1 << 3 ;
404
405
const kFlagWeak = 1 << 4 ;
405
406
const kFlagRemoved = 1 << 5 ;
407
+ const kFlagResistStopPropagation = 1 << 6 ;
406
408
407
409
// The listeners for an EventTarget are maintained as a linked list.
408
410
// Unfortunately, the way EventTarget is defined, listeners are accounted
@@ -413,7 +415,7 @@ const kFlagRemoved = 1 << 5;
413
415
// slower.
414
416
class Listener {
415
417
constructor ( previous , listener , once , capture , passive ,
416
- isNodeStyleListener , weak ) {
418
+ isNodeStyleListener , weak , resistStopPropagation ) {
417
419
this . next = undefined ;
418
420
if ( previous !== undefined )
419
421
previous . next = this ;
@@ -431,6 +433,8 @@ class Listener {
431
433
flags |= kFlagNodeStyle ;
432
434
if ( weak )
433
435
flags |= kFlagWeak ;
436
+ if ( resistStopPropagation )
437
+ flags |= kFlagResistStopPropagation ;
434
438
this . flags = flags ;
435
439
436
440
this . removed = false ;
@@ -468,6 +472,9 @@ class Listener {
468
472
get weak ( ) {
469
473
return Boolean ( this . flags & kFlagWeak ) ;
470
474
}
475
+ get resistStopPropagation ( ) {
476
+ return Boolean ( this . flags & kFlagResistStopPropagation ) ;
477
+ }
471
478
get removed ( ) {
472
479
return Boolean ( this . flags & kFlagRemoved ) ;
473
480
}
@@ -564,6 +571,7 @@ class EventTarget {
564
571
signal,
565
572
isNodeStyleListener,
566
573
weak,
574
+ resistStopPropagation,
567
575
} = validateEventListenerOptions ( options ) ;
568
576
569
577
if ( ! validateEventListener ( listener ) ) {
@@ -588,16 +596,16 @@ class EventTarget {
588
596
// not prevent the event target from GC.
589
597
signal . addEventListener ( 'abort' , ( ) => {
590
598
this . removeEventListener ( type , listener , options ) ;
591
- } , { once : true , [ kWeakHandler ] : this } ) ;
599
+ } , { __proto__ : null , once : true , [ kWeakHandler ] : this , [ kResistStopPropagation ] : true } ) ;
592
600
}
593
601
594
602
let root = this [ kEvents ] . get ( type ) ;
595
603
596
604
if ( root === undefined ) {
597
- root = { size : 1 , next : undefined } ;
605
+ root = { size : 1 , next : undefined , resistStopPropagation : Boolean ( resistStopPropagation ) } ;
598
606
// This is the first handler in our linked list.
599
607
new Listener ( root , listener , once , capture , passive ,
600
- isNodeStyleListener , weak ) ;
608
+ isNodeStyleListener , weak , resistStopPropagation ) ;
601
609
this [ kNewListener ] (
602
610
root . size ,
603
611
type ,
@@ -624,8 +632,9 @@ class EventTarget {
624
632
}
625
633
626
634
new Listener ( previous , listener , once , capture , passive ,
627
- isNodeStyleListener , weak ) ;
635
+ isNodeStyleListener , weak , resistStopPropagation ) ;
628
636
root . size ++ ;
637
+ root . resistStopPropagation ||= Boolean ( resistStopPropagation ) ;
629
638
this [ kNewListener ] ( root . size , type , listener , once , capture , passive , weak ) ;
630
639
}
631
640
@@ -709,14 +718,21 @@ class EventTarget {
709
718
let handler = root . next ;
710
719
let next ;
711
720
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 ( ) ) {
714
728
// Cache the next item in case this iteration removes the current one
715
729
next = handler . next ;
716
730
717
- if ( handler . removed ) {
731
+ if ( handler . removed || ( event ?. [ kStop ] === true && ! handler . resistStopPropagation ) ) {
718
732
// Deal with the case an event is removed while event handlers are
719
733
// Being processed (removeEventListener called from a listener)
734
+ // And the case of event.stopImmediatePropagation() being called
735
+ // For events not flagged as resistStopPropagation
720
736
handler = next ;
721
737
continue ;
722
738
}
@@ -984,6 +1000,7 @@ function validateEventListenerOptions(options) {
984
1000
passive : Boolean ( options . passive ) ,
985
1001
signal : options . signal ,
986
1002
weak : options [ kWeakHandler ] ,
1003
+ resistStopPropagation : options [ kResistStopPropagation ] ?? false ,
987
1004
isNodeStyleListener : Boolean ( options [ kIsNodeStyleListener ] ) ,
988
1005
} ;
989
1006
}
@@ -1099,5 +1116,6 @@ module.exports = {
1099
1116
kRemoveListener,
1100
1117
kEvents,
1101
1118
kWeakHandler,
1119
+ kResistStopPropagation,
1102
1120
isEventTarget,
1103
1121
} ;
0 commit comments