A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
1/// #if !MOBILE
2import {getInstanceById, setPanelFocus} from "../layout/util";
3import {Tab} from "../layout/Tab";
4import {initSearchMenu} from "./search";
5import {initDockMenu} from "./dock";
6import {initFileMenu, initNavigationMenu} from "./navigation";
7import {initTabMenu} from "./tab";
8/// #endif
9/// #if !BROWSER
10import {ipcRenderer} from "electron";
11/// #endif
12import {Menu} from "./Menu";
13import {hasClosestByClassName, hasTopClosestByTag} from "../protyle/util/hasClosest";
14import {App} from "../index";
15import {Constants} from "../constants";
16import {textMenu} from "./text";
17import {hideTooltip} from "../dialog/tooltip";
18
19export class Menus {
20 public menu: Menu;
21
22 constructor(app: App) {
23 this.menu = new Menu();
24 /// #if !MOBILE
25 window.addEventListener("contextmenu", (event) => {
26 if (event.shiftKey) {
27 return;
28 }
29 let target = event.target as HTMLElement;
30 if (hasClosestByClassName(target, "av__panel") && !hasClosestByClassName(target, "b3-menu")) {
31 document.querySelector(".av__panel").dispatchEvent(new CustomEvent("click", {detail: "close"}));
32 event.stopPropagation();
33 event.preventDefault();
34 return;
35 }
36 if (target.classList.contains("b3-text-field") || (target.tagName === "INPUT" && (target as HTMLInputElement).type === "text")) {
37 /// #if !BROWSER
38 ipcRenderer.send(Constants.SIYUAN_CONTEXT_MENU, {
39 undo: window.siyuan.languages.undo,
40 redo: window.siyuan.languages.redo,
41 copy: window.siyuan.languages.copy,
42 cut: window.siyuan.languages.cut,
43 delete: window.siyuan.languages.delete,
44 paste: window.siyuan.languages.paste,
45 pasteAsPlainText: window.siyuan.languages.pasteAsPlainText,
46 selectAll: window.siyuan.languages.selectAll,
47 });
48 /// #endif
49 event.stopPropagation();
50 } else {
51 event.preventDefault();
52 }
53 while (target && target.parentElement // ⌃⇥ 后点击会为空
54 && !target.parentElement.isEqualNode(document.querySelector("body"))) {
55 const dataType = target.getAttribute("data-type");
56 if (dataType === "tab-header") {
57 this.unselect();
58 initTabMenu(app, (getInstanceById(target.getAttribute("data-id")) as Tab)).popup({
59 x: event.clientX,
60 y: event.clientY
61 });
62 event.stopPropagation();
63 break;
64 } else if (dataType === "navigation-root" && !window.siyuan.config.readonly) {
65 if (target.querySelector(".b3-list-item__text").classList.contains("ft__on-surface")) {
66 return;
67 }
68 this.unselect();
69 // navigation 根上:新建文档/文件夹/取消挂在/打开文件位置
70 initNavigationMenu(app, target).popup({x: event.clientX, y: event.clientY});
71 setPanelFocus(hasClosestByClassName(target, "sy__file") as HTMLElement);
72 event.stopPropagation();
73 break;
74 } else if (dataType === "navigation-file") {
75 this.unselect();
76 // navigation 文件上:删除/重命名/打开文件位置/导出
77 initFileMenu(app, this.getDir(target), target.getAttribute("data-path"), target).popup({
78 x: event.clientX,
79 y: event.clientY
80 });
81 setPanelFocus(hasClosestByClassName(target, "sy__file") as HTMLElement);
82 event.stopPropagation();
83 break;
84 } else if (dataType === "search-item") {
85 const nodeId = target.getAttribute("data-node-id");
86 if (nodeId) {
87 initSearchMenu(nodeId).popup({x: event.clientX, y: event.clientY});
88 }
89 event.stopPropagation();
90 break;
91 } else if (dataType && target.classList.contains("dock__item")) {
92 hideTooltip();
93 initDockMenu(target).popup({x: event.clientX, y: event.clientY});
94 event.stopPropagation();
95 break;
96 } else if (dataType === "textMenu") {
97 /// #if !BROWSER
98 textMenu(target).open({x: event.clientX, y: event.clientY});
99 event.stopPropagation();
100 event.preventDefault();
101 break;
102 /// #endif
103 }
104
105 target = target.parentElement;
106 }
107 }, false);
108 /// #endif
109 }
110
111 private getDir(target: HTMLElement) {
112 const rootElement = hasTopClosestByTag(target, "UL");
113 if (rootElement) {
114 return rootElement.getAttribute("data-url");
115 }
116 }
117
118 private unselect() {
119 if (getSelection().rangeCount > 0) {
120 getSelection().getRangeAt(0).collapse(true);
121 }
122 }
123}