diff --git a/app/src/boot/globalEvent/keydown.ts b/app/src/boot/globalEvent/keydown.ts index 6c27c3931..1513be864 100644 --- a/app/src/boot/globalEvent/keydown.ts +++ b/app/src/boot/globalEvent/keydown.ts @@ -72,6 +72,7 @@ import {setReadOnly} from "../../config/util/setReadOnly"; import {copyPNGByLink} from "../../menus/util"; import {globalCommand} from "./command/global"; import {duplicateCompletely} from "../../protyle/render/av/action"; +import {copyTextByType} from "../../protyle/toolbar/util"; const switchDialogEvent = (app: App, event: MouseEvent) => { event.preventDefault(); @@ -487,7 +488,7 @@ const editKeydown = (app: App, event: KeyboardEvent) => { event.preventDefault(); return true; } - if (matchHotKey(window.siyuan.config.keymap.editor.general.copyBlockRef.custom, event)) { + if (!isFileFocus && matchHotKey(window.siyuan.config.keymap.editor.general.copyBlockRef.custom, event)) { event.preventDefault(); event.stopPropagation(); if (hasClosestByClassName(range.startContainer, "protyle-title")) { @@ -592,6 +593,12 @@ const fileTreeKeydown = (app: App, event: KeyboardEvent) => { const notebookId = topULElement.getAttribute("data-url"); const pathString = liElements[0].getAttribute("data-path"); const isFile = liElements[0].getAttribute("data-type") === "navigation-file"; + const ids: string[] = []; + liElements.forEach(item => { + if (item.getAttribute("data-type") === "navigation-file") { + ids.push(item.getAttribute("data-node-id")); + } + }) if (matchHotKey(window.siyuan.config.keymap.editor.general.spaceRepetition.custom, event) && !window.siyuan.config.readonly) { if (isFile) { @@ -604,25 +611,20 @@ const fileTreeKeydown = (app: App, event: KeyboardEvent) => { openCardByData(app, response.data, "notebook", notebookId, getNotebookName(notebookId)); }); } + event.preventDefault(); + return true; } if (matchHotKey(window.siyuan.config.keymap.editor.general.quickMakeCard.custom, event)) { - const blockIDs: string[] = []; - liElements.forEach(item => { - const id = item.getAttribute("data-node-id"); - if (id) { - blockIDs.push(id); - } - }); - if (blockIDs.length > 0) { + if (ids.length > 0) { transaction(undefined, [{ action: "addFlashcards", deckID: Constants.QUICK_DECK_ID, - blockIDs, + blockIDs: ids, }], [{ action: "removeFlashcards", deckID: Constants.QUICK_DECK_ID, - blockIDs, + blockIDs: ids, }]); } event.preventDefault(); @@ -664,12 +666,54 @@ const fileTreeKeydown = (app: App, event: KeyboardEvent) => { return true; } - if (isFile && !event.repeat && matchHotKey(window.siyuan.config.keymap.editor.general.duplicate.custom, event)) { + if (!event.repeat && matchHotKey(window.siyuan.config.keymap.editor.general.duplicate.custom, event)) { event.preventDefault(); event.stopPropagation(); - fetchPost("/api/filetree/duplicateDoc", { - id: liElements[0].getAttribute("data-node-id"), - }); + ids.forEach(item => { + fetchPost("/api/filetree/duplicateDoc", { + id: item, + }); + }) + return true; + } + + if (!event.repeat && matchHotKey(window.siyuan.config.keymap.editor.general.copyBlockRef.custom, event)) { + event.preventDefault(); + event.stopPropagation(); + copyTextByType(ids, "ref"); + return true; + } + + if (!event.repeat && matchHotKey(window.siyuan.config.keymap.editor.general.copyBlockEmbed.custom, event)) { + event.preventDefault(); + event.stopPropagation(); + copyTextByType(ids, "blockEmbed"); + return true; + } + + if (!event.repeat && matchHotKey(window.siyuan.config.keymap.editor.general.copyProtocol.custom, event)) { + event.preventDefault(); + event.stopPropagation(); + copyTextByType(ids, "protocol"); + return true; + } + + if (!event.repeat && matchHotKey(window.siyuan.config.keymap.editor.general.copyProtocolInMd.custom, event)) { + event.preventDefault(); + event.stopPropagation(); + copyTextByType(ids, "protocolMd"); + return true; + } + if (!event.repeat && matchHotKey(window.siyuan.config.keymap.editor.general.copyHPath.custom, event)) { + event.preventDefault(); + event.stopPropagation(); + copyTextByType(ids, "hPath"); + return true; + } + if (!event.repeat && matchHotKey(window.siyuan.config.keymap.editor.general.copyID.custom, event)) { + event.preventDefault(); + event.stopPropagation(); + copyTextByType(ids, "id"); return true; } diff --git a/app/src/menus/commonMenuItem.ts b/app/src/menus/commonMenuItem.ts index 2f59504de..fd1e3ea15 100644 --- a/app/src/menus/commonMenuItem.ts +++ b/app/src/menus/commonMenuItem.ts @@ -22,6 +22,7 @@ import {App} from "../index"; import {renderAVAttribute} from "../protyle/render/av/blockAttr"; import {openAssetNewWindow} from "../window/openNewWindow"; import {escapeHtml} from "../util/escape"; +import {copyTextByType} from "../protyle/toolbar/util"; const bindAttrInput = (inputElement: HTMLInputElement, id: string) => { inputElement.addEventListener("change", () => { @@ -377,21 +378,8 @@ export const copySubMenu = (ids: string[], accelerator = true, focusElement?: El iconHTML: "", accelerator: accelerator ? window.siyuan.config.keymap.editor.general.copyBlockRef.custom : undefined, label: window.siyuan.languages.copyBlockRef, - click: async () => { - let text = ""; - for (let i = 0; i < ids.length; i++) { - const id = ids[i]; - const response = await fetchSyncPost("/api/block/getRefText", {id}); - const content = `((${id} '${response.data}'))`; - if (ids.length > 1) { - text += "* "; - } - text += content; - if (ids.length > 1 && i !== ids.length - 1) { - text += "\n"; - } - } - writeText(text); + click: () => { + copyTextByType(ids, "ref"); if (focusElement) { focusBlock(focusElement); } @@ -402,17 +390,7 @@ export const copySubMenu = (ids: string[], accelerator = true, focusElement?: El label: window.siyuan.languages.copyBlockEmbed, accelerator: accelerator ? window.siyuan.config.keymap.editor.general.copyBlockEmbed.custom : undefined, click: () => { - let text = ""; - ids.forEach((id, index) => { - if (ids.length > 1) { - text += "* "; - } - text += `{{select * from blocks where id='${id}'}}`; - if (ids.length > 1 && index !== ids.length - 1) { - text += "\n"; - } - }); - writeText(text); + copyTextByType(ids, "blockEmbed"); if (focusElement) { focusBlock(focusElement); } @@ -423,17 +401,7 @@ export const copySubMenu = (ids: string[], accelerator = true, focusElement?: El label: window.siyuan.languages.copyProtocol, accelerator: accelerator ? window.siyuan.config.keymap.editor.general.copyProtocol.custom : undefined, click: () => { - let text = ""; - ids.forEach((id, index) => { - if (ids.length > 1) { - text += "* "; - } - text += `siyuan://blocks/${id}`; - if (ids.length > 1 && index !== ids.length - 1) { - text += "\n"; - } - }); - writeText(text); + copyTextByType(ids, "protocol"); if (focusElement) { focusBlock(focusElement); } @@ -443,21 +411,8 @@ export const copySubMenu = (ids: string[], accelerator = true, focusElement?: El iconHTML: "", label: window.siyuan.languages.copyProtocolInMd, accelerator: accelerator ? window.siyuan.config.keymap.editor.general.copyProtocolInMd.custom : undefined, - click: async () => { - let text = ""; - for (let i = 0; i < ids.length; i++) { - const id = ids[i]; - const response = await fetchSyncPost("/api/block/getRefText", {id}); - const content = `[${response.data}](siyuan://blocks/${id})`; - if (ids.length > 1) { - text += "* "; - } - text += content; - if (ids.length > 1 && i !== ids.length - 1) { - text += "\n"; - } - } - writeText(text); + click: () => { + copyTextByType(ids, "protocolMd"); if (focusElement) { focusBlock(focusElement); } @@ -467,21 +422,11 @@ export const copySubMenu = (ids: string[], accelerator = true, focusElement?: El iconHTML: "", label: window.siyuan.languages.copyHPath, accelerator: accelerator ? window.siyuan.config.keymap.editor.general.copyHPath.custom : undefined, - click: async () => { - let text = ""; - for (let i = 0; i < ids.length; i++) { - const id = ids[i]; - const response = await fetchSyncPost("/api/filetree/getHPathByID", {id}); - const content = response.data; - if (ids.length > 1) { - text += "* "; - } - text += content; - if (ids.length > 1 && i !== ids.length - 1) { - text += "\n"; - } + click: () => { + copyTextByType(ids, "hPath"); + if (focusElement) { + focusBlock(focusElement); } - writeText(text); } }, { id: "copyID", @@ -489,17 +434,7 @@ export const copySubMenu = (ids: string[], accelerator = true, focusElement?: El label: window.siyuan.languages.copyID, accelerator: accelerator ? window.siyuan.config.keymap.editor.general.copyID.custom : undefined, click: () => { - let text = ""; - ids.forEach((id, index) => { - if (ids.length > 1) { - text += "* "; - } - text += id; - if (ids.length > 1 && index !== ids.length - 1) { - text += "\n"; - } - }); - writeText(text); + copyTextByType(ids, "id"); if (focusElement) { focusBlock(focusElement); } diff --git a/app/src/menus/index.ts b/app/src/menus/index.ts index e9cd4f89a..6dce9022a 100644 --- a/app/src/menus/index.ts +++ b/app/src/menus/index.ts @@ -1,5 +1,5 @@ /// #if !MOBILE -import {getInstanceById} from "../layout/util"; +import {getInstanceById, setPanelFocus} from "../layout/util"; import {Tab} from "../layout/Tab"; import {initSearchMenu} from "./search"; import {initDockMenu} from "./dock"; @@ -68,6 +68,7 @@ export class Menus { this.unselect(); // navigation 根上:新建文档/文件夹/取消挂在/打开文件位置 initNavigationMenu(app, target).popup({x: event.clientX, y: event.clientY}); + setPanelFocus(hasClosestByClassName(target, "sy__file") as HTMLElement); event.stopPropagation(); break; } else if (dataType === "navigation-file") { @@ -77,6 +78,7 @@ export class Menus { x: event.clientX, y: event.clientY }); + setPanelFocus(hasClosestByClassName(target, "sy__file") as HTMLElement); event.stopPropagation(); break; } else if (dataType === "search-item") { diff --git a/app/src/menus/navigation.ts b/app/src/menus/navigation.ts index 013812fb6..05149c5b0 100644 --- a/app/src/menus/navigation.ts +++ b/app/src/menus/navigation.ts @@ -54,7 +54,19 @@ const initMultiMenu = (selectItemElements: NodeListOf, app: App) => { label: window.siyuan.languages.copy, type: "submenu", icon: "iconCopy", - submenu: copySubMenu(blockIDs, false) + submenu: copySubMenu(blockIDs).concat([{ + id: "duplicate", + iconHTML: "", + label: window.siyuan.languages.duplicate, + accelerator: window.siyuan.config.keymap.editor.general.duplicate.custom, + click() { + blockIDs.forEach((id) => { + fetchPost("/api/filetree/duplicateDoc", { + id + }); + }); + } + }]) }).element); } @@ -481,7 +493,7 @@ export const initFileMenu = (app: App, notebookId: string, pathString: string, l label: window.siyuan.languages.copy, type: "submenu", icon: "iconCopy", - submenu: (copySubMenu([id], false) as IMenu[]).concat([{ + submenu: (copySubMenu([id]) as IMenu[]).concat([{ id: "duplicate", iconHTML: "", label: window.siyuan.languages.duplicate, diff --git a/app/src/protyle/toolbar/util.ts b/app/src/protyle/toolbar/util.ts index 840b85f08..536144a54 100644 --- a/app/src/protyle/toolbar/util.ts +++ b/app/src/protyle/toolbar/util.ts @@ -1,6 +1,7 @@ -import {fetchPost} from "../../util/fetch"; +import {fetchPost, fetchSyncPost} from "../../util/fetch"; import {Constants} from "../../constants"; import {focusByRange, focusByWbr} from "../util/selection"; +import {writeText} from "../util/compatibility"; export const previewTemplate = (pathString: string, element: Element, parentId: string) => { if (!pathString) { @@ -213,3 +214,34 @@ export const toolbarKeyToMenu = (toolbar: Array) => { }); return toolbarResult; }; + +export const copyTextByType = async (ids: string[], + type: "ref" | "blockEmbed" | "protocol" | "protocolMd" | "hPath" | "id") => { + let text = ""; + for (let i = 0; i < ids.length; i++) { + const id = ids[i]; + if (ids.length > 1) { + text += "* "; + } + if (type === "ref") { + const response = await fetchSyncPost("/api/block/getRefText", {id}); + text += `((${id} '${response.data}'))`; + } else if (type === "blockEmbed") { + text += `{{select * from blocks where id='${id}'}}`; + } else if (type === "protocol") { + text += `siyuan://blocks/${id}`; + } else if (type === "protocolMd") { + const response = await fetchSyncPost("/api/block/getRefText", {id}); + text += `[${response.data}](siyuan://blocks/${id})`; + } else if (type === "hPath") { + const response = await fetchSyncPost("/api/filetree/getHPathByID", {id}); + text += response.data; + } else if (type === "id") { + text += id; + } + if (ids.length > 1 && i !== ids.length - 1) { + text += "\n"; + } + } + writeText(text); +}