added fallback mechanic to imageviewer.js
This commit is contained in:
parent
5881fa76e0
commit
d8ebe94657
3 changed files with 207 additions and 189 deletions
174
static/js/dynamicscrollingimages.js
Normal file
174
static/js/dynamicscrollingimages.js
Normal file
|
@ -0,0 +1,174 @@
|
|||
(function() {
|
||||
// Configuration
|
||||
const imageStatusInterval = 500; // Interval in milliseconds to check image status
|
||||
const scrollThreshold = 500; // Distance from bottom of the page to trigger loading
|
||||
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;
|
||||
isFetching = true;
|
||||
page += 1;
|
||||
|
||||
fetch(`/search?q=${encodeURIComponent(query)}&t=image&p=${page}&ajax=true`)
|
||||
.then(response => response.text())
|
||||
.then(html => {
|
||||
// Parse the returned HTML and extract image elements
|
||||
let parser = new DOMParser();
|
||||
let doc = parser.parseFromString(html, 'text/html');
|
||||
let newImages = doc.querySelectorAll('.image');
|
||||
|
||||
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) {
|
||||
if (hardCacheEnabled) {
|
||||
// Replace image with placeholder
|
||||
img.src = '/static/images/placeholder.svg';
|
||||
img.onerror = function() {
|
||||
handleImageError(img);
|
||||
};
|
||||
|
||||
let id = img.getAttribute('data-id');
|
||||
if (id) { // Only include if ID is not empty
|
||||
imageElements.push(img);
|
||||
imageIds.push(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
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 => {
|
||||
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
|
||||
if (hardCacheEnabled) {
|
||||
imageElements = Array.from(document.querySelectorAll('img[data-id]'));
|
||||
imageIds = imageElements
|
||||
.map(img => img.getAttribute('data-id'))
|
||||
.filter(id => id); // Exclude empty IDs
|
||||
|
||||
// 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
|
||||
|
||||
// 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');
|
||||
})();
|
|
@ -60,10 +60,29 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
|
||||
const imgElement = imageList[index];
|
||||
const parentImageDiv = imgElement.closest('.image');
|
||||
const fullImageUrl = imgElement.getAttribute('data-full'); // Use data-full for the full image URL
|
||||
const title = imgElement.alt || '';
|
||||
const sourceUrl = parentImageDiv.querySelector('.img_source').href || '#'; // Source webpage URL
|
||||
|
||||
if (!parentImageDiv) {
|
||||
console.warn('Parent image div not found');
|
||||
return;
|
||||
}
|
||||
|
||||
// Use the `data-full` attribute for the full image URL
|
||||
let fullImageUrl = imgElement.getAttribute('data-full') || imgElement.src;
|
||||
const title = imgElement.alt || 'Untitled';
|
||||
|
||||
// Gracefully handle the source URL or other attributes
|
||||
const sourceElement = parentImageDiv.querySelector('.img_source');
|
||||
const sourceUrl = sourceElement ? sourceElement.href : null;
|
||||
|
||||
// Fallback logic: if sourceUrl is null, use `data-proxy-full` or a meaningful default
|
||||
const proxyFullUrl = imgElement.getAttribute('data-proxy-full') || fullImageUrl;
|
||||
|
||||
// Check if full image is missing, fallback to proxy size
|
||||
if (fullImageUrl === '/static/images/missing.svg') {
|
||||
fullImageUrl = proxyFullUrl;
|
||||
}
|
||||
|
||||
// Elements in the viewer
|
||||
const viewerImage = document.getElementById('viewer-image');
|
||||
const viewerTitle = document.getElementById('viewer-title');
|
||||
const viewerSourceButton = document.getElementById('viewer-source-button');
|
||||
|
@ -71,13 +90,14 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
const proxySizeLink = document.getElementById('viewer-proxy-size-link');
|
||||
const viewerImageLink = document.getElementById('viewer-image-link');
|
||||
|
||||
// Set the viewer image to the full image URL
|
||||
viewerImage.src = fullImageUrl;
|
||||
// Assign values to the viewer elements
|
||||
viewerImage.src = fullImageUrl; // Full-size image in the viewer
|
||||
viewerTitle.textContent = title;
|
||||
viewerSourceButton.href = sourceUrl;
|
||||
fullSizeLink.href = sourceUrl; // Link to the source website
|
||||
proxySizeLink.href = fullImageUrl; // Link to the proxied full-size image
|
||||
viewerImageLink.href = fullImageUrl; // Make image clickable to open in new tab
|
||||
|
||||
viewerSourceButton.href = sourceUrl || proxyFullUrl; // Use proxy URL if source is missing
|
||||
fullSizeLink.href = sourceUrl || proxyFullUrl; // Link to source website or proxy
|
||||
proxySizeLink.href = fullImageUrl; // Link to the proxied full-size image
|
||||
viewerImageLink.href = fullImageUrl; // Make image clickable to open in a new tab
|
||||
}
|
||||
|
||||
// Attach event listener to the document body
|
||||
|
|
|
@ -152,182 +152,6 @@
|
|||
<script defer src="/static/js/autocomplete.js"></script>
|
||||
<script defer src="/static/js/imagetitletrim.js"></script>
|
||||
<script defer src="/static/js/imageviewer.js"></script>
|
||||
<!-- JavaScript to Load Images and Dynamic loading of the page -->
|
||||
<script>
|
||||
(function() {
|
||||
// Configuration
|
||||
const imageStatusInterval = 500; // Interval in milliseconds to check image status
|
||||
const scrollThreshold = 500; // Distance from bottom of the page to trigger loading
|
||||
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;
|
||||
isFetching = true;
|
||||
page += 1;
|
||||
|
||||
fetch(`/search?q=${encodeURIComponent(query)}&t=image&p=${page}&ajax=true`)
|
||||
.then(response => response.text())
|
||||
.then(html => {
|
||||
// Parse the returned HTML and extract image elements
|
||||
let parser = new DOMParser();
|
||||
let doc = parser.parseFromString(html, 'text/html');
|
||||
let newImages = doc.querySelectorAll('.image');
|
||||
|
||||
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) {
|
||||
if (hardCacheEnabled) {
|
||||
// Replace image with placeholder
|
||||
img.src = '/static/images/placeholder.svg';
|
||||
img.onerror = function() {
|
||||
handleImageError(img);
|
||||
};
|
||||
|
||||
let id = img.getAttribute('data-id');
|
||||
if (id) { // Only include if ID is not empty
|
||||
imageElements.push(img);
|
||||
imageIds.push(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
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 => {
|
||||
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
|
||||
if (hardCacheEnabled) {
|
||||
imageElements = Array.from(document.querySelectorAll('img[data-id]'));
|
||||
imageIds = imageElements
|
||||
.map(img => img.getAttribute('data-id'))
|
||||
.filter(id => id); // Exclude empty IDs
|
||||
|
||||
// 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
|
||||
|
||||
// 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');
|
||||
})();
|
||||
</script>
|
||||
<script defer src="/static/js/dynamicscrollingimages.js"></script>
|
||||
</body>
|
||||
</html>
|
Loading…
Add table
Reference in a new issue