Fix VisibilityTimer visibilitychange listener typo Co-authored-by: Carl Bender <mvpcarl@gmail.com>
85 lines
2.5 KiB
TypeScript
85 lines
2.5 KiB
TypeScript
// Copyright (c) 2020 The Brave Authors. All rights reserved.
|
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
|
|
/**
|
|
* Waits until the viewport (and an optional element) has been in view for a certain number of seconds
|
|
* continuously before calling a provided function.
|
|
*/
|
|
export default class VisibilityTimer {
|
|
private readonly element?: HTMLElement
|
|
private timerId?: number = undefined
|
|
private isIntersecting: boolean
|
|
private readonly viewTimeMs: number = 0
|
|
private readonly onTimerExpired: Function
|
|
private readonly intersectionObserver?: IntersectionObserver
|
|
|
|
constructor (onTimerExpired: Function, viewTimeMs: number, elementToObserve?: HTMLElement) {
|
|
this.element = elementToObserve
|
|
this.onTimerExpired = onTimerExpired
|
|
this.viewTimeMs = viewTimeMs
|
|
this.isIntersecting = !elementToObserve
|
|
if (elementToObserve) {
|
|
this.intersectionObserver = new IntersectionObserver(entries => {
|
|
this.isIntersecting = entries.some(entry => entry.isIntersecting)
|
|
this.handleVisibility()
|
|
}, {
|
|
threshold: 0.5
|
|
})
|
|
}
|
|
}
|
|
|
|
startTracking () {
|
|
document.addEventListener(
|
|
'visibilitychange',
|
|
this.handleVisibility
|
|
)
|
|
if (this.intersectionObserver && this.element) {
|
|
this.intersectionObserver.observe(this.element)
|
|
}
|
|
this.handleVisibility()
|
|
}
|
|
|
|
stopTracking () {
|
|
this.resetTimer()
|
|
// Stop tracking visibility.
|
|
document.removeEventListener(
|
|
'visibilitychange',
|
|
this.handleVisibility
|
|
)
|
|
if (this.intersectionObserver && this.element) {
|
|
this.intersectionObserver.unobserve(this.element)
|
|
}
|
|
}
|
|
|
|
private readonly handleVisibility = () => {
|
|
if (document.visibilityState === 'visible' && this.isIntersecting) {
|
|
if (!this.timerId) {
|
|
// Start the timer again
|
|
this.startWaiting()
|
|
}
|
|
} else {
|
|
// Stop the timer. It will start again when the page is next visible.
|
|
this.resetTimer()
|
|
}
|
|
}
|
|
|
|
private startWaiting () {
|
|
if (this.timerId) {
|
|
return
|
|
}
|
|
this.timerId = window.setTimeout(() => {
|
|
// If we made it here, then we have received enough uninterupted time
|
|
// and we can call the provided function.
|
|
this.stopTracking()
|
|
this.onTimerExpired()
|
|
}, this.viewTimeMs)
|
|
}
|
|
|
|
private resetTimer () {
|
|
window.clearTimeout(this.timerId)
|
|
this.timerId = undefined
|
|
}
|
|
}
|