Files
Carl BenderandCarl Bender c38ce2b5a2 Fix VisibilityTimer visibilitychange handling (#36300)
Fix VisibilityTimer visibilitychange listener typo

Co-authored-by: Carl Bender <mvpcarl@gmail.com>
2026-05-11 09:05:24 -07:00

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
}
}