let fileTree = []; let editor = null; let showdotfile = false; // 隐藏右键菜单 function hideContextMenu() { const contextMenu = document.getElementById("contextMenu"); contextMenu.style.display = "none"; } // 加载文件树 function loadFileTree() { fetch('/vsc-like/file-tree') .then(response => response.json()) .then(data => { fileTree = sortFileTree(data); const fileTreeDiv = document.getElementById('fileTreeContent'); fileTreeDiv.innerHTML = ''; renderFileTree(fileTree, fileTreeDiv); for (const item of fileTree) { if (item.type === 'directory') { // 如果选中的文件夹是当前文件夹,则显示或选中的文件处于当前文件夹(祖先)则显示 if (selectedItem && (selectedItem.path+'/'+selectedItem.name).includes(item.path+'/'+item.name)) { } else{ showOrHideChildren(item.div); showOrHideChildren(item.div); } } if (showdotfile==false) { if (item.name.startsWith('.')) { item.div.style.display = 'none'; } } } bindRightClickMenu(fileTree); }); // code-like 工作区变动 ChangeWorkspacefileTree(fileTree); } let selectedItem = null; // 用来保存当前选中的文件/文件夹 let copiedItem = null; // 用于存储复制的文件或文件夹 function selectItem(item) { if (selectedItem) { selectedItem.div.classList.remove('selected'); } item.div.classList.add('selected'); selectedItem = item; } // 右键点击文件或文件夹时显示菜单 function showContextMenu(event, item) { event.preventDefault(); // 阻止默认右键菜单 // 记录当前右键点击的文件/文件夹 selectedItem = item; if (selectedItem) { selectedItem.div.classList.remove('selected'); } item.div.classList.add('selected'); // 获取右键菜单元素 const contextMenu = document.getElementById("contextMenu"); // 设置菜单位置 contextMenu.style.top = `${event.clientY}px`; contextMenu.style.left = `${event.clientX}px`; // 显示右键菜单 contextMenu.style.display = "block"; } // 绑定右键点击事件到文件/文件夹 function bindRightClickMenu(treeData) { treeData.forEach(item => { item.div.oncontextmenu = (event) => { event.preventDefault() event.stopPropagation(); selectItem(item); showContextMenu(event, item); }; if (item.children) { bindRightClickMenu(item.children); } }); } // 检查是否为空或仅包含空格 function checkValidName(name) { if (!name.trim()) { return false; } // 检查是否包含非法字符 const invalidChars = /[\/\\*?<>|":]/; if (invalidChars.test(name)) { return false; } // 检查文件名是否过长(例如,限制为 255 字符) if (name.length > 255) { return false; } // 检查是否使用保留的文件名(Windows 系统常见保留名称) const reservedNames = ['CON', 'PRN', 'AUX', 'NUL', 'COM1', 'COM2', 'COM3', 'COM4', 'COM5', 'COM6', 'COM7', 'COM8', 'COM9', 'LPT1', 'LPT2', 'LPT3', 'LPT4', 'LPT5', 'LPT6', 'LPT7', 'LPT8', 'LPT9']; if (reservedNames.includes(name.toUpperCase())) { return false; } // 不允许以空格结尾 if (name.endsWith(' ')) { return false; } return true; } // 右键菜单项点击事件 document.getElementById("renameOption").onclick = () => { if (selectedItem && selectedItem.type !== 'directory') { const newName = prompt("Enter new name for the file:", selectedItem.name); if (newName && checkValidName(newName)) { fetch(`/vsc-like/rename-file`, { method: 'POST', body: JSON.stringify({ path: selectedItem.path+'/'+selectedItem.name, newName: newName }) , headers: { 'Content-Type': 'application/json' } }) .then(() => { selectedItem.name = newName; selectedItem.div.textContent = newName; loadFileTree(); }); } } if (selectedItem && selectedItem.type === 'directory') { const newName = prompt("Enter new name for the folder:", selectedItem.name); if (newName && checkValidName(newName)) { fetch(`/vsc-like/rename-folder`, { method: 'POST', body: JSON.stringify({ path: selectedItem.path+'/'+selectedItem.name, newName: newName }) , headers: { 'Content-Type': 'application/json' } }) .then(() => { selectedItem.name = newName; selectedItem.div.textContent = newName; loadFileTree(); }); } } hideContextMenu(); }; document.getElementById("copyOption").onclick = () => { if (selectedItem) { copiedItem = selectedItem; console.log("Item copied:", copiedItem); } hideContextMenu(); }; document.getElementById("pasteOption").onclick = (event) => { event.stopPropagation(); if (copiedItem) { if (selectedItem.type === 'directory') { newPath = selectedItem.path+'/'+selectedItem.name+'/'; } else{ newPath = selectedItem.path; } fetch(`/vsc-like/copy-files`, { method: 'POST', body: JSON.stringify({ oldPath: copiedItem.path+'/'+copiedItem.name, newPath: newPath }) , headers: { 'Content-Type': 'application/json' } }) .then(() => loadFileTree()); console.log("Item pasted:", selectedItem); } hideContextMenu(); }; document.getElementById("deleteOption").onclick = (event) => { event.stopPropagation(); //二次确认 if (confirm("Are you sure you want to delete selected file/folder?")) { if (selectedItem) { fetch(`/vsc-like/delete-file`, { method: 'POST', body: JSON.stringify({ path: selectedItem.path+'/'+selectedItem.name }) , headers: { 'Content-Type': 'application/json' } }) .then(() => loadFileTree()); } } hideContextMenu(); }; // 隐藏右键菜单的点击事件 document.addEventListener("click", (event) => { const contextMenu = document.getElementById("contextMenu"); if (!contextMenu.contains(event.target)) { hideContextMenu(); } }); function renderFileTree(treeData, container, level = 0, parent = null) { treeData.forEach(item => { const div = document.createElement('div'); div.textContent = item.name; if (parent) { item.path = parent + '/'; } else { item.path = '.' } // 根据类型添加不同的类 if (item.type === 'directory') { div.classList.add('tree-item', 'directory', `tree-item-level-${level}`); // 文件夹样式,添加层级类 const iconDiv = document.createElement('i'); div.prepend(iconDiv); // 为文件夹添加图标 const childrenDiv = document.createElement('div'); renderFileTree(item.children, childrenDiv, level + 1, item.path + '/' + item.name); // 递归调用,层级加1 div.appendChild(childrenDiv); item.div = div; } else { div.classList.add('tree-item', 'file', `tree-item-level-${level}`); // 文件样式,添加层级类 const iconDiv = document.createElement('i'); div.prepend(iconDiv); // 为文件添加图标 item.div = div; } div.onclick = (event) => { event.stopPropagation(); if (selectedItem) { selectedItem.div.classList.remove('selected'); // 取消之前选中的文件夹/文件的选中状态 } div.classList.add('selected'); // 为当前点击的文件夹/文件添加选中样式 selectedItem = item; // 更新选中项 hideContextMenu(); // 获取选中的文件或文件夹的详细信息 console.log("Selected Item:", item); if (item.type === 'directory') { showOrHideChildren(div); } else { loadFileContent(item); } }; container.appendChild(div); }); } function selectEmpty(div) { if (selectedItem) { selectedItem.div.classList.remove('selected'); } selectedItem = {type: 'directory', path: '.', name: '.', div:div}; } function showOrHideChildren(d) { const childrenDiv = d.querySelector('div'); if (childrenDiv) { // 切换显示和隐藏 childrenDiv.style.display = (childrenDiv.style.display === 'none' || childrenDiv.style.display === '') ? 'block' : 'none'; } } // 加载文件内容 function loadFileContent(item) { fetch(`/vsc-like/file-content`, { method: 'POST', body: JSON.stringify({ path: item.path+'/'+item.name }) , headers: { 'Content-Type': 'application/json' } }) .then(response => response.json()) .then(data => { if (data.content) { editor.setValue(data.content); } }); // code-like 打开文件 ChangeActiveTextEditor(item.path+'/'+item.name); } // 新建文件 function createNewFile(event) { event.stopPropagation(); const fileName = prompt('Enter new file name:'); if (fileName) { if (selectedItem) { if (selectedItem.type === 'directory') { fetch(`/vsc-like/create-file`, { method: 'POST', body: JSON.stringify({ path: fileName, parent: selectedItem.path+'/'+selectedItem.name }) , headers: { 'Content-Type': 'application/json' } }) .then(() => loadFileTree()); } else { console.log("selectedItem.path",selectedItem.path); fetch(`/vsc-like/create-file`, { method: 'POST', body: JSON.stringify({ path: fileName, parent: selectedItem.path }) , headers: { 'Content-Type': 'application/json' } }) .then(() => loadFileTree()); } }else{ fetch(`/vsc-like/create-file`, { method: 'POST', body: JSON.stringify({ path: fileName, parent: '.' }) , headers: { 'Content-Type': 'application/json' } }) .then(() => loadFileTree()); } } } // 新建文件夹 function createNewFolder(event) { event.stopPropagation(); const folderName = prompt('Enter new folder name:'); if (folderName) { if (selectedItem) { if (selectedItem.type === 'directory') { fetch(`/vsc-like/create-folder`, { method: 'POST', body: JSON.stringify({ path: fileName, parent: selectedItem.path+'/'+selectedItem.name }) , headers: { 'Content-Type': 'application/json' } }) .then(() => loadFileTree()); } else { fetch(`/vsc-like/create-folder`, { method: 'POST', body: JSON.stringify({ path: fileName, parent: selectedItem.path }) , headers: { 'Content-Type': 'application/json' } }) .then(() => loadFileTree()); } } } } // 保存文件 function saveFile(event) { event.stopPropagation(); const content = editor.getValue(); console.log(selectItem) if (selectedItem.path==undefined){ selectedItem.path='.'; } fetch(`/vsc-like/save-file`, { method: 'POST', body: JSON.stringify({ path: selectedItem.path+'/'+selectedItem.name, content: content }) , headers: { 'Content-Type': 'application/json' } }) .then(() => loadFileTree()); } function sortFileTree(treeData) { // 排序函数 return treeData.sort((a, b) => { // 首先按照 type 排序: 'directory' 优先 if (a.type === b.type) { // 如果 type 相同,则按 name 排序 return a.name.localeCompare(b.name); } // 'directory' 在前,'file' 在后 return a.type === 'directory' ? -1 : 1; }).map(item => { // 对每个子元素(children)也进行排序 if (item.children && item.children.length > 0) { item.children = sortFileTree(item.children); // 递归排序子树 } return item; }); }