diff --git a/app/src/layout/dock/Graph.ts b/app/src/layout/dock/Graph.ts index 10c596937..708ee3ce3 100644 --- a/app/src/layout/dock/Graph.ts +++ b/app/src/layout/dock/Graph.ts @@ -464,7 +464,9 @@ export class Graph extends Model { if (id) { this.blockId = id; } - if (!isCurrentEditor(this.blockId)) { + if (!isCurrentEditor(this.blockId) && + this.graphElement.firstElementChild.classList.contains("fn__none") // 引用右键打开关系图 + ) { return; } this.graphData = response.data; diff --git a/app/src/layout/dock/util.ts b/app/src/layout/dock/util.ts index 4cb2bfc31..e809b273c 100644 --- a/app/src/layout/dock/util.ts +++ b/app/src/layout/dock/util.ts @@ -2,12 +2,21 @@ import {getAllModels} from "../getAll"; import {Tab} from "../Tab"; import {Graph} from "./Graph"; import {Outline} from "./Outline"; -import {resizeTabs, switchWnd} from "../util"; +import {getInstanceById, getWndByLayout, resizeTabs, switchWnd} from "../util"; import {Backlink} from "./Backlink"; +import {App} from "../../index"; +import {Wnd} from "../Wnd"; +import {fetchSyncPost} from "../../util/fetch"; -export const openBacklink = (protyle: IProtyle) => { +export const openBacklink = async (options: { + app: App, + blockId: string, + rootId?: string, + title?: string, + useBlockId?: boolean, +}) => { const backlink = getAllModels().backlink.find(item => { - if (item.blockId === protyle.block.id && item.type === "local") { + if (item.blockId === options.blockId && item.type === "local") { item.parent.parent.removeTab(item.parent.id); return true; } @@ -15,27 +24,49 @@ export const openBacklink = (protyle: IProtyle) => { if (backlink) { return; } - const newWnd = protyle.model.parent.parent.split("lr"); - const tab = new Tab({ + let wnd: Wnd = undefined; + const element = document.querySelector(".layout__wnd--active"); + if (element) { + wnd = getInstanceById(element.getAttribute("data-id")) as Wnd; + } + if (!wnd) { + wnd = getWndByLayout(window.siyuan.layout.centerLayout); + } + const newWnd = wnd.split("lr"); + if (!options.rootId) { + const response = await fetchSyncPost("api/block/getDocInfo", {id: options.blockId}); + options.rootId = response.data.rootID + options.useBlockId = response.data.rootID !== response.data.id + options.title = response.data.name || "Untitled" + } else if (!options.title) { + const response = await fetchSyncPost("api/block/getDocInfo", {id: options.blockId}); + options.title = response.data.name || "Untitled" + } + newWnd.addTab(new Tab({ icon: "iconLink", - title: protyle.title.editElement.textContent || "Untitled", + title: options.title, callback(tab: Tab) { tab.addModel(new Backlink({ - app: protyle.app, + app: options.app, type: "local", tab, // 通过搜索打开的包含上下文,但不是缩放,因此需要传 rootID https://ld246.com/article/1666786639708 - blockId: protyle.block.showAll ? protyle.block.id : protyle.block.rootID, - rootId: protyle.block.rootID, + blockId: options.useBlockId ? options.blockId : options.rootId, + rootId: options.rootId, })); } - }); - newWnd.addTab(tab); + })); }; -export const openGraph = (protyle: IProtyle) => { +export const openGraph = async (options: { + app: App, + blockId: string, + rootId?: string, + title?: string, + useBlockId?: boolean, +}) => { const graph = getAllModels().graph.find(item => { - if (item.blockId === protyle.block.id && item.type === "local") { + if (item.blockId === options.blockId && item.type === "local") { item.parent.parent.removeTab(item.parent.id); return true; } @@ -43,24 +74,40 @@ export const openGraph = (protyle: IProtyle) => { if (graph) { return; } - const wnd = protyle.model.parent.parent.split("lr"); - const tab = new Tab({ + let wnd: Wnd = undefined; + const element = document.querySelector(".layout__wnd--active"); + if (element) { + wnd = getInstanceById(element.getAttribute("data-id")) as Wnd; + } + if (!wnd) { + wnd = getWndByLayout(window.siyuan.layout.centerLayout); + } + const newWnd = wnd.split("lr"); + if (!options.rootId) { + const response = await fetchSyncPost("api/block/getDocInfo", {id: options.blockId}); + options.rootId = response.data.rootID + options.useBlockId = response.data.rootID !== response.data.id + options.title = response.data.name || "Untitled" + } else if (!options.title) { + const response = await fetchSyncPost("api/block/getDocInfo", {id: options.blockId}); + options.title = response.data.name || "Untitled" + } + newWnd.addTab(new Tab({ icon: "iconGraph", - title: protyle.title.editElement.textContent || "Untitled", + title: options.title, callback(tab: Tab) { tab.addModel(new Graph({ - app: protyle.app, + app: options.app, type: "local", tab, - blockId: protyle.block.id, - rootId: protyle.block.rootID, + blockId: options.blockId, + rootId: options.rootId, })); } - }); - wnd.addTab(tab); + })); }; -export const openOutline = (protyle: IProtyle) => { +export const openOutline = async (protyle: IProtyle) => { const outlinePanel = getAllModels().outline.find(item => { if (item.blockId === protyle.block.rootID && item.type === "local") { item.parent.parent.removeTab(item.parent.id); @@ -70,10 +117,25 @@ export const openOutline = (protyle: IProtyle) => { if (outlinePanel) { return; } - const newWnd = protyle.model.parent.parent.split("lr"); - const tab = new Tab({ + let wnd: Wnd = undefined; + const element = document.querySelector(".layout__wnd--active"); + if (element) { + wnd = getInstanceById(element.getAttribute("data-id")) as Wnd; + } + if (!wnd) { + wnd = getWndByLayout(window.siyuan.layout.centerLayout); + } + const newWnd = wnd.split("lr"); + let title = "" + if (!protyle.title) { + const response = await fetchSyncPost("api/block/getDocInfo", {id: protyle.block.rootID}); + title = response.data.name || "Untitled" + } else { + title = protyle.title.editElement.textContent || "Untitled" + } + newWnd.addTab(new Tab({ icon: "iconAlignCenter", - title: protyle.title.editElement.textContent || "Untitled", + title, callback(tab: Tab) { tab.addModel(new Outline({ app: protyle.app, @@ -83,11 +145,10 @@ export const openOutline = (protyle: IProtyle) => { isPreview: !protyle.preview.element.classList.contains("fn__none") })); } - }); - newWnd.addTab(tab); + })); newWnd.element.classList.remove("fn__flex-1"); newWnd.element.style.width = "200px"; - switchWnd(newWnd, protyle.model.parent.parent); + switchWnd(newWnd, wnd); }; export const resetFloatDockSize = () => { @@ -102,7 +163,7 @@ export const resetFloatDockSize = () => { } }; -export const toggleDockBar = (useElement:Element)=> { +export const toggleDockBar = (useElement: Element) => { const dockIsShow = useElement.getAttribute("xlink:href") === "#iconHideDock"; if (dockIsShow) { useElement.setAttribute("xlink:href", "#iconDock"); diff --git a/app/src/menus/protyle.ts b/app/src/menus/protyle.ts index bbd82b0a9..993340738 100644 --- a/app/src/menus/protyle.ts +++ b/app/src/menus/protyle.ts @@ -44,6 +44,7 @@ import {renameTag} from "../util/noRelyPCFunction"; import {hideElements} from "../protyle/ui/hideElements"; import {emitOpenMenu} from "../plugin/EventBus"; import {openMobileFileById} from "../mobile/editor"; +import {openBacklink, openGraph} from "../layout/dock/util"; export const fileAnnotationRefMenu = (protyle: IProtyle, refElement: HTMLElement) => { const nodeElement = hasClosestBlock(refElement); @@ -255,6 +256,30 @@ export const refMenu = (protyle: IProtyle, element: HTMLElement) => { } }).element); /// #endif + window.siyuan.menus.menu.append(new MenuItem({type: "separator"}).element); + window.siyuan.menus.menu.append(new MenuItem({ + icon: "iconLink", + label: window.siyuan.languages.backlinks, + accelerator: window.siyuan.config.keymap.editor.general.backlinks.custom, + click: () => { + openBacklink({ + app: protyle.app, + blockId: refBlockId, + }); + } + }).element); + window.siyuan.menus.menu.append(new MenuItem({ + icon: "iconGraph", + label: window.siyuan.languages.graphView, + accelerator: window.siyuan.config.keymap.editor.general.graphView.custom, + click: () => { + openGraph({ + app: protyle.app, + blockId: refBlockId, + }); + } + }).element); + window.siyuan.menus.menu.append(new MenuItem({type: "separator"}).element); /// #endif let submenu: IMenu[] = []; if (element.getAttribute("data-subtype") === "s") { diff --git a/app/src/protyle/header/openTitleMenu.ts b/app/src/protyle/header/openTitleMenu.ts index 395fd123f..20509926d 100644 --- a/app/src/protyle/header/openTitleMenu.ts +++ b/app/src/protyle/header/openTitleMenu.ts @@ -57,33 +57,43 @@ export const openTitleMenu = (protyle: IProtyle, position: IPosition) => { }).element); } /// #if !MOBILE - if (protyle.model) { - window.siyuan.menus.menu.append(new MenuItem({type: "separator"}).element); - window.siyuan.menus.menu.append(new MenuItem({ - icon: "iconAlignCenter", - label: window.siyuan.languages.outline, - accelerator: window.siyuan.config.keymap.editor.general.outline.custom, - click: () => { - openOutline(protyle); - } - }).element); - window.siyuan.menus.menu.append(new MenuItem({ - icon: "iconLink", - label: window.siyuan.languages.backlinks, - accelerator: window.siyuan.config.keymap.editor.general.backlinks.custom, - click: () => { - openBacklink(protyle); - } - }).element); - window.siyuan.menus.menu.append(new MenuItem({ - icon: "iconGraph", - label: window.siyuan.languages.graphView, - accelerator: window.siyuan.config.keymap.editor.general.graphView.custom, - click: () => { - openGraph(protyle); - } - }).element); - } + window.siyuan.menus.menu.append(new MenuItem({type: "separator"}).element); + window.siyuan.menus.menu.append(new MenuItem({ + icon: "iconAlignCenter", + label: window.siyuan.languages.outline, + accelerator: window.siyuan.config.keymap.editor.general.outline.custom, + click: () => { + openOutline(protyle); + } + }).element); + window.siyuan.menus.menu.append(new MenuItem({ + icon: "iconLink", + label: window.siyuan.languages.backlinks, + accelerator: window.siyuan.config.keymap.editor.general.backlinks.custom, + click: () => { + openBacklink({ + app: protyle.app, + blockId: protyle.block.id, + rootId: protyle.block.rootID, + useBlockId: protyle.block.showAll, + title: protyle.title ? (protyle.title.editElement.textContent || "Untitled") : null + }); + } + }).element); + window.siyuan.menus.menu.append(new MenuItem({ + icon: "iconGraph", + label: window.siyuan.languages.graphView, + accelerator: window.siyuan.config.keymap.editor.general.graphView.custom, + click: () => { + openGraph({ + app: protyle.app, + blockId: protyle.block.id, + rootId: protyle.block.rootID, + useBlockId: protyle.block.showAll, + title: protyle.title ? (protyle.title.editElement.textContent || "Untitled") : null + }); + } + }).element); /// #endif window.siyuan.menus.menu.append(new MenuItem({type: "separator"}).element); window.siyuan.menus.menu.append(new MenuItem({ @@ -209,7 +219,12 @@ export const openTitleMenu = (protyle: IProtyle, position: IPosition) => { label: window.siyuan.languages.fileHistory, icon: "iconHistory", click() { - openDocHistory({app: protyle.app, id: protyle.block.rootID, notebookId: protyle.notebookId, pathString: response.data.name}); + openDocHistory({ + app: protyle.app, + id: protyle.block.rootID, + notebookId: protyle.notebookId, + pathString: response.data.name + }); } }).element); } diff --git a/app/src/protyle/wysiwyg/commonHotkey.ts b/app/src/protyle/wysiwyg/commonHotkey.ts index aa613d1cf..886c693b5 100644 --- a/app/src/protyle/wysiwyg/commonHotkey.ts +++ b/app/src/protyle/wysiwyg/commonHotkey.ts @@ -12,7 +12,7 @@ import {netImg2LocalAssets} from "../breadcrumb/action"; import {openBacklink, openGraph, openOutline} from "../../layout/dock/util"; /// #endif import {getContenteditableElement, hasNextSibling, hasPreviousSibling} from "./getBlock"; -import {hasClosestByMatchTag} from "../util/hasClosest"; +import {hasClosestByAttribute, hasClosestByMatchTag} from "../util/hasClosest"; import {hideElements} from "../ui/hideElements"; import {countBlockWord} from "../../layout/status"; import {scrollCenter} from "../../util/highlightById"; @@ -21,7 +21,7 @@ import {onGet} from "../util/onGet"; import {Constants} from "../../constants"; import * as dayjs from "dayjs"; -export const commonHotkey = (protyle: IProtyle, event: KeyboardEvent, nodeElement?: HTMLElement) => { +export const commonHotkey = (protyle: IProtyle, event: KeyboardEvent, nodeElement?: HTMLElement, range?: Range) => { const target = event.target as HTMLElement; if (matchHotKey(window.siyuan.config.keymap.editor.general.copyHPath.custom, event)) { fetchPost("/api/filetree/getHPathByID", { @@ -66,28 +66,58 @@ export const commonHotkey = (protyle: IProtyle, event: KeyboardEvent, nodeElemen return true; } /// #if !MOBILE - if (protyle.model) { - if (matchHotKey(window.siyuan.config.keymap.editor.general.backlinks.custom, event)) { - event.preventDefault(); - event.stopPropagation(); - openBacklink(protyle); - return true; + if (matchHotKey(window.siyuan.config.keymap.editor.general.backlinks.custom, event)) { + event.preventDefault(); + event.stopPropagation(); + if (range) { + const refElement = hasClosestByAttribute(range.startContainer, "data-type", "block-ref"); + if (refElement) { + openBacklink({ + app: protyle.app, + blockId: refElement.dataset.id, + }); + return true; + } } - if (matchHotKey(window.siyuan.config.keymap.editor.general.graphView.custom, event)) { - event.preventDefault(); - event.stopPropagation(); - openGraph(protyle); - return true; - } - if (matchHotKey(window.siyuan.config.keymap.editor.general.outline.custom, event)) { - event.preventDefault(); - event.stopPropagation(); - const offset = getSelectionOffset(target); - openOutline(protyle); - // switchWnd 后,range会被清空,需要重新设置 - focusByOffset(target, offset.start, offset.end); - return true; + openBacklink({ + app: protyle.app, + blockId: protyle.block.id, + rootId: protyle.block.rootID, + useBlockId: protyle.block.showAll, + title: protyle.title ? (protyle.title.editElement.textContent || "Untitled") : null, + }); + return true; + } + if (matchHotKey(window.siyuan.config.keymap.editor.general.graphView.custom, event)) { + event.preventDefault(); + event.stopPropagation(); + if (range) { + const refElement = hasClosestByAttribute(range.startContainer, "data-type", "block-ref"); + if (refElement) { + openGraph({ + app: protyle.app, + blockId: refElement.dataset.id, + }); + return true; + } } + openGraph({ + app: protyle.app, + blockId: protyle.block.id, + rootId: protyle.block.rootID, + useBlockId: protyle.block.showAll, + title: protyle.title ? (protyle.title.editElement.textContent || "Untitled") : null, + }); + return true; + } + if (matchHotKey(window.siyuan.config.keymap.editor.general.outline.custom, event)) { + event.preventDefault(); + event.stopPropagation(); + const offset = getSelectionOffset(target); + openOutline(protyle); + // switchWnd 后,range会被清空,需要重新设置 + focusByOffset(target, offset.start, offset.end); + return true; } let matchCommand = false; diff --git a/app/src/protyle/wysiwyg/keydown.ts b/app/src/protyle/wysiwyg/keydown.ts index ba5cbe92a..6a052db01 100644 --- a/app/src/protyle/wysiwyg/keydown.ts +++ b/app/src/protyle/wysiwyg/keydown.ts @@ -983,7 +983,7 @@ export const keydown = (protyle: IProtyle, editorElement: HTMLElement) => { return true; } /// #if !MOBILE - if (commonHotkey(protyle, event, nodeElement)) { + if (commonHotkey(protyle, event, nodeElement, range)) { return true; } /// #endif