From ced6f0165d8c992b4a6b753751180e58962734ec Mon Sep 17 00:00:00 2001 From: Vanessa Date: Fri, 28 Oct 2022 23:29:07 +0800 Subject: [PATCH] :sparkles: fix https://github.com/siyuan-note/siyuan/issues/4781 --- app/src/block/popover.ts | 273 ++++++++++++++++++--------------- app/src/util/globalShortcut.ts | 4 + 2 files changed, 157 insertions(+), 120 deletions(-) diff --git a/app/src/block/popover.ts b/app/src/block/popover.ts index 73b8a2151..28f23e19b 100644 --- a/app/src/block/popover.ts +++ b/app/src/block/popover.ts @@ -3,6 +3,7 @@ import {hasClosestBlock, hasClosestByAttribute, hasClosestByClassName} from "../ import {fetchSyncPost} from "../util/fetch"; import {hideTooltip, showTooltip} from "../dialog/tooltip"; +let popoverTargetElement: HTMLElement export const initBlockPopover = () => { let timeout: number; let timeoutHide: number; @@ -35,6 +36,17 @@ export const initBlockPopover = () => { hideTooltip(); } + if (window.siyuan.config.editor.floatWindowMode === 1) { + if (!getTarget(event, aElement)) { + hidePopover(event); + return; + } + if (window.siyuan.ctrlIsPressed) { + showPopover() + } + return; + } + clearTimeout(timeout); clearTimeout(timeoutHide); timeoutHide = window.setTimeout(() => { @@ -45,9 +57,9 @@ export const initBlockPopover = () => { ) { // b3-menu 需要处理,(( 后的 hint 上的图表移上去需显示预览 // gutter & mindmap & 文件树上的数字 & 关系图节点不处理 - return; + return false; } - let popoverTargetElement = hasClosestByAttribute(event.target, "data-type", "block-ref") as HTMLElement || + popoverTargetElement = hasClosestByAttribute(event.target, "data-type", "block-ref") as HTMLElement || hasClosestByAttribute(event.target, "data-type", "virtual-block-ref") as HTMLElement; if (popoverTargetElement && popoverTargetElement.classList.contains("b3-tooltips")) { popoverTargetElement = undefined; @@ -60,133 +72,154 @@ export const initBlockPopover = () => { popoverTargetElement = linkElement; } if (!popoverTargetElement) { - const blockElement = hasClosestByClassName(event.target, "block__popover", true); - const maxEditLevels: { [key: string]: number } = {oid: 0}; - window.siyuan.blockPanels.forEach((item) => { - if (item.targetElement && item.element.getAttribute("data-pin") === "true") { - const level = parseInt(item.element.getAttribute("data-level")); - const oid = item.element.getAttribute("data-oid"); - if (maxEditLevels[oid]) { - if (level > maxEditLevels[oid]) { - maxEditLevels[oid] = level; - } - } else { - maxEditLevels[oid] = level; // 不能为1,否则 pin 住第三层,第二层会消失 - } - } - }); - if (blockElement) { - for (let i = 0; i < window.siyuan.blockPanels.length; i++) { - const item = window.siyuan.blockPanels[i]; - if (item.targetElement && - parseInt(item.element.getAttribute("data-level")) > (maxEditLevels[item.element.getAttribute("data-oid")] || 0) && - item.element.getAttribute("data-pin") === "false" && - parseInt(item.element.getAttribute("data-level")) > parseInt(blockElement.getAttribute("data-level"))) { - item.destroy(); - i--; - } - } - } else { - for (let i = 0; i < window.siyuan.blockPanels.length; i++) { - const item = window.siyuan.blockPanels[i]; - if (item.targetElement && item.element.getAttribute("data-pin") === "false" && - parseInt(item.element.getAttribute("data-level")) > (maxEditLevels[item.element.getAttribute("data-oid")] || 0)) { - item.destroy(); - i--; - } - } - } + hidePopover(event) + return; } if (!popoverTargetElement && !aElement) { clearTimeout(timeout); } }, 200); timeout = window.setTimeout(async () => { - if (hasClosestByClassName(event.target, "history__repo", true)) { + if (!getTarget(event, aElement)) { return; } - let popoverTargetElement = hasClosestByAttribute(event.target, "data-type", "block-ref") as HTMLElement || - hasClosestByAttribute(event.target, "data-type", "virtual-block-ref") as HTMLElement; - if (popoverTargetElement && popoverTargetElement.classList.contains("b3-tooltips")) { - popoverTargetElement = undefined; - } - if (!popoverTargetElement) { - popoverTargetElement = hasClosestByClassName(event.target, "popover__block") as HTMLElement; - } - if (!popoverTargetElement && aElement && aElement.getAttribute("data-href")?.startsWith("siyuan://blocks") && aElement.getAttribute("prevent-popover") !== "true") { - popoverTargetElement = aElement; - } - if (!popoverTargetElement || window.siyuan.altIsPressed || window.siyuan.shiftIsPressed || window.siyuan.ctrlIsPressed || - (popoverTargetElement && popoverTargetElement.getAttribute("prevent-popover") === "true")) { - return; - } - // https://github.com/siyuan-note/siyuan/issues/4314 - if (popoverTargetElement && getSelection().rangeCount > 0) { - const range = getSelection().getRangeAt(0); - if (range.toString() !== "" && popoverTargetElement.contains(range.startContainer)) { - return; - } - } clearTimeout(timeoutHide); - let ids: string[]; - let defIds: string[]; - const dataId = popoverTargetElement.getAttribute("data-id"); - if (dataId) { - // backlink/util/hint/正文标题 上的弹层 - if (dataId.startsWith("[")) { - ids = JSON.parse(dataId); - } else { - ids = [dataId]; - } - defIds = JSON.parse(popoverTargetElement.getAttribute("data-defids") || "[]"); - } else if (popoverTargetElement.getAttribute("data-type")?.indexOf("virtual-block-ref") > -1) { - const nodeElement = hasClosestBlock(popoverTargetElement); - if (nodeElement) { - const postResponse = await fetchSyncPost("/api/block/getBlockDefIDsByRefText", { - anchor: popoverTargetElement.textContent, - excludeIDs: [nodeElement.getAttribute("data-node-id")] - }); - ids = postResponse.data; - } - } else if (popoverTargetElement.getAttribute("data-type")?.split(" ").includes("a")) { - // 以思源协议开头的链接 - ids = [popoverTargetElement.getAttribute("data-href").substr(16, 22)]; - } else { - // pdf - let targetId; - let url = "/api/block/getRefIDs"; - if (popoverTargetElement.classList.contains("protyle-attr--refcount")) { - // 编辑器中的引用数 - targetId = popoverTargetElement.parentElement.parentElement.getAttribute("data-node-id"); - } else if (popoverTargetElement.classList.contains("pdf__rect")) { - targetId = popoverTargetElement.getAttribute("data-node-id"); - url = "/api/block/getRefIDsByFileAnnotationID"; - } else if (!targetId) { - // 文件树中的引用数 - targetId = popoverTargetElement.parentElement.getAttribute("data-node-id"); - } - const postResponse = await fetchSyncPost(url, {id: targetId}); - ids = postResponse.data.refIDs; - defIds = postResponse.data.defIDs; - } - - let hasPin = false; - window.siyuan.blockPanels.find((item) => { - if (item.targetElement && item.element.getAttribute("data-pin") === "true" - && JSON.stringify(ids) === JSON.stringify(item.nodeIds)) { - hasPin = true; - return true; - } - }); - if (!hasPin && - popoverTargetElement.parentElement.style.opacity !== "0.1" // 反向面板图标拖拽时不应该弹层 - ) { - window.siyuan.blockPanels.push(new BlockPanel({ - targetElement: popoverTargetElement, - nodeIds: ids, - defIds, - })); - } + showPopover() }, 620); }); }; + +const hidePopover = (event: MouseEvent & { target: HTMLElement }) => { + const blockElement = hasClosestByClassName(event.target, "block__popover", true); + const maxEditLevels: { [key: string]: number } = {oid: 0}; + window.siyuan.blockPanels.forEach((item) => { + if (item.targetElement && item.element.getAttribute("data-pin") === "true") { + const level = parseInt(item.element.getAttribute("data-level")); + const oid = item.element.getAttribute("data-oid"); + if (maxEditLevels[oid]) { + if (level > maxEditLevels[oid]) { + maxEditLevels[oid] = level; + } + } else { + maxEditLevels[oid] = level; // 不能为1,否则 pin 住第三层,第二层会消失 + } + } + }); + if (blockElement) { + for (let i = 0; i < window.siyuan.blockPanels.length; i++) { + const item = window.siyuan.blockPanels[i]; + if (item.targetElement && + parseInt(item.element.getAttribute("data-level")) > (maxEditLevels[item.element.getAttribute("data-oid")] || 0) && + item.element.getAttribute("data-pin") === "false" && + parseInt(item.element.getAttribute("data-level")) > parseInt(blockElement.getAttribute("data-level"))) { + item.destroy(); + i--; + } + } + } else { + for (let i = 0; i < window.siyuan.blockPanels.length; i++) { + const item = window.siyuan.blockPanels[i]; + if (item.targetElement && item.element.getAttribute("data-pin") === "false" && + parseInt(item.element.getAttribute("data-level")) > (maxEditLevels[item.element.getAttribute("data-oid")] || 0)) { + item.destroy(); + i--; + } + } + } +} + +const getTarget = (event: MouseEvent & { target: HTMLElement }, aElement: false | HTMLElement) => { + if (hasClosestByClassName(event.target, "history__repo", true)) { + return false; + } + popoverTargetElement = hasClosestByAttribute(event.target, "data-type", "block-ref") as HTMLElement || + hasClosestByAttribute(event.target, "data-type", "virtual-block-ref") as HTMLElement; + if (popoverTargetElement && popoverTargetElement.classList.contains("b3-tooltips")) { + popoverTargetElement = undefined; + } + if (!popoverTargetElement) { + popoverTargetElement = hasClosestByClassName(event.target, "popover__block") as HTMLElement; + } + if (!popoverTargetElement && aElement && aElement.getAttribute("data-href")?.startsWith("siyuan://blocks") && + aElement.getAttribute("prevent-popover") !== "true") { + popoverTargetElement = aElement; + } + if (!popoverTargetElement || window.siyuan.altIsPressed || window.siyuan.shiftIsPressed || + (window.siyuan.config.editor.floatWindowMode === 0 && window.siyuan.ctrlIsPressed) || + (popoverTargetElement && popoverTargetElement.getAttribute("prevent-popover") === "true")) { + return false; + } + // https://github.com/siyuan-note/siyuan/issues/4314 + if (popoverTargetElement && getSelection().rangeCount > 0) { + const range = getSelection().getRangeAt(0); + if (range.toString() !== "" && popoverTargetElement.contains(range.startContainer)) { + return false; + } + } + return true +} + +export const showPopover = async () => { + if (!popoverTargetElement) { + return; + } + let ids: string[]; + let defIds: string[]; + const dataId = popoverTargetElement.getAttribute("data-id"); + if (dataId) { + // backlink/util/hint/正文标题 上的弹层 + if (dataId.startsWith("[")) { + ids = JSON.parse(dataId); + } else { + ids = [dataId]; + } + defIds = JSON.parse(popoverTargetElement.getAttribute("data-defids") || "[]"); + } else if (popoverTargetElement.getAttribute("data-type")?.indexOf("virtual-block-ref") > -1) { + const nodeElement = hasClosestBlock(popoverTargetElement); + if (nodeElement) { + const postResponse = await fetchSyncPost("/api/block/getBlockDefIDsByRefText", { + anchor: popoverTargetElement.textContent, + excludeIDs: [nodeElement.getAttribute("data-node-id")] + }); + ids = postResponse.data; + } + } else if (popoverTargetElement.getAttribute("data-type")?.split(" ").includes("a")) { + // 以思源协议开头的链接 + ids = [popoverTargetElement.getAttribute("data-href").substr(16, 22)]; + } else { + // pdf + let targetId; + let url = "/api/block/getRefIDs"; + if (popoverTargetElement.classList.contains("protyle-attr--refcount")) { + // 编辑器中的引用数 + targetId = popoverTargetElement.parentElement.parentElement.getAttribute("data-node-id"); + } else if (popoverTargetElement.classList.contains("pdf__rect")) { + targetId = popoverTargetElement.getAttribute("data-node-id"); + url = "/api/block/getRefIDsByFileAnnotationID"; + } else if (!targetId) { + // 文件树中的引用数 + targetId = popoverTargetElement.parentElement.getAttribute("data-node-id"); + } + const postResponse = await fetchSyncPost(url, {id: targetId}); + ids = postResponse.data.refIDs; + defIds = postResponse.data.defIDs; + } + + let hasPin = false; + window.siyuan.blockPanels.find((item) => { + if (item.targetElement && item.element.getAttribute("data-pin") === "true" + && JSON.stringify(ids) === JSON.stringify(item.nodeIds)) { + hasPin = true; + return true; + } + }); + if (!hasPin && + popoverTargetElement.parentElement.style.opacity !== "0.1" // 反向面板图标拖拽时不应该弹层 + ) { + window.siyuan.blockPanels.push(new BlockPanel({ + targetElement: popoverTargetElement, + nodeIds: ids, + defIds, + })); + } +} diff --git a/app/src/util/globalShortcut.ts b/app/src/util/globalShortcut.ts index 3c7ebb8a0..63a2eb2ce 100644 --- a/app/src/util/globalShortcut.ts +++ b/app/src/util/globalShortcut.ts @@ -38,6 +38,7 @@ import {unicode2Emoji} from "../emoji"; import {deleteFile} from "../editor/deleteFile"; import {escapeHtml} from "./escape"; import {syncGuide} from "../sync/syncGuide"; +import {showPopover} from "../block/popover"; const getRightBlock = (element: HTMLElement, x: number, y: number) => { let index = 1; @@ -338,6 +339,9 @@ export const globalShortcut = () => { if (!event.altKey && !event.shiftKey && isCtrl(event)) { if (event.key === "Meta" || event.key === "Control" || event.ctrlKey || event.metaKey) { window.siyuan.ctrlIsPressed = true; + if (window.siyuan.config.editor.floatWindowMode === 1) { + showPopover() + } } else { window.siyuan.ctrlIsPressed = false; }