You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
173 lines
4.5 KiB
173 lines
4.5 KiB
import {copyText} from '../../shared'
|
|
import {computed, nextTick, reactive} from "vue";
|
|
import {deleteFile, store} from "../store";
|
|
import {dispatch} from "../worker.ts";
|
|
import {showDirectoryNaming} from "./UiDirectoryNamingController";
|
|
import {toast} from "./UiToastController";
|
|
|
|
export type ContextmenuTarget =
|
|
| "directory" // 作用在侧边栏文件夹按钮上
|
|
| "file" // 作用在右侧文件图标上
|
|
| "filename" // 作用在右侧文件标题图标上
|
|
| "sidebar" // 作用在侧边栏上
|
|
| "content"; // 作用在右侧文件容器上
|
|
|
|
export interface ContextMenuOptions {
|
|
x: number;
|
|
y: number;
|
|
directoryId?: number;
|
|
fileId?: number;
|
|
target?: ContextmenuTarget;
|
|
}
|
|
|
|
interface ContextMenuState extends ContextMenuOptions {
|
|
visible: boolean;
|
|
}
|
|
|
|
export const controller = reactive<ContextMenuState>({
|
|
x: 0,
|
|
y: 0,
|
|
directoryId: 0,
|
|
fileId: undefined,
|
|
visible: false,
|
|
});
|
|
|
|
export const file = computed((): CloudFile | undefined => {
|
|
return controller.fileId
|
|
? store.files[controller.directoryId ?? 0]?.find(f => f.id === controller.fileId)
|
|
: undefined
|
|
})
|
|
|
|
export const directory = computed(() => {
|
|
const dirId = controller.directoryId
|
|
return dirId == 0
|
|
? store.rootDirectory
|
|
: dirId != null
|
|
? store.directories.get(dirId)
|
|
: undefined
|
|
})
|
|
|
|
export function isTarget(...targets: ContextmenuTarget[]): boolean {
|
|
return controller.target != null && targets.includes(controller.target);
|
|
}
|
|
|
|
export function showContextMenu(opts: ContextMenuOptions): void {
|
|
if (opts.target && opts.directoryId != null) {
|
|
controller.visible = true;
|
|
void nextTick(() => {
|
|
controller.x = opts.x;
|
|
controller.y = opts.y;
|
|
controller.fileId = opts.fileId;
|
|
controller.directoryId = opts.directoryId;
|
|
controller.target = opts.target;
|
|
});
|
|
} else {
|
|
hideContextMenu();
|
|
}
|
|
}
|
|
|
|
export function hideContextMenu() {
|
|
if (controller.visible) {
|
|
controller.visible = false;
|
|
void nextTick(() => {
|
|
if (!controller.visible) {
|
|
controller.directoryId = undefined;
|
|
controller.fileId = undefined;
|
|
controller.target = undefined;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
export function toggleContextMenu(evt: MouseEvent): void {
|
|
const elm = evt.target as HTMLElement;
|
|
if (elm.closest('[data-role="contextmenu"]')) {
|
|
return;
|
|
}
|
|
const dataset = elm.closest<HTMLElement>("[data-contextmenu]")?.dataset;
|
|
if (dataset && dataset.target != null && dataset.directoryId != null) {
|
|
showContextMenu({
|
|
x: evt.clientX,
|
|
y: evt.clientY,
|
|
fileId: dataset.fileId ? Number(dataset.fileId) : undefined,
|
|
directoryId: Number(dataset.directoryId),
|
|
target: dataset.target as ContextmenuTarget,
|
|
});
|
|
} else {
|
|
hideContextMenu();
|
|
}
|
|
}
|
|
|
|
export function handleNewDir(child?: boolean) {
|
|
showDirectoryNaming({
|
|
action: "create",
|
|
pid: child ? controller.directoryId : undefined,
|
|
});
|
|
}
|
|
|
|
// 重命名文件或文件夹
|
|
export function renameDir() {
|
|
const {directoryId} = controller
|
|
if (isTarget("directory") && directoryId) {
|
|
showDirectoryNaming({
|
|
id: directoryId,
|
|
action: "rename",
|
|
});
|
|
}
|
|
}
|
|
|
|
export function copyDirName() {
|
|
const text = directory.value?.title
|
|
text?.length && copyText(text)
|
|
}
|
|
|
|
export function copyFileName() {
|
|
const text = file.value?.name
|
|
text?.length && copyText(text)
|
|
}
|
|
|
|
export function copyFilePath() {
|
|
const text = file.value?.object.path
|
|
text?.length && copyText(text)
|
|
}
|
|
|
|
export function removeDir() {
|
|
const {directoryId} = controller
|
|
if (isTarget("directory") && directoryId) {
|
|
dispatch("dir", "delete", directoryId)
|
|
.then(() => store.directories.delete(directoryId))
|
|
.then(() => toast("success", "删除成功"))
|
|
.catch((error) => toast("error", error));
|
|
}
|
|
}
|
|
|
|
export function removeFile() {
|
|
const f = file.value;
|
|
if (isTarget("file", "filename") && f) {
|
|
dispatch("file", "delete", f.id)
|
|
.then(() => deleteFile(f))
|
|
.then(() => toast("success", "删除成功"))
|
|
.catch((error) => toast("error", error));
|
|
}
|
|
}
|
|
|
|
export function canShare() {
|
|
return typeof navigator.canShare === 'function' && navigator.canShare({
|
|
title: "MDN",
|
|
text: "Learn web development on MDN!",
|
|
url: "https://developer.mozilla.org",
|
|
})
|
|
}
|
|
|
|
export function share() {
|
|
if (file.value) {
|
|
navigator
|
|
.share({
|
|
title: file.value!.name,
|
|
text: file.value!.object.path,
|
|
url: file.value!.object.path,
|
|
})
|
|
.then(() => toast("success", "分享成功"))
|
|
.catch((error) => toast("error", error));
|
|
}
|
|
}
|
|
|