...
This commit is contained in:
		| @@ -18,17 +18,15 @@ class FileTree { | ||||
|     setupEventListeners() { | ||||
|         // Click handler for tree nodes | ||||
|         this.container.addEventListener('click', (e) => { | ||||
|             console.log('Container clicked', e.target); | ||||
|             const node = e.target.closest('.tree-node'); | ||||
|             if (!node) return; | ||||
|              | ||||
|             console.log('Node found', node); | ||||
|             const path = node.dataset.path; | ||||
|             const isDir = node.dataset.isdir === 'true'; | ||||
|              | ||||
|             // Toggle folder | ||||
|             if (e.target.closest('.tree-node-toggle')) { | ||||
|                 this.toggleFolder(node); | ||||
|                 return; | ||||
|             } | ||||
|             // The toggle is handled inside renderNodes now | ||||
|              | ||||
|             // Select node | ||||
|             if (isDir) { | ||||
| @@ -69,87 +67,46 @@ class FileTree { | ||||
|      | ||||
|     renderNodes(nodes, parentElement, level) { | ||||
|         nodes.forEach(node => { | ||||
|             const nodeWrapper = document.createElement('div'); | ||||
|             nodeWrapper.className = 'tree-node-wrapper'; | ||||
|  | ||||
|             // Create node element | ||||
|             const nodeElement = this.createNodeElement(node, level); | ||||
|             parentElement.appendChild(nodeElement); | ||||
|              | ||||
|             nodeWrapper.appendChild(nodeElement); | ||||
|  | ||||
|             // Create children container ONLY if has children | ||||
|             if (node.children && node.children.length > 0) { | ||||
|                 const childContainer = document.createElement('div'); | ||||
|                 childContainer.className = 'tree-children'; | ||||
|                 childContainer.style.display = 'none'; | ||||
|                 nodeElement.appendChild(childContainer); | ||||
|                 childContainer.dataset.parent = node.path; | ||||
|                 childContainer.style.marginLeft = `${(level + 1) * 12}px`; | ||||
|  | ||||
|                 // Recursively render children | ||||
|                 this.renderNodes(node.children, childContainer, level + 1); | ||||
|                 nodeWrapper.appendChild(childContainer); | ||||
|  | ||||
|                 // Make toggle functional | ||||
|                 const toggle = nodeElement.querySelector('.tree-node-toggle'); | ||||
|                 if (toggle) { | ||||
|                     toggle.addEventListener('click', (e) => { | ||||
|                         console.log('Toggle clicked', e.target); | ||||
|                         e.stopPropagation(); | ||||
|                         const isHidden = childContainer.style.display === 'none'; | ||||
|                         console.log('Is hidden?', isHidden); | ||||
|                         childContainer.style.display = isHidden ? 'block' : 'none'; | ||||
|                         toggle.innerHTML = isHidden ? '▼' : '▶'; | ||||
|                         toggle.classList.toggle('expanded'); | ||||
|                     }); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             parentElement.appendChild(nodeWrapper); | ||||
|         }); | ||||
|     } | ||||
|      | ||||
|     createNodeElement(node, level) { | ||||
|         const nodeWrapper = document.createElement('div'); | ||||
|         nodeWrapper.className = 'tree-node-wrapper'; | ||||
|         nodeWrapper.style.marginLeft = `${level * 12}px`; | ||||
|          | ||||
|         const div = document.createElement('div'); | ||||
|         div.className = 'tree-node'; | ||||
|         div.dataset.path = node.path; | ||||
|         div.dataset.isdir = node.isDirectory; | ||||
|          | ||||
|         // Toggle arrow for folders | ||||
|         if (node.isDirectory) { | ||||
|             const toggle = document.createElement('span'); | ||||
|             toggle.className = 'tree-node-toggle'; | ||||
|             toggle.innerHTML = '▶'; | ||||
|             div.appendChild(toggle); | ||||
|         } else { | ||||
|             const spacer = document.createElement('span'); | ||||
|             spacer.style.width = '16px'; | ||||
|             spacer.style.display = 'inline-block'; | ||||
|             div.appendChild(spacer); | ||||
|         } | ||||
|          | ||||
|         // Icon | ||||
|         const icon = document.createElement('i'); | ||||
|         icon.className = `bi ${node.isDirectory ? 'bi-folder-fill' : 'bi-file-earmark-text'} tree-node-icon`; | ||||
|         div.appendChild(icon); | ||||
|          | ||||
|         // Content wrapper | ||||
|         const contentWrapper = document.createElement('div'); | ||||
|         contentWrapper.className = 'tree-node-content'; | ||||
|          | ||||
|         // Name | ||||
|         const name = document.createElement('span'); | ||||
|         name.className = 'tree-node-name'; | ||||
|         name.textContent = node.name; | ||||
|         name.title = node.name; // Tooltip on hover | ||||
|         contentWrapper.appendChild(name); | ||||
|          | ||||
|         // Size for files | ||||
|         if (!node.isDirectory && node.size) { | ||||
|             const size = document.createElement('span'); | ||||
|             size.className = 'file-size-badge'; | ||||
|             size.textContent = this.formatSize(node.size); | ||||
|             contentWrapper.appendChild(size); | ||||
|         } | ||||
|          | ||||
|         div.appendChild(contentWrapper); | ||||
|         nodeWrapper.appendChild(div); | ||||
|          | ||||
|         return nodeWrapper; | ||||
|     } | ||||
|      | ||||
|     toggleFolder(nodeElement) { | ||||
|         const childContainer = nodeElement.querySelector('.tree-children'); | ||||
|         if (!childContainer) return; | ||||
|          | ||||
|         const toggle = nodeElement.querySelector('.tree-node-toggle'); | ||||
|         const isExpanded = childContainer.style.display !== 'none'; | ||||
|          | ||||
|         if (isExpanded) { | ||||
|             childContainer.style.display = 'none'; | ||||
|             toggle.innerHTML = '▶'; | ||||
|         } else { | ||||
|             childContainer.style.display = 'block'; | ||||
|             toggle.innerHTML = '▼'; | ||||
|         } | ||||
|     } | ||||
|     // toggleFolder is no longer needed as the event listener is added in renderNodes. | ||||
|      | ||||
|     selectFile(path) { | ||||
|         this.selectedPath = path; | ||||
| @@ -181,6 +138,32 @@ class FileTree { | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     createNodeElement(node, level) { | ||||
|         const nodeElement = document.createElement('div'); | ||||
|         nodeElement.className = 'tree-node'; | ||||
|         nodeElement.dataset.path = node.path; | ||||
|         nodeElement.dataset.isdir = node.isDirectory; | ||||
|         nodeElement.style.paddingLeft = `${level * 12}px`; | ||||
|  | ||||
|         const icon = document.createElement('span'); | ||||
|         icon.className = 'tree-node-icon'; | ||||
|         if (node.isDirectory) { | ||||
|             icon.innerHTML = '▶'; // Collapsed by default | ||||
|             icon.classList.add('tree-node-toggle'); | ||||
|         } else { | ||||
|             icon.innerHTML = '●'; // File icon | ||||
|         } | ||||
|  | ||||
|         const title = document.createElement('span'); | ||||
|         title.className = 'tree-node-title'; | ||||
|         title.textContent = node.name; | ||||
|  | ||||
|         nodeElement.appendChild(icon); | ||||
|         nodeElement.appendChild(title); | ||||
|  | ||||
|         return nodeElement; | ||||
|     } | ||||
|      | ||||
|     formatSize(bytes) { | ||||
|         if (bytes === 0) return '0 B'; | ||||
| @@ -190,11 +173,21 @@ class FileTree { | ||||
|         return Math.round(bytes / Math.pow(k, i) * 10) / 10 + ' ' + sizes[i]; | ||||
|     } | ||||
|      | ||||
|     newFile() { | ||||
|         this.selectedPath = null; | ||||
|         this.updateSelection(); | ||||
|         // Potentially clear editor via callback | ||||
|         if (this.onFileSelect) { | ||||
|             this.onFileSelect({ path: null, isDirectory: false }); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     async createFile(parentPath, filename) { | ||||
|         try { | ||||
|             const fullPath = parentPath ? `${parentPath}/${filename}` : filename; | ||||
|             await this.webdavClient.put(fullPath, '# New File\n\nStart typing...\n'); | ||||
|             await this.load(); | ||||
|             this.selectFile(fullPath); // Select the new file | ||||
|             showNotification('File created', 'success'); | ||||
|             return fullPath; | ||||
|         } catch (error) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user