/* ---------- 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
};