// ── Bounded decoded-image lifecycle ───────────────────────────────────────── // Native loading="lazy" controls network work, but browsers may retain decoded // pixels for every image that has entered the viewport. Keep a small LRU of // visible library images and drop src from old, off-screen elements so their // decoded surfaces can be reclaimed. data-ttvc-src restores them on re-entry. (function () { 'use strict'; var root = window.TTVC = window.TTVC || {}; var entries = new Map(); var visible = new Set(); var observer = 'IntersectionObserver' in window ? new IntersectionObserver(function (records) { records.forEach(function (record) { var img = record.target; if (record.isIntersecting) { visible.add(img); var source = img.dataset.ttvcSrc; if (source && !img.getAttribute('src')) img.setAttribute('src', source); entries.delete(img); entries.set(img, Date.now()); } else { visible.delete(img); } }); evict(); }, { rootMargin: '160px' }) : null; function limit() { return typeof window.ttvcIsLowMemoryDevice === 'function' && window.ttvcIsLowMemoryDevice() ? 24 : 64; } function evict() { // Disconnected nodes are no longer useful cache entries. entries.forEach(function (_, img) { if (!img.isConnected) entries.delete(img); }); while (entries.size > limit()) { var candidate = null; for (var img of entries.keys()) { if (!visible.has(img)) { candidate = img; break; } } if (!candidate) break; // never evict an image currently near the viewport entries.delete(candidate); if (candidate.getAttribute('src')) candidate.dataset.ttvcSrc = candidate.getAttribute('src'); candidate.removeAttribute('src'); } } function observeImages(container) { if (!container) return; container.querySelectorAll('img').forEach(function (img) { if (!img.dataset.ttvcSrc && img.getAttribute('src')) img.dataset.ttvcSrc = img.getAttribute('src'); if (observer && !img.dataset.ttvcObserved) { img.dataset.ttvcObserved = '1'; observer.observe(img); } entries.delete(img); entries.set(img, Date.now()); }); evict(); } root.imageCache = { observe: observeImages, evict: evict, size: function () { return entries.size; } }; window.ttvcObserveImages = observeImages; })();