<!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>