A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
1import {getAllEditor, getAllModels} from "../../layout/getAll";
2import {isWindow} from "../../util/functions";
3import {hasClosestBlock, hasClosestByClassName, hasClosestByTag} from "../../protyle/util/hasClosest";
4import {getColIndex} from "../../protyle/util/table";
5
6const getRightBlock = (element: HTMLElement, x: number, y: number) => {
7 let index = 1;
8 let nodeElement = element;
9 if (nodeElement && nodeElement.classList.contains("protyle-action")) {
10 return nodeElement;
11 }
12 while (nodeElement && (nodeElement.classList.contains("list") || nodeElement.classList.contains("li"))) {
13 nodeElement = document.elementFromPoint(x + 73 * index, y) as HTMLElement;
14 nodeElement = hasClosestBlock(nodeElement) as HTMLElement;
15 index++;
16 }
17 return nodeElement;
18};
19
20export const windowMouseMove = (event: MouseEvent, mouseIsEnter: boolean) => {
21 if (document.body.classList.contains("body--blur") || document.getElementById("progress")) {
22 // 非激活状态下不执行 https://ld246.com/article/1693474547631
23 return;
24 }
25 // https://github.com/siyuan-note/siyuan/pull/8793
26 const coordinates = window.siyuan.coordinates ?? (window.siyuan.coordinates = {
27 pageX: 0,
28 pageY: 0,
29 clientX: 0,
30 clientY: 0,
31 screenX: 0,
32 screenY: 0,
33 });
34 coordinates.pageX = event.pageX;
35 coordinates.pageY = event.pageY;
36 coordinates.clientX = event.clientX;
37 coordinates.clientY = event.clientY;
38 coordinates.screenX = event.screenX;
39 coordinates.screenY = event.screenY;
40
41 // breadcrumb
42 if (window.siyuan.hideBreadcrumb) {
43 window.siyuan.hideBreadcrumb = false;
44 getAllEditor().forEach(item => {
45 if (item.protyle.breadcrumb?.element.classList.contains("protyle-breadcrumb__bar--hide")) {
46 item.protyle.breadcrumb.element.classList.remove("protyle-breadcrumb__bar--hide");
47 item.protyle.breadcrumb.render(item.protyle, true);
48 }
49 });
50 }
51 const target = event.target as Element;
52 // Dock
53 if (!mouseIsEnter &&
54 event.buttons === 0 && // 鼠标按键被按下时不触发
55 window.siyuan.layout.bottomDock &&
56 !isWindow()) {
57 if (event.clientX < Math.max(document.getElementById("dockLeft").clientWidth + 1, 16)) {
58 if (!window.siyuan.layout.leftDock.pin && window.siyuan.layout.leftDock.layout.element.clientWidth > 0 &&
59 // 隐藏停靠栏会导致点击两侧内容触发浮动面板弹出,因此需减小鼠标范围
60 (window.siyuan.layout.leftDock.element.clientWidth > 0 || (window.siyuan.layout.leftDock.element.clientWidth === 0 && event.clientX < 8))) {
61 if (event.clientY > document.getElementById("toolbar").clientHeight &&
62 event.clientY < window.innerHeight - document.getElementById("status").clientHeight - document.getElementById("dockBottom").clientHeight) {
63 if (!hasClosestByClassName(target, "b3-menu") &&
64 !hasClosestByClassName(target, "protyle-toolbar") &&
65 !hasClosestByClassName(target, "protyle-util") &&
66 !hasClosestByClassName(target, "b3-dialog", true) &&
67 !hasClosestByClassName(target, "layout--float")) {
68 window.siyuan.layout.leftDock.showDock();
69 }
70 } else {
71 window.siyuan.layout.leftDock.hideDock();
72 }
73 }
74 } else if (event.clientX > window.innerWidth - Math.max(document.getElementById("dockRight").clientWidth - 2, 16)) {
75 if (!window.siyuan.layout.rightDock.pin && window.siyuan.layout.rightDock.layout.element.clientWidth > 0 &&
76 (window.siyuan.layout.rightDock.element.clientWidth > 0 || (window.siyuan.layout.rightDock.element.clientWidth === 0 && event.clientX > window.innerWidth - 8))) {
77 if (event.clientY > document.getElementById("toolbar").clientHeight &&
78 event.clientY < window.innerHeight - document.getElementById("status").clientHeight - document.getElementById("dockBottom").clientHeight) {
79 if (!hasClosestByClassName(target, "b3-menu") &&
80 !hasClosestByClassName(target, "layout--float") &&
81 !hasClosestByClassName(target, "protyle-toolbar") &&
82 !hasClosestByClassName(target, "protyle-util") &&
83 !hasClosestByClassName(target, "b3-dialog", true)) {
84 window.siyuan.layout.rightDock.showDock();
85 }
86 } else {
87 window.siyuan.layout.rightDock.hideDock();
88 }
89 }
90 }
91 if (event.clientY > Math.min(window.innerHeight - 10, window.innerHeight - (window.siyuan.config.uiLayout.hideDock ? 0 : document.getElementById("dockBottom").clientHeight) - document.querySelector("#status").clientHeight)) {
92 window.siyuan.layout.bottomDock.showDock();
93 }
94 }
95
96 // gutter
97 const eventPath0 = event.composedPath()[0] as HTMLElement;
98 if (eventPath0 && eventPath0.nodeType !== 3 && eventPath0.classList.contains("protyle-wysiwyg") && eventPath0.style.paddingLeft) {
99 // 光标在编辑器右边也需要进行显示
100 const mouseElement = document.elementFromPoint(eventPath0.getBoundingClientRect().left + parseInt(eventPath0.style.paddingLeft) + 13, event.clientY);
101 const blockElement = hasClosestBlock(mouseElement);
102 if (blockElement) {
103 const targetBlockElement = getRightBlock(blockElement, blockElement.getBoundingClientRect().left + 1, event.clientY);
104 if (!targetBlockElement) {
105 return;
106 }
107 let rowElement: Element;
108 if (targetBlockElement.classList.contains("av")) {
109 rowElement = hasClosestByClassName(mouseElement, "av__row") as HTMLElement;
110 }
111 const allModels = getAllModels();
112 let findNode = false;
113 allModels.editor.find(item => {
114 if (item.editor.protyle.wysiwyg.element === eventPath0) {
115 item.editor.protyle.gutter.render(item.editor.protyle, targetBlockElement, item.editor.protyle.wysiwyg.element, rowElement);
116 findNode = true;
117 return true;
118 }
119 });
120 if (!findNode) {
121 window.siyuan.blockPanels.find(item => {
122 item.editors.find(eItem => {
123 if (eItem.protyle.wysiwyg.element.contains(eventPath0)) {
124 eItem.protyle.gutter.render(eItem.protyle, targetBlockElement, eItem.protyle.wysiwyg.element, rowElement);
125 findNode = true;
126 return true;
127 }
128 });
129 if (findNode) {
130 return true;
131 }
132 });
133 }
134 if (!findNode) {
135 allModels.backlink.find(item => {
136 item.editors.find(eItem => {
137 if (eItem.protyle.wysiwyg.element === eventPath0) {
138 eItem.protyle.gutter.render(eItem.protyle, targetBlockElement, eItem.protyle.wysiwyg.element, rowElement);
139 findNode = true;
140 return true;
141 }
142 });
143 if (findNode) {
144 return true;
145 }
146 });
147 }
148 }
149 return;
150 }
151 if (eventPath0 && eventPath0.nodeType !== 3 && (
152 eventPath0.classList.contains("li") ||
153 eventPath0.classList.contains("list") ||
154 (eventPath0.classList.contains("protyle-action") && eventPath0.getAttribute("data-type") === "NodeListItem")
155 )) {
156 // 光标在列表下部应显示右侧的元素,而不是列表本身
157 const targetBlockElement = getRightBlock(eventPath0, eventPath0.getBoundingClientRect().left + 1, event.clientY);
158 if (!targetBlockElement) {
159 return;
160 }
161 const allModels = getAllModels();
162 let findNode = false;
163 allModels.editor.find(item => {
164 if (item.editor.protyle.wysiwyg.element.contains(eventPath0)) {
165 item.editor.protyle.gutter.render(item.editor.protyle, targetBlockElement, item.editor.protyle.wysiwyg.element);
166 findNode = true;
167 return true;
168 }
169 });
170 if (!findNode) {
171 window.siyuan.blockPanels.find(item => {
172 item.editors.find(eItem => {
173 if (eItem.protyle.wysiwyg.element.contains(eventPath0)) {
174 eItem.protyle.gutter.render(eItem.protyle, targetBlockElement, eItem.protyle.wysiwyg.element);
175 findNode = true;
176 return true;
177 }
178 });
179 if (findNode) {
180 return true;
181 }
182 });
183 }
184 if (!findNode) {
185 allModels.backlink.find(item => {
186 item.editors.find(eItem => {
187 if (eItem.protyle.wysiwyg.element.contains(eventPath0)) {
188 eItem.protyle.gutter.render(eItem.protyle, targetBlockElement, eItem.protyle.wysiwyg.element);
189 findNode = true;
190 return true;
191 }
192 });
193 if (findNode) {
194 return true;
195 }
196 });
197 }
198 return;
199 }
200
201 if (eventPath0 && eventPath0.nodeType !== 3 && eventPath0.classList.contains("av")) {
202 // 数据库居中时光标在数据库侧边 https://github.com/siyuan-note/siyuan/issues/13853
203 if (eventPath0.getAttribute("data-type") === "NodeAttributeView") {
204 const rowElement = hasClosestByClassName(document.elementFromPoint(eventPath0.firstElementChild.getBoundingClientRect().left + 10, event.clientY), "av__row");
205 if (rowElement && !rowElement.classList.contains("av__row--header")) {
206 getAllEditor().find(item => {
207 if (item.protyle.wysiwyg.element.contains(eventPath0)) {
208 item.protyle.gutter.render(item.protyle, eventPath0, item.protyle.wysiwyg.element, rowElement);
209 return true;
210 }
211 });
212 return;
213 }
214 }
215 }
216
217 if (!hasClosestByClassName(target, "protyle", true)) {
218 document.querySelectorAll(".protyle-gutters").forEach(item => {
219 item.classList.add("fn__none");
220 item.innerHTML = "";
221 });
222 }
223
224 const blockElement = hasClosestByClassName(target, "table");
225 if (blockElement && blockElement.style.cursor !== "col-resize" && !hasClosestByClassName(blockElement, "protyle-wysiwyg__embed")) {
226 const cellElement = (hasClosestByTag(target, "TH") || hasClosestByTag(target, "TD")) as HTMLTableCellElement;
227 const tableElement = blockElement.querySelector("table");
228 if (cellElement && tableElement && tableElement.getAttribute("contenteditable") === "true") {
229 const tableHeight = blockElement.querySelector("table").clientHeight;
230 const resizeElement = blockElement.querySelector(".table__resize");
231 if (blockElement.style.textAlign === "center" || blockElement.style.textAlign === "right") {
232 resizeElement.parentElement.style.left = tableElement.offsetLeft + "px";
233 } else {
234 resizeElement.parentElement.style.left = "";
235 }
236 const rect = cellElement.getBoundingClientRect();
237 if (rect.right - event.clientX < 3 && rect.right - event.clientX > 0) {
238 resizeElement.setAttribute("data-col-index", (getColIndex(cellElement) + cellElement.colSpan - 1).toString());
239 resizeElement.setAttribute("style", `height:${tableHeight}px;left: ${Math.round(cellElement.offsetWidth + cellElement.offsetLeft - blockElement.firstElementChild.scrollLeft - 3)}px;display:block`);
240 } else if (event.clientX - rect.left < 3 && event.clientX - rect.left > 0 && cellElement.previousElementSibling) {
241 resizeElement.setAttribute("data-col-index", (getColIndex(cellElement) - 1).toString());
242 resizeElement.setAttribute("style", `height:${tableHeight}px;left: ${Math.round(cellElement.offsetLeft - blockElement.firstElementChild.scrollLeft - 3)}px;display:block`);
243 }
244 }
245 }
246};