Explorar o código

:art: https://github.com/siyuan-note/siyuan/issues/1359 批量删除

Vanessa %!s(int64=2) %!d(string=hai) anos
pai
achega
c8680c9fb3

+ 2 - 0
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",
   "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",
   "microphoneNotAccess": "Access to the microphone is denied, go to System Preferences to reset",
   "dynamicLoadBlocks": "Number of dynamically loaded blocks",
   "dynamicLoadBlocks": "Number of dynamically loaded blocks",

+ 2 - 0
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",
   "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",
   "microphoneNotAccess": "Acceso al micrófono denegado, ve a Preferencias del Sistema para reiniciar",
   "dynamicLoadBlocks": "Número de bloques cargados dinámicamente",
   "dynamicLoadBlocks": "Número de bloques cargados dinámicamente",

+ 2 - 0
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",
   "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",
   "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",
   "dynamicLoadBlocks": "Nombre de blocs chargés dynamiquement",

+ 2 - 0
app/appearance/langs/zh_CHT.json

@@ -1,4 +1,6 @@
 {
 {
+  "notBatchRemove": "筆記本不支持批量刪除",
+  "confirmRemove": "確定刪除選中的 ${count} 個文件?",
   "microphoneDenied": "需在系統偏好設置中允許思源訪問麥克風",
   "microphoneDenied": "需在系統偏好設置中允許思源訪問麥克風",
   "microphoneNotAccess": "麥克風被拒絕訪問,可前往系統偏好設置中重新設置",
   "microphoneNotAccess": "麥克風被拒絕訪問,可前往系統偏好設置中重新設置",
   "dynamicLoadBlocks": "動態加載塊數",
   "dynamicLoadBlocks": "動態加載塊數",

+ 2 - 0
app/appearance/langs/zh_CN.json

@@ -1,4 +1,6 @@
 {
 {
+  "notBatchRemove": "笔记本不支持批量删除",
+  "confirmRemove": "确定删除选中的 ${count} 个文件?",
   "microphoneDenied": "需在系统偏好设置中允许思源访问麦克风",
   "microphoneDenied": "需在系统偏好设置中允许思源访问麦克风",
   "microphoneNotAccess": "麦克风被拒绝访问,可前往系统偏好设置中重新设置",
   "microphoneNotAccess": "麦克风被拒绝访问,可前往系统偏好设置中重新设置",
   "dynamicLoadBlocks": "动态加载块数",
   "dynamicLoadBlocks": "动态加载块数",

+ 39 - 1
app/src/editor/deleteFile.ts

@@ -1,6 +1,9 @@
 import {fetchPost} from "../util/fetch";
 import {fetchPost} from "../util/fetch";
-import {getDisplayName} from "../util/pathName";
+import {getDisplayName, getNotebookName} from "../util/pathName";
 import {confirmDialog} from "../dialog/confirmDialog";
 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) => {
 export const deleteFile = (notebookId: string, pathString: string, name: string) => {
     if (window.siyuan.config.fileTree.removeDocWithoutConfirm) {
     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} <b>${Lute.EscapeHTMLStr(getNotebookName(itemNotebookId))}</b>?`, () => {
+                        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
+                });
+            });
+    }
+}

+ 0 - 11
app/src/menus/commonMenuItem.ts

@@ -778,17 +778,6 @@ export const openMenu = (src: string, onlyMenu: boolean, showAccelerator: boolea
     }).element);
     }).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: {
 export const renameMenu = (options: {
     path: string
     path: string
     notebookId: string
     notebookId: string

+ 18 - 10
app/src/menus/navigation.ts

@@ -1,6 +1,5 @@
 import {
 import {
     copySubMenu,
     copySubMenu,
-    deleteMenu,
     exportMd,
     exportMd,
     movePathToMenu,
     movePathToMenu,
     openFileAttr,
     openFileAttr,
@@ -24,6 +23,7 @@ import {confirmDialog} from "../dialog/confirmDialog";
 import {Constants} from "../constants";
 import {Constants} from "../constants";
 import {newFile} from "../util/newFile";
 import {newFile} from "../util/newFile";
 import {hasClosestByClassName} from "../protyle/util/hasClosest";
 import {hasClosestByClassName} from "../protyle/util/hasClosest";
+import {deleteFile, deleteFiles} from "../editor/deleteFile";
 
 
 export const initNavigationMenu = (liElement: HTMLElement) => {
 export const initNavigationMenu = (liElement: HTMLElement) => {
     if (!liElement.classList.contains("b3-list-item--focus")) {
     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) => {
 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")) {
     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");
         liElement.classList.add("b3-list-item--focus");
     }
     }
     const id = liElement.getAttribute("data-node-id");
     const id = liElement.getAttribute("data-node-id");
@@ -213,7 +214,14 @@ export const initFileMenu = (notebookId: string, pathString: string, liElement:
             }])
             }])
         }).element);
         }).element);
         window.siyuan.menus.menu.append(movePathToMenu(notebookId, pathString));
         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(new MenuItem({type: "separator"}).element);
         window.siyuan.menus.menu.append(renameMenu({
         window.siyuan.menus.menu.append(renameMenu({
             path: pathString,
             path: pathString,

+ 2 - 19
app/src/util/globalShortcut.ts

@@ -35,7 +35,7 @@ import {showMessage} from "../dialog/message";
 import {openHistory} from "./history";
 import {openHistory} from "./history";
 import {Dialog} from "../dialog";
 import {Dialog} from "../dialog";
 import {unicode2Emoji} from "../emoji";
 import {unicode2Emoji} from "../emoji";
-import {deleteFile} from "../editor/deleteFile";
+import {deleteFile, deleteFiles} from "../editor/deleteFile";
 import {escapeHtml} from "./escape";
 import {escapeHtml} from "./escape";
 import {syncGuide} from "../sync/syncGuide";
 import {syncGuide} from "../sync/syncGuide";
 import {showPopover} from "../block/popover";
 import {showPopover} from "../block/popover";
@@ -1094,26 +1094,9 @@ const fileTreeKeydown = (event: KeyboardEvent) => {
             return true;
             return true;
         }
         }
     }
     }
-
     if (event.key === "Delete" || (event.key === "Backspace" && isMac())) {
     if (event.key === "Delete" || (event.key === "Backspace" && isMac())) {
         window.siyuan.menus.menu.remove();
         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} <b>${Lute.EscapeHTMLStr(getNotebookName(itemNotebookId))}</b>?`, () => {
-                            fetchPost("/api/notebook/removeNotebook", {
-                                notebook: itemNotebookId,
-                                callback: Constants.CB_MOUNT_REMOVE
-                            });
-                        });
-                }
-            }
-        })
+        deleteFiles(liElements)
         return true;
         return true;
     }
     }
     if (event.key === "Enter") {
     if (event.key === "Enter") {