(function() { // Configuration const imageStatusInterval = 500; // Interval in milliseconds to check image status const scrollThreshold = 500; // Distance from bottom of the page to trigger loading const loadingIndicator = document.getElementById('message-bottom-left'); let loadingTimer; let isFetching = false; let page = parseInt(document.getElementById('template-data').getAttribute('data-page')) || 1; let query = document.getElementById('template-data').getAttribute('data-query'); let hardCacheEnabled = document.getElementById('template-data').getAttribute('data-hard-cache-enabled') === 'true'; let noMoreImages = false; // Flag to indicate if there are no more images to load let imageElements = []; let imageIds = []; /** * Function to handle image load errors with retry logic * @param {HTMLElement} imgElement - The image element that failed to load * @param {number} retryCount - Number of retries left * @param {number} retryDelay - Delay between retries in milliseconds */ function handleImageError(imgElement, retryCount = 3, retryDelay = 1000) { if (retryCount > 0) { setTimeout(() => { imgElement.src = imgElement.getAttribute('data-full'); imgElement.onerror = function() { handleImageError(imgElement, retryCount - 1, retryDelay); }; }, retryDelay); } else { // After retries, hide the image container or set a fallback image console.warn('Image failed to load after retries:', imgElement.getAttribute('data-full')); imgElement.parentElement.style.display = 'none'; // Hide the image container // Alternatively, set a fallback image: // imgElement.src = '/static/images/fallback.svg'; } } /** * Function to ensure the page is scrollable by loading more images if necessary */ function ensureScrollable() { if (noMoreImages) return; // Do not attempt if no more images are available // Check if the page is not scrollable if (document.body.scrollHeight <= window.innerHeight) { // If not scrollable, fetch the next page fetchNextPage(); } } /** * Function to fetch the next page of images */ function fetchNextPage() { if (isFetching || noMoreImages) return; // Start the timer for loading indicator loadingTimer = setTimeout(() => { loadingIndicator.style.display = 'flex'; }, 150); isFetching = true; page += 1; fetch(`/search?q=${encodeURIComponent(query)}&t=image&p=${page}&ajax=true`) .then(response => response.text()) .then(html => { clearTimeout(loadingTimer); // Clear the timer if fetch is successful loadingIndicator.style.display = 'none'; // Hide the loading indicator let parser = new DOMParser(); let doc = parser.parseFromString(html, 'text/html'); let newImages = doc.querySelectorAll('.image'); if (newImages.length > 0) { let resultsContainer = document.querySelector('.images'); newImages.forEach(imageDiv => { // Append new images to the container resultsContainer.appendChild(imageDiv); // Get the img element let img = imageDiv.querySelector('img'); if (img) { if (hardCacheEnabled) { // Replace image with placeholder img.src = '/static/images/placeholder.svg'; img.onerror = function() { handleImageError(img); }; let id = img.getAttribute('data-id'); if (id) { imageElements.push(img); imageIds.push(id); } } } }); if (hardCacheEnabled) { checkImageStatus(); } // After appending new images, ensure the page is scrollable ensureScrollable(); } else { // No more images to load noMoreImages = true; } isFetching = false; }) .catch(error => { clearTimeout(loadingTimer); // Clear the timer if fetch fails loadingIndicator.style.display = 'none'; // Hide the loading indicator console.error('Error fetching next page:', error); isFetching = false; }); } /** * Function to check image status via AJAX */ function checkImageStatus() { if (!hardCacheEnabled) return; if (imageIds.length === 0) { // No images to check, do nothing return; } // Send AJAX request to check image status fetch(`/image_status?image_ids=${imageIds.join(',')}`) .then(response => response.json()) .then(statusMap => { imageElements = imageElements.filter(img => { let id = img.getAttribute('data-id'); if (statusMap[id]) { // Image is ready, update src img.src = statusMap[id]; img.onerror = function() { handleImageError(img); }; // Remove the image id from the list imageIds = imageIds.filter(imageId => imageId !== id); return false; // Remove img from imageElements } return true; // Keep img in imageElements }); // After updating images, ensure the page is scrollable ensureScrollable(); }) .catch(error => { console.error('Error checking image status:', error); }); } // Initialize imageElements and imageIds if (hardCacheEnabled) { imageElements = Array.from(document.querySelectorAll('img[data-id]')); imageIds = imageElements .map(img => img.getAttribute('data-id')) .filter(id => id); // Exclude empty IDs // Replace images with placeholders imageElements.forEach(img => { img.src = '/static/images/placeholder.svg'; }); // Start checking image status let imageStatusTimer = setInterval(checkImageStatus, imageStatusInterval); checkImageStatus(); // Initial check // After initial images are loaded, ensure the page is scrollable window.addEventListener('load', ensureScrollable); } // Infinite scrolling window.addEventListener('scroll', function() { if (isFetching || noMoreImages) return; if (window.innerHeight + window.scrollY >= document.body.offsetHeight - scrollThreshold) { // User scrolled near the bottom fetchNextPage(); } }); // Remove 'js-enabled' class from content document.getElementById('content').classList.remove('js-enabled'); })();