/** * Navigation functionality - breadcrumbs and folder tree */ export class NavigationManager { /** * Build breadcrumb navigation based on current path */ buildBreadcrumb() { const currentPath = window.location.pathname; const pathParts = currentPath.split('/').filter(part => part !== '' && part !== 'index.html'); const breadcrumb = document.getElementById('breadcrumb'); if (!breadcrumb) return; if (pathParts.length === 0) { breadcrumb.innerHTML = '🏠 Root'; return; } let html = '🏠 Root'; for (let i = 0; i < pathParts.length; i++) { const part = pathParts[i]; html += '/'; if (i === pathParts.length - 1) { html += `${decodeURIComponent(part)}`; } else { const levelsUp = pathParts.length - 1 - i; const relativePath = '../'.repeat(levelsUp) + 'index.html'; html += `${decodeURIComponent(part)}`; } } breadcrumb.innerHTML = html; } /** * Build and display the folder tree structure */ async buildFolderTree() { const treeContainer = document.getElementById('folderTree'); const currentPath = window.location.pathname; if (!treeContainer) return; try { const tree = await this.buildTreeRecursive(currentPath, 0, currentPath); treeContainer.innerHTML = tree; } catch (error) { console.error('Error building folder tree:', error); treeContainer.innerHTML = '
❌ Error loading folder tree
'; } } /** * Recursively build tree structure for folders with collapsed empty directories */ async buildTreeRecursive(path, depth, currentPath, maxDepth = 5) { if (depth > maxDepth) { const indent = ' '.repeat(depth); return `
${indent}└─ ...
`; } try { const response = await fetch(path); const htmlContent = await response.text(); const parser = new DOMParser(); const doc = parser.parseFromString(htmlContent, 'text/html'); const subdirs = doc.querySelectorAll('h2 + ul li a'); const items = doc.querySelectorAll('.grid-item'); // Check if this is an empty directory (only one subdirectory, no items) if (items.length === 0 && subdirs.length === 1) { const subdir = subdirs[0]; const href = subdir.getAttribute('href'); if (href) { const baseUrl = path.replace(/\/[^\/]*$/, '/'); const subPath = baseUrl + href; const collapsedPath = await this.getCollapsedPath(path, subPath); return await this.buildCollapsedTreeItem(collapsedPath, depth, currentPath, maxDepth); } } // Normal directory processing const indent = ' '.repeat(depth); const folderName = path.split('/').filter(p => p !== '' && p !== 'index.html').pop() || 'Gallery'; const totalItems = items.length + subdirs.length; const arrow = depth === 0 ? '' : '└─ '; let html = ''; if (path === currentPath) { html += `
${indent}${arrow}📁 ${folderName} (${totalItems} items)
`; } else { html += `
${indent}${arrow}📁 ${folderName} (${totalItems} items)
`; } for (let i = 0; i < subdirs.length; i++) { const subdir = subdirs[i]; const href = subdir.getAttribute('href'); if (href) { const baseUrl = path.replace(/\/[^\/]*$/, '/'); const subPath = baseUrl + href; html += await this.buildTreeRecursive(subPath, depth + 1, currentPath, maxDepth); } } return html; } catch (error) { const indent = ' '.repeat(depth); const arrow = depth === 0 ? '' : '└─ '; const folderName = path.split('/').filter(p => p !== '' && p !== 'index.html').pop() || 'Gallery'; return `
${indent}${arrow}📁 ${folderName} (error loading)
`; } } /** * Get the collapsed path by following empty directories */ async getCollapsedPath(startPath, currentPath) { const pathSegments = []; let path = startPath; while (true) { try { const response = await fetch(path); const htmlContent = await response.text(); const parser = new DOMParser(); const doc = parser.parseFromString(htmlContent, 'text/html'); const subdirs = doc.querySelectorAll('h2 + ul li a'); const items = doc.querySelectorAll('.grid-item'); const folderName = path.split('/').filter(p => p !== '' && p !== 'index.html').pop() || 'Gallery'; pathSegments.push({ name: folderName, path: path }); if (items.length > 0 || subdirs.length !== 1) { break; } const subdir = subdirs[0]; const href = subdir.getAttribute('href'); if (href) { const baseUrl = path.replace(/\/[^\/]*$/, '/'); path = baseUrl + href; } else { break; } } catch (error) { break; } } return { segments: pathSegments, finalPath: path }; } /** * Build a collapsed tree item for empty directory chains */ async buildCollapsedTreeItem(collapsedPath, depth, currentPath, maxDepth) { const indent = ' '.repeat(depth); const arrow = depth === 0 ? '' : '└─ '; const displayName = collapsedPath.segments.map(seg => seg.name).join(' / '); const finalPath = collapsedPath.finalPath; let totalItems = 0; let subdirs = []; try { const response = await fetch(finalPath); const htmlContent = await response.text(); const parser = new DOMParser(); const doc = parser.parseFromString(htmlContent, 'text/html'); const subdirElements = doc.querySelectorAll('h2 + ul li a'); const items = doc.querySelectorAll('.grid-item'); totalItems = items.length + subdirElements.length; subdirs = Array.from(subdirElements); } catch (error) { // Handle error case } let html = ''; if (finalPath === currentPath) { html += `
${indent}${arrow}📁 ${displayName} (${totalItems} items)
`; } else { html += `
${indent}${arrow}📁 ${displayName} (${totalItems} items)
`; } for (let i = 0; i < subdirs.length; i++) { const subdir = subdirs[i]; const href = subdir.getAttribute('href'); if (href) { const baseUrl = finalPath.replace(/\/[^\/]*$/, '/'); const subPath = baseUrl + href; html += await this.buildTreeRecursive(subPath, depth + 1, currentPath, maxDepth); } } return html; } }