diff options
author | elioat <elioat@tilde.institute> | 2024-10-09 21:27:46 -0400 |
---|---|---|
committer | elioat <elioat@tilde.institute> | 2024-10-09 21:27:46 -0400 |
commit | 12c1148bdc5259a230b93c99ad69bd18a22e5ae3 (patch) | |
tree | 7568d525f028935e9a78ca0780f4dff68c6d3b0d | |
parent | 322e15fd5ca01d3dca485f6b33e59e56bbc84496 (diff) | |
download | tour-12c1148bdc5259a230b93c99ad69bd18a22e5ae3.tar.gz |
*
-rw-r--r-- | html/file-system/index.html | 318 |
1 files changed, 162 insertions, 156 deletions
diff --git a/html/file-system/index.html b/html/file-system/index.html index cd2e70d..89e05b8 100644 --- a/html/file-system/index.html +++ b/html/file-system/index.html @@ -3,7 +3,7 @@ <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <title>Files and Folders</title> + <title>Folders in Folders in Folders</title> <style> body { font-family: Arial, sans-serif; @@ -38,16 +38,11 @@ margin: 0.3125em 0; cursor: pointer; } - .file, .folder { + .folder { display: inline-block; padding: 0.3125em 0; cursor: pointer; font-size: 1.125em; - } - .file { - color: teal; - } - .folder { color: black; } #editor { @@ -76,7 +71,7 @@ font-size: 0.875em; padding: 0.5em 0.625em; } - .file, .folder { + .folder { font-size: 1em; } #editor textarea { @@ -92,199 +87,210 @@ <button onclick="goToRoot()">Go to Root</button> <button onclick="goUp()">Go Up One Level</button> <button onclick="createFolderPrompt()">Create Folder</button> - <button onclick="createFilePrompt()">Create File</button> - <button onclick="cutItem()">Cut</button> + <button onclick="copyItem()">Copy</button> <button onclick="pasteItem()">Paste</button> <button onclick="deleteItem()">Delete</button> </div> -<p id="currentPath">Current Folder: /</p> +<h1 id="currentPath">Current Folder: /</h1> <ul id="fileSystemTree"></ul> <div id="editor"> - <h3>File Editor</h3> - <textarea id="fileContent" placeholder="Select a file to edit"></textarea> - <button onclick="saveFileContent()">Save</button> + <h2>Folder Content Editor</h2> + <textarea id="folderContent" placeholder="Select a folder to edit its contents"></textarea> </div> <script> - let fileSystem = JSON.parse(localStorage.getItem('fileSystem')) || { root: { type: 'folder', children: {} } }; - let currentFolderPath = 'root'; - let currentFilePath = null; - let cutItemPath = null; // For storing the path of the item being cut +const initialState = () => ({ + root: { type: 'folder', children: {}, content: '' } +}); - function saveFileSystem() { - localStorage.setItem('fileSystem', JSON.stringify(fileSystem)); - } +const loadFileSystem = () => JSON.parse(localStorage.getItem('fileSystem')) || initialState(); - function getFolder(path) { - let parts = path.split('/'); - let current = fileSystem.root; - for (let part of parts) { - if (part && current.children[part]) { - current = current.children[part]; - } - } - return current; - } +const state = { + fileSystem: loadFileSystem(), + currentFolderPath: 'root', + copiedFolderData: null, // Pastebin for the copied folder + copiedItemPath: null +}; - function createFile(path, name, content = '') { - let folder = getFolder(path); - folder.children[name] = { type: 'file', content }; - saveFileSystem(); - renderFileSystem(); - } +const clone = (obj) => JSON.parse(JSON.stringify(obj)); - function createFolder(path, name) { - let folder = getFolder(path); - folder.children[name] = { type: 'folder', children: {} }; - saveFileSystem(); - renderFileSystem(); - } +const updateFileSystem = (newFileSystem) => { + state.fileSystem = newFileSystem; + saveFileSystem(newFileSystem); +}; + +const getFolder = (path, fileSystem = state.fileSystem) => { + const parts = path.split('/').filter(part => part !== 'root'); + return parts.reduce((current, part) => { + if (!current || !current.children[part]) { + return null; + } + return current.children[part]; + }, fileSystem.root); +}; - function moveItem(oldPath, newPath, itemName) { - let oldFolder = getFolder(oldPath); - let newFolder = getFolder(newPath); - newFolder.children[itemName] = oldFolder.children[itemName]; - delete oldFolder.children[itemName]; - saveFileSystem(); - renderFileSystem(); +const updateFolder = (fileSystem, path, updateFn) => { + const rootCopy = clone(fileSystem); + const folderToUpdate = getFolder(path, rootCopy); + if (!folderToUpdate) { + alert(`Folder not found for path: ${path}`); + return null; } - function deleteItem() { - if (!currentFilePath && currentFolderPath === 'root') { - alert("Can't delete the root folder!"); + updateFn(folderToUpdate); + return rootCopy; +}; + +const addFolder = (path, name, folderData, fileSystem) => { + return updateFolder(fileSystem, path, (folder) => { + if (folder.children[name]) { + alert(`Folder with name "${name}" already exists.`); return; } + folder.children[name] = folderData || { type: 'folder', children: {}, content: '' }; + }); +}; - let [parentPath, itemName] = (currentFilePath || currentFolderPath).split(/\/([^\/]+)$/); - let parentFolder = getFolder(parentPath); +const deleteFolder = (path, fileSystem) => { + const [parentPath, folderName] = path.split(/\/([^\/]+)$/); + return updateFolder(fileSystem, parentPath, (folder) => { + delete folder.children[folderName]; + }); +}; - // Check if the item to delete is a folder with children - if (parentFolder.children[itemName].type === 'folder') { - let childCount = Object.keys(parentFolder.children[itemName].children).length; - if (childCount > 0) { - let confirmDelete = confirm(`Are you sure you want to delete the folder "${itemName}" and all its contents?`); - if (!confirmDelete) return; - } - } +const saveFileSystem = (fileSystem) => { + localStorage.setItem('fileSystem', JSON.stringify(fileSystem)); +}; - // Delete the file/folder - delete parentFolder.children[itemName]; - saveFileSystem(); +const goToRoot = () => { + state.currentFolderPath = 'root'; + render(); +}; - // After deletion, reset selection to the parent folder - currentFilePath = null; - currentFolderPath = parentPath || 'root'; - document.getElementById('currentPath').textContent = currentFolderPath.replace('root', '') || '/'; - renderFileSystem(); +const goUp = () => { + const parts = state.currentFolderPath.split('/'); + if (parts.length > 1) { + parts.pop(); + state.currentFolderPath = parts.join('/'); + render(); } +}; - function editFileContent(path, fileName, newContent) { - let folder = getFolder(path); - folder.children[fileName].content = newContent; - saveFileSystem(); +const createFolder = (path, name) => { + const updatedFileSystem = addFolder(path, name, null, state.fileSystem); + if (updatedFileSystem) { + updateFileSystem(updatedFileSystem); + render(); + } else { + console.error('Error creating folder', path, name); + alert('Error creating folder'); } +}; - function saveFileContent() { - if (currentFilePath) { - let [path, fileName] = currentFilePath.split(/\/([^\/]+)$/); - let content = document.getElementById('fileContent').value; - editFileContent(path, fileName, content); - } - } +const deleteItem = () => { + if (state.currentFolderPath === 'root') return alert("Can't delete the root!"); - // Recursive function to render the file system - function renderFileSystem(folder = fileSystem.root, parentElement = document.getElementById('fileSystemTree'), path = 'root') { - parentElement.innerHTML = ''; // Clear existing tree - for (const [name, item] of Object.entries(folder.children)) { - let listItem = document.createElement('li'); - - // Create a separate clickable span for the folder or file name - let clickableName = document.createElement('span'); - clickableName.textContent = name; - clickableName.classList.add(item.type === 'file' ? 'file' : 'folder'); - listItem.appendChild(clickableName); - - // Folder click sets the current folder path - clickableName.onclick = () => { - if (item.type === 'folder') { - currentFolderPath = `${path}/${name}`; - currentFilePath = null; - document.getElementById('currentPath').textContent = currentFolderPath.replace('root', ''); - renderFileSystem(); // Re-render after changing the folder - } else if (item.type === 'file') { - currentFilePath = `${path}/${name}`; - document.getElementById('fileContent').value = item.content; - } - }; - - // If it's a folder, render its children recursively - if (item.type === 'folder') { - let nestedList = document.createElement('ul'); - renderFileSystem(item, nestedList, `${path}/${name}`); - listItem.appendChild(nestedList); - } + const folderToDelete = getFolder(state.currentFolderPath); + if (!folderToDelete) return alert("Folder not found!"); - parentElement.appendChild(listItem); + const hasNestedFolders = Object.keys(folderToDelete.children).length > 0; + + if (hasNestedFolders) { + const confirmDelete = confirm(`The folder contains nested folders. Do you really wanna delete them too?`); + if (!confirmDelete) { + return; } } - // Navigation: Go to root - function goToRoot() { - currentFolderPath = 'root'; - currentFilePath = null; - document.getElementById('currentPath').textContent = '/'; - renderFileSystem(); + const updatedFileSystem = deleteFolder(state.currentFolderPath, state.fileSystem); + if (updatedFileSystem) { + const parts = state.currentFolderPath.split('/'); + parts.pop(); + state.currentFolderPath = parts.join('/') || 'root'; + updateFileSystem(updatedFileSystem); + render(); } +}; - // Navigation: Go up one level - function goUp() { - if (currentFolderPath !== 'root') { - let parts = currentFolderPath.split('/'); - parts.pop(); // Remove the current folder - currentFolderPath = parts.join('/') || 'root'; - currentFilePath = null; - document.getElementById('currentPath').textContent = currentFolderPath.replace('root', '') || '/'; - renderFileSystem(); - } +const copyItem = () => { + const folder = getFolder(state.currentFolderPath); + if (folder) { + state.copiedFolderData = clone(folder); // Store a deep copy of the folder + state.copiedItemPath = state.currentFolderPath; // Store the path so that we can remove later + // console.log('Folder copied:', state.copiedFolderData); } +}; - // Cut a file or folder (select it for moving) - function cutItem() { - cutItemPath = currentFilePath || currentFolderPath; // Store the path of the selected file/folder - alert(`Cut: ${cutItemPath}`); - } +const pasteItem = () => { + if (!state.copiedItemPath || !state.copiedFolderData) return alert('No item to paste'); - // Paste a cut item into the current folder - function pasteItem() { - if (!cutItemPath) { - alert('No item selected to move.'); - return; - } + const [oldPath, folderName] = state.copiedItemPath.split(/\/([^\/]+)$/); + const updatedFileSystem = addFolder(state.currentFolderPath, folderName, state.copiedFolderData, state.fileSystem); - let [oldPath, itemName] = cutItemPath.split(/\/([^\/]+)$/); - moveItem(oldPath, currentFolderPath, itemName); - cutItemPath = null; // Reset the cut item - alert(`Moved to: ${currentFolderPath}`); + if (updatedFileSystem) { + updateFileSystem(deleteFolder(oldPath, updatedFileSystem)); // Remove original + state.copiedFolderData = null; // Clear the copied data + state.copiedItemPath = null; + render(); + } else { + alert('Error pasting item'); } +}; - function createFilePrompt() { - let name = prompt('Enter file name:'); - if (name) { - createFile(currentFolderPath, name); - } +const saveFolderContent = () => { + const updatedFileSystem = updateFolder(state.fileSystem, state.currentFolderPath, (folder) => { + folder.content = document.getElementById('folderContent').value; + }); + if (updatedFileSystem) { + updateFileSystem(updatedFileSystem); } +}; - function createFolderPrompt() { - let name = prompt('Enter folder name:'); - if (name) { - createFolder(currentFolderPath, name); - } +document.getElementById('folderContent').addEventListener('input', () => { + saveFolderContent(); +}); + +const renderFolderTree = (folder, path = 'root') => { + const entries = Object.entries(folder.children); + return entries.length ? entries.map(([name, item]) => ` + <li> + <span class="folder" onclick="selectFolder('${path}/${name}')">${name}</span> + <ul>${renderFolderTree(item, `${path}/${name}`)}</ul> + </li> + `).join('') : ''; +}; + +const selectFolder = (path) => { + const folder = getFolder(path); + if (folder) { + state.currentFolderPath = path; + document.getElementById('folderContent').value = folder.content || ''; + render(); + } else { + console.error('Folder not found', path); + alert('Folder not found'); } +}; + +const render = () => { + if (!state.fileSystem.root) { + console.error('File system is not initialized correctly', state.fileSystem); + alert('File system is not initialized correctly'); + return; + } + document.getElementById('currentPath').textContent = state.currentFolderPath.replace('root', '') || '/'; + document.getElementById('fileSystemTree').innerHTML = renderFolderTree(state.fileSystem.root); +}; + +const createFolderPrompt = () => { + const name = prompt('Enter folder name:'); + if (name) createFolder(state.currentFolderPath, name); +}; - renderFileSystem(); +render(); </script> </body> |