about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorelioat <elioat@tilde.institute>2024-10-09 21:27:46 -0400
committerelioat <elioat@tilde.institute>2024-10-09 21:27:46 -0400
commit12c1148bdc5259a230b93c99ad69bd18a22e5ae3 (patch)
tree7568d525f028935e9a78ca0780f4dff68c6d3b0d
parent322e15fd5ca01d3dca485f6b33e59e56bbc84496 (diff)
downloadtour-12c1148bdc5259a230b93c99ad69bd18a22e5ae3.tar.gz
*
-rw-r--r--html/file-system/index.html318
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>