Search/static/js/dynamicscrollingimages.js
partisan 1acd1c0cab
Some checks failed
Run Integration Tests / test (push) Failing after 38s
Fixed image dynamic scrolling not working with DriveCache = true
2025-03-26 20:27:07 +01:00

152 lines
No EOL
5.6 KiB
JavaScript

(function() {
// Configuration
const imageStatusInterval = 500;
const scrollThreshold = 500;
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;
let imageElements = [];
let imageIds = [];
let imageStatusTimer;
function handleImageError(imgElement, retryCount = 3, retryDelay = 1000) {
if (retryCount > 0) {
setTimeout(() => {
imgElement.src = imgElement.getAttribute('data-full');
imgElement.onerror = () => handleImageError(imgElement, retryCount - 1, retryDelay);
}, retryDelay);
} else {
console.warn('Image failed to load:', imgElement.getAttribute('data-full'));
imgElement.parentElement.style.display = 'none';
}
}
function ensureScrollable() {
if (noMoreImages) return;
if (document.body.scrollHeight <= window.innerHeight) {
fetchNextPage();
}
}
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';
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')) {
if (hardCacheEnabled) {
img.src = '/static/images/placeholder.svg';
img.onerror = () => handleImageError(img);
imageElements.push(img);
imageIds.push(img.getAttribute('data-id'));
} else {
img.src = img.getAttribute('data-full');
img.onerror = () => handleImageError(img);
}
}
});
if (hardCacheEnabled) {
checkImageStatus(); // Immediately check status for new images
}
ensureScrollable();
} else {
noMoreImages = true;
}
isFetching = false;
})
.catch(error => {
clearTimeout(loadingTimer);
loadingIndicator.style.display = 'none';
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.onerror = () => handleImageError(img);
} else {
pendingImages.push(img);
pendingIds.push(id);
}
});
imageElements = pendingImages;
imageIds = pendingIds;
ensureScrollable();
})
.catch(error => {
console.error('Status check error:', error);
});
}
// Initialize
document.querySelectorAll('img[data-id]').forEach(img => {
const id = img.getAttribute('data-id');
if (id) {
imageElements.push(img);
imageIds.push(id);
if (hardCacheEnabled) {
img.src = '/static/images/placeholder.svg';
} else {
img.src = img.getAttribute('data-full');
}
img.onerror = () => handleImageError(img);
}
});
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();
}
});
// Cleanup
window.addEventListener('beforeunload', () => {
if (imageStatusTimer) clearInterval(imageStatusTimer);
});
})();