From d968077c5d41c1ce1d5534d41ec6457be975c96f Mon Sep 17 00:00:00 2001 From: Jona <8698248+jonamil@users.noreply.github.com> Date: Fri, 19 Jul 2024 18:33:31 +0200 Subject: [PATCH] Update object tag error handling Add Safari-specific timeout workaround #16 --- src/components/TheLinkColumnBody.vue | 125 +++++++++++++++++---------- src/stores/ViewStore.ts | 2 + 2 files changed, 80 insertions(+), 47 deletions(-) diff --git a/src/components/TheLinkColumnBody.vue b/src/components/TheLinkColumnBody.vue index 0406002..01ef6ea 100644 --- a/src/components/TheLinkColumnBody.vue +++ b/src/components/TheLinkColumnBody.vue @@ -1,36 +1,46 @@ @@ -39,6 +49,7 @@ import { ref, computed, watch, nextTick } from 'vue'; import { useEventListener } from '@vueuse/core'; import BaseButton from '@/components/BaseButton.vue'; import PageColumnBody from '@/components/PageColumnBody.vue'; +import StatusItem from '@/components/StatusItem.vue'; import { useViewStore } from '@/stores/ViewStore'; import { useContentStore } from '@/stores/ContentStore'; @@ -48,43 +59,63 @@ const content = useContentStore(); // array of post IDs for which loading error has occurred const errorPostIds = ref([]); -// whether loading the current post item results in an error -const error = computed(() => +// whether loading the current post item has previously resulted in an error +const previousErrorForPostId = computed(() => content.currentPostItem ? errorPostIds.value.includes(content.currentPostItem.id) : false ); -// whether an error for a specific post ID has just occurred for the first time (relevant for fade-in of error message) -const firstErrorForPostId = ref(false); +// Safari-specific timeout for showing error message (see comment below) +let safariErrorMessageTimeout: ReturnType | undefined = undefined; -// whether the object element is being rendered (see comment below) +const showErrorMessage = ref(false); const renderObject = ref(true); watch( () => content.currentPostItem, async () => { - // if error is already apparent, skip replacing object element - if (error.value) return; - - firstErrorForPostId.value = false; - - // force object element to be replaced when current post item changes - // (object element seems to refuse to load new content once it encounters an error) + // if error is already apparent, remove object element and show error message immediately + if (previousErrorForPostId.value) { + renderObject.value = false; + showErrorMessage.value = true; + return; + } + + // force object element to re-render (as seems to refuse to load new content once it has encountered an error) renderObject.value = false; await nextTick(); renderObject.value = true; await nextTick(); - } + + // hide error message + showErrorMessage.value = false; + + // as the object element does not ever fire an error event on Safari, show the error message after a timeout there instead + if (view.isSafari) { + clearTimeout(safariErrorMessageTimeout); + + safariErrorMessageTimeout = setTimeout(() => { + showErrorMessage.value = true; + }, 4000); + } + }, + { immediate: true } ); const objectElement = ref(null); -useEventListener(objectElement, 'error', () => { - // when an error occurs, push ID of unloadable post to errorPostIds array - if (content.currentPostItem && !errorPostIds.value.includes(content.currentPostItem.id)) { - errorPostIds.value.push(content.currentPostItem.id); - firstErrorForPostId.value = true; - } -}); +// on browsers other than Safari, listen for error events on the object element to show the error message +if (!view.isSafari) { + useEventListener(objectElement, 'error', () => { + // remove object element and show error message + renderObject.value = false; + showErrorMessage.value = true; + + // push ID of unloadable post to errorPostIds array + if (content.currentPostItem && !errorPostIds.value.includes(content.currentPostItem.id)) { + errorPostIds.value.push(content.currentPostItem.id); + } + }); +} const maxErrorAssetIndex = 5; const errorAssetIndexes = [...Array(maxErrorAssetIndex + 1).keys()]; diff --git a/src/stores/ViewStore.ts b/src/stores/ViewStore.ts index 882a9b9..91fe537 100644 --- a/src/stores/ViewStore.ts +++ b/src/stores/ViewStore.ts @@ -32,6 +32,7 @@ export const useViewStore = defineStore('view', () => { ); }); + const isSafari = navigator.vendor && navigator.vendor.indexOf('Apple') !== -1; const isTouchDevice = useMediaQuery('(pointer: coarse)'); const isStandaloneDisplayMode = useMediaQuery('(display-mode: standalone)'); const { width: windowWidth } = useWindowSize(); @@ -94,6 +95,7 @@ export const useViewStore = defineStore('view', () => { return { colorScheme, darkColorSchemeIsActive, + isSafari, isTouchDevice, isStandaloneDisplayMode, windowWidth,