diff --git a/app/appearance/langs/en_US.json b/app/appearance/langs/en_US.json index 7a7cce078..10dcaecb3 100644 --- a/app/appearance/langs/en_US.json +++ b/app/appearance/langs/en_US.json @@ -1,4 +1,6 @@ { + "notBatchRemove": "Notebooks do not support batch deletion", + "confirmRemove": "Are you sure you want to delete the ${count} selected files?", "microphoneDenied": "Need to allow Siyuan to access the microphone in System Preferences", "microphoneNotAccess": "Access to the microphone is denied, go to System Preferences to reset", "dynamicLoadBlocks": "Number of dynamically loaded blocks", diff --git a/app/appearance/langs/es_ES.json b/app/appearance/langs/es_ES.json index 3eeecb32d..97c0e25cd 100644 --- a/app/appearance/langs/es_ES.json +++ b/app/appearance/langs/es_ES.json @@ -1,4 +1,6 @@ { + "notBatchRemove": "Los portátiles no admiten la eliminación por lotes", + "confirmRemove": "¿Está seguro de que desea eliminar los ${count} archivos seleccionados?", "microphoneDenied": "Necesito permitir que Siyuan acceda al micrófono en Preferencias del Sistema", "microphoneNotAccess": "Acceso al micrófono denegado, ve a Preferencias del Sistema para reiniciar", "dynamicLoadBlocks": "Número de bloques cargados dinámicamente", diff --git a/app/appearance/langs/fr_FR.json b/app/appearance/langs/fr_FR.json index 6ad82b21e..7a06187bc 100644 --- a/app/appearance/langs/fr_FR.json +++ b/app/appearance/langs/fr_FR.json @@ -1,4 +1,6 @@ { + "notBatchRemove": "Les blocs-notes ne prennent pas en charge la suppression par lots", + "confirmRemove": "Êtes-vous sûr de vouloir supprimer les ${count} fichiers sélectionnés ?", "microphoneDenied": "Vous devez autoriser Siyuan à accéder au microphone dans les Préférences Système", "microphoneNotAccess": "L'accès au microphone est refusé, allez dans les Préférences Système pour réinitialiser", "dynamicLoadBlocks": "Nombre de blocs chargés dynamiquement", diff --git a/app/appearance/langs/zh_CHT.json b/app/appearance/langs/zh_CHT.json index 4c0e04700..20767bb42 100644 --- a/app/appearance/langs/zh_CHT.json +++ b/app/appearance/langs/zh_CHT.json @@ -1,4 +1,6 @@ { + "notBatchRemove": "筆記本不支持批量刪除", + "confirmRemove": "確定刪除選中的 ${count} 個文件?", "microphoneDenied": "需在系統偏好設置中允許思源訪問麥克風", "microphoneNotAccess": "麥克風被拒絕訪問,可前往系統偏好設置中重新設置", "dynamicLoadBlocks": "動態加載塊數", diff --git a/app/appearance/langs/zh_CN.json b/app/appearance/langs/zh_CN.json index 5dfe7358b..648363095 100644 --- a/app/appearance/langs/zh_CN.json +++ b/app/appearance/langs/zh_CN.json @@ -1,4 +1,6 @@ { + "notBatchRemove": "笔记本不支持批量删除", + "confirmRemove": "确定删除选中的 ${count} 个文件?", "microphoneDenied": "需在系统偏好设置中允许思源访问麦克风", "microphoneNotAccess": "麦克风被拒绝访问,可前往系统偏好设置中重新设置", "dynamicLoadBlocks": "动态加载块数", diff --git a/app/src/editor/deleteFile.ts b/app/src/editor/deleteFile.ts index 911659acf..2df6794b5 100644 --- a/app/src/editor/deleteFile.ts +++ b/app/src/editor/deleteFile.ts @@ -1,6 +1,9 @@ import {fetchPost} from "../util/fetch"; -import {getDisplayName} from "../util/pathName"; +import {getDisplayName, getNotebookName} from "../util/pathName"; import {confirmDialog} from "../dialog/confirmDialog"; +import {hasTopClosestByTag} from "../protyle/util/hasClosest"; +import {Constants} from "../constants"; +import {showMessage} from "../dialog/message"; export const deleteFile = (notebookId: string, pathString: string, name: string) => { if (window.siyuan.config.fileTree.removeDocWithoutConfirm) { @@ -25,3 +28,38 @@ export const deleteFile = (notebookId: string, pathString: string, name: string) }); }); }; + +export const deleteFiles = (liElements: Element[]) => { + if (liElements.length === 1) { + const itemTopULElement = hasTopClosestByTag(liElements[0], "UL"); + if (itemTopULElement) { + const itemNotebookId = itemTopULElement.getAttribute("data-url") + if (liElements[0].getAttribute("data-type") === "navigation-file") { + deleteFile(itemNotebookId, liElements[0].getAttribute("data-path"), getDisplayName(liElements[0].getAttribute("data-name"), false, true)); + } else { + confirmDialog(window.siyuan.languages.deleteOpConfirm, + `${window.siyuan.languages.confirmDelete} ${Lute.EscapeHTMLStr(getNotebookName(itemNotebookId))}?`, () => { + fetchPost("/api/notebook/removeNotebook", { + notebook: itemNotebookId, + callback: Constants.CB_MOUNT_REMOVE + }); + }); + } + } + } else { + const paths: string[] = [] + liElements.forEach(item => { + paths.push(item.getAttribute("data-path")); + }) + if (paths.includes("/")) { + showMessage(window.siyuan.languages.notBatchRemove); + return; + } + confirmDialog(window.siyuan.languages.deleteOpConfirm, + window.siyuan.languages.confirmRemove.replace("${count}", liElements.length), () => { + fetchPost("/api/notebook/removeDocs", { + paths + }); + }); + } +} diff --git a/app/src/menus/commonMenuItem.ts b/app/src/menus/commonMenuItem.ts index 09c04391c..de365c530 100644 --- a/app/src/menus/commonMenuItem.ts +++ b/app/src/menus/commonMenuItem.ts @@ -778,17 +778,6 @@ export const openMenu = (src: string, onlyMenu: boolean, showAccelerator: boolea }).element); }; -export const deleteMenu = (notebookId: string, name: string, pathString: string) => { - return new MenuItem({ - icon: "iconTrashcan", - label: window.siyuan.languages.delete, - accelerator: "⌦", - click: () => { - deleteFile(notebookId, pathString, name); - } - }).element; -}; - export const renameMenu = (options: { path: string notebookId: string diff --git a/app/src/menus/navigation.ts b/app/src/menus/navigation.ts index 76ed26280..2e874435f 100644 --- a/app/src/menus/navigation.ts +++ b/app/src/menus/navigation.ts @@ -1,6 +1,5 @@ import { copySubMenu, - deleteMenu, exportMd, movePathToMenu, openFileAttr, @@ -24,6 +23,7 @@ import {confirmDialog} from "../dialog/confirmDialog"; import {Constants} from "../constants"; import {newFile} from "../util/newFile"; import {hasClosestByClassName} from "../protyle/util/hasClosest"; +import {deleteFile, deleteFiles} from "../editor/deleteFile"; export const initNavigationMenu = (liElement: HTMLElement) => { if (!liElement.classList.contains("b3-list-item--focus")) { @@ -148,15 +148,16 @@ export const initNavigationMenu = (liElement: HTMLElement) => { }; export const initFileMenu = (notebookId: string, pathString: string, liElement: Element) => { + const fileElement = hasClosestByClassName(liElement, "sy__file") + if (!fileElement) { + return; + } if (!liElement.classList.contains("b3-list-item--focus")) { - const fileElement = hasClosestByClassName(liElement, "sy__file") - if (fileElement) { - fileElement.querySelectorAll(".b3-list-item--focus").forEach(item => { - item.classList.remove("b3-list-item--focus"); - item.removeAttribute("select-end") - item.removeAttribute("select-start") - }) - } + fileElement.querySelectorAll(".b3-list-item--focus").forEach(item => { + item.classList.remove("b3-list-item--focus"); + item.removeAttribute("select-end") + item.removeAttribute("select-start") + }) liElement.classList.add("b3-list-item--focus"); } const id = liElement.getAttribute("data-node-id"); @@ -213,7 +214,14 @@ export const initFileMenu = (notebookId: string, pathString: string, liElement: }]) }).element); window.siyuan.menus.menu.append(movePathToMenu(notebookId, pathString)); - window.siyuan.menus.menu.append(deleteMenu(notebookId, name, pathString)); + window.siyuan.menus.menu.append(new MenuItem({ + icon: "iconTrashcan", + label: window.siyuan.languages.delete, + accelerator: "⌦", + click: () => { + deleteFiles(Array.from(fileElement.querySelectorAll(".b3-list-item--focus"))) + } + }).element); window.siyuan.menus.menu.append(new MenuItem({type: "separator"}).element); window.siyuan.menus.menu.append(renameMenu({ path: pathString, diff --git a/app/src/util/globalShortcut.ts b/app/src/util/globalShortcut.ts index 26ededeb5..cee6c6169 100644 --- a/app/src/util/globalShortcut.ts +++ b/app/src/util/globalShortcut.ts @@ -35,7 +35,7 @@ import {showMessage} from "../dialog/message"; import {openHistory} from "./history"; import {Dialog} from "../dialog"; import {unicode2Emoji} from "../emoji"; -import {deleteFile} from "../editor/deleteFile"; +import {deleteFile, deleteFiles} from "../editor/deleteFile"; import {escapeHtml} from "./escape"; import {syncGuide} from "../sync/syncGuide"; import {showPopover} from "../block/popover"; @@ -1094,26 +1094,9 @@ const fileTreeKeydown = (event: KeyboardEvent) => { return true; } } - if (event.key === "Delete" || (event.key === "Backspace" && isMac())) { window.siyuan.menus.menu.remove(); - liElements.forEach(item => { - const itemTopULElement = hasTopClosestByTag(item, "UL"); - if (itemTopULElement) { - const itemNotebookId = itemTopULElement.getAttribute("data-url") - if (item.getAttribute("data-type") === "navigation-file") { - deleteFile(itemNotebookId, item.getAttribute("data-path"), getDisplayName(item.getAttribute("data-name"), false, true)); - } else { - confirmDialog(window.siyuan.languages.deleteOpConfirm, - `${window.siyuan.languages.confirmDelete} ${Lute.EscapeHTMLStr(getNotebookName(itemNotebookId))}?`, () => { - fetchPost("/api/notebook/removeNotebook", { - notebook: itemNotebookId, - callback: Constants.CB_MOUNT_REMOVE - }); - }); - } - } - }) + deleteFiles(liElements) return true; } if (event.key === "Enter") {