2024-08-13 16:38:02 +02:00
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
<html lang="en">
|
|
|
|
|
<head>
|
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
2024-08-28 21:31:27 +02:00
|
|
|
|
{{ if .IsThemeDark }}
|
|
|
|
|
<meta name="darkreader-lock">
|
|
|
|
|
{{ end }}
|
2024-10-09 21:03:53 +02:00
|
|
|
|
<title>{{ .Query }} - {{ translate "site_name" }}</title>
|
2024-08-13 16:38:02 +02:00
|
|
|
|
<link rel="stylesheet" href="/static/css/style.css">
|
2024-11-19 12:14:11 +01:00
|
|
|
|
<noscript>
|
|
|
|
|
<style>
|
|
|
|
|
img.placeholder-img {
|
|
|
|
|
display: none;
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
</noscript>
|
2024-10-06 01:24:59 +02:00
|
|
|
|
<link rel="stylesheet" href="/static/css/style-fixedwidth.css">
|
2024-08-13 16:38:02 +02:00
|
|
|
|
<link rel="stylesheet" href="/static/css/{{.Theme}}.css">
|
2024-10-28 10:52:39 +01:00
|
|
|
|
<link rel="search" type="application/opensearchdescription+xml" title="{{ translate "site_name" }}" href="/opensearch.xml">
|
|
|
|
|
<!-- Icons -->
|
|
|
|
|
<link rel="icon" href="{{ .IconPathSVG }}" type="image/svg+xml">
|
|
|
|
|
<link rel="icon" href="{{ .IconPathPNG }}" type="image/png">
|
|
|
|
|
<link rel="apple-touch-icon" href="{{ .IconPathPNG }}">
|
2024-08-13 16:38:02 +02:00
|
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
<form action="/search" id="prev-next-form" class="results-search-container" method="GET" autocomplete="off">
|
2024-10-22 12:15:09 +02:00
|
|
|
|
<h1 class="logomobile">
|
|
|
|
|
<div class="logo-container" herf="/">
|
|
|
|
|
<a href="/">
|
2024-11-26 08:07:35 +01:00
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="29" height="86" viewBox="0 0 29 86"><path fill-rule="evenodd" d="M-44.35.78C-70.8 6.76-74.8 43.17-50.67 55.73c1.7.88 4.42 1.7 7.83 2.22 4.48.68 9.6.86 9.58.15-.04-1.43-7.3-8.28-8.67-8.28-3.15 0-9.94-5.66-11.97-10C-61.95 22.66-48.1 4.54-31.12 10c13.5 4.34 18.1 22.7 8.66 34.44-1.85 2.3-1.75 2.3-4.4-.22-4.8-4.59-8.57-5.25-11.98-2.1-2.18 2-2.15 2.66.15 4.14 1.9 1.22 13.4 12.95 17.49 17.83 4.3 5.13 5.24 6.14 7.52 7.97C-9.25 75.6-1.23 77.91 1 76.28c.67-.5 1.86-7.8 1.35-8.3-.12-.12-1.34-.4-2.7-.61-5.36-.86-9.23-3.46-14.2-9.55-3.49-4.27-4.12-5.26-3.38-5.26 2.54 0 8.05-8.62 9.86-15.43C-2.36 15.63-22.18-4.23-44.35.78m65.13 1.53C4.92 6.02-4.86 22.36-.72 38.24 3 52.62 18.43 59.63 33.67 57.64c4.7-.62 2.43-.66 4.45-.8s6.45-.01 6.93-.2c.4.03.72-.45.72-.94V42.31c0-7.36-.16-13.62-.33-13.9-.26-.4-2.36-.49-10.19-.4-11.44.15-10.96-.03-10.96 4.09 0 2.44-.04 3.99 1.17 4.7 1.13.68 3.43.59 6.68.41l3.76-.2.27 5.68c.33 6.59.57 6.15-3.64 6.7-15.53 2.04-24-5.02-23.37-19.43.66-15.1 12.2-22.78 26.96-17.94 4.5 1.47 4.4 1.52 6.16-2.8 1.5-3.68 1.5-3.69-.82-4.69C36.03 2.2 25.9 1.11 20.78 2.31m78.83.8c-2.87.76-2.9.84-3.15 6.12-.25 5.56.12 4.96-3.35 5.29-3.43.32-3.32.15-2.76 4.2.61 4.37.6 4.34 3.76 4.34h2.65v12.7c0 14.5 1.55 16.33 3.5 18.3 3.6 3.48 9.59 4.92 14.93 3.06 2.45-.85 2.43-.8 2.18-4.95-.25-4.1-.43-3.5-3.16-2.91-7.73 1.64-8.27.6-8.27-15.05V22.87h5.66l5.34-.1c.67-.01.97.4 1.28-3.9.35-4.8-.2-4.01-.8-4.14l-5.82.18-5.66.26v-5.16c0-5.84-.2-6.48-2.25-7.04-1.75-.49-1.76-.49-4.08.13m-34.5 11.02c-2.64.38-4.71 1.04-8.54 2.72l-4.03 1.76c-1.09.39-.28 1.29.69 3.89 1.06 2.75 1.35 3.35 2.11 3.03.76-.32.7-.23 1.43-.65 9.08-5.25 20.26-2.63 20.26 4.74v2.14l-5.95.2c-13.84.48-20.29 4.75-20.38 13.51-.13 12.4 14.18 17.22 24.62 8.3l2.3-1.97.23 1.85c.32 2.53.6 3.06 2.04 3.67 1.42.6 7.16.62 7.75.03.77-.77.37-6-.25-6.34-.94-.5-.77-1.57-.88-12.63-.15-14.87-.5-16.5-4.4-20.13-3.03-2.84-11.55-4.9-17-4.12m72.86 0c-27.2 5.27-24.13 43.96 3.47 43.9 14.67-.04 24.4-12.77 21.53-28.16-1.86-9.95-14.33-17.8-25-15.73m8.29 8.96c6.88 2.34 9.61 11.51 5.9 19.79-4.13 9.19-17.89 9.17-22.14-.03-1.32-2.85-1.24-10.79.14-13.54 3-6 9.45-8.49 16.1-6.22m-68.84 18.5v3.09l-1.85 1.63c-7.46 6.58-16.36 5.49-15.6-1.9.45-4.35 3.62-5.77 13.06-5.87l4.4-.05v3.1" style="fill:currentColor" transform="translate(-31.68 4.9)"/><path d="M-13.47 73.3v1.11q-.65-.3-1.23-.46-.57-.15-1.11-.15-.93 0-1.44.36-.5.36-.5 1.03 0 .56.33.85.34.28 1.28.46l.69.14q1.27.24 1.88.86.6.6.6 1.64 0 1.22-.82 1.86-.82.63-2.4.63-.6 0-1.28-.14-.68-.13-1.4-.4v-1.17q.7.39 1.36.58.67.2 1.31.2.98 0 1.51-.38.54-.39.54-1.1 0-.62-.39-.97-.38-.35-1.25-.53l-.7-.13q-1.27-.26-1.84-.8-.57-.54-.57-1.51 0-1.12.78-1.76.8-.65 2.18-.65.6 0 1.2.1.63.12 1.27.33zm2.29-.28h5.34V74h-4.2v2.5h4.02v.96h-4.02v3.05h4.3v.97h-5.44zm10.14 1.13-1.55 4.2H.5zm-.65-1.13h1.3l3.21 8.45H1.64L.87 79.3h-3.8l-.78 2.17h-1.2zm9.75 4.48q.37.13.71.54.35.4.7 1.12l1.16 2.3H9.41L8.33 79.3q-.42-.85-.82-1.13-.39-.27-1.07-.27H5.2v3.57H4.06v-8.45h2.58q1.44 0 2.16.6.7.61.7 1.84 0 .8-.36 1.32-.37.52-1.08.73zM5.2 73.97v3h1.44q.82 0 1.24-.38.42-.38.42-1.12 0-.75-.42-1.12-.42-.38-1.24-.38zm12.65-.3v1.2q-.58-.53-1.23-.8-.65-.26-1.39-.26-1.45 0-2.22.89-.77.88-.77 2.55t.77 2.56q.77.88 2.22.88.74 0 1.39-.26.65-.27 1.23-.8v1.19q-.6.4-1.27.6-.67.21-1.42.21-1.91 0-3.02-1.17-1.1-1.18-1.1-3.2 0-2.04 1.1-3.21 1.1-1.18 3.02-1.18.76 0 1.43.2.67.2 1.26.6zm1.76-.65h1.14v3.46h4.15v-3.46h1.15v8.45H24.9v-4.02h-4.15v4.02h-1.14zm12.39 0h5.34V74h-4.2v2.5h4.02v.96h-4.02v3.05h4.3v.97H32zm7.32 0h1.53l3.75 7.07v-7.07h1.1v8.45h-1.53l-3.74-7.07v7.07h-1.11zm14.42 7.24V78h-1.87v-.93h3v3.62q-.67.47-1.46.71-.8.24-1.7.24-1.98 0-3.1-1.15-1.12-1.16-1.12-3.23 0-2.07 1.12-3.22 1.12-1.16 3.1-1.16.82 0 1.56.2.75.2 1.38.6v1.22q-.64-.54-1.35-.8-.71-.28-1.5-.28-1.55 0-2.33.86-.77.87-.77 2.58t.77 2.58q.78.86 2.33.86.6 0 1.08-.1.48-.1.86-.33zm3.21-7.24h1.14v8.45h-1.14zm3.42 0h1.54l3.74 7.07v-7.07h1.1v8.45h-1.53l-3.74-7.07v7.07h-1.11zm8.66 0h5.34V74h-4.2v2.5h4.02v.96h-4.02v3.05h4.3v.97h-5.44z" aria-label="SEARCH ENGINE" style="font-family:'ADLaM Display';white-space:pre;fi
|
2024-10-22 12:15:09 +02:00
|
|
|
|
</a>
|
|
|
|
|
</div>
|
|
|
|
|
</h1>
|
2024-08-13 16:38:02 +02:00
|
|
|
|
<div class="wrapper-results">
|
2024-09-27 17:27:16 +02:00
|
|
|
|
<input type="text" name="q" value="{{ .Query }}" id="search-input"/>
|
2024-08-13 16:38:02 +02:00
|
|
|
|
<button id="search-wrapper-ico" class="material-icons-round" name="t" value="image">search</button>
|
2024-08-21 23:23:08 +02:00
|
|
|
|
<div class="autocomplete">
|
|
|
|
|
<ul>
|
|
|
|
|
</ul>
|
|
|
|
|
</div>
|
2024-08-13 16:38:02 +02:00
|
|
|
|
<input type="submit" class="hide" name="t" value="image" />
|
|
|
|
|
</div>
|
|
|
|
|
<div class="sub-search-button-wrapper">
|
|
|
|
|
<div class="search-container-results-btn">
|
|
|
|
|
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="text">search</button>
|
2024-10-08 22:11:06 +02:00
|
|
|
|
<button name="t" value="text" class="clickable">{{ translate "web" }}</button>
|
2024-08-13 16:38:02 +02:00
|
|
|
|
</div>
|
|
|
|
|
<div class="search-container-results-btn">
|
|
|
|
|
<button id="sub-search-wrapper-ico" class="material-icons-round clickable search-active" name="t" value="image">image</button>
|
2024-10-08 22:11:06 +02:00
|
|
|
|
<button name="t" value="image" class="clickable search-active">{{ translate "images" }}</button>
|
2024-08-13 16:38:02 +02:00
|
|
|
|
</div>
|
|
|
|
|
<div class="search-container-results-btn">
|
|
|
|
|
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="video">movie</button>
|
2024-10-08 22:11:06 +02:00
|
|
|
|
<button name="t" value="video" class="clickable">{{ translate "videos" }}</button>
|
2024-08-13 16:38:02 +02:00
|
|
|
|
</div>
|
|
|
|
|
<div class="search-container-results-btn">
|
|
|
|
|
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="forum">forum</button>
|
2024-10-08 22:11:06 +02:00
|
|
|
|
<button name="t" value="forum" class="clickable">{{ translate "forums" }}</button>
|
2024-08-13 16:38:02 +02:00
|
|
|
|
</div>
|
|
|
|
|
<div id="content" class="js-enabled">
|
|
|
|
|
<div class="search-container-results-btn">
|
|
|
|
|
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="map">map</button>
|
2024-10-08 22:11:06 +02:00
|
|
|
|
<button name="t" value="map" class="clickable">{{ translate "maps" }}</button>
|
2024-08-13 16:38:02 +02:00
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="search-container-results-btn">
|
|
|
|
|
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="file">share</button>
|
2024-10-08 22:11:06 +02:00
|
|
|
|
<button name="t" value="file" class="clickable">{{ translate "torrents" }}</button>
|
2024-08-13 16:38:02 +02:00
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2024-11-19 10:36:33 +01:00
|
|
|
|
<noscript>
|
|
|
|
|
<input type="hidden" name="js_enabled" value="true">
|
|
|
|
|
</noscript>
|
2024-08-13 16:38:02 +02:00
|
|
|
|
</form>
|
|
|
|
|
<form class="results_settings" action="/search" method="get">
|
|
|
|
|
<input type="hidden" name="q" value="{{ .Query }}">
|
|
|
|
|
<select class="results-settings" name="safe" id="safeSearchSelect">
|
2024-10-08 22:11:06 +02:00
|
|
|
|
<option value="disabled" {{if eq .Safe "disabled"}}selected{{end}}>{{ translate "safe_search_off" }}</option>
|
|
|
|
|
<option value="active" {{if eq .Safe "active"}}selected{{end}}>{{ translate "safe_search_on" }}</option>
|
2024-08-13 16:38:02 +02:00
|
|
|
|
</select>
|
|
|
|
|
<select class="results-settings" name="lang" id="languageSelect">
|
|
|
|
|
{{range .LanguageOptions}}
|
2024-10-10 18:41:53 +02:00
|
|
|
|
<option value="{{.Code}}" {{if eq .Code $.CurrentLang}}selected{{end}}>{{.Name}}</option> <!-- this is too wide or too less, fix -->
|
2024-08-13 16:38:02 +02:00
|
|
|
|
{{end}}
|
|
|
|
|
</select>
|
2024-10-08 22:11:06 +02:00
|
|
|
|
<button class="results-save" name="t" value="image">{{ translate "save_settings" }}</button>
|
2024-08-13 16:38:02 +02:00
|
|
|
|
</form>
|
2024-10-06 01:24:59 +02:00
|
|
|
|
<div class="search-results" id="results">
|
|
|
|
|
|
2024-11-13 16:59:42 +01:00
|
|
|
|
<!-- Results go here -->
|
|
|
|
|
{{ if .Results }}
|
|
|
|
|
<div class="images images_viewer_hidden">
|
|
|
|
|
<!-- Images Grid -->
|
|
|
|
|
{{ range $index, $result := .Results }}
|
|
|
|
|
<div class="image">
|
|
|
|
|
{{ if $.HardCacheEnabled }}
|
2024-11-19 10:36:33 +01:00
|
|
|
|
<noscript>
|
2024-11-13 16:59:42 +01:00
|
|
|
|
<!-- JavaScript is disabled; serve actual images -->
|
|
|
|
|
<img src="{{ $result.ProxyFull }}" alt="{{ $result.Title }}" class="clickable" />
|
2024-11-19 10:36:33 +01:00
|
|
|
|
</noscript>
|
|
|
|
|
|
|
|
|
|
<!-- JavaScript is enabled; use placeholders -->
|
2024-11-19 12:14:11 +01:00
|
|
|
|
<img
|
|
|
|
|
src="/static/images/placeholder.svg"
|
|
|
|
|
data-id="{{ $result.ID }}"
|
|
|
|
|
data-full="{{ $result.ProxyFull }}"
|
|
|
|
|
data-proxy-full="{{ $result.ProxyThumb }}"
|
|
|
|
|
alt="{{ $result.Title }}"
|
|
|
|
|
class="clickable placeholder-img"
|
|
|
|
|
/>
|
2024-11-13 16:59:42 +01:00
|
|
|
|
{{ else }}
|
|
|
|
|
<!-- HardCacheEnabled is false; serve images directly -->
|
|
|
|
|
<img src="{{ $result.ProxyFull }}" alt="{{ $result.Title }}" class="clickable" />
|
|
|
|
|
{{ end }}
|
|
|
|
|
<div class="resolution">{{ $result.Width }} × {{ $result.Height }}</div>
|
|
|
|
|
<div class="details">
|
|
|
|
|
<span class="img_title clickable">{{ $result.Title }}</span>
|
2024-10-13 00:04:46 +02:00
|
|
|
|
</div>
|
2024-11-13 16:59:42 +01:00
|
|
|
|
</div>
|
|
|
|
|
{{ end }}
|
|
|
|
|
</div>
|
|
|
|
|
<!-- Nav buttons -->
|
|
|
|
|
<noscript>
|
|
|
|
|
<form action="/search" id="prev-next-form" class="results-search-container" method="GET" autocomplete="off">
|
|
|
|
|
<!-- Existing form fields -->
|
|
|
|
|
<input type="hidden" name="js_disabled" value="true">
|
|
|
|
|
</form>
|
|
|
|
|
<!-- Nav buttons -->
|
|
|
|
|
<div class="pagination">
|
|
|
|
|
{{ if .HasPrevPage }}
|
2024-11-19 12:14:11 +01:00
|
|
|
|
<a href="/search?q={{ .Query }}&t=image&p={{ sub .Page 1 }}">{{ translate "previous" }}</a>
|
2024-11-13 16:59:42 +01:00
|
|
|
|
{{ end }}
|
|
|
|
|
{{ if .HasNextPage }}
|
2024-11-19 12:14:11 +01:00
|
|
|
|
<a href="/search?q={{ .Query }}&t=image&p={{ add .Page 1 }}">{{ translate "next" }}</a>
|
2024-08-13 16:38:02 +02:00
|
|
|
|
{{ end }}
|
|
|
|
|
</div>
|
2024-11-13 16:59:42 +01:00
|
|
|
|
</noscript>
|
|
|
|
|
{{ else if .NoResults }}
|
|
|
|
|
<div class="no-results">{{ translate "no_results" .Query }}</div>
|
|
|
|
|
{{ else }}
|
|
|
|
|
<div class="no-more-results">{{ translate "no_more_results" }}</div>
|
|
|
|
|
{{ end }}
|
2024-08-13 16:38:02 +02:00
|
|
|
|
</div>
|
|
|
|
|
<div class="message-bottom-left" id="message-bottom-left">
|
2024-10-08 22:11:06 +02:00
|
|
|
|
<span>{{ translate "searching_for_new_results" }}</span>
|
2024-08-13 16:38:02 +02:00
|
|
|
|
</div>
|
2024-10-06 01:24:59 +02:00
|
|
|
|
|
|
|
|
|
<div id="image-viewer-overlay" style="display: none;"></div>
|
|
|
|
|
|
2024-10-16 22:51:13 +02:00
|
|
|
|
<div id="template-data" data-page="{{ .Page }}" data-query="{{ .Query }}" data-type="image" data-hard-cache-enabled="{{ .HardCacheEnabled }}"></div>
|
2024-08-21 23:23:08 +02:00
|
|
|
|
<script defer src="/static/js/autocomplete.js"></script>
|
2024-10-06 18:11:58 +02:00
|
|
|
|
<script defer src="/static/js/imagetitletrim.js"></script>
|
2024-10-22 21:58:06 +02:00
|
|
|
|
<script defer src="/static/js/imageviewer.js"></script>
|
2024-11-13 16:59:42 +01:00
|
|
|
|
<!-- JavaScript to Load Images and Dynamic loading of the page -->
|
2024-10-13 00:04:46 +02:00
|
|
|
|
<script>
|
2024-11-13 16:59:42 +01:00
|
|
|
|
(function() {
|
|
|
|
|
// Configuration
|
2024-11-13 17:49:02 +01:00
|
|
|
|
const imageStatusInterval = 500; // Interval in milliseconds to check image status
|
2024-11-13 16:59:42 +01:00
|
|
|
|
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';
|
2024-11-14 16:33:04 +01:00
|
|
|
|
let noMoreImages = false; // Flag to indicate if there are no more images to load
|
2024-11-13 16:59:42 +01:00
|
|
|
|
|
|
|
|
|
let imageElements = [];
|
|
|
|
|
let imageIds = [];
|
|
|
|
|
|
2024-11-14 16:33:04 +01:00
|
|
|
|
/**
|
|
|
|
|
* 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;
|
2024-11-19 10:36:33 +01:00
|
|
|
|
|
2024-11-14 16:33:04 +01:00
|
|
|
|
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');
|
2024-11-19 10:36:33 +01:00
|
|
|
|
|
2024-11-14 16:33:04 +01:00
|
|
|
|
if (newImages.length > 0) {
|
|
|
|
|
let resultsContainer = document.querySelector('.images');
|
|
|
|
|
newImages.forEach(imageDiv => {
|
|
|
|
|
// Append new images to the container
|
|
|
|
|
resultsContainer.appendChild(imageDiv);
|
2024-11-19 10:36:33 +01:00
|
|
|
|
|
2024-11-14 16:33:04 +01:00
|
|
|
|
// 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);
|
|
|
|
|
};
|
2024-11-19 10:36:33 +01:00
|
|
|
|
|
2024-11-14 16:33:04 +01:00
|
|
|
|
let id = img.getAttribute('data-id');
|
2024-11-19 10:36:33 +01:00
|
|
|
|
if (id) { // Only include if ID is not empty
|
|
|
|
|
imageElements.push(img);
|
|
|
|
|
imageIds.push(id);
|
|
|
|
|
}
|
2024-11-14 16:33:04 +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 => {
|
|
|
|
|
console.error('Error fetching next page:', error);
|
|
|
|
|
isFetching = false;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Function to check image status via AJAX
|
|
|
|
|
*/
|
2024-10-13 00:04:46 +02:00
|
|
|
|
function checkImageStatus() {
|
2024-11-13 16:59:42 +01:00
|
|
|
|
if (!hardCacheEnabled) return;
|
|
|
|
|
if (imageIds.length === 0) {
|
|
|
|
|
// No images to check, do nothing
|
2024-10-13 00:04:46 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2024-11-13 16:59:42 +01:00
|
|
|
|
|
|
|
|
|
// Send AJAX request to check image status
|
2024-11-14 16:33:04 +01:00
|
|
|
|
fetch(`/image_status?image_ids=${imageIds.join(',')}`)
|
2024-10-13 00:04:46 +02:00
|
|
|
|
.then(response => response.json())
|
|
|
|
|
.then(statusMap => {
|
2024-11-13 16:59:42 +01:00
|
|
|
|
imageElements = imageElements.filter(img => {
|
|
|
|
|
let id = img.getAttribute('data-id');
|
|
|
|
|
if (statusMap[id]) {
|
|
|
|
|
// Image is ready, update src
|
|
|
|
|
img.src = statusMap[id];
|
2024-11-14 16:33:04 +01:00
|
|
|
|
img.onerror = function() {
|
|
|
|
|
handleImageError(img);
|
|
|
|
|
};
|
2024-11-13 16:59:42 +01:00
|
|
|
|
// Remove the image id from the list
|
|
|
|
|
imageIds = imageIds.filter(imageId => imageId !== id);
|
|
|
|
|
return false; // Remove img from imageElements
|
2024-10-13 00:04:46 +02:00
|
|
|
|
}
|
2024-11-13 16:59:42 +01:00
|
|
|
|
return true; // Keep img in imageElements
|
|
|
|
|
});
|
2024-11-14 16:33:04 +01:00
|
|
|
|
// After updating images, ensure the page is scrollable
|
|
|
|
|
ensureScrollable();
|
2024-10-13 00:04:46 +02:00
|
|
|
|
})
|
|
|
|
|
.catch(error => {
|
|
|
|
|
console.error('Error checking image status:', error);
|
|
|
|
|
});
|
|
|
|
|
}
|
2024-11-13 16:59:42 +01:00
|
|
|
|
|
|
|
|
|
// Initialize imageElements and imageIds
|
|
|
|
|
if (hardCacheEnabled) {
|
|
|
|
|
imageElements = Array.from(document.querySelectorAll('img[data-id]'));
|
2024-11-19 10:36:33 +01:00
|
|
|
|
imageIds = imageElements
|
|
|
|
|
.map(img => img.getAttribute('data-id'))
|
|
|
|
|
.filter(id => id); // Exclude empty IDs
|
2024-11-13 16:59:42 +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-11-14 16:33:04 +01:00
|
|
|
|
|
|
|
|
|
// After initial images are loaded, ensure the page is scrollable
|
|
|
|
|
window.addEventListener('load', ensureScrollable);
|
2024-11-13 16:59:42 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Infinite scrolling
|
|
|
|
|
window.addEventListener('scroll', function() {
|
2024-11-14 16:33:04 +01:00
|
|
|
|
if (isFetching || noMoreImages) return;
|
2024-11-13 16:59:42 +01:00
|
|
|
|
|
|
|
|
|
if (window.innerHeight + window.scrollY >= document.body.offsetHeight - scrollThreshold) {
|
|
|
|
|
// User scrolled near the bottom
|
2024-11-14 16:33:04 +01:00
|
|
|
|
fetchNextPage();
|
2024-11-13 16:59:42 +01:00
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Remove 'js-enabled' class from content
|
|
|
|
|
document.getElementById('content').classList.remove('js-enabled');
|
|
|
|
|
})();
|
2024-08-13 16:38:02 +02:00
|
|
|
|
</script>
|
|
|
|
|
</body>
|
2024-10-06 18:11:58 +02:00
|
|
|
|
</html>
|