diff --git a/package.json b/package.json index 29ca7b0f..19f2672c 100644 --- a/package.json +++ b/package.json @@ -142,6 +142,7 @@ "NodeList", "NotificationEvent", "OffscreenCanvas", + "PointerEvent", "URL", "WebSocket", "__assets__", diff --git a/src/inline-script/inline-script.js b/src/inline-script/inline-script.js index 938431ad..8b737dc3 100644 --- a/src/inline-script/inline-script.js +++ b/src/inline-script/inline-script.js @@ -7,6 +7,7 @@ import { INLINE_THEME, DEFAULT_THEME, switchToTheme } from '../routes/_utils/the import { basename } from '../routes/_api/utils' import { onUserIsLoggedOut } from '../routes/_actions/onUserIsLoggedOut' import { storeLite } from '../routes/_store/storeLite' +import { isIOSPre12Point2, isMac } from '../routes/_utils/userAgent' window.__themeColors = process.env.THEME_COLORS @@ -51,7 +52,7 @@ if (disableCustomScrollbars) { } // hack to make the scrollbars rounded only on macOS -if (/mac/i.test(navigator.platform)) { +if (isMac()) { document.documentElement.style.setProperty('--scrollbar-border-radius', '50px') } @@ -59,9 +60,7 @@ if (/mac/i.test(navigator.platform)) { // for cross-origin authentication: https://github.com/nolanlawson/pinafore/issues/45 // Here we sniff for iOS <12.2 by checking for the existence of a native IntersectionObserver // function, which was added in 12.2. -if (/iP(?:hone|ad|od)/.test(navigator.userAgent) && - !(typeof IntersectionObserver === 'function' && - IntersectionObserver.toString().includes('[native code]'))) { +if (isIOSPre12Point2()) { document.head.removeChild(document.getElementById('theManifest')) } diff --git a/src/routes/_static/media.js b/src/routes/_static/media.js index 0c7405c0..43d47d41 100644 --- a/src/routes/_static/media.js +++ b/src/routes/_static/media.js @@ -1,3 +1,5 @@ +import { isIOSPre13 } from '../_utils/userAgent' + export const DEFAULT_MEDIA_WIDTH = 300 export const DEFAULT_MEDIA_HEIGHT = 250 @@ -51,10 +53,8 @@ const acceptedFileTypes = [ 'video/x-ms-asf' ] -const isIOS = process.browser && /iP(?:hone|ad|od)/.test(navigator.userAgent) - // TODO: iOS has a bug where it does not allow audio uploads unless you either *only* accept audio, or // you accept everything. Since this is not a great user experience (e.g. it could lead someone trying // to upload a PDF, which is not allowed), then we only use the */* for iOS. // WebKit bug: https://bugs.webkit.org/show_bug.cgi?id=190982#c2 -export const mediaAccept = isIOS ? '*/*' : acceptedFileTypes.join(',') +export const mediaAccept = isIOSPre13() ? '*/*' : acceptedFileTypes.join(',') diff --git a/src/routes/_store/storeLite.js b/src/routes/_store/storeLite.js index 86f0d0af..3f9cee94 100644 --- a/src/routes/_store/storeLite.js +++ b/src/routes/_store/storeLite.js @@ -1,9 +1,9 @@ // "lite" version of the store used in the inline script. import { safeParse } from './safeParse' -import { testHasLocalStorageOnce } from '../_utils/testStorage' +import { testHasLocalStorage } from '../_utils/testStorage' -const hasLocalStorage = testHasLocalStorageOnce() +const hasLocalStorage = testHasLocalStorage() export const storeLite = { get () { diff --git a/src/routes/_utils/runMediumPriorityTask.js b/src/routes/_utils/runMediumPriorityTask.js index a17c5ffb..597f05ca 100644 --- a/src/routes/_utils/runMediumPriorityTask.js +++ b/src/routes/_utils/runMediumPriorityTask.js @@ -1,9 +1,9 @@ import { scheduleIdleTask } from './scheduleIdleTask' import { store } from '../_store/store' +import { isMobile } from './userAgent' // Rough guess at whether this is a "mobile" device or not, for the purposes // of "device class" estimations -const IS_MOBILE = process.browser && navigator.userAgent.match(/(?:iPhone|iPod|iPad|Android|KAIOS)/) // Run a task that doesn't need to be processed immediately, but should // probably be delayed if we're on a mobile device. Also run it sooner @@ -11,7 +11,7 @@ const IS_MOBILE = process.browser && navigator.userAgent.match(/(?:iPhone|iPod|i export function runMediumPriorityTask (fn) { if (store.get().pageVisibilityHidden) { fn() - } else if (IS_MOBILE) { + } else if (isMobile()) { scheduleIdleTask(fn) } else { requestAnimationFrame(fn) diff --git a/src/routes/_utils/testStorage.js b/src/routes/_utils/testStorage.js index 581a7ad7..36bde6d6 100644 --- a/src/routes/_utils/testStorage.js +++ b/src/routes/_utils/testStorage.js @@ -5,7 +5,7 @@ import { thunk } from './thunk' const testKey = '__test__' -export const testHasLocalStorageOnce = () => { +export const testHasLocalStorage = thunk(() => { try { localStorage.setItem(testKey, testKey) if (!localStorage.length || localStorage.getItem(testKey) !== testKey) { @@ -16,9 +16,7 @@ export const testHasLocalStorageOnce = () => { return false } return true -} - -export const testHasLocalStorage = thunk(testHasLocalStorageOnce) +}) export const testHasIndexedDB = thunk(async () => { if (typeof indexedDB === 'undefined') { diff --git a/src/routes/_utils/userAgent.js b/src/routes/_utils/userAgent.js index 52c6868f..ca00151b 100644 --- a/src/routes/_utils/userAgent.js +++ b/src/routes/_utils/userAgent.js @@ -1,3 +1,19 @@ import { thunk } from './thunk' export const isKaiOS = thunk(() => process.browser && /KAIOS/.test(navigator.userAgent)) + +export const isIOS = thunk(() => process.browser && /iP(?:hone|ad|od)/.test(navigator.userAgent)) + +export const isMac = thunk(() => process.browser && /mac/i.test(navigator.platform)) + +// IntersectionObserver introduced in iOS 12.2 https://caniuse.com/#feat=intersectionobserver +export const isIOSPre12Point2 = thunk(() => process.browser && isIOS() && + !(typeof IntersectionObserver === 'function' && + IntersectionObserver.toString().includes('[native code]'))) + +// PointerEvent introduced in iOS 13 https://caniuse.com/#feat=pointer +export const isIOSPre13 = thunk(() => process.browser && isIOS() && + !(typeof PointerEvent === 'function' && + PointerEvent.toString().includes('[native code]'))) + +export const isMobile = thunk(() => process.browser && navigator.userAgent.match(/(?:iPhone|iPod|iPad|Android|KAIOS)/))