2024-12-02 10:45:50 +01:00
|
|
|
(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;
|
2024-12-02 10:45:50 +01:00
|
|
|
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);
|
|
|
|
|
2024-12-02 10:45:50 +01:00
|
|
|
isFetching = true;
|
|
|
|
page += 1;
|
2024-12-02 21:32:30 +01:00
|
|
|
|
2024-12-02 10:45:50 +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
|
|
|
|
|
2024-12-02 10:45:50 +01:00
|
|
|
let parser = new DOMParser();
|
|
|
|
let doc = parser.parseFromString(html, 'text/html');
|
|
|
|
let newImages = doc.querySelectorAll('.image');
|
2024-12-02 21:32:30 +01:00
|
|
|
|
2024-12-02 10:45:50 +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) {
|
2024-12-05 19:19:18 +01:00
|
|
|
let id = img.getAttribute('data-id');
|
|
|
|
if (id) {
|
|
|
|
imageElements.push(img);
|
|
|
|
imageIds.push(id);
|
|
|
|
}
|
2024-12-02 10:45:50 +01:00
|
|
|
if (hardCacheEnabled) {
|
|
|
|
// Replace image with placeholder
|
|
|
|
img.src = '/static/images/placeholder.svg';
|
|
|
|
img.onerror = function() {
|
|
|
|
handleImageError(img);
|
|
|
|
};
|
2024-12-05 19:19:18 +01:00
|
|
|
} else {
|
|
|
|
// HardCacheEnabled is false; load images immediately
|
|
|
|
img.src = img.getAttribute('data-full');
|
|
|
|
img.onerror = function() {
|
|
|
|
handleImageError(img);
|
|
|
|
};
|
2024-12-02 10:45:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
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
|
2024-12-02 10:45:50 +01:00
|
|
|
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
|
2024-12-05 19:19:18 +01:00
|
|
|
imageElements = Array.from(document.querySelectorAll('img[data-id]'));
|
|
|
|
imageIds = imageElements
|
|
|
|
.map(img => img.getAttribute('data-id'))
|
|
|
|
.filter(id => id); // Exclude empty IDs
|
2024-12-02 10:45:50 +01:00
|
|
|
|
2024-12-05 19:19:18 +01:00
|
|
|
if (hardCacheEnabled) {
|
2024-12-02 10:45:50 +01:00
|
|
|
// 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
|
2024-12-05 19:19:18 +01:00
|
|
|
} else {
|
|
|
|
// HardCacheEnabled is false; load images immediately
|
|
|
|
imageElements.forEach(img => {
|
|
|
|
img.src = img.getAttribute('data-full');
|
|
|
|
img.onerror = function() {
|
|
|
|
handleImageError(img);
|
|
|
|
};
|
|
|
|
});
|
2024-12-02 10:45:50 +01:00
|
|
|
}
|
|
|
|
|
2024-12-05 19:19:18 +01:00
|
|
|
// After initial images are loaded, ensure the page is scrollable
|
|
|
|
window.addEventListener('load', ensureScrollable);
|
|
|
|
|
2024-12-02 10:45:50 +01:00
|
|
|
// 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();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
})();
|