// Debug alert for mobile debugging
if (typeof debugAlert === 'function') debugAlert('files.js loaded');
// ===== Shared state (globals so tilepicker.js can read them) =====
window.selectedImage = null; // URL of currently selected sheet
window.selectedImageName = null; // Name of selected sheet
window.selectedTileSize = null; // Numeric folder (e.g. 16 / 32 / 64)
// Internal UI state
let selectedImageDiv = null;
// Keep ALL locally chosen sheets (multiple)
const localSheets = []; // [{ name, url }]
// Revoke created blob URLs on page exit to avoid leaks
window.addEventListener('beforeunload', () => {
localSheets.forEach(ls => {
if (ls.url && ls.url.startsWith('blob:')) try { URL.revokeObjectURL(ls.url); } catch {}
});
});
// ===== DOM =====
const fileList = document.getElementById('fileList');
const breadcrumb = document.querySelector('.breadcrumb');
const preview = document.getElementById('preview');
/** Load files for a subdirectory (server) */
function loadFiles(sub) {
fetch('media.php?sub=' + encodeURIComponent(sub))
.then(r => r.json())
.then(data => {
if (data.error) throw new Error(data.error);
renderBreadcrumb(data.breadcrumb);
renderFiles(data);
})
.catch(err => {
console.error('Error loading files:', err);
if (typeof debugAlert === 'function') alert('Error loading files: ' + err.message);
// Fallback: still render so user can work with local sheets
renderBreadcrumb([{ label: 'tiles', sub: '' }]);
renderFiles({ folders: [], images: [] });
});
}
/** Breadcrumb */
function renderBreadcrumb(crumbs) {
breadcrumb.innerHTML = '';
crumbs.forEach((c, i) => {
const span = document.createElement('span');
span.textContent = c.label;
span.style.cursor = 'pointer';
span.onclick = () => loadFiles(c.sub);
breadcrumb.appendChild(span);
if (i < crumbs.length - 1) {
const sep = document.createElement('span');
sep.textContent = ' / ';
breadcrumb.appendChild(sep);
}
});
}
/** Add the "➕ Local sheet…" tile (mobile-safe file input over the tile) */
function addLocalSheetTile() {
const div = document.createElement('div');
div.className = 'folder local-sheet-tile';
div.title = 'Pick image(s) from your device (Files)';
div.textContent = '➕ Local sheet…';
div.style.position = 'relative';
fileList.appendChild(div);
const input = document.createElement('input');
input.type = 'file';
input.multiple = true;
input.accept = '.png,.jpg,.jpeg,.webp,.gif,.bmp,.svg'; // favors file explorer over camera
Object.assign(input.style, {
position: 'absolute',
inset: '0',
width: '100%',
height: '100%',
opacity: '0',
cursor: 'pointer',
zIndex: '1'
});
input.addEventListener('change', (e) => handleLocalFiles(e.target.files), { passive: true });
input.addEventListener('input', (e) => handleLocalFiles(e.target.files), { passive: true });
input.addEventListener('touchstart', () => {}, { passive: true });
div.appendChild(input);
}
/** Render locally added sheets as image tiles */
function renderLocalSheets() {
if (!localSheets.length) return;
localSheets.forEach(ls => {
const div = document.createElement('div');
div.className = 'image';
div.title = `Local: ${ls.name}`;
const imgElement = document.createElement('img');
imgElement.src = ls.url;
imgElement.alt = ls.name;
div.appendChild(imgElement);
div.onclick = () => {
if (selectedImageDiv) selectedImageDiv.classList.remove('selected');
div.classList.add('selected');
selectedImageDiv = div;
window.selectedImage = ls.url;
window.selectedImageName = ls.name;
showPreview({ name: ls.name, url: ls.url });
refreshTilePickerIfOpen(); // <-- push into tilepicker if open
};
fileList.appendChild(div);
});
}
/** Handle files picked or dropped locally (supports MULTIPLE) */
function handleLocalFiles(fileListLike) {
if (!fileListLike || !fileListLike.length) return;
// Add each file as its own local sheet
Array.from(fileListLike).forEach(file => {
// Avoid duplicates by name+size if user re-selects
const exists = localSheets.find(ls => ls.name === file.name && ls.size === file.size);
if (exists) return;
const url = URL.createObjectURL(file);
localSheets.push({ name: file.name, url, size: file.size });
});
// Auto-select the LAST picked file (most recent user choice)
const last = localSheets[localSheets.length - 1];
window.selectedImage = last.url;
window.selectedImageName = last.name;
selectedImageDiv = null;
showPreview({ name: last.name, url: last.url });
// Re-render current directory: keep folders/images + show all locals
// (We don't have server data cached here; render minimal view that always shows locals first)
const currentChildren = Array.from(fileList.children).filter(Boolean);
fileList.innerHTML = '';
addLocalSheetTile();
renderLocalSheets();
// If you want to keep server items too, you can reload current breadcrumb path:
// const lastCrumb = breadcrumb.querySelector('span:last-child');
// loadFiles(lastCrumb ? lastCrumb.textContent : '');
refreshTilePickerIfOpen(); // <-- auto-update overlay if it’s open
}
/** Optional: Drag & Drop onto the file grid */
['dragenter','dragover'].forEach(ev =>
fileList.addEventListener(ev, e => {
e.preventDefault();
e.dataTransfer.dropEffect = 'copy';
fileList.classList.add('dropping');
})
);
['dragleave','drop'].forEach(ev =>
fileList.addEventListener(ev, e => {
e.preventDefault();
fileList.classList.remove('dropping');
})
);
fileList.addEventListener('drop', e => {
const files = e.dataTransfer.files;
if (files && files.length) handleLocalFiles(files);
});
/** Render folders + images + local sheets */
function renderFiles(data) {
fileList.innerHTML = '';
preview.innerHTML = '';
// 1) Local sheet tile + local sheets (requested: in the same place as folders)
addLocalSheetTile();
renderLocalSheets();
// 2) Folders
(data.folders || []).forEach(f => {
const div = document.createElement('div');
div.className = 'folder';
div.textContent = f.name;
div.onclick = () => {
if (/^\d+$/.test(f.name)) window.selectedTileSize = parseInt(f.name, 10);
loadFiles(f.sub);
};
fileList.appendChild(div);
});
// 3) Server images
(data.images || []).forEach(img => {
const div = document.createElement('div');
div.className = 'image';
const imgElement = document.createElement('img');
imgElement.src = img.url;
imgElement.alt = img.name;
div.appendChild(imgElement);
div.onclick = () => {
if (selectedImageDiv) selectedImageDiv.classList.remove('selected');
div.classList.add('selected');
selectedImageDiv = div;
window.selectedImage = img.url;
window.selectedImageName = img.name;
showPreview(img);
refreshTilePickerIfOpen(); // <-- ensure overlay shows this image if open
};
fileList.appendChild(div);
});
}
/** Preview + click-to-open tile picker */
function showPreview(img) {
preview.innerHTML = `
<h3>Selected: ${img.name}</h3>
<img id="previewImg" src="${img.url}" alt="${img.name}">
`;
const big = document.getElementById('previewImg');
big.onclick = () => openOverlay('tiles');
}
/** If the tile picker overlay is already open, refresh it to the new selectedImage */
function refreshTilePickerIfOpen() {
const overlay = document.getElementById('overlay');
if (!overlay || overlay.style.display !== 'block') return;
// If overlay is open, simply re-open Tile Picker content to rebuild with new image
if (typeof openTilePickerOverlay === 'function') {
openTilePickerOverlay();
}
}