📜
files.js
Back
📝 Javascript ⚡ Executable Ctrl+S: Save • Ctrl+R: Run • Ctrl+F: Find
// 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(); } }