65 lines
1.8 KiB
JavaScript
65 lines
1.8 KiB
JavaScript
export default class SessionTicker {
|
|
constructor({ duration, onTick, onExpire, tickInterval = 1 }) {
|
|
this.duration = duration;
|
|
this.onTick = onTick;
|
|
this.onExpire = onExpire;
|
|
this.tickInterval = tickInterval;
|
|
this.expiresAt = null;
|
|
this._interval = null;
|
|
this._onVisibility = this._onVisibility.bind(this);
|
|
this._onPageShow = this._onPageShow.bind(this);
|
|
}
|
|
|
|
start() {
|
|
this.expiresAt = Date.now() + this.duration * 1000;
|
|
this._attachListeners();
|
|
this._tick();
|
|
this._interval = setInterval(() => this._tick(), this.tickInterval * 1000);
|
|
return this;
|
|
}
|
|
|
|
stop() {
|
|
clearInterval(this._interval);
|
|
this._interval = null;
|
|
this._detachListeners();
|
|
return this;
|
|
}
|
|
|
|
reset(newDuration) {
|
|
if (newDuration != null) this.duration = newDuration;
|
|
this.stop();
|
|
return this.start();
|
|
}
|
|
|
|
getRemaining() {
|
|
if (!this.expiresAt) return 0;
|
|
return Math.max(0, Math.ceil((this.expiresAt - Date.now()) / 1000));
|
|
}
|
|
|
|
_tick() {
|
|
const remaining = this.getRemaining();
|
|
this.onTick?.(remaining);
|
|
if (remaining <= 0) {
|
|
this.stop();
|
|
this.onExpire?.();
|
|
}
|
|
}
|
|
|
|
_onVisibility() {
|
|
if (document.visibilityState === 'visible') this._tick();
|
|
}
|
|
|
|
_onPageShow(e) {
|
|
if (e.persisted) this._tick();
|
|
}
|
|
|
|
_attachListeners() {
|
|
document.addEventListener('visibilitychange', this._onVisibility);
|
|
window.addEventListener('pageshow', this._onPageShow);
|
|
}
|
|
|
|
_detachListeners() {
|
|
document.removeEventListener('visibilitychange', this._onVisibility);
|
|
window.removeEventListener('pageshow', this._onPageShow);
|
|
}
|
|
} |