Added virtual drive + terminal directory commands
This commit is contained in:
parent
1f70f610f7
commit
f11820436b
20 changed files with 347 additions and 152 deletions
15
src/App.js
15
src/App.js
|
|
@ -2,15 +2,18 @@ import "./App.css";
|
||||||
import { Taskbar } from "./components/TaskBar.js";
|
import { Taskbar } from "./components/TaskBar.js";
|
||||||
import { WindowsManagerProvider } from "./hooks/WindowsManagerContext.js";
|
import { WindowsManagerProvider } from "./hooks/WindowsManagerContext.js";
|
||||||
import { WindowsView } from "./components/WindowsView.js";
|
import { WindowsView } from "./components/WindowsView.js";
|
||||||
|
import { VirtualRootProvider } from "./hooks/VirtualRootContext.js";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<WindowsManagerProvider>
|
<VirtualRootProvider>
|
||||||
<div className="App">
|
<WindowsManagerProvider>
|
||||||
<Taskbar/>
|
<div className="App">
|
||||||
<WindowsView/>
|
<Taskbar/>
|
||||||
</div>
|
<WindowsView/>
|
||||||
</WindowsManagerProvider>
|
</div>
|
||||||
|
</WindowsManagerProvider>
|
||||||
|
</VirtualRootProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { useEffect, useState } from "react";
|
||||||
import "./TaskBar.css";
|
import "./TaskBar.css";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import { faBatteryFull, faSearch, faVolumeHigh, faWifi } from "@fortawesome/free-solid-svg-icons";
|
import { faBatteryFull, faSearch, faVolumeHigh, faWifi } from "@fortawesome/free-solid-svg-icons";
|
||||||
import ApplicationsManager from "../modules/applications/applications.js";
|
import ApplicationsManager from "../features/applications/applications.js";
|
||||||
import { AppButton } from "./task-bar/AppButton.js";
|
import { AppButton } from "./task-bar/AppButton.js";
|
||||||
|
|
||||||
export function Taskbar() {
|
export function Taskbar() {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import styles from "./Terminal.module.css";
|
import styles from "./Terminal.module.css";
|
||||||
import { Command } from "./commands.js";
|
import { Command } from "./commands.js";
|
||||||
|
import { useVirtualRoot } from "../../../hooks/VirtualRootContext.js";
|
||||||
const PREFIX = "$ ";
|
|
||||||
|
|
||||||
function OutputLine({ text }) {
|
function OutputLine({ text }) {
|
||||||
return (
|
return (
|
||||||
|
|
@ -14,7 +13,7 @@ function InputLine({ value, prefix, onChange, onKeyUp, onKeyDown }) {
|
||||||
return (
|
return (
|
||||||
<span className={styles.Input}>
|
<span className={styles.Input}>
|
||||||
{prefix && <p className={[styles.Prefix]}>{prefix}</p>}
|
{prefix && <p className={[styles.Prefix]}>{prefix}</p>}
|
||||||
<label for="input"/>
|
<label htmlFor="input"/>
|
||||||
<input
|
<input
|
||||||
id="input"
|
id="input"
|
||||||
value={value}
|
value={value}
|
||||||
|
|
@ -22,6 +21,7 @@ function InputLine({ value, prefix, onChange, onKeyUp, onKeyDown }) {
|
||||||
onKeyUp={onKeyUp}
|
onKeyUp={onKeyUp}
|
||||||
onKeyDown={onKeyDown}
|
onKeyDown={onKeyDown}
|
||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
|
autoComplete={null}
|
||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -31,6 +31,10 @@ function InputLine({ value, prefix, onChange, onKeyUp, onKeyDown }) {
|
||||||
export function Terminal() {
|
export function Terminal() {
|
||||||
const [inputValue, setInputValue] = useState("");
|
const [inputValue, setInputValue] = useState("");
|
||||||
const [history, setHistory] = useState([]);
|
const [history, setHistory] = useState([]);
|
||||||
|
const virtualRoot = useVirtualRoot();
|
||||||
|
const [currentDirectory, setCurrentDirectory] = useState(virtualRoot);
|
||||||
|
|
||||||
|
const prefix = `user@prozilla-os:${currentDirectory.formattedPath}$ `;
|
||||||
|
|
||||||
const updatedHistory = history;
|
const updatedHistory = history;
|
||||||
const pushHistory = (entry) => {
|
const pushHistory = (entry) => {
|
||||||
|
|
@ -51,7 +55,7 @@ export function Terminal() {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pushHistory({
|
pushHistory({
|
||||||
text: PREFIX + value,
|
text: prefix + value,
|
||||||
isInput: true
|
isInput: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -65,7 +69,7 @@ export function Terminal() {
|
||||||
const command = Command.find(commandName);
|
const command = Command.find(commandName);
|
||||||
|
|
||||||
if (!command) {
|
if (!command) {
|
||||||
return promptOutput("Command not found: " + commandName);
|
return promptOutput(`${commandName}: Command not found`);
|
||||||
}
|
}
|
||||||
|
|
||||||
let response = null;
|
let response = null;
|
||||||
|
|
@ -73,17 +77,20 @@ export function Terminal() {
|
||||||
try {
|
try {
|
||||||
response = command.execute(args, {
|
response = command.execute(args, {
|
||||||
promptOutput,
|
promptOutput,
|
||||||
pushHistory
|
pushHistory,
|
||||||
|
virtualRoot,
|
||||||
|
currentDirectory,
|
||||||
|
setCurrentDirectory
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response == null)
|
if (response == null)
|
||||||
return promptOutput("Command failed.");
|
return promptOutput(`${commandName}: Command failed`);
|
||||||
|
|
||||||
if (!response.blank)
|
if (!response.blank)
|
||||||
promptOutput(response);
|
promptOutput(response);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
promptOutput("Command failed.");
|
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
promptOutput(`${commandName}: Command failed`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -120,7 +127,7 @@ export function Terminal() {
|
||||||
{displayHistory()}
|
{displayHistory()}
|
||||||
<InputLine
|
<InputLine
|
||||||
value={inputValue}
|
value={inputValue}
|
||||||
prefix={PREFIX}
|
prefix={prefix}
|
||||||
onKeyDown={onKeyDown}
|
onKeyDown={onKeyDown}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
.Prefix {
|
.Prefix {
|
||||||
width: max-content;
|
width: max-content;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Input, .Output {
|
.Input, .Output {
|
||||||
|
|
|
||||||
|
|
@ -38,5 +38,35 @@ export class Command {
|
||||||
|
|
||||||
return { blank: true };
|
return { blank: true };
|
||||||
}),
|
}),
|
||||||
|
new Command("ls", (args, { currentDirectory }) => {
|
||||||
|
let directory = currentDirectory;
|
||||||
|
|
||||||
|
if (args.length > 0) {
|
||||||
|
directory = currentDirectory.navigate(args[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!directory)
|
||||||
|
return `ls: Cannot access '${args[0]}': No such file or directory`;
|
||||||
|
|
||||||
|
const fodlerNames = directory.subFolders.map((folder) => folder.id);
|
||||||
|
const fileNames = directory.files.map((file) => file.id);
|
||||||
|
|
||||||
|
const contents = fodlerNames.concat(fileNames);
|
||||||
|
|
||||||
|
if (contents.length === 0)
|
||||||
|
return { blank: true };
|
||||||
|
|
||||||
|
return contents.sort((nameA, nameB) => nameA.localeCompare(nameB)).join(" ");
|
||||||
|
}),
|
||||||
|
new Command("cd", (args, { currentDirectory, setCurrentDirectory }) => {
|
||||||
|
const destination = currentDirectory.navigate(args[0]);
|
||||||
|
|
||||||
|
if (!destination)
|
||||||
|
return `cd: ${args[0]}: No such file or directory`;
|
||||||
|
|
||||||
|
console.log(destination);
|
||||||
|
setCurrentDirectory(destination);
|
||||||
|
return { blank: true };
|
||||||
|
})
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
61
src/features/virtual-drive/virtual-base.js
Normal file
61
src/features/virtual-drive/virtual-base.js
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
|
||||||
|
export class VirtualBase {
|
||||||
|
/**
|
||||||
|
* @param {String} name
|
||||||
|
*/
|
||||||
|
constructor(name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
get id() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {String} name
|
||||||
|
*/
|
||||||
|
setName(name) {
|
||||||
|
this.name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
setAlias(alias) {
|
||||||
|
this.alias = alias;
|
||||||
|
this.getRoot().addShortcut(alias, this);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {VirtualBase} parent
|
||||||
|
*/
|
||||||
|
setParent(parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete() {
|
||||||
|
this.parent.remove?.(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
open() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
get path() {
|
||||||
|
return this.parent?.path + "/" + this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
get formattedPath() {
|
||||||
|
return this.alias ?? this.path;
|
||||||
|
}
|
||||||
|
|
||||||
|
getRoot() {
|
||||||
|
const root = this.root ?? this.parent.getRoot();
|
||||||
|
|
||||||
|
if (root === null) {
|
||||||
|
throw new Error("Root not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/features/virtual-drive/virtual-file.js
Normal file
12
src/features/virtual-drive/virtual-file.js
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { VirtualBase } from "./virtual-base.js";
|
||||||
|
|
||||||
|
export class VirtualFile extends VirtualBase {
|
||||||
|
constructor(name, extension) {
|
||||||
|
super(name);
|
||||||
|
this.extension = extension;
|
||||||
|
}
|
||||||
|
|
||||||
|
get id() {
|
||||||
|
return this.name + this.extension;
|
||||||
|
}
|
||||||
|
}
|
||||||
159
src/features/virtual-drive/virtual-folder.js
Normal file
159
src/features/virtual-drive/virtual-folder.js
Normal file
|
|
@ -0,0 +1,159 @@
|
||||||
|
import { VirtualBase } from "./virtual-base.js";
|
||||||
|
import { VirtualFile } from "./virtual-file.js";
|
||||||
|
|
||||||
|
export class VirtualFolder extends VirtualBase {
|
||||||
|
static TYPE = {
|
||||||
|
GENERAL: 0,
|
||||||
|
MEDIA: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {String} name
|
||||||
|
* @param {Number} type
|
||||||
|
*/
|
||||||
|
constructor(name, type) {
|
||||||
|
super(name);
|
||||||
|
this.subFolders = [];
|
||||||
|
this.files = [];
|
||||||
|
this.type = type ?? VirtualFolder.TYPE.GENERAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add(element) {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
hasFile(name, extension) {
|
||||||
|
return this.findFile(name, extension) !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasFolder(name) {
|
||||||
|
return this.findSubFolder(name) !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
findFile(name, extension) {
|
||||||
|
let resultFile = null;
|
||||||
|
|
||||||
|
this.files.forEach((file) => {
|
||||||
|
if ((file.name === name || (file.alias && file.alias === name)) && file.extension === extension) {
|
||||||
|
return resultFile = file;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return resultFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
findSubFolder(name) {
|
||||||
|
let resultFolder = null;
|
||||||
|
|
||||||
|
this.subFolders.forEach((folder) => {
|
||||||
|
if (folder.name === name || (folder.alias && folder.alias === name)) {
|
||||||
|
return resultFolder = folder;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return resultFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
createFile(name, extension) {
|
||||||
|
const newFile = new VirtualFile(name, extension);
|
||||||
|
this.files.push(newFile);
|
||||||
|
newFile.parent = this;
|
||||||
|
return newFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
createFolder(name) {
|
||||||
|
const newFolder = new VirtualFolder(name);
|
||||||
|
this.subFolders.push(newFolder);
|
||||||
|
newFolder.parent = this;
|
||||||
|
return newFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {String} destination
|
||||||
|
*/
|
||||||
|
addFile(destination) {
|
||||||
|
const folderNames = destination.split("/");
|
||||||
|
const fileExtendedName = folderNames.pop().split();
|
||||||
|
const fileExtendedNameSegments = fileExtendedName.split(".");
|
||||||
|
|
||||||
|
const fileName = fileExtendedNameSegments[0];
|
||||||
|
const fileExtension = fileExtendedNameSegments.length > 1 ? fileExtendedNameSegments[1] : "txt";
|
||||||
|
|
||||||
|
// To do: check if file already exists
|
||||||
|
|
||||||
|
const file = new VirtualFile(fileName, fileExtension);
|
||||||
|
|
||||||
|
const folders = this.addFolder(folderNames.join("/"));
|
||||||
|
|
||||||
|
const parent = folders[folders.length - 1];
|
||||||
|
parent.files.push(file);
|
||||||
|
file.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {String} destination
|
||||||
|
*/
|
||||||
|
addFolder(destination) {
|
||||||
|
if (destination.endsWith("/"))
|
||||||
|
destination = destination.slice(0, -1);
|
||||||
|
|
||||||
|
const folderNames = destination.split("/");
|
||||||
|
|
||||||
|
let currentFolder = this;
|
||||||
|
folderNames.forEach((folderName) => {
|
||||||
|
if (!currentFolder.hasFolder(folderName)) {
|
||||||
|
currentFolder.createFolder(folderName);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(child) {
|
||||||
|
if (child instanceof VirtualFile) {
|
||||||
|
// Remove file by id
|
||||||
|
} else if (child instanceof VirtualFolder) {
|
||||||
|
// Remove folder by id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
navigate(relativePath) {
|
||||||
|
const segments = relativePath.split("/");
|
||||||
|
let currentDirectory = this;
|
||||||
|
|
||||||
|
const getDirectory = (path, isStart) => {
|
||||||
|
if (isStart && path === "") {
|
||||||
|
return this.getRoot();
|
||||||
|
} else if (isStart && Object.keys(this.getRoot().shortcuts).includes(path)) {
|
||||||
|
return this.getRoot().shortcuts[path];
|
||||||
|
} else if (path === ".") {
|
||||||
|
return this;
|
||||||
|
} else if (path === "..") {
|
||||||
|
return currentDirectory?.parent;
|
||||||
|
} else {
|
||||||
|
return currentDirectory?.findSubFolder(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (segments.length === 1) {
|
||||||
|
const directory = getDirectory(segments[0], true);
|
||||||
|
if (directory !== null)
|
||||||
|
return directory;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < segments.length - 1; i++) {
|
||||||
|
const segment = segments[i];
|
||||||
|
currentDirectory = getDirectory(segment, i === 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const lastSegment = segments[segments.length - 1];
|
||||||
|
|
||||||
|
if (lastSegment === "") {
|
||||||
|
return currentDirectory;
|
||||||
|
} else if (currentDirectory !== null) {
|
||||||
|
// To do: add support for file names with dots
|
||||||
|
const [name, extension] = lastSegment.split(".");
|
||||||
|
return currentDirectory.findFile(name, extension);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
21
src/features/virtual-drive/virtual-root.js
Normal file
21
src/features/virtual-drive/virtual-root.js
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { VirtualFolder } from "./virtual-folder.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A virtual folder that serves as the root folder
|
||||||
|
*/
|
||||||
|
export class VirtualRoot extends VirtualFolder {
|
||||||
|
constructor() {
|
||||||
|
super("root");
|
||||||
|
this.root = this;
|
||||||
|
this.shortcuts = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
addShortcut(name, destination) {
|
||||||
|
this.shortcuts[name] = destination;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
get path() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
import { createContext, useContext } from "react";
|
|
||||||
import { VirtualDrive } from "../modules/virtual-drive/virtual-drive.js";
|
|
||||||
|
|
||||||
const VirtualDriveContext = createContext();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {React.Provider<any>}
|
|
||||||
*/
|
|
||||||
export function VirtualDriveProvider({ children }) {
|
|
||||||
const virtualDrive = new VirtualDrive();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<VirtualDriveContext.Provider value={virtualDrive}>
|
|
||||||
{children}
|
|
||||||
</VirtualDriveContext.Provider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {VirtualDrive}
|
|
||||||
*/
|
|
||||||
export function useWindowsManager() {
|
|
||||||
return useContext(VirtualDriveContext);
|
|
||||||
}
|
|
||||||
36
src/hooks/VirtualRootContext.js
Normal file
36
src/hooks/VirtualRootContext.js
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { createContext, useContext } from "react";
|
||||||
|
import { VirtualRoot } from "../features/virtual-drive/virtual-root.js";
|
||||||
|
|
||||||
|
const VirtualRootContext = createContext();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {React.Provider<VirtualRoot>}
|
||||||
|
*/
|
||||||
|
export function VirtualRootProvider({ children }) {
|
||||||
|
const virtualRoot = new VirtualRoot().setAlias("/");
|
||||||
|
|
||||||
|
virtualRoot.createFolder("bin");
|
||||||
|
virtualRoot.createFolder("dev");
|
||||||
|
virtualRoot.createFolder("etc");
|
||||||
|
virtualRoot.createFolder("usr");
|
||||||
|
virtualRoot.createFolder("home").createFolder("prozilla-os").setAlias("~");
|
||||||
|
virtualRoot.createFolder("lib");
|
||||||
|
virtualRoot.createFolder("sbin");
|
||||||
|
virtualRoot.createFolder("tmp");
|
||||||
|
virtualRoot.createFolder("var");
|
||||||
|
|
||||||
|
console.log(virtualRoot.subFolders);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<VirtualRootContext.Provider value={virtualRoot}>
|
||||||
|
{children}
|
||||||
|
</VirtualRootContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {VirtualRoot}
|
||||||
|
*/
|
||||||
|
export function useVirtualRoot() {
|
||||||
|
return useContext(VirtualRootContext);
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { createContext, useContext } from "react";
|
import { createContext, useContext } from "react";
|
||||||
import WindowsManager from "../modules/windows/windows.js";
|
import WindowsManager from "../features/windows/windows.js";
|
||||||
import { WindowsProvider } from "./WindowsContext.js";
|
import { WindowsProvider } from "./WindowsContext.js";
|
||||||
|
|
||||||
const WindowsManagerContext = createContext();
|
const WindowsManagerContext = createContext();
|
||||||
|
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
import { VirtualFolder } from "./virtual-folder.js";
|
|
||||||
|
|
||||||
export class VirtualDrive extends VirtualFolder {
|
|
||||||
constructor() {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
export class VirtualFile {
|
|
||||||
constructor(name, extension) {
|
|
||||||
this.name = name;
|
|
||||||
this.extension = extension;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,98 +0,0 @@
|
||||||
import { VirtualFile } from "./virtual-file.js";
|
|
||||||
|
|
||||||
export class VirtualFolder {
|
|
||||||
static TYPE = {
|
|
||||||
GENERAL: 0,
|
|
||||||
MEDIA: 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {String} name
|
|
||||||
* @param {Number} type
|
|
||||||
*/
|
|
||||||
constructor(name, type) {
|
|
||||||
this.name = name;
|
|
||||||
this.subFolders = [];
|
|
||||||
this.files = [];
|
|
||||||
this.type = type ?? this.TYPE.GENERAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// add(element) {
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
hasFile(name, extension) {
|
|
||||||
let exists = false;
|
|
||||||
|
|
||||||
this.files.forEach(({ name: fileName, extension: fileExtension }) => {
|
|
||||||
if (fileName === name && fileExtension === extension) {
|
|
||||||
return exists = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return exists;
|
|
||||||
}
|
|
||||||
|
|
||||||
hasFolder(name) {
|
|
||||||
let exists = false;
|
|
||||||
|
|
||||||
this.folders.forEach(({ name: folderName }) => {
|
|
||||||
if (folderName === name) {
|
|
||||||
return exists = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return exists;
|
|
||||||
}
|
|
||||||
|
|
||||||
createFile(name, extension) {
|
|
||||||
const file = new VirtualFile(name, extension);
|
|
||||||
this.files.push(file);
|
|
||||||
file.parent = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
createFolder(name) {
|
|
||||||
const newFolder = new VirtualFolder(name);
|
|
||||||
this.subFolders.push(newFolder);
|
|
||||||
newFolder.parent = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {String} destination
|
|
||||||
*/
|
|
||||||
addFile(destination) {
|
|
||||||
const folderNames = destination.split("/");
|
|
||||||
const fileExtendedName = folderNames.pop().split();
|
|
||||||
const fileExtendedNameSegments = fileExtendedName.split(".");
|
|
||||||
|
|
||||||
const fileName = fileExtendedNameSegments[0];
|
|
||||||
const fileExtension = fileExtendedNameSegments.length > 1 ? fileExtendedNameSegments[1] : "txt";
|
|
||||||
|
|
||||||
// To do: check if file already exists
|
|
||||||
|
|
||||||
const file = new VirtualFile(fileName, fileExtension);
|
|
||||||
|
|
||||||
const folders = this.addFolder(folderNames.join("/"));
|
|
||||||
|
|
||||||
const parent = folders[folders.length - 1];
|
|
||||||
parent.files.push(file);
|
|
||||||
file.parent = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {String} destination
|
|
||||||
*/
|
|
||||||
addFolder(destination) {
|
|
||||||
if (destination.endsWith("/"))
|
|
||||||
destination = destination.slice(0, -1);
|
|
||||||
|
|
||||||
const folderNames = destination.split("/");
|
|
||||||
|
|
||||||
let currentFolder = this;
|
|
||||||
folderNames.forEach((folderName) => {
|
|
||||||
if (!currentFolder.hasFolder(folderName)) {
|
|
||||||
currentFolder.createFolder(folderName);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in a new issue