mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 00:12:39 +00:00
76 lines
2.4 KiB
TypeScript
76 lines
2.4 KiB
TypeScript
/**
|
|
* Visual alerts (Settings > Accessibility): the browser-tab title swaps
|
|
* slowly between the page's own title and a short alert ("3 new messages")
|
|
* while the tab is in the background, for people who can't hear the sound.
|
|
*
|
|
* It never swaps faster than once a second and never flashes colours
|
|
* (WCAG 2.3.1), and it stops after a few rounds or as soon as the tab gets
|
|
* the focus. hooks/use-document-title leaves the title alone while it runs.
|
|
*/
|
|
|
|
/** Time between two swaps. At least a second. */
|
|
export const TITLE_ALERT_INTERVAL_MS = 1500;
|
|
/** Swaps before it stops by itself: five rounds of alert and title. */
|
|
export const TITLE_ALERT_MAX_SWAPS = 10;
|
|
|
|
let timer: ReturnType<typeof setInterval> | null = null;
|
|
let baseTitle = '';
|
|
let alertText = '';
|
|
let swaps = 0;
|
|
let showingAlert = false;
|
|
|
|
export function isTitleAlertActive(): boolean {
|
|
return timer !== null;
|
|
}
|
|
|
|
function tabInView(): boolean {
|
|
return !document.hidden && document.hasFocus();
|
|
}
|
|
|
|
function onVisibilityChange() {
|
|
if (tabInView()) stopTitleAlert();
|
|
}
|
|
|
|
/**
|
|
* Starts the alert, or changes its text and starts its rounds again when
|
|
* it is already running. Nothing happens while the tab is in front: the
|
|
* toast or the list says it there.
|
|
*/
|
|
export function startTitleAlert(text: string): void {
|
|
if (typeof document === 'undefined' || !text) return;
|
|
if (tabInView()) return;
|
|
alertText = text;
|
|
swaps = 0;
|
|
if (timer !== null) {
|
|
if (showingAlert) document.title = alertText;
|
|
return;
|
|
}
|
|
baseTitle = document.title;
|
|
showingAlert = true;
|
|
document.title = alertText;
|
|
timer = setInterval(() => {
|
|
swaps += 1;
|
|
if (swaps >= TITLE_ALERT_MAX_SWAPS) {
|
|
stopTitleAlert();
|
|
return;
|
|
}
|
|
showingAlert = !showingAlert;
|
|
document.title = showingAlert ? alertText : baseTitle;
|
|
}, TITLE_ALERT_INTERVAL_MS);
|
|
window.addEventListener('focus', stopTitleAlert);
|
|
document.addEventListener('visibilitychange', onVisibilityChange);
|
|
}
|
|
|
|
/** Stops the alert and puts the page's title back. */
|
|
export function stopTitleAlert(): void {
|
|
if (timer === null) return;
|
|
clearInterval(timer);
|
|
timer = null;
|
|
showingAlert = false;
|
|
window.removeEventListener('focus', stopTitleAlert);
|
|
document.removeEventListener('visibilitychange', onVisibilityChange);
|
|
// useDocumentTitle sees the change and writes the current title if the
|
|
// page moved on in the meantime.
|
|
document.title = baseTitle;
|
|
}
|