197 lines
No EOL
4.3 KiB
TypeScript
197 lines
No EOL
4.3 KiB
TypeScript
import { APPS } from "../../../config/apps.config";
|
|
import { IMAGE_FORMATS } from "../../../config/apps/mediaViewer.config";
|
|
import { AppsManager } from "../../apps/appsManager";
|
|
import { WindowsManager } from "../../windows/windowsManager";
|
|
import { VirtualBase, VirtualBaseJson } from "../virtualBase";
|
|
|
|
export interface VirtualFileJson extends VirtualBaseJson {
|
|
ext?: string;
|
|
cnt?: string;
|
|
src?: string;
|
|
}
|
|
|
|
type OptionalStringProperty = string | null | undefined;
|
|
|
|
/**
|
|
* A virtual file that can be stored inside a folder
|
|
*/
|
|
export class VirtualFile extends VirtualBase {
|
|
extension: OptionalStringProperty;
|
|
source: OptionalStringProperty;
|
|
content: OptionalStringProperty;
|
|
|
|
static NON_TEXT_EXTENSIONS = [
|
|
"png"
|
|
];
|
|
|
|
static EVENT_NAMES = {
|
|
CONTENT_CHANGE: "contentchange"
|
|
};
|
|
|
|
constructor(name: string, extension?: string | undefined) {
|
|
super(name);
|
|
this.extension = extension;
|
|
}
|
|
|
|
setAlias(alias: string): this {
|
|
return super.setAlias(alias);
|
|
}
|
|
|
|
/**
|
|
* Sets the source of this file and removes the content
|
|
*/
|
|
setSource(source: string): this {
|
|
if (this.source === source || !this.canBeEdited)
|
|
return this;
|
|
|
|
this.source = source;
|
|
this.content = null;
|
|
|
|
this.emit(VirtualFile.EVENT_NAMES.CONTENT_CHANGE, this);
|
|
|
|
this.confirmChanges();
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets the content of this file and removes the source
|
|
*/
|
|
setContent(content: string): this {
|
|
if (this.content === content || !this.canBeEdited)
|
|
return this;
|
|
|
|
this.content = content;
|
|
this.source = null;
|
|
|
|
this.emit(VirtualFile.EVENT_NAMES.CONTENT_CHANGE, this);
|
|
|
|
this.confirmChanges();
|
|
return this;
|
|
}
|
|
|
|
get id() {
|
|
if (this.extension == null || this.extension.trim() === "")
|
|
return this.name;
|
|
|
|
return `${this.name}.${this.extension}`;
|
|
}
|
|
|
|
static splitId(id: string): {
|
|
name: string;
|
|
extension: OptionalStringProperty;
|
|
} {
|
|
if (!id.includes("."))
|
|
return { name: id, extension: "" };
|
|
|
|
const sections = id.split(".");
|
|
const extension = sections.pop();
|
|
const name = sections.join(".");
|
|
return { name, extension };
|
|
}
|
|
|
|
/**
|
|
* Opens this file in an app associated with its extension
|
|
*/
|
|
open(windowsManager: WindowsManager): object | null {
|
|
return windowsManager.openFile(this);
|
|
}
|
|
|
|
async read(): Promise<OptionalStringProperty | undefined> {
|
|
if (this.content != null) return this.content;
|
|
if (this.source == null) return null;
|
|
|
|
const isText = this.extension == null || !VirtualFile.NON_TEXT_EXTENSIONS.includes(this.extension);
|
|
|
|
if (!isText) return this.source;
|
|
|
|
return await fetch(this.source).then((response) => {
|
|
return response.text();
|
|
}).catch((error) => {
|
|
console.error(`Error while reading file with id "${this.id}":`, error);
|
|
return null;
|
|
}) as string;
|
|
}
|
|
|
|
isFile(): boolean {
|
|
return true;
|
|
}
|
|
|
|
getIconUrl(): string {
|
|
if (this.iconUrl != null)
|
|
return this.iconUrl;
|
|
|
|
let iconUrl = null;
|
|
|
|
if (this.source != null && this.extension != null && IMAGE_FORMATS.includes(this.extension))
|
|
return this.source;
|
|
|
|
switch (this.extension) {
|
|
case "txt":
|
|
case "md":
|
|
iconUrl = AppsManager.getAppIconUrl(APPS.FILE_EXPLORER, "file-text");
|
|
break;
|
|
case "xml":
|
|
case "js":
|
|
case "json":
|
|
case "jsx":
|
|
case "ts":
|
|
case "tsx":
|
|
case "css":
|
|
case "html":
|
|
case "yml":
|
|
iconUrl = AppsManager.getAppIconUrl(APPS.FILE_EXPLORER, "file-code");
|
|
break;
|
|
default:
|
|
iconUrl = AppsManager.getAppIconUrl(APPS.FILE_EXPLORER, "file");
|
|
break;
|
|
}
|
|
|
|
return iconUrl;
|
|
}
|
|
|
|
getType(): string {
|
|
let type = "";
|
|
|
|
if (this.extension == null) return "Unknown file";
|
|
|
|
switch (this.extension) {
|
|
case "png":
|
|
type = "PNG Image";
|
|
break;
|
|
case "txt":
|
|
type = "Text";
|
|
break;
|
|
case "md":
|
|
type = "Markdown source";
|
|
break;
|
|
case "xml":
|
|
type = "XML source";
|
|
break;
|
|
}
|
|
|
|
return `${type} file (.${this.extension.toLowerCase()})`.trim();
|
|
}
|
|
|
|
toJSON(): VirtualFileJson | null {
|
|
// Don't return file if it can't or hasn't been edited
|
|
if (!this.canBeEdited || (this.editedByUser == null || !this.editedByUser))
|
|
return null;
|
|
|
|
const object = super.toJSON() as VirtualFileJson;
|
|
|
|
if (object == null)
|
|
return null;
|
|
|
|
if (this.extension != null) {
|
|
object.ext = this.extension;
|
|
}
|
|
|
|
if (this.content != null) {
|
|
object.cnt = this.content;
|
|
} else if (this.source != null) {
|
|
object.src = this.source;
|
|
}
|
|
|
|
return object;
|
|
}
|
|
} |