diff options
Diffstat (limited to 'html/file-system/index.html')
-rw-r--r-- | html/file-system/index.html | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/html/file-system/index.html b/html/file-system/index.html new file mode 100644 index 0000000..89e05b8 --- /dev/null +++ b/html/file-system/index.html @@ -0,0 +1,297 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Folders in Folders in Folders</title> + <style> + body { + font-family: Arial, sans-serif; + background-color: beige; + display: flex; + flex-direction: column; + align-items: center; + } + #navigation { + display: flex; + flex-wrap: wrap; + justify-content: center; + margin: 0.625em 0; + } + #navigation button { + margin: 0.3125em; + padding: 0.625em 0.9375em; + font-size: 1em; + flex-grow: 1; + min-width: 7.5em; + } + #currentPath { + font-weight: bold; + margin: 0.625em 0; + } + ul { + list-style-type: none; + width: 100%; + max-width: 37.5em; + } + li { + margin: 0.3125em 0; + cursor: pointer; + } + .folder { + display: inline-block; + padding: 0.3125em 0; + cursor: pointer; + font-size: 1.125em; + color: black; + } + #editor { + margin-top: 1.25em; + width: 100%; + max-width: 37.5em; + } + #editor textarea { + width: 100%; + height: 9.375em; + font-size: 1em; + padding: 0.625em; + box-sizing: border-box; + resize: none; + } + h1 { + text-align: center; + font-size: 1.5em; + margin-top: 0.625em; + } + @media (max-width: 37.5em) { + h1 { + font-size: 1.25em; + } + #navigation button { + font-size: 0.875em; + padding: 0.5em 0.625em; + } + .folder { + font-size: 1em; + } + #editor textarea { + height: 7.5em; + font-size: 0.875em; + } + } + </style> +</head> +<body> + +<div id="navigation"> + <button onclick="goToRoot()">Go to Root</button> + <button onclick="goUp()">Go Up One Level</button> + <button onclick="createFolderPrompt()">Create Folder</button> + <button onclick="copyItem()">Copy</button> + <button onclick="pasteItem()">Paste</button> + <button onclick="deleteItem()">Delete</button> +</div> + +<h1 id="currentPath">Current Folder: /</h1> + +<ul id="fileSystemTree"></ul> + +<div id="editor"> + <h2>Folder Content Editor</h2> + <textarea id="folderContent" placeholder="Select a folder to edit its contents"></textarea> +</div> + +<script> +const initialState = () => ({ + root: { type: 'folder', children: {}, content: '' } +}); + +const loadFileSystem = () => JSON.parse(localStorage.getItem('fileSystem')) || initialState(); + +const state = { + fileSystem: loadFileSystem(), + currentFolderPath: 'root', + copiedFolderData: null, // Pastebin for the copied folder + copiedItemPath: null +}; + +const clone = (obj) => JSON.parse(JSON.stringify(obj)); + +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); +}; + +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; + } + + 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: '' }; + }); +}; + +const deleteFolder = (path, fileSystem) => { + const [parentPath, folderName] = path.split(/\/([^\/]+)$/); + return updateFolder(fileSystem, parentPath, (folder) => { + delete folder.children[folderName]; + }); +}; + +const saveFileSystem = (fileSystem) => { + localStorage.setItem('fileSystem', JSON.stringify(fileSystem)); +}; + +const goToRoot = () => { + state.currentFolderPath = 'root'; + render(); +}; + +const goUp = () => { + const parts = state.currentFolderPath.split('/'); + if (parts.length > 1) { + parts.pop(); + state.currentFolderPath = parts.join('/'); + render(); + } +}; + +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'); + } +}; + +const deleteItem = () => { + if (state.currentFolderPath === 'root') return alert("Can't delete the root!"); + + const folderToDelete = getFolder(state.currentFolderPath); + if (!folderToDelete) return alert("Folder not found!"); + + 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; + } + } + + const updatedFileSystem = deleteFolder(state.currentFolderPath, state.fileSystem); + if (updatedFileSystem) { + const parts = state.currentFolderPath.split('/'); + parts.pop(); + state.currentFolderPath = parts.join('/') || 'root'; + updateFileSystem(updatedFileSystem); + render(); + } +}; + +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); + } +}; + +const pasteItem = () => { + if (!state.copiedItemPath || !state.copiedFolderData) return alert('No item to paste'); + + const [oldPath, folderName] = state.copiedItemPath.split(/\/([^\/]+)$/); + const updatedFileSystem = addFolder(state.currentFolderPath, folderName, state.copiedFolderData, state.fileSystem); + + if (updatedFileSystem) { + updateFileSystem(deleteFolder(oldPath, updatedFileSystem)); // Remove original + state.copiedFolderData = null; // Clear the copied data + state.copiedItemPath = null; + render(); + } else { + alert('Error pasting item'); + } +}; + +const saveFolderContent = () => { + const updatedFileSystem = updateFolder(state.fileSystem, state.currentFolderPath, (folder) => { + folder.content = document.getElementById('folderContent').value; + }); + if (updatedFileSystem) { + updateFileSystem(updatedFileSystem); + } +}; + +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); +}; + +render(); +</script> + +</body> +</html> \ No newline at end of file |