Skip to content

Commit 55a5a69

Browse files
authored
Merge pull request #278 from huumanoid/fix-track-removal-firefox
Make MutationObserver-based removal tracking
2 parents 9399d75 + cf6427e commit 55a5a69

File tree

2 files changed

+55
-10
lines changed

2 files changed

+55
-10
lines changed

src/decorators/trackRemoval.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
* Tracking target removing from DOM.
3+
* It's nessesary to hide tooltip when it's target disappears.
4+
* Otherwise, the tooltip would be shown forever until another target
5+
* is triggered.
6+
*
7+
* If MutationObserver is not available, this feature just doesn't work.
8+
*/
9+
10+
// https://hacks.mozilla.org/2012/05/dom-mutationobserver-reacting-to-dom-changes-without-killing-browser-performance/
11+
const getMutationObserverClass = () => {
12+
return window.MutationObserver ||
13+
window.WebKitMutationObserver ||
14+
window.MozMutationObserver
15+
}
16+
17+
export default function (target) {
18+
target.prototype.bindRemovalTracker = function () {
19+
const MutationObserver = getMutationObserverClass()
20+
if (MutationObserver == null) return
21+
22+
const observer = new MutationObserver((mutations) => {
23+
for (const mutation of mutations) {
24+
for (const element of mutation.removedNodes) {
25+
if (element === this.state.currentTarget) {
26+
this.hideTooltip()
27+
return
28+
}
29+
}
30+
}
31+
})
32+
33+
observer.observe(window.document, { childList: true, subtree: true })
34+
35+
this.removalTracker = observer
36+
}
37+
38+
target.prototype.unbindRemovalTracker = function () {
39+
if (this.removalTracker) {
40+
this.removalTracker.disconnect()
41+
this.removalTracker = null
42+
}
43+
}
44+
}

src/index.js

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import windowListener from './decorators/windowListener'
1010
import customEvent from './decorators/customEvent'
1111
import isCapture from './decorators/isCapture'
1212
import getEffect from './decorators/getEffect'
13+
import trackRemoval from './decorators/trackRemoval'
1314

1415
/* Utils */
1516
import getPosition from './utils/getPosition'
@@ -20,7 +21,12 @@ import nodeListToArray from './utils/nodeListToArray'
2021
/* CSS */
2122
import cssStyle from './style'
2223

23-
@staticMethods @windowListener @customEvent @isCapture @getEffect
24+
@staticMethods
25+
@windowListener
26+
@customEvent
27+
@isCapture
28+
@getEffect
29+
@trackRemoval
2430
class ReactTooltip extends Component {
2531

2632
static propTypes = {
@@ -86,7 +92,6 @@ class ReactTooltip extends Component {
8692
this.bind([
8793
'showTooltip',
8894
'updateTooltip',
89-
'checkSameTarget',
9095
'hideTooltip',
9196
'globalRebuild',
9297
'globalShow',
@@ -181,14 +186,16 @@ class ReactTooltip extends Component {
181186
target.addEventListener('mousemove', this.updateTooltip, isCaptureMode)
182187
}
183188
target.addEventListener('mouseleave', this.hideTooltip, isCaptureMode)
184-
target.addEventListener('DOMNodeRemovedFromDocument', this.checkSameTarget, isCaptureMode)
185189
})
186190

187191
// Global event to hide tooltip
188192
if (globalEventOff) {
189193
window.removeEventListener(globalEventOff, this.hideTooltip)
190194
window.addEventListener(globalEventOff, this.hideTooltip, false)
191195
}
196+
197+
// Track removal of targetArray elements from DOM
198+
this.bindRemovalTracker()
192199
}
193200

194201
/**
@@ -203,6 +210,7 @@ class ReactTooltip extends Component {
203210
})
204211

205212
if (globalEventOff) window.removeEventListener(globalEventOff, this.hideTooltip)
213+
this.unbindRemovalTracker()
206214
}
207215

208216
/**
@@ -215,7 +223,6 @@ class ReactTooltip extends Component {
215223
target.removeEventListener('mouseenter', this.showTooltip, isCaptureMode)
216224
target.removeEventListener('mousemove', this.updateTooltip, isCaptureMode)
217225
target.removeEventListener('mouseleave', this.hideTooltip, isCaptureMode)
218-
target.removeEventListener('DOMNodeRemovedFromDocument', this.checkSameTarget, isCaptureMode)
219226
}
220227

221228
/**
@@ -332,12 +339,6 @@ class ReactTooltip extends Component {
332339
}
333340
}
334341

335-
checkSameTarget (e) {
336-
if (this.state.currentTarget === e.currentTarget) {
337-
this.hideTooltip(e)
338-
}
339-
}
340-
341342
/**
342343
* When mouse leave, hide tooltip
343344
*/

0 commit comments

Comments
 (0)