(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; 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); loadingIndicator.style.display = 'none'; // Use a temporary div to parse the HTML fragment let tempDiv = document.createElement('div'); tempDiv.innerHTML = html; let newImages = tempDiv.querySelectorAll('.image'); if (newImages.length > 0) { let resultsContainer = document.querySelector('.images'); newImages.forEach(imageDiv => { // Clone the node to ensure it's part of the main document let clonedImageDiv = imageDiv.cloneNode(true); resultsContainer.appendChild(clonedImageDiv); let img = clonedImageDiv.querySelector('img'); if (img) { let id = img.getAttribute('data-id'); if (id) { imageElements.push(img); imageIds.push(id); } if (hardCacheEnabled) { img.src = '/static/images/placeholder.svg'; img.onerror = function() { handleImageError(img); }; } else { img.src = img.getAttribute('data-full'); img.onerror = function() { handleImageError(img); }; } } }); if (hardCacheEnabled) { checkImageStatus(); } ensureScrollable(); } else { noMoreImages = true; } isFetching = false; }) .catch(error => { clearTimeout(loadingTimer); loadingIndicator.style.display = 'none'; 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 imageElements = Array.from(document.querySelectorAll('img[data-id]')); imageIds = imageElements .map(img => img.getAttribute('data-id')) .filter(id => id); // Exclude empty IDs if (hardCacheEnabled) { // 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 } else { // HardCacheEnabled is false; load images immediately imageElements.forEach(img => { img.src = img.getAttribute('data-full'); img.onerror = function() { handleImageError(img); }; }); } // 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(); } }); })();