Первая версия
This commit is contained in:
92
src/core/FileSaveService.js
Normal file
92
src/core/FileSaveService.js
Normal file
@@ -0,0 +1,92 @@
|
||||
import { PathUtils } from "./PathUtils.js";
|
||||
|
||||
export class FileSaveService {
|
||||
constructor() {
|
||||
this.fallbackHandles = new Map();
|
||||
}
|
||||
|
||||
async saveFile(projectStore, path, content) {
|
||||
const normalizedPath = PathUtils.normalizeRelative(path);
|
||||
|
||||
if (projectStore.rootHandle) {
|
||||
await this.#writeWithRootHandle(projectStore.rootHandle, normalizedPath, content);
|
||||
return { mode: "inplace", path: normalizedPath };
|
||||
}
|
||||
|
||||
const knownHandle = projectStore.fileHandles.get(normalizedPath) || this.fallbackHandles.get(normalizedPath);
|
||||
if (knownHandle && typeof knownHandle.createWritable === "function") {
|
||||
await this.#writeWithFileHandle(knownHandle, content);
|
||||
return { mode: "inplace", path: normalizedPath };
|
||||
}
|
||||
|
||||
if (typeof window.showSaveFilePicker === "function") {
|
||||
const pickerOptions = {
|
||||
suggestedName: PathUtils.basename(normalizedPath),
|
||||
id: this.#buildProjectSaveId(projectStore)
|
||||
};
|
||||
const startInHandle = projectStore.rootHandle || knownHandle || this.fallbackHandles.get(normalizedPath);
|
||||
if (startInHandle) pickerOptions.startIn = startInHandle;
|
||||
|
||||
const handle = await window.showSaveFilePicker(pickerOptions);
|
||||
await this.#writeWithFileHandle(handle, content);
|
||||
this.fallbackHandles.set(normalizedPath, handle);
|
||||
return { mode: "save_as", path: normalizedPath };
|
||||
}
|
||||
|
||||
this.#downloadFile(normalizedPath, content);
|
||||
return { mode: "download", path: normalizedPath };
|
||||
}
|
||||
|
||||
async deleteFile(projectStore, path) {
|
||||
const normalizedPath = PathUtils.normalizeRelative(path);
|
||||
if (!projectStore.rootHandle) return false;
|
||||
const parts = normalizedPath.split("/");
|
||||
const fileName = parts.pop();
|
||||
let dir = projectStore.rootHandle;
|
||||
|
||||
for (const part of parts) {
|
||||
dir = await dir.getDirectoryHandle(part);
|
||||
}
|
||||
|
||||
await dir.removeEntry(fileName);
|
||||
return true;
|
||||
}
|
||||
|
||||
async #writeWithRootHandle(rootHandle, path, content) {
|
||||
const parts = path.split("/");
|
||||
const fileName = parts.pop();
|
||||
let dir = rootHandle;
|
||||
|
||||
for (const part of parts) {
|
||||
dir = await dir.getDirectoryHandle(part, { create: true });
|
||||
}
|
||||
|
||||
const handle = await dir.getFileHandle(fileName, { create: true });
|
||||
await this.#writeWithFileHandle(handle, content);
|
||||
}
|
||||
|
||||
async #writeWithFileHandle(handle, content) {
|
||||
const writable = await handle.createWritable();
|
||||
await writable.write(content);
|
||||
await writable.close();
|
||||
}
|
||||
|
||||
#downloadFile(path, content) {
|
||||
const blob = new Blob([content], { type: "text/plain;charset=utf-8" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = PathUtils.basename(path);
|
||||
a.style.display = "none";
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
a.remove();
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
#buildProjectSaveId(projectStore) {
|
||||
const projectName = projectStore?.rootNode?.name || "project";
|
||||
const normalized = projectName.toLowerCase().replaceAll(/[^a-z0-9_-]/g, "-").replaceAll(/-+/g, "-");
|
||||
return `save-${normalized || "project"}`;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user