@@ -27,8 +27,17 @@ function Event() {
2727 * @private
2828 */
2929 this . _listeners = new Map ( ) ;
30- this . _toRemove = [ ] ;
31- this . _insideRaiseEvent = false ;
30+ /**
31+ * @type {Map<Listener,Set<object>> }
32+ * @private
33+ */
34+ this . _toRemove = new Map ( ) ;
35+ /**
36+ * @type {Map<Listener,Set<object>> }
37+ * @private
38+ */
39+ this . _toAdd = new Map ( ) ;
40+ this . _invokingListeners = false ;
3241 this . _listenerCount = 0 ; // Tracks number of listener + scope pairs
3342}
3443
@@ -63,22 +72,34 @@ Event.prototype.addEventListener = function (listener, scope) {
6372 //>>includeStart('debug', pragmas.debug);
6473 Check . typeOf . func ( "listener" , listener ) ;
6574 //>>includeEnd('debug');
75+ const event = this ;
6676
67- if ( ! this . _listeners . has ( listener ) ) {
68- this . _listeners . set ( listener , new Set ( ) ) ;
69- }
70- const scopes = this . _listeners . get ( listener ) ;
71- if ( ! scopes . has ( scope ) ) {
72- scopes . add ( scope ) ;
73- this . _listenerCount ++ ;
77+ const listenerMap = event . _invokingListeners
78+ ? event . _toAdd
79+ : event . _listeners ;
80+ const added = addEventListener ( this , listenerMap , listener , scope ) ;
81+ if ( added ) {
82+ event . _listenerCount ++ ;
7483 }
7584
76- const event = this ;
7785 return function ( ) {
7886 event . removeEventListener ( listener , scope ) ;
7987 } ;
8088} ;
8189
90+ function addEventListener ( event , listenerMap , listener , scope ) {
91+ if ( ! listenerMap . has ( listener ) ) {
92+ listenerMap . set ( listener , new Set ( ) ) ;
93+ }
94+ const scopes = listenerMap . get ( listener ) ;
95+ if ( ! scopes . has ( scope ) ) {
96+ scopes . add ( scope ) ;
97+ return true ;
98+ }
99+
100+ return false ;
101+ }
102+
82103/**
83104 * Unregisters a previously registered callback.
84105 *
@@ -94,23 +115,47 @@ Event.prototype.removeEventListener = function (listener, scope) {
94115 Check . typeOf . func ( "listener" , listener ) ;
95116 //>>includeEnd('debug');
96117
97- const scopes = this . _listeners . get ( listener ) ;
118+ const removedFromListeners = removeEventListener (
119+ this ,
120+ this . _listeners ,
121+ listener ,
122+ scope ,
123+ ) ;
124+ const removedFromToAdd = removeEventListener (
125+ this ,
126+ this . _toAdd ,
127+ listener ,
128+ scope ,
129+ ) ;
130+
131+ const removed = removedFromListeners || removedFromToAdd ;
132+ if ( removed ) {
133+ this . _listenerCount -- ;
134+ }
135+
136+ return removed ;
137+ } ;
138+
139+ function removeEventListener ( event , listenerMap , listener , scope ) {
140+ const scopes = listenerMap . get ( listener ) ;
98141 if ( ! scopes || ! scopes . has ( scope ) ) {
99142 return false ;
100143 }
101144
102- if ( this . _insideRaiseEvent ) {
103- this . _toRemove . push ( { listener, scope } ) ;
145+ if ( event . _invokingListeners ) {
146+ if ( ! addEventListener ( event , event . _toRemove , listener , scope ) ) {
147+ // Already marked for removal
148+ return false ;
149+ }
104150 } else {
105151 scopes . delete ( scope ) ;
106152 if ( scopes . size === 0 ) {
107- this . _listeners . delete ( listener ) ;
153+ listenerMap . delete ( listener ) ;
108154 }
109155 }
110156
111- this . _listenerCount -- ;
112157 return true ;
113- } ;
158+ }
114159
115160/**
116161 * Raises the event by calling each registered listener with all supplied arguments.
@@ -121,7 +166,7 @@ Event.prototype.removeEventListener = function (listener, scope) {
121166 * @see Event#removeEventListener
122167 */
123168Event . prototype . raiseEvent = function ( ) {
124- this . _insideRaiseEvent = true ;
169+ this . _invokingListeners = true ;
125170
126171 for ( const [ listener , scopes ] of this . _listeners . entries ( ) ) {
127172 if ( ! defined ( listener ) ) {
@@ -133,19 +178,23 @@ Event.prototype.raiseEvent = function () {
133178 }
134179 }
135180
136- // Actually remove items marked for removal
137- if ( this . _toRemove . length > 0 ) {
138- for ( const { listener, scope } of this . _toRemove ) {
139- const scopes = this . _listeners . get ( listener ) ;
140- scopes . delete ( scope ) ;
141- if ( scopes . size === 0 ) {
142- this . _listeners . delete ( listener ) ;
143- }
181+ this . _invokingListeners = false ;
182+
183+ // Actually add items marked for addition
184+ for ( const [ listener , scopes ] of this . _toAdd . entries ( ) ) {
185+ for ( const scope of scopes ) {
186+ addEventListener ( this , this . _listeners , listener , scope ) ;
144187 }
145- this . _toRemove . length = 0 ;
146188 }
189+ this . _toAdd . clear ( ) ;
147190
148- this . _insideRaiseEvent = false ;
191+ // Actually remove items marked for removal
192+ for ( const [ listener , scopes ] of this . _toRemove . entries ( ) ) {
193+ for ( const scope of scopes ) {
194+ removeEventListener ( this , this . _listeners , listener , scope ) ;
195+ }
196+ }
197+ this . _toRemove . clear ( ) ;
149198} ;
150199
151200/**
0 commit comments