@@ -138,6 +138,15 @@ var MOZ_HACK_REGEXP = /^moz([A-Z])/;
138
138
var MOUSE_EVENT_MAP = { mouseleave : "mouseout" , mouseenter : "mouseover" } ;
139
139
var jqLiteMinErr = minErr ( 'jqLite' ) ;
140
140
141
+ /**
142
+ * Returns the key under which the related event-type listener is stored on the original listener
143
+ * function. See the special handling of mouseenter/mouseleave events in `jqLiteOn/Off`.
144
+ * @param relatedEventType The type of the related event
145
+ */
146
+ function getRelatedListenerKey ( relatedEventType ) {
147
+ return '$$' + relatedEventType + 'Listener' ;
148
+ }
149
+
141
150
/**
142
151
* Converts snake_case to camelCase.
143
152
* Also there is special case for Moz prefix starting with upper case letter.
@@ -300,12 +309,28 @@ function jqLiteOff(element, type, fn, unsupported) {
300
309
}
301
310
} else {
302
311
forEach ( type . split ( ' ' ) , function ( type ) {
303
- if ( isDefined ( fn ) ) {
304
- var listenerFns = events [ type ] ;
305
- arrayRemove ( listenerFns || [ ] , fn ) ;
306
- if ( listenerFns && listenerFns . length > 0 ) {
307
- return ;
308
- }
312
+ var relatedType = MOUSE_EVENT_MAP [ type ] ;
313
+ var relatedListenerKey = relatedType && getRelatedListenerKey ( relatedType ) ;
314
+ var isDefinedFn = isDefined ( fn ) ;
315
+
316
+ var allListenerFnsForType = events [ type ] || [ ] ;
317
+ var allListenerFnsForRelatedType = ( relatedType && events [ relatedType ] ) || [ ] ;
318
+ var listenerFnsToRemove = isDefinedFn ? [ fn ] : allListenerFnsForType ;
319
+
320
+ // Remove the "related" listeners (if any)
321
+ if ( allListenerFnsForRelatedType . length ) {
322
+ forEach ( listenerFnsToRemove , function ( fn ) {
323
+ var relatedListenerFn = fn [ relatedListenerKey ] ;
324
+ arrayRemove ( allListenerFnsForRelatedType , relatedListenerFn ) ;
325
+ } ) ;
326
+
327
+ if ( ! allListenerFnsForRelatedType . length ) jqLiteOff ( element , relatedType ) ;
328
+ }
329
+
330
+ // Remove the listener or all listeners for `type`
331
+ if ( isDefinedFn ) {
332
+ arrayRemove ( allListenerFnsForType , fn ) ;
333
+ if ( allListenerFnsForType . length ) return ;
309
334
}
310
335
311
336
removeEventListenerFn ( element , type , handle ) ;
@@ -822,7 +847,10 @@ forEach({
822
847
// Read about mouseenter and mouseleave:
823
848
// http://www.quirksmode.org/js/events_mouse.html#link8
824
849
825
- jqLiteOn ( element , MOUSE_EVENT_MAP [ type ] , function ( event ) {
850
+ // We need to keep track of the actual listener
851
+ var relatedType = MOUSE_EVENT_MAP [ type ] ;
852
+ var relatedListenerKey = getRelatedListenerKey ( relatedType ) ;
853
+ var listenerFn = fn [ relatedListenerKey ] || ( fn [ relatedListenerKey ] = function ( event ) {
826
854
var target = this , related = event . relatedTarget ;
827
855
// For mousenter/leave call the handler if related is outside the target.
828
856
// NB: No relatedTarget if the mouse left/entered the browser window
@@ -831,6 +859,7 @@ forEach({
831
859
}
832
860
} ) ;
833
861
862
+ jqLiteOn ( element , relatedType , listenerFn ) ;
834
863
} else {
835
864
if ( type !== '$destroy' ) {
836
865
addEventListenerFn ( element , type , handle ) ;
0 commit comments