A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
1import {matchHotKey} from "../../util/hotKey";
2import {deleteRow, insertRows, selectRow} from "./row";
3import {addDragFill, cellScrollIntoView, popTextCell, updateCellsValue} from "./cell";
4import {avContextmenu} from "./action";
5import {hasClosestByClassName} from "../../util/hasClosest";
6import {Constants} from "../../../constants";
7import {upDownHint} from "../../../util/upDownHint";
8import {clearSelect} from "../../util/clearSelect";
9
10export const avKeydown = (event: KeyboardEvent, nodeElement: HTMLElement, protyle: IProtyle) => {
11 if (!nodeElement.classList.contains("av") || !window.siyuan.menus.menu.element.classList.contains("fn__none")) {
12 return false;
13 }
14 if (event.isComposing) {
15 return true;
16 }
17 // 避免浏览器默认快捷键
18 if (matchHotKey("⌘B", event) || matchHotKey("⌘I", event) || matchHotKey("⌘U", event)) {
19 event.preventDefault();
20 return true;
21 }
22 const selectCellElement = nodeElement.querySelector(".av__cell--select") as HTMLElement;
23 if (selectCellElement) {
24 const rowElement = hasClosestByClassName(selectCellElement, "av__row");
25 if (!rowElement || rowElement.dataset.type === "ghost") {
26 return false;
27 }
28 const avPanelElement = document.querySelector(".av__panel");
29 if (avPanelElement &&
30 (event.key === "Backspace" || event.key === "Delete" || event.key === "Escape" ||
31 event.key.startsWith("ArrowLeft") || event.key === "Enter" || matchHotKey("⇥", event) ||
32 matchHotKey("⇧⇥", event))) {
33 avPanelElement.remove();
34 event.preventDefault();
35 event.stopPropagation();
36 return true;
37 }
38 // 需在 avPanelElement 之后,否则点击资源单元格后删除,资源面板不会更新
39 if (event.key === "Backspace" || event.key === "Delete") {
40 updateCellsValue(protyle, nodeElement, undefined, Array.from(nodeElement.querySelectorAll(".av__cell--active, .av__cell--select")));
41 event.preventDefault();
42 return true;
43 }
44 if (event.key === "Escape") {
45 clearSelect(["cell"], nodeElement);
46 selectRow(rowElement.querySelector(".av__firstcol"), "select");
47 event.preventDefault();
48 return true;
49 }
50 if (event.key === "Enter") {
51 popTextCell(protyle, [selectCellElement]);
52 event.preventDefault();
53 return true;
54 }
55 let newCellElement;
56 if (event.key === "ArrowLeft" || matchHotKey("⇧⇥", event)) {
57 const previousRowElement = rowElement.previousElementSibling;
58 if (selectCellElement.previousElementSibling && !selectCellElement.previousElementSibling.classList.contains("av__firstcol")) {
59 if (selectCellElement.previousElementSibling.classList.contains("av__colsticky")) {
60 newCellElement = selectCellElement.previousElementSibling.lastElementChild;
61 if (newCellElement.classList.contains("av__firstcol")) {
62 newCellElement = undefined;
63 }
64 } else if (selectCellElement.previousElementSibling.classList.contains("av__cell")) {
65 newCellElement = selectCellElement.previousElementSibling;
66 }
67 }
68 if (!newCellElement && previousRowElement && !previousRowElement.classList.contains("av__row--header")) {
69 const previousCellElements = previousRowElement.querySelectorAll(".av__cell");
70 newCellElement = previousCellElements[previousCellElements.length - 1];
71 }
72 if (newCellElement) {
73 clearSelect(["cell"], nodeElement);
74 newCellElement.classList.add("av__cell--select");
75 addDragFill(newCellElement);
76 cellScrollIntoView(nodeElement, newCellElement, false);
77 }
78 event.preventDefault();
79 return true;
80 }
81 if (event.key === "ArrowRight" || matchHotKey("⇥", event)) {
82 const nextRowElement = rowElement.nextElementSibling;
83 if (selectCellElement.nextElementSibling && selectCellElement.nextElementSibling.classList.contains("av__cell")) {
84 newCellElement = selectCellElement.nextElementSibling;
85 } else if (!selectCellElement.nextElementSibling && selectCellElement.parentElement.nextElementSibling) {
86 // pin
87 newCellElement = selectCellElement.parentElement.nextElementSibling;
88 } else if (nextRowElement && !nextRowElement.classList.contains("av__row--footer")) {
89 newCellElement = nextRowElement.querySelector(".av__cell");
90 }
91 if (newCellElement) {
92 clearSelect(["cell"], nodeElement);
93 newCellElement.classList.add("av__cell--select");
94 addDragFill(newCellElement);
95 cellScrollIntoView(nodeElement, newCellElement, false);
96 } else if (event.key !== "ArrowRight") {
97 clearSelect(["cell"], nodeElement);
98 insertRows({
99 blockElement: nodeElement,
100 protyle,
101 count: 1,
102 previousID: rowElement.getAttribute("data-id"),
103 groupID: rowElement.parentElement.getAttribute("data-group-id")
104 });
105 }
106 event.preventDefault();
107 return true;
108 }
109 if (event.key === "ArrowUp") {
110 const previousRowElement = rowElement.previousElementSibling;
111 if (previousRowElement && !previousRowElement.classList.contains("av__row--header")) {
112 newCellElement = previousRowElement.querySelector(`.av__cell[data-col-id="${selectCellElement.dataset.colId}"]`);
113 }
114 if (newCellElement) {
115 clearSelect(["cell"], nodeElement);
116 newCellElement.classList.add("av__cell--select");
117 addDragFill(newCellElement);
118 cellScrollIntoView(nodeElement, newCellElement);
119 }
120 event.preventDefault();
121 return true;
122 }
123 if (event.key === "ArrowDown") {
124 const nextRowElement = rowElement.nextElementSibling;
125 if (nextRowElement && !nextRowElement.classList.contains("av__row--footer")) {
126 newCellElement = nextRowElement.querySelector(`.av__cell[data-col-id="${selectCellElement.dataset.colId}"]`);
127 }
128 if (newCellElement) {
129 clearSelect(["cell"], nodeElement);
130 newCellElement.classList.add("av__cell--select");
131 addDragFill(newCellElement);
132 cellScrollIntoView(nodeElement, newCellElement);
133 }
134 event.preventDefault();
135 return true;
136 }
137
138 if (!Constants.KEYCODELIST[event.keyCode] ||
139 (Constants.KEYCODELIST[event.keyCode].length === 1 &&
140 !event.metaKey && !event.ctrlKey &&
141 !["⇧", "⌃", "⌥", "⌘"].includes(Constants.KEYCODELIST[event.keyCode]))) {
142 if (!selectCellElement.style.backgroundColor) {
143 popTextCell(protyle, [selectCellElement]);
144 } else {
145 event.preventDefault();
146 }
147 return true;
148 }
149 }
150 const selectRowElements = nodeElement.querySelectorAll(".av__row--select:not(.av__row--header)");
151 if (selectRowElements.length > 0) {
152 if (matchHotKey("⌘/", event)) {
153 event.stopPropagation();
154 event.preventDefault();
155 avContextmenu(protyle, selectRowElements[0] as HTMLElement, {
156 x: nodeElement.querySelector(".layout-tab-bar").getBoundingClientRect().left,
157 y: selectRowElements[0].getBoundingClientRect().bottom
158 });
159 return true;
160 }
161 if (event.key === "Escape") {
162 event.preventDefault();
163 selectRow(selectRowElements[0].querySelector(".av__firstcol"), "unselectAll");
164 return true;
165 }
166 if (event.key === "Backspace") {
167 event.preventDefault();
168 deleteRow(nodeElement, protyle);
169 return true;
170 }
171 if (event.key === "Enter") {
172 selectRow(selectRowElements[0].querySelector(".av__firstcol"), "unselectAll");
173 popTextCell(protyle, [selectRowElements[0].querySelector(".av__cell")]);
174 event.preventDefault();
175 return true;
176 }
177 // TODO event.shiftKey
178 if (event.key === "ArrowUp") {
179 const previousRowElement = selectRowElements[0].previousElementSibling;
180 selectRow(selectRowElements[0].querySelector(".av__firstcol"), "unselectAll");
181 if (previousRowElement && !previousRowElement.classList.contains("av__row--header")) {
182 selectRow(previousRowElement.querySelector(".av__firstcol"), "select");
183 cellScrollIntoView(nodeElement, previousRowElement);
184 } else {
185 nodeElement.classList.add("protyle-wysiwyg--select");
186 }
187 event.preventDefault();
188 return true;
189 }
190 if (event.key === "ArrowDown") {
191 const nextRowElement = selectRowElements[selectRowElements.length - 1].nextElementSibling;
192 selectRow(selectRowElements[0].querySelector(".av__firstcol"), "unselectAll");
193 if (nextRowElement && !nextRowElement.classList.contains("av__row--util")) {
194 selectRow(nextRowElement.querySelector(".av__firstcol"), "select");
195 cellScrollIntoView(nodeElement, nextRowElement);
196 } else {
197 nodeElement.classList.add("protyle-wysiwyg--select");
198 }
199 event.preventDefault();
200 return true;
201 }
202 }
203 return false;
204};
205
206export const bindAVPanelKeydown = (event: KeyboardEvent) => {
207 const avPanelElement = document.querySelector(".av__panel");
208 if (avPanelElement && window.siyuan.menus.menu.element.classList.contains("fn__none")) {
209 if ((avPanelElement.querySelector('[data-type="goSearchRollupCol"]') && !avPanelElement.querySelector(".b3-text-field")) ||
210 avPanelElement.querySelector('[data-type="addAssetExist"]')) {
211 const menuElement = avPanelElement.querySelector(".b3-menu__items");
212 if (event.key === "Enter") {
213 const currentElement = menuElement.querySelector(".b3-menu__item--current");
214 if (currentElement) {
215 const editElement = currentElement.querySelector('[data-type="editAssetItem"]');
216 const uploadElement = currentElement.querySelector(".b3-form__upload");
217 if (editElement) {
218 avPanelElement.dispatchEvent(new CustomEvent("click", {
219 detail: {
220 type: editElement.getAttribute("data-type"),
221 target: editElement
222 }
223 }));
224 } else if (uploadElement) {
225 uploadElement.dispatchEvent(new MouseEvent("click", {bubbles: true}));
226 } else {
227 avPanelElement.dispatchEvent(new CustomEvent("click", {
228 detail: {
229 type: currentElement.getAttribute("data-type"),
230 target: currentElement
231 }
232 }));
233 }
234 return true;
235 }
236 } else if (event.key === "Escape") {
237 avPanelElement.dispatchEvent(new CustomEvent("click", {detail: "close"}));
238 return true;
239 } else if (upDownHint(menuElement, event, "b3-menu__item--current", menuElement.firstElementChild)) {
240 return true;
241 }
242 }
243 }
244 return false;
245};