2022-05-26 15:18:53 +08:00
|
|
|
|
import {BlockPanel} from "./Panel";
|
|
|
|
|
|
import {hasClosestBlock, hasClosestByAttribute, hasClosestByClassName} from "../protyle/util/hasClosest";
|
|
|
|
|
|
import {fetchSyncPost} from "../util/fetch";
|
|
|
|
|
|
import {hideTooltip, showTooltip} from "../dialog/tooltip";
|
2023-04-19 11:27:32 +08:00
|
|
|
|
import {getIdFromSYProtocol} from "../util/pathName";
|
2022-05-26 15:18:53 +08:00
|
|
|
|
|
2022-10-30 00:16:48 +08:00
|
|
|
|
let popoverTargetElement: HTMLElement;
|
2022-05-26 15:18:53 +08:00
|
|
|
|
export const initBlockPopover = () => {
|
|
|
|
|
|
let timeout: number;
|
|
|
|
|
|
let timeoutHide: number;
|
|
|
|
|
|
// 编辑器内容块引用/backlinks/tag/bookmark/套娃中使用
|
2023-01-15 23:16:48 +08:00
|
|
|
|
document.addEventListener("mouseover", (event: MouseEvent & { target: HTMLElement, path: HTMLElement[] }) => {
|
2022-10-29 21:58:09 +08:00
|
|
|
|
if (!window.siyuan.config) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2022-08-31 01:14:45 +08:00
|
|
|
|
const aElement = hasClosestByAttribute(event.target, "data-type", "a", true) ||
|
2022-05-26 15:18:53 +08:00
|
|
|
|
hasClosestByAttribute(event.target, "data-type", "tab-header") ||
|
|
|
|
|
|
hasClosestByClassName(event.target, "emojis__item") ||
|
2022-09-17 23:14:02 +08:00
|
|
|
|
hasClosestByClassName(event.target, "emojis__type") ||
|
|
|
|
|
|
hasClosestByAttribute(event.target, "data-type", "inline-memo");
|
2022-05-26 15:18:53 +08:00
|
|
|
|
if (aElement) {
|
2022-09-17 23:14:02 +08:00
|
|
|
|
let tip = aElement.getAttribute("aria-label") || aElement.getAttribute("data-inline-memo-content");
|
2022-05-26 15:18:53 +08:00
|
|
|
|
// 折叠块标文案替换
|
|
|
|
|
|
if (hasClosestByAttribute(event.target, "data-type", "fold", true)) {
|
|
|
|
|
|
tip = window.siyuan.languages.fold;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!tip) {
|
|
|
|
|
|
tip = aElement.getAttribute("data-href");
|
|
|
|
|
|
const title = aElement.getAttribute("data-title");
|
|
|
|
|
|
if (title) {
|
2022-10-09 22:22:33 +08:00
|
|
|
|
tip += "<br>" + title;
|
2022-05-26 15:18:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-09-15 11:57:33 +08:00
|
|
|
|
if (tip && !tip.startsWith("siyuan://blocks") && !aElement.classList.contains("b3-tooltips")) {
|
2022-05-26 15:18:53 +08:00
|
|
|
|
showTooltip(tip, aElement);
|
|
|
|
|
|
event.stopPropagation();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if (!aElement) {
|
|
|
|
|
|
hideTooltip();
|
|
|
|
|
|
}
|
2022-10-28 23:29:07 +08:00
|
|
|
|
if (window.siyuan.config.editor.floatWindowMode === 1) {
|
2022-10-29 00:10:08 +08:00
|
|
|
|
clearTimeout(timeoutHide);
|
|
|
|
|
|
timeoutHide = window.setTimeout(() => {
|
2022-10-30 00:16:48 +08:00
|
|
|
|
hidePopover(event);
|
2022-10-29 00:10:08 +08:00
|
|
|
|
}, 200);
|
|
|
|
|
|
|
2022-10-28 23:29:07 +08:00
|
|
|
|
if (!getTarget(event, aElement)) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (window.siyuan.ctrlIsPressed) {
|
2022-10-29 00:10:08 +08:00
|
|
|
|
clearTimeout(timeoutHide);
|
2022-10-30 00:16:48 +08:00
|
|
|
|
showPopover();
|
2022-10-28 23:29:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-05-26 15:18:53 +08:00
|
|
|
|
clearTimeout(timeout);
|
|
|
|
|
|
clearTimeout(timeoutHide);
|
|
|
|
|
|
timeoutHide = window.setTimeout(() => {
|
2022-10-29 00:10:08 +08:00
|
|
|
|
if (!hidePopover(event)) {
|
2022-10-28 23:29:07 +08:00
|
|
|
|
return;
|
2022-05-26 15:18:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
if (!popoverTargetElement && !aElement) {
|
|
|
|
|
|
clearTimeout(timeout);
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 200);
|
|
|
|
|
|
timeout = window.setTimeout(async () => {
|
2022-10-28 23:29:07 +08:00
|
|
|
|
if (!getTarget(event, aElement)) {
|
2022-05-26 15:18:53 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
clearTimeout(timeoutHide);
|
2022-10-30 00:16:48 +08:00
|
|
|
|
showPopover();
|
2022-10-28 23:29:07 +08:00
|
|
|
|
}, 620);
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2023-01-15 23:16:48 +08:00
|
|
|
|
const hidePopover = (event: MouseEvent & { target: HTMLElement, path: HTMLElement[] }) => {
|
2022-10-29 00:10:08 +08:00
|
|
|
|
if (hasClosestByClassName(event.target, "b3-menu") ||
|
|
|
|
|
|
(event.target.id && event.target.tagName !== "svg" && (event.target.id.startsWith("minder_node") || event.target.id.startsWith("kity_") || event.target.id.startsWith("node_")))
|
|
|
|
|
|
|| event.target.classList.contains("counter")
|
|
|
|
|
|
|| event.target.tagName === "circle"
|
|
|
|
|
|
) {
|
|
|
|
|
|
// b3-menu 需要处理,(( 后的 hint 上的图表移上去需显示预览
|
|
|
|
|
|
// gutter & mindmap & 文件树上的数字 & 关系图节点不处理
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
const linkElement = hasClosestByAttribute(event.target, "data-type", "a", true);
|
|
|
|
|
|
if (!popoverTargetElement && linkElement && linkElement.getAttribute("data-href")?.startsWith("siyuan://blocks")) {
|
|
|
|
|
|
popoverTargetElement = linkElement;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!popoverTargetElement) {
|
2023-01-15 23:16:48 +08:00
|
|
|
|
// 移动到弹窗的 loading 元素上,但经过 settimeout 后 loading 已经被移除了
|
|
|
|
|
|
// https://ld246.com/article/1673596577519/comment/1673767749885#comments
|
2023-01-16 00:00:53 +08:00
|
|
|
|
let targetElement = event.target;
|
2023-02-11 12:33:09 +08:00
|
|
|
|
if (!targetElement.parentElement && event.path && event.path[1]) {
|
2023-01-16 00:00:53 +08:00
|
|
|
|
targetElement = event.path[1];
|
2023-01-15 23:16:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
const blockElement = hasClosestByClassName(targetElement, "block__popover", true);
|
2022-10-29 00:10:08 +08:00
|
|
|
|
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 住第三层,第二层会消失
|
2022-05-26 15:18:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-10-29 00:10:08 +08:00
|
|
|
|
});
|
|
|
|
|
|
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--;
|
|
|
|
|
|
}
|
2022-10-28 23:29:07 +08:00
|
|
|
|
}
|
2022-10-29 00:10:08 +08:00
|
|
|
|
} 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--;
|
|
|
|
|
|
}
|
2022-10-28 23:29:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-10-30 00:16:48 +08:00
|
|
|
|
};
|
2022-05-26 15:18:53 +08:00
|
|
|
|
|
2022-10-28 23:29:07 +08:00
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-10-30 00:16:48 +08:00
|
|
|
|
return true;
|
|
|
|
|
|
};
|
2022-10-28 23:29:07 +08:00
|
|
|
|
|
|
|
|
|
|
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")]
|
2022-05-26 15:18:53 +08:00
|
|
|
|
});
|
2022-10-28 23:29:07 +08:00
|
|
|
|
ids = postResponse.data;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if (popoverTargetElement.getAttribute("data-type")?.split(" ").includes("a")) {
|
|
|
|
|
|
// 以思源协议开头的链接
|
2023-04-19 11:27:32 +08:00
|
|
|
|
ids = [getIdFromSYProtocol(popoverTargetElement.getAttribute("data-href"))];
|
2022-10-28 23:29:07 +08:00
|
|
|
|
} 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;
|
|
|
|
|
|
}
|
2022-05-26 15:18:53 +08:00
|
|
|
|
});
|
2023-02-08 14:58:53 +08:00
|
|
|
|
if (!hasPin && popoverTargetElement.parentElement &&
|
2022-10-28 23:29:07 +08:00
|
|
|
|
popoverTargetElement.parentElement.style.opacity !== "0.1" // 反向面板图标拖拽时不应该弹层
|
|
|
|
|
|
) {
|
|
|
|
|
|
window.siyuan.blockPanels.push(new BlockPanel({
|
|
|
|
|
|
targetElement: popoverTargetElement,
|
|
|
|
|
|
nodeIds: ids,
|
|
|
|
|
|
defIds,
|
|
|
|
|
|
}));
|
|
|
|
|
|
}
|
2022-10-29 00:10:08 +08:00
|
|
|
|
popoverTargetElement = undefined;
|
2022-10-30 00:16:48 +08:00
|
|
|
|
};
|