@@ -22,6 +22,7 @@ const customEvents = {
22
22
mouseenter : 'mouseover' ,
23
23
mouseleave : 'mouseout'
24
24
}
25
+ const customEventsRegex = / ^ ( m o u s e e n t e r | m o u s e l e a v e ) / i
25
26
const nativeEvents = new Set ( [
26
27
'click' ,
27
28
'dblclick' ,
@@ -113,7 +114,7 @@ function bootstrapDelegationHandler(element, selector, fn) {
113
114
114
115
if ( handler . oneOff ) {
115
116
// eslint-disable-next-line unicorn/consistent-destructuring
116
- EventHandler . off ( element , event . type , fn )
117
+ EventHandler . off ( element , event . type , selector , fn )
117
118
}
118
119
119
120
return fn . apply ( target , [ event ] )
@@ -144,14 +145,7 @@ function normalizeParams(originalTypeEvent, handler, delegationFn) {
144
145
const delegation = typeof handler === 'string'
145
146
const originalHandler = delegation ? delegationFn : handler
146
147
147
- // allow to get the native events from namespaced events ('click.bs.button' --> 'click')
148
- let typeEvent = originalTypeEvent . replace ( stripNameRegex , '' )
149
- const custom = customEvents [ typeEvent ]
150
-
151
- if ( custom ) {
152
- typeEvent = custom
153
- }
154
-
148
+ let typeEvent = getTypeEvent ( originalTypeEvent )
155
149
const isNative = nativeEvents . has ( typeEvent )
156
150
157
151
if ( ! isNative ) {
@@ -171,6 +165,24 @@ function addHandler(element, originalTypeEvent, handler, delegationFn, oneOff) {
171
165
delegationFn = null
172
166
}
173
167
168
+ // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position
169
+ // this prevents the handler from being dispatched the same way as mouseover or mouseout does
170
+ if ( customEventsRegex . test ( originalTypeEvent ) ) {
171
+ const wrapFn = fn => {
172
+ return function ( event ) {
173
+ if ( ! event . relatedTarget || ( event . relatedTarget !== event . delegateTarget && event . relatedTarget . contains ( event . delegateTarget ) ) ) {
174
+ return fn . call ( this , event )
175
+ }
176
+ }
177
+ }
178
+
179
+ if ( delegationFn ) {
180
+ delegationFn = wrapFn ( delegationFn )
181
+ } else {
182
+ handler = wrapFn ( handler )
183
+ }
184
+ }
185
+
174
186
const [ delegation , originalHandler , typeEvent ] = normalizeParams ( originalTypeEvent , handler , delegationFn )
175
187
const events = getEvent ( element )
176
188
const handlers = events [ typeEvent ] || ( events [ typeEvent ] = { } )
@@ -219,6 +231,12 @@ function removeNamespacedHandlers(element, events, typeEvent, namespace) {
219
231
} )
220
232
}
221
233
234
+ function getTypeEvent ( event ) {
235
+ // allow to get the native events from namespaced events ('click.bs.button' --> 'click')
236
+ event = event . replace ( stripNameRegex , '' )
237
+ return customEvents [ event ] || event
238
+ }
239
+
222
240
const EventHandler = {
223
241
on ( element , event , handler , delegationFn ) {
224
242
addHandler ( element , event , handler , delegationFn , false )
@@ -272,7 +290,7 @@ const EventHandler = {
272
290
}
273
291
274
292
const $ = getjQuery ( )
275
- const typeEvent = event . replace ( stripNameRegex , '' )
293
+ const typeEvent = getTypeEvent ( event )
276
294
const inNamespace = event !== typeEvent
277
295
const isNative = nativeEvents . has ( typeEvent )
278
296
0 commit comments