From 217e182d326208a4c131af856fd153f6faffc7c0 Mon Sep 17 00:00:00 2001 From: Dominik Dorfmeister Date: Wed, 8 Dec 2021 22:22:22 +0100 Subject: [PATCH] Revert "refactor(core): unify focusManager and onlineManager" This reverts commit f1cb1a66a65423201ff8f5998a3b89e0c80a32df. --- src/core/eventManager.ts | 78 ---------------------- src/core/focusManager.ts | 95 ++++++++++++++++++++------- src/core/onlineManager.ts | 95 ++++++++++++++++++++------- src/core/tests/focusManager.test.tsx | 12 ++-- src/core/tests/onlineManager.test.tsx | 12 ++-- 5 files changed, 152 insertions(+), 140 deletions(-) delete mode 100644 src/core/eventManager.ts diff --git a/src/core/eventManager.ts b/src/core/eventManager.ts deleted file mode 100644 index be94551dd9..0000000000 --- a/src/core/eventManager.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { isServer } from './utils' - -type ListenerFn = () => void - -export function createEventManager( - events: ReadonlyArray[0]> -) { - let value: boolean | undefined - let removeEventListener: ListenerFn | undefined - let listeners: ListenerFn[] = [] - let setupFn: ( - param: (newValue?: boolean) => void - ) => ListenerFn | undefined = onEvent => { - if (!isServer && window?.addEventListener) { - const listener = () => onEvent() - events.forEach(eventName => { - window.addEventListener(eventName, listener, false) - }) - - return () => { - events.forEach(eventName => { - window.removeEventListener(eventName, listener) - }) - } - } - } - - const subscribe = (listener: ListenerFn): ListenerFn => { - listeners.push(listener) - - if (!removeEventListener) { - setEventListener(setupFn) - } - - return () => { - listeners = listeners.filter(x => x !== listener) - if (listeners.length === 0) { - removeEventListener?.() - removeEventListener = undefined - } - } - } - - const setValue = (newValue?: boolean): void => { - value = newValue - - if (newValue) { - onEvent() - } - } - - const setEventListener = ( - setup: (param: (newValue?: boolean) => void) => ListenerFn | undefined - ): void => { - removeEventListener?.() - setupFn = setup - removeEventListener = setupFn(newValue => { - if (typeof newValue === 'boolean') { - setValue(newValue) - } else { - onEvent() - } - }) - } - - const onEvent = (): void => { - listeners.forEach(listener => { - listener() - }) - } - - return { - setEventListener, - subscribe, - setValue, - getValue: () => value, - } as const -} diff --git a/src/core/focusManager.ts b/src/core/focusManager.ts index 7a98cf03a2..18bfdcbc46 100644 --- a/src/core/focusManager.ts +++ b/src/core/focusManager.ts @@ -1,31 +1,76 @@ -import { createEventManager } from './eventManager' - -export const createFocusManager = () => { - const { setEventListener, subscribe, ...manager } = createEventManager([ - 'visibilitychange', - 'focus', - ]) - - return { - subscribe, - setEventListener, - setFocused: manager.setValue, - isFocused: (): boolean => { - const value = manager.getValue() - if (typeof value === 'boolean') { - return value - } +import { Subscribable } from './subscribable' +import { isServer } from './utils' + +class FocusManager extends Subscribable { + private focused?: boolean + private removeEventListener?: () => void + + protected onSubscribe(): void { + if (!this.removeEventListener) { + this.setDefaultEventListener() + } + } - // document global can be unavailable in react native - if (typeof document === 'undefined') { - return true + setEventListener( + setup: (setFocused: (focused?: boolean) => void) => () => void + ): void { + if (this.removeEventListener) { + this.removeEventListener() + } + this.removeEventListener = setup(focused => { + if (typeof focused === 'boolean') { + this.setFocused(focused) + } else { + this.onFocus() } + }) + } + + setFocused(focused?: boolean): void { + this.focused = focused + + if (focused) { + this.onFocus() + } + } + + onFocus(): void { + this.listeners.forEach(listener => { + listener() + }) + } + + isFocused(): boolean { + if (typeof this.focused === 'boolean') { + return this.focused + } + + // document global can be unavailable in react native + if (typeof document === 'undefined') { + return true + } + + return [undefined, 'visible', 'prerender'].includes( + document.visibilityState + ) + } + + private setDefaultEventListener() { + if (!isServer && window?.addEventListener) { + this.setEventListener(onFocus => { + const listener = () => onFocus() + // Listen to visibillitychange and focus + window.addEventListener('visibilitychange', listener, false) + window.addEventListener('focus', listener, false) - return [undefined, 'visible', 'prerender'].includes( - document.visibilityState - ) - }, + return () => { + // Be sure to unsubscribe if a new handler is set + window.removeEventListener('visibilitychange', listener) + window.removeEventListener('focus', listener) + } + }) + } } } -export const focusManager = createFocusManager() +export const focusManager = new FocusManager() diff --git a/src/core/onlineManager.ts b/src/core/onlineManager.ts index 5c3f45cdeb..f02a03c9bf 100644 --- a/src/core/onlineManager.ts +++ b/src/core/onlineManager.ts @@ -1,31 +1,76 @@ -import { createEventManager } from './eventManager' - -export const createOnlineManager = () => { - const { setEventListener, subscribe, ...manager } = createEventManager([ - 'online', - 'offline', - ]) - - return { - subscribe, - setEventListener, - setOnline: manager.setValue, - isOnline: (): boolean => { - const value = manager.getValue() - if (typeof value === 'boolean') { - return value - } +import { Subscribable } from './subscribable' +import { isServer } from './utils' + +class OnlineManager extends Subscribable { + private online?: boolean + private removeEventListener?: () => void + + protected onSubscribe(): void { + if (!this.removeEventListener) { + this.setDefaultEventListener() + } + } - if ( - typeof navigator === 'undefined' || - typeof navigator.onLine === 'undefined' - ) { - return true + setEventListener( + setup: (setOnline: (online?: boolean) => void) => () => void + ): void { + if (this.removeEventListener) { + this.removeEventListener() + } + this.removeEventListener = setup((online?: boolean) => { + if (typeof online === 'boolean') { + this.setOnline(online) + } else { + this.onOnline() } + }) + } + + setOnline(online?: boolean): void { + this.online = online + + if (online) { + this.onOnline() + } + } + + onOnline(): void { + this.listeners.forEach(listener => { + listener() + }) + } + + isOnline(): boolean { + if (typeof this.online === 'boolean') { + return this.online + } + + if ( + typeof navigator === 'undefined' || + typeof navigator.onLine === 'undefined' + ) { + return true + } + + return navigator.onLine + } + + private setDefaultEventListener() { + if (!isServer && window?.addEventListener) { + this.setEventListener(onOnline => { + const listener = () => onOnline() + // Listen to online + window.addEventListener('online', listener, false) + window.addEventListener('offline', listener, false) - return navigator.onLine - }, + return () => { + // Be sure to unsubscribe if a new handler is set + window.removeEventListener('online', listener) + window.removeEventListener('offline', listener) + } + }) + } } } -export const onlineManager = createOnlineManager() +export const onlineManager = new OnlineManager() diff --git a/src/core/tests/focusManager.test.tsx b/src/core/tests/focusManager.test.tsx index 1d45c81cdd..ca071ec16d 100644 --- a/src/core/tests/focusManager.test.tsx +++ b/src/core/tests/focusManager.test.tsx @@ -1,10 +1,10 @@ import { sleep } from '../utils' -import { createFocusManager } from '../focusManager' +import { focusManager } from '../focusManager' describe('focusManager', () => { - let focusManager: ReturnType - beforeEach(() => { - focusManager = createFocusManager() + afterEach(() => { + // Reset removeEventListener private property to avoid side effects between tests + focusManager['removeEventListener'] = undefined }) it('should call previous remove handler when replacing an event listener', () => { @@ -69,7 +69,7 @@ describe('focusManager', () => { const setEventListenerSpy = jest.spyOn(focusManager, 'setEventListener') - const unsubscribe = focusManager.subscribe(() => undefined) + const unsubscribe = focusManager.subscribe() expect(setEventListenerSpy).toHaveBeenCalledTimes(0) unsubscribe() @@ -88,7 +88,7 @@ describe('focusManager', () => { ) // Should set the default event listener with window event listeners - const unsubscribe = focusManager.subscribe(() => undefined) + const unsubscribe = focusManager.subscribe() expect(addEventListenerSpy).toHaveBeenCalledTimes(2) // Should replace the window default event listener by a new one diff --git a/src/core/tests/onlineManager.test.tsx b/src/core/tests/onlineManager.test.tsx index b7e36b6e9d..2e7d35c3f4 100644 --- a/src/core/tests/onlineManager.test.tsx +++ b/src/core/tests/onlineManager.test.tsx @@ -1,10 +1,10 @@ -import { createOnlineManager } from '../onlineManager' +import { onlineManager } from '../onlineManager' import { sleep } from '../utils' describe('onlineManager', () => { - let onlineManager: ReturnType - beforeEach(() => { - onlineManager = createOnlineManager() + afterEach(() => { + // Reset removeEventListener private property to avoid side effects between tests + onlineManager['removeEventListener'] = undefined }) test('isOnline should return true if navigator is undefined', () => { @@ -64,7 +64,7 @@ describe('onlineManager', () => { const setEventListenerSpy = jest.spyOn(onlineManager, 'setEventListener') - const unsubscribe = onlineManager.subscribe(() => undefined) + const unsubscribe = onlineManager.subscribe() expect(setEventListenerSpy).toHaveBeenCalledTimes(0) unsubscribe() @@ -83,7 +83,7 @@ describe('onlineManager', () => { ) // Should set the default event listener with window event listeners - const unsubscribe = onlineManager.subscribe(() => undefined) + const unsubscribe = onlineManager.subscribe() expect(addEventListenerSpy).toHaveBeenCalledTimes(2) // Should replace the window default event listener by a new one