diff --git a/app/src/menus/commonMenuItem.ts b/app/src/menus/commonMenuItem.ts index 333e76b2a..873bed15e 100644 --- a/app/src/menus/commonMenuItem.ts +++ b/app/src/menus/commonMenuItem.ts @@ -4,7 +4,7 @@ import {shell} from "electron"; import {getDockByType} from "../layout/util"; import {confirmDialog} from "../dialog/confirmDialog"; import {getSearch, isMobile} from "../util/functions"; -import {isLocalPath, movePathTo, pathPosix} from "../util/pathName"; +import {isLocalPath, movePathTo, moveToPath, pathPosix} from "../util/pathName"; import {MenuItem} from "./Menu"; import {hasClosestByClassName} from "../protyle/util/hasClosest"; import {saveExport} from "../protyle/export"; @@ -805,7 +805,9 @@ export const movePathToMenu = (paths: string[]) => { icon: "iconMove", accelerator: window.siyuan.config.keymap.general.move.custom, click() { - movePathTo(paths); + movePathTo((toPath, toNotebook) =>{ + moveToPath(paths, toNotebook[0], toPath[0]); + }, paths); } }).element; }; diff --git a/app/src/protyle/gutter/index.ts b/app/src/protyle/gutter/index.ts index f210a3c21..c76273780 100644 --- a/app/src/protyle/gutter/index.ts +++ b/app/src/protyle/gutter/index.ts @@ -648,8 +648,8 @@ export class Gutter { accelerator: window.siyuan.config.keymap.general.move.custom, icon: "iconMove", click: () => { - movePathTo([], undefined, (toPath) => { - hintMoveBlock(toPath, selectsElement, protyle); + movePathTo((toPath) => { + hintMoveBlock(toPath[0], selectsElement, protyle); }); } }).element); @@ -1019,8 +1019,8 @@ export class Gutter { accelerator: window.siyuan.config.keymap.general.move.custom, icon: "iconMove", click: () => { - movePathTo([], undefined, (toPath) => { - hintMoveBlock(toPath, [nodeElement], protyle); + movePathTo((toPath) => { + hintMoveBlock(toPath[0], [nodeElement], protyle); }); } }).element); diff --git a/app/src/search/spread.ts b/app/src/search/spread.ts index edeab9ff8..001564bd0 100644 --- a/app/src/search/spread.ts +++ b/app/src/search/spread.ts @@ -62,17 +62,17 @@ export const openSearch = async (hotkey: string, key?: string, notebookId?: stri }; } let hPath = "" - let idPath = "" + const idPath: string[] = [] if (notebookId) { hPath = escapeHtml(getNotebookName(notebookId)); - idPath = notebookId; + idPath.push(notebookId); if (searchPath && searchPath !== "/") { const response = await fetchSyncPost("/api/filetree/getHPathByPath", { notebook: notebookId, path: searchPath.endsWith(".sy") ? searchPath : searchPath + ".sy" }); hPath = pathPosix().join(hPath, escapeHtml(response.data)); - idPath = pathPosix().join(idPath, searchPath); + idPath[0] = pathPosix().join(idPath[0], searchPath); } } diff --git a/app/src/search/util.ts b/app/src/search/util.ts index 4ff0911e6..aad3b35cd 100644 --- a/app/src/search/util.ts +++ b/app/src/search/util.ts @@ -62,7 +62,7 @@ export const openGlobalSearch = (text: string, replace: boolean) => { hasReplace: false, method: localData.method || 0, hPath: "", - idPath: "", + idPath: [], list: [], replaceList: [], group: localData.group || 0, @@ -183,7 +183,7 @@ export const genSearch = (config: ISearchOption, element: Element, closeCB?: () let target = event.target as HTMLElement; while (target && !target.isSameNode(element)) { if (target.classList.contains("search__rmpath")) { - config.idPath = ""; + config.idPath = []; config.hPath = ""; element.querySelector("#searchPathInput").innerHTML = config.hPath; inputTimeout = inputEvent(element, config, inputTimeout, edit, false); @@ -211,21 +211,17 @@ export const genSearch = (config: ISearchOption, element: Element, closeCB?: () event.preventDefault(); break; } else if (target.id === "searchPath") { - movePathTo([], undefined, (toPath, toNotebook) => { - if (toPath === "/") { - config.idPath = toNotebook; - config.hPath = escapeHtml(getNotebookName(toNotebook)); + movePathTo((toPath, toNotebook) => { + fetchPost("/api/filetree/getHPathsByPaths", {paths: toPath}, (response) => { + config.idPath = [] + toNotebook.forEach((item, index) => { + config.idPath.push(pathPosix().join(item, toPath[index])); + }) + config.hPath = escapeHtml(response.data ? response.data.join(", ") : ""); element.querySelector("#searchPathInput").innerHTML = `${config.hPath}`; inputTimeout = inputEvent(element, config, inputTimeout, edit, false); - } else { - config.idPath = pathPosix().join(toNotebook, toPath); - fetchPost("/api/filetree/getHPathsByPaths", {paths: [toPath]}, (response) => { - config.hPath = escapeHtml(response.data ? response.data[0] : ""); - element.querySelector("#searchPathInput").innerHTML = `${config.hPath}`; - inputTimeout = inputEvent(element, config, inputTimeout, edit, false); - }); - } - }, window.siyuan.languages.specifyPath); + }); + }, [], undefined, window.siyuan.languages.specifyPath); event.stopPropagation(); event.preventDefault(); break; @@ -278,30 +274,36 @@ export const genSearch = (config: ISearchOption, element: Element, closeCB?: () break; } else if (target.id === "searchFilter") { window.siyuan.menus.menu.remove(); + let includeChild = true + config.idPath.find(item => { + if (!item.endsWith(".sy")) { + includeChild = false + return true; + } + }); window.siyuan.menus.menu.append(new MenuItem({ label: `
${window.siyuan.languages.includeChildDoc} -
`, +`, bind(menuItemElement) { menuItemElement.addEventListener("click", (event: MouseEvent & { target: HTMLElement }) => { const inputElement = menuItemElement.querySelector("input"); if (event.target.tagName !== "INPUT") { inputElement.checked = !inputElement.checked; } - let reload = false; if (!inputElement.checked) { - if (!config.idPath.endsWith(".sy") && config.idPath.split("/").length > 1) { - config.idPath = config.idPath + ".sy"; - reload = true; - } + config.idPath.forEach((item, index) => { + if (!item.endsWith(".sy") && item.split("/").length > 1) { + config.idPath[index] = item + ".sy"; + } + }); } else { - if (config.idPath.endsWith(".sy")) { - config.idPath = config.idPath.replace(".sy", ""); - reload = true; - } - } - if (reload) { - inputTimeout = inputEvent(element, config, inputTimeout, edit); + config.idPath.forEach((item, index) => { + if (item.endsWith(".sy")) { + config.idPath[index] = item.replace(".sy", ""); + } + }); } + inputTimeout = inputEvent(element, config, inputTimeout, edit); window.siyuan.menus.menu.remove(); }); } @@ -730,7 +732,7 @@ const inputEvent = (element: Element, config: ISearchOption, inputTimeout: numbe query: inputValue, method: config.method, types: config.types, - path: config.idPath || "", + paths: config.idPath || [], groupBy: config.group, // 0:不分组,1:按文档分组 }, (response) => { onSearch(response.data.blocks, edit, element); diff --git a/app/src/types/index.d.ts b/app/src/types/index.d.ts index 9d9e097e7..c7bd0b62a 100644 --- a/app/src/types/index.d.ts +++ b/app/src/types/index.d.ts @@ -53,7 +53,7 @@ interface ISearchOption { hasReplace: boolean, method: number // 0:文本,1:查询语法,2:SQL,3:正则表达式 hPath: string - idPath: string + idPath: string[] k: string r: string replaceList: string[] diff --git a/app/src/util/globalShortcut.ts b/app/src/util/globalShortcut.ts index 5d68567f6..976bef9c3 100644 --- a/app/src/util/globalShortcut.ts +++ b/app/src/util/globalShortcut.ts @@ -22,7 +22,7 @@ import {hideElements} from "../protyle/ui/hideElements"; import {fetchPost} from "./fetch"; import {goBack, goForward} from "./backForward"; import {onGet} from "../protyle/util/onGet"; -import {getDisplayName, getNotebookName, getTopPaths, movePathTo} from "./pathName"; +import {getDisplayName, getNotebookName, getTopPaths, movePathTo, moveToPath} from "./pathName"; import {openFileById} from "../editor/util"; import {getAllDocks, getAllModels, getAllTabs} from "../layout/getAll"; import {openGlobalSearch} from "../search/util"; @@ -817,14 +817,16 @@ const editKeydown = (event: KeyboardEvent) => { nodeElement = hasClosestBlock(range.startContainer); } if (protyle.title?.editElement.contains(range.startContainer)) { - movePathTo([protyle.path], range); + movePathTo((toPath, toNotebook) => { + moveToPath([protyle.path], toNotebook[0], toPath[0]); + }, [protyle.path], range); } else if (nodeElement && range && protyle.element.contains(range.startContainer)) { let selectElements = Array.from(protyle.wysiwyg.element.querySelectorAll(".protyle-wysiwyg--select")); if (selectElements.length === 0) { selectElements = [nodeElement]; } - movePathTo([], undefined, (toPath) => { - hintMoveBlock(toPath, selectElements, protyle); + movePathTo((toPath) => { + hintMoveBlock(toPath[0], selectElements, protyle); }); } event.preventDefault(); @@ -939,7 +941,10 @@ const fileTreeKeydown = (event: KeyboardEvent) => { } if (isFile && matchHotKey(window.siyuan.config.keymap.general.move.custom, event)) { window.siyuan.menus.menu.remove(); - movePathTo(getTopPaths(liElements)); + const pathes = getTopPaths(liElements) + movePathTo((toPath, toNotebook) => { + moveToPath(pathes, toNotebook[0], toPath[0]); + }, pathes); event.preventDefault(); event.stopPropagation(); return true; diff --git a/app/src/util/pathName.ts b/app/src/util/pathName.ts index 74d199dc9..03742ada1 100644 --- a/app/src/util/pathName.ts +++ b/app/src/util/pathName.ts @@ -77,7 +77,7 @@ export const getTopPaths = (liElements: Element[]) => { return fromPaths; }; -const moveToPath = (fromPaths: string[], toNotebook: string, toPath: string) => { +export const moveToPath = (fromPaths: string[], toNotebook: string, toPath: string) => { fetchPost("/api/filetree/moveDocs", { toNotebook, fromPaths, @@ -85,7 +85,7 @@ const moveToPath = (fromPaths: string[], toNotebook: string, toPath: string) => }); }; -export const movePathTo = (paths?: string[], range?: Range, cb?: (toPath: string, toNotebook:string) => void, title?: string) => { +export const movePathTo = (cb: (toPath: string[], toNotebook: string[]) => void, paths?: string[], range?: Range, title?: string) => { const exitDialog = window.siyuan.dialogs.find((item) => { if (item.element.querySelector("#foldList")) { item.destroy(); @@ -178,10 +178,18 @@ export const movePathTo = (paths?: string[], range?: Range, cb?: (toPath: string return; } const currentPanelElement = searchListElement.classList.contains("fn__none") ? searchTreeElement : searchListElement; - let currentItemElement: HTMLElement = currentPanelElement.querySelector(".b3-list-item--focus"); - if (!currentItemElement) { + const currentItemElements = currentPanelElement.querySelectorAll(".b3-list-item--focus"); + if (currentItemElements.length === 0) { return; } + let currentItemElement: HTMLElement = currentItemElements[0] as HTMLElement; + if (event.key.startsWith("Arrow")) { + currentItemElements.forEach((item, index) => { + if (index !== 0) { + item.classList.remove("b3-list-item--focus") + } + }) + } if (searchListElement.classList.contains("fn__none")) { if ((event.key === "ArrowRight" && !currentItemElement.querySelector(".b3-list-item__arrow--open") && !currentItemElement.querySelector(".b3-list-item__toggle").classList.contains("fn__hidden")) || (event.key === "ArrowLeft" && currentItemElement.querySelector(".b3-list-item__arrow--open"))) { @@ -308,11 +316,17 @@ export const movePathTo = (paths?: string[], range?: Range, cb?: (toPath: string } } if (event.key === "Enter") { - if (cb) { - cb(currentItemElement.getAttribute("data-path"), currentItemElement.getAttribute("data-box")); - } else { - moveToPath(paths, currentItemElement.getAttribute("data-box"), currentItemElement.getAttribute("data-path")); + const currentItemElements = currentPanelElement.querySelectorAll(".b3-list-item--focus"); + if (currentItemElements.length === 0) { + return; } + const pathList: string[] = [] + const notebookIdList: string[] = [] + currentItemElements.forEach(item => { + pathList.push(item.getAttribute("data-path")) + notebookIdList.push(item.getAttribute("data-box")) + }) + cb(pathList, notebookIdList); dialog.destroy(); event.preventDefault(); } @@ -327,15 +341,17 @@ export const movePathTo = (paths?: string[], range?: Range, cb?: (toPath: string break; } else if (target.classList.contains("b3-button--text")) { const currentPanelElement = searchListElement.classList.contains("fn__none") ? searchTreeElement : searchListElement; - const currentItemElement: HTMLElement = currentPanelElement.querySelector(".b3-list-item--focus"); - if (!currentItemElement) { + const currentItemElements = currentPanelElement.querySelectorAll(".b3-list-item--focus"); + if (currentItemElements.length === 0) { return; } - if (cb) { - cb(currentItemElement.getAttribute("data-path"), currentItemElement.getAttribute("data-box")); - } else { - moveToPath(paths, currentItemElement.getAttribute("data-box"), currentItemElement.getAttribute("data-path")); - } + const pathList: string[] = [] + const notebookIdList: string[] = [] + currentItemElements.forEach(item => { + pathList.push(item.getAttribute("data-path")) + notebookIdList.push(item.getAttribute("data-box")) + }) + cb(pathList, notebookIdList); dialog.destroy(); event.preventDefault(); event.stopPropagation(); @@ -347,12 +363,20 @@ export const movePathTo = (paths?: string[], range?: Range, cb?: (toPath: string break; } else if (target.classList.contains("b3-list-item")) { const currentPanelElement = searchListElement.classList.contains("fn__none") ? searchTreeElement : searchListElement; - const currentItemElement: HTMLElement = currentPanelElement.querySelector(".b3-list-item--focus"); - if (!currentItemElement) { + const currentItemElements = currentPanelElement.querySelectorAll(".b3-list-item--focus"); + if (currentItemElements.length === 0) { return; } - currentItemElement.classList.remove("b3-list-item--focus"); - target.classList.add("b3-list-item--focus"); + if (title === window.siyuan.languages.specifyPath && (event.ctrlKey || event.metaKey)) { + if (currentItemElements.length === 1 && currentItemElements[0].isSameNode(target)) { + // 至少需选中一个 + } else { + target.classList.toggle("b3-list-item--focus"); + } + } else { + currentItemElements[0].classList.remove("b3-list-item--focus"); + target.classList.add("b3-list-item--focus"); + } event.preventDefault(); event.stopPropagation(); break;