📜
gallery.js
Back
📝 Javascript ⚡ Executable Ctrl+S: Save • Ctrl+R: Run • Ctrl+F: Find
/* ---------- Gallery Management ---------- */ /* DOM Elements */ const crumbsEl = document.getElementById('crumbs'); const foldersTrack = document.getElementById('foldersTrack'); const emptyFolders = document.getElementById('emptyFolders'); const galleryTrack = document.getElementById('galleryTrack'); const emptyImages = document.getElementById('emptyImages'); const goUpBtn = document.getElementById('goUpBtn'); const refreshBtn = document.getElementById('refreshBtn'); /* State */ let currentSub = ''; /* Auto-hide functionality - MINIMAL ADDITION */ let hideTimer = null; function resetHideTimer() { if (hideTimer) clearTimeout(hideTimer); const imagesPanel = document.getElementById('imagesPanel'); if (imagesPanel && imagesPanel.classList.contains('open')) { hideTimer = setTimeout(() => { imagesPanel.classList.remove('open'); }, 5000); } } function startHideTimer() { const imagesPanel = document.getElementById('imagesPanel'); if (imagesPanel && imagesPanel.classList.contains('open')) { resetHideTimer(); } } /* ---------- API Communication ---------- */ async function fetchDir(sub = '') { const res = await fetch(`media.php?sub=${encodeURIComponent(sub)}`, {cache:'no-store'}); if(!res.ok) throw new Error(`HTTP ${res.status}`); return await res.json(); } /* ---------- Rendering Functions ---------- */ function renderBreadcrumb(bc) { crumbsEl.innerHTML = ''; bc.forEach((c, i) => { const b = document.createElement('button'); b.textContent = c.label; b.onclick = () => { openSub(c.sub); resetHideTimer(); // ONLY ADDITION HERE }; crumbsEl.appendChild(b); if(i < bc.length - 1) { const s = document.createElement('span'); s.className = 'sep'; s.textContent = '›'; crumbsEl.appendChild(s); } }); } function renderFolders(items) { foldersTrack.innerHTML = ''; emptyFolders.hidden = !!items.length; for(const f of items) { const card = document.createElement('div'); card.className = 'folder-card'; card.innerHTML = `<span>📂</span><span>${f.name}</span>`; card.onclick = () => { openSub(f.sub); resetHideTimer(); // ONLY ADDITION HERE }; foldersTrack.appendChild(card); } } function renderImages(items) { galleryTrack.innerHTML = ''; emptyImages.hidden = !!items.length; for(const im of items) { const img = document.createElement('img'); img.alt = im.name; img.loading = 'lazy'; img.decoding = 'async'; img.src = im.url; img.onclick = () => { window.CoreAPI.setImage(im.url); resetHideTimer(); // ONLY ADDITION HERE }; galleryTrack.appendChild(img); } } /* ---------- Auto Tile Size Detection ---------- */ function inferTileFromPath(sub) { if (!sub) return null; const parts = sub.split('/').filter(Boolean).reverse(); for (const p of parts) { const n = parseInt(p, 10); if (String(n) === p && n > 0) return n; } return null; } /* ---------- Navigation ---------- */ async function openSub(sub) { try { const data = await fetchDir(sub); currentSub = data.cwd || ''; renderBreadcrumb(data.breadcrumb || []); renderFolders(data.folders || []); renderImages(data.images || []); // Auto-detect tile size from folder name const inferred = inferTileFromPath(currentSub); if (inferred) { window.CoreAPI.setTileSize(inferred); } } catch(err) { console.error(err); alert('Failed to load folder.'); } } function parentOf(sub) { if(!sub) return ''; const p = sub.split('/').filter(Boolean); p.pop(); return p.join('/'); } /* ---------- Event Handlers ---------- */ function initGalleryEvents() { goUpBtn.addEventListener('click', () => { openSub(parentOf(currentSub)); resetHideTimer(); // ONLY ADDITION HERE }); refreshBtn.addEventListener('click', () => { openSub(currentSub); resetHideTimer(); // ONLY ADDITION HERE }); // MINIMAL AUTO-HIDE SETUP const imagesPanel = document.getElementById('imagesPanel'); if (imagesPanel) { // Add activity listeners ['mousemove', 'click', 'scroll', 'mouseenter'].forEach(event => { imagesPanel.addEventListener(event, resetHideTimer, { passive: true }); }); // Start timer when gallery opens const observer = new MutationObserver((mutations) => { mutations.forEach(mutation => { if (mutation.type === 'attributes' && mutation.attributeName === 'class') { if (imagesPanel.classList.contains('open')) { // Small delay to ensure the class change is complete setTimeout(startHideTimer, 50); } } }); }); observer.observe(imagesPanel, { attributes: true, attributeFilter: ['class'], attributeOldValue: true }); } } /* ---------- Initialization ---------- */ function initializeGallery() { try { // Get DOM elements crumbsEl = document.getElementById('crumbs'); foldersTrack = document.getElementById('foldersTrack'); emptyFolders = document.getElementById('emptyFolders'); galleryTrack = document.getElementById('galleryTrack'); emptyImages = document.getElementById('emptyImages'); goUpBtn = document.getElementById('goUpBtn'); refreshBtn = document.getElementById('refreshBtn'); // Check required DOM elements and dependencies if (!crumbsEl || !foldersTrack || !galleryTrack || !goUpBtn) { throw new Error('Required DOM elements not found'); } if (!window.CoreAPI || typeof window.CoreAPI.setImage !== 'function') { throw new Error('CoreAPI not available'); } initGalleryEvents(); openSub(''); // Load root folder } catch (error) { alert(`Gallery module failed to initialize: ${error.message}\n\nNote: Gallery requires media.php to be present and working.`); // Don't throw here since gallery failure shouldn't break the whole app } } // Export API for other modules window.GalleryAPI = { openSub, currentSub: () => currentSub };