diff --git a/static/js/dynamicscrollingimages.js b/static/js/dynamicscrollingimages.js
new file mode 100644
index 0000000..5213f7f
--- /dev/null
+++ b/static/js/dynamicscrollingimages.js
@@ -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');
+})();
\ No newline at end of file
diff --git a/static/js/imageviewer.js b/static/js/imageviewer.js
index d703741..740c4d1 100644
--- a/static/js/imageviewer.js
+++ b/static/js/imageviewer.js
@@ -57,27 +57,47 @@ document.addEventListener('DOMContentLoaded', function() {
function displayImage(index) {
if (index < 0 || index >= imageList.length) return;
-
+
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');
const fullSizeLink = document.getElementById('viewer-full-size-link');
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
diff --git a/templates/images.html b/templates/images.html
index 62819ee..837d5ed 100755
--- a/templates/images.html
+++ b/templates/images.html
@@ -152,182 +152,6 @@
-
-
+