Search/static/js/dynamicscrollingimages.js

199 lines
8 KiB
JavaScript
Raw Normal View History

(function() {
// Configuration
const imageStatusInterval = 500; // Interval in milliseconds to check image status
const scrollThreshold = 500; // Distance from bottom of the page to trigger loading
2024-12-02 21:32:30 +01:00
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;
2024-12-02 21:32:30 +01:00
// Start the timer for loading indicator
loadingTimer = setTimeout(() => {
loadingIndicator.style.display = 'flex';
}, 150);
isFetching = true;
page += 1;
2024-12-02 21:32:30 +01:00
fetch(`/search?q=${encodeURIComponent(query)}&t=image&p=${page}&ajax=true`)
.then(response => response.text())
.then(html => {
2024-12-02 21:32:30 +01:00
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');
2024-12-02 21:32:30 +01:00
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) {
let id = img.getAttribute('data-id');
if (id) {
imageElements.push(img);
imageIds.push(id);
}
if (hardCacheEnabled) {
// Replace image with placeholder
img.src = '/static/images/placeholder.svg';
img.onerror = function() {
handleImageError(img);
};
} else {
// HardCacheEnabled is false; load images immediately
img.src = img.getAttribute('data-full');
img.onerror = function() {
handleImageError(img);
};
}
}
});
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 => {
2024-12-02 21:32:30 +01:00
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
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();
}
});
// Remove 'js-enabled' class from content
document.getElementById('content').classList.remove('js-enabled');
})();