diff --git a/composables/useInfiniteScroll.ts b/composables/useInfiniteScroll.ts index d79d0fc..0180852 100644 --- a/composables/useInfiniteScroll.ts +++ b/composables/useInfiniteScroll.ts @@ -1,18 +1,58 @@ // composables/useInfiniteScroll.ts +import { ref, onMounted, onBeforeUnmount } from "vue"; + export default function useInfiniteScroll( - callback: () => void, - elementId: string + callback: () => Promise, + elementId?: string ) { + const route = useRoute(); const isFetching = ref(false); - const infiniteScroll = ref(null); + const infiniteScroll = ref(null); - const handleScroll = () => { - if (isFetching.value) return; - const scrollPosition = - infiniteScroll.value.scrollTop + infiniteScroll.value.clientHeight; - const threshold = infiniteScroll.value.scrollHeight - 100; + // Throttle function to limit scroll event frequency + const throttle = (func: (...args: any[]) => void, limit: number) => { + let lastFunc: ReturnType; + let lastRan: number; + return function (this: any, ...args: any[]) { + const context = this; + if (!lastRan) { + func.apply(context, args); + lastRan = Date.now(); + } else { + clearTimeout(lastFunc); + lastFunc = setTimeout(() => { + if (Date.now() - lastRan >= limit) { + func.apply(context, args); + lastRan = Date.now(); + } + }, limit - (Date.now() - lastRan)); + } + }; + }; - if (scrollPosition >= threshold) { + const checkScrollPosition = () => { + if (isFetching.value || !infiniteScroll.value) return; + + let scrollPosition: number; + let threshold: number; + let clientHeight: number; + let scrollHeight: number; + + if (infiniteScroll.value === window) { + scrollPosition = window.scrollY || window.pageYOffset; + clientHeight = document.documentElement.clientHeight; + scrollHeight = document.documentElement.scrollHeight; + } else { + const el = infiniteScroll.value as HTMLElement; + scrollPosition = el.scrollTop; + clientHeight = el.clientHeight; + scrollHeight = el.scrollHeight; + } + + threshold = scrollHeight - 100; + const currentPosition = scrollPosition + clientHeight; + + if (currentPosition >= threshold) { isFetching.value = true; callback().finally(() => { isFetching.value = false; @@ -20,28 +60,57 @@ export default function useInfiniteScroll( } }; + // Throttled version of scroll handler + const throttledScrollHandler = throttle(checkScrollPosition, 200); + const handleTouchEnd = () => { - // Add a slight delay to ensure scroll position is updated - setTimeout(handleScroll, 100); + setTimeout(throttledScrollHandler, 100); }; onMounted(() => { - const targetElement = document.getElementById(elementId); - infiniteScroll.value = targetElement; + console.info(route.name) + + if (route.name == "hadithaSearch" || route.name == "hadithaLibrary") { + const targetElement = elementId + ? document.getElementById(elementId) + : window; - if (targetElement) { - targetElement.addEventListener("scroll", handleScroll); - targetElement.addEventListener("touchend", handleTouchEnd); + if (!targetElement) { + console.warn( + `Element ${elementId || "window"} not found for infinite scroll` + ); + return; + } + + infiniteScroll.value = targetElement; + + if (targetElement === window) { + window.addEventListener("scroll", throttledScrollHandler); + window.addEventListener("touchend", handleTouchEnd); + } else { + targetElement.addEventListener("scroll", throttledScrollHandler); + targetElement.addEventListener("touchend", handleTouchEnd); + } } }); onBeforeUnmount(() => { - const targetElement = document.getElementById(elementId); - infiniteScroll.value = targetElement; + if (route.name == "hadithaSearch" || route.name == "hadithaLibrary") { + if (!infiniteScroll.value) return; - if (targetElement) { - targetElement.removeEventListener("scroll", handleScroll); - targetElement.removeEventListener("touchend", handleTouchEnd); + if (infiniteScroll.value === window) { + window.removeEventListener("scroll", throttledScrollHandler); + window.removeEventListener("touchend", handleTouchEnd); + } else { + (infiniteScroll.value as HTMLElement).removeEventListener( + "scroll", + throttledScrollHandler + ); + (infiniteScroll.value as HTMLElement).removeEventListener( + "touchend", + handleTouchEnd + ); + } } }); diff --git a/public/img/haditha/search-show-header.png b/public/img/haditha/search-show-header.png new file mode 100644 index 0000000..88efce1 Binary files /dev/null and b/public/img/haditha/search-show-header.png differ diff --git a/systems/hadith_ui b/systems/hadith_ui index be9e992..1df5c5d 160000 --- a/systems/hadith_ui +++ b/systems/hadith_ui @@ -1 +1 @@ -Subproject commit be9e992c68be3240d197244ff87e5ae910dc88c1 +Subproject commit 1df5c5d35659e965e51faf69d32a525534421d15