// dynamicscrollingimages.js (function() { // Add loading effects to image and title function addLoadingEffects(imgElement) { const title = imgElement.closest('.image').querySelector('.img_title'); imgElement.classList.add('loading-image'); title.classList.add('title-loading'); } function removeLoadingEffects(imgElement) { const title = imgElement.closest('.image').querySelector('.img_title'); imgElement.classList.remove('loading-image'); title.classList.remove('title-loading'); if (imgElement.src.endsWith('/images/missing.svg')) { imgElement.closest('.image').remove(); } } // Modified handleImageError with theme-consistent error handling function handleImageError(imgElement, retryCount = 3, retryDelay = 1000) { const container = imgElement.closest('.image'); const title = container.querySelector('.img_title'); if (retryCount > 0) { setTimeout(() => { imgElement.src = imgElement.getAttribute('data-full'); imgElement.onerror = () => handleImageError(imgElement, retryCount - 1, retryDelay); }, retryDelay); } else { imgElement.classList.remove('loading-image'); title.classList.remove('title-loading'); container.style.display = 'none'; } } // Rest of your existing code with minor additions const imageStatusInterval = 500; const scrollThreshold = 500; const loadingIndicator = document.getElementById('message-bottom-right'); 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; let imageElements = []; let imageIds = []; let imageStatusTimer; function showLoadingMessage() { loadingIndicator.classList.add('visible'); } function hideLoadingMessage() { loadingIndicator.classList.remove('visible'); } function ensureScrollable() { if (noMoreImages) return; if (document.body.scrollHeight <= window.innerHeight) { fetchNextPage(); } } function fetchNextPage() { if (isFetching || noMoreImages) return; loadingTimer = setTimeout(() => { showLoadingMessage(); }, 150); isFetching = true; page += 1; fetch(`/search?q=${encodeURIComponent(query)}&t=image&p=${page}&ajax=true`) .then(response => response.text()) .then(html => { clearTimeout(loadingTimer); hideLoadingMessage(); 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 => { let clonedImageDiv = imageDiv.cloneNode(true); resultsContainer.appendChild(clonedImageDiv); let img = clonedImageDiv.querySelector('img'); if (img && img.getAttribute('data-id')) { addLoadingEffects(img); if (hardCacheEnabled) { img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='; img.onerror = () => handleImageError(img); imageElements.push(img); imageIds.push(img.getAttribute('data-id')); } else { img.src = img.getAttribute('data-full'); img.onload = () => removeLoadingEffects(img); img.onerror = () => handleImageError(img); } } }); if (hardCacheEnabled) checkImageStatus(); ensureScrollable(); } else { noMoreImages = true; } isFetching = false; }) .catch(error => { clearTimeout(loadingTimer); hideLoadingMessage(); console.error('Fetch error:', error); isFetching = false; }); } function checkImageStatus() { if (!hardCacheEnabled || imageIds.length === 0) return; fetch(`/image_status?image_ids=${imageIds.join(',')}`) .then(response => response.json()) .then(statusMap => { const pendingImages = []; const pendingIds = []; imageElements.forEach(img => { const id = img.getAttribute('data-id'); if (statusMap[id]) { img.src = statusMap[id]; img.onload = () => removeLoadingEffects(img); img.onerror = () => handleImageError(img); } else { pendingImages.push(img); pendingIds.push(id); } }); imageElements = pendingImages; imageIds = pendingIds; ensureScrollable(); }) .catch(error => { console.error('Status check error:', error); }); } // Initialize with loading effects document.querySelectorAll('img[data-id]').forEach(img => { const id = img.getAttribute('data-id'); if (id) { addLoadingEffects(img); imageElements.push(img); imageIds.push(id); if (hardCacheEnabled) { img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='; } else { img.src = img.getAttribute('data-full'); img.onload = () => removeLoadingEffects(img); } img.onerror = () => handleImageError(img); } }); // Rest of your existing code remains unchanged if (hardCacheEnabled) { imageStatusTimer = setInterval(checkImageStatus, imageStatusInterval); checkImageStatus(); } window.addEventListener('load', ensureScrollable); window.addEventListener('scroll', () => { if (isFetching || noMoreImages) return; if (window.innerHeight + window.scrollY >= document.body.offsetHeight - scrollThreshold) { fetchNextPage(); } }); window.addEventListener('beforeunload', () => { if (imageStatusTimer) clearInterval(imageStatusTimer); }); })();