A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
1import {transaction} from "../../wysiwyg/transaction";
2import {fetchPost} from "../../../util/fetch";
3import {
4 addCol,
5 bindEditEvent,
6 duplicateCol,
7 getColIconByType,
8 getColId,
9 getColNameByType,
10 getEditHTML,
11 removeCol
12} from "./col";
13import {setPosition} from "../../../util/setPosition";
14import {hasClosestByAttribute, hasClosestByClassName} from "../../util/hasClosest";
15import {addColOptionOrCell, bindSelectEvent, getSelectHTML, removeCellOption, setColOption} from "./select";
16import {addFilter, getFiltersHTML, setFilter} from "./filter";
17import {addSort, bindSortsEvent, getSortsHTML} from "./sort";
18import {bindDateEvent, getDateHTML} from "./date";
19import {formatNumber} from "./number";
20import {updateAttrViewCellAnimation} from "./action";
21import {addAssetLink, bindAssetEvent, editAssetItem, getAssetHTML, updateAssetCell} from "./asset";
22import {Constants} from "../../../constants";
23import {hideElements} from "../../ui/hideElements";
24import {isLocalPath, pathPosix} from "../../../util/pathName";
25import {openEmojiPanel, unicode2Emoji} from "../../../emoji";
26import {getSearch, isMobile} from "../../../util/functions";
27/// #if !MOBILE
28import {openAsset} from "../../../editor/util";
29/// #endif
30import {previewAttrViewImages} from "../../preview/image";
31import {assetMenu} from "../../../menus/protyle";
32import {
33 addView,
34 bindSwitcherEvent,
35 bindViewEvent,
36 getFieldsByData,
37 getSwitcherHTML,
38 getViewHTML,
39 openViewMenu
40} from "./view";
41import {focusBlock} from "../../util/selection";
42import {getFieldIdByCellElement, setPageSize} from "./row";
43import {bindRelationEvent, getRelationHTML, openSearchAV, setRelationCell, updateRelation} from "./relation";
44import {bindRollupData, getRollupHTML, goSearchRollupCol} from "./rollup";
45import {updateCellsValue} from "./cell";
46import {openCalcMenu} from "./calc";
47import {escapeAttr, escapeHtml} from "../../../util/escape";
48import {Dialog} from "../../../dialog";
49import {bindLayoutEvent, getLayoutHTML, updateLayout} from "./layout";
50import {setGalleryCover, setGalleryRatio, setGallerySize} from "./gallery/util";
51import {
52 bindGroupsEvent, bindGroupsNumber,
53 getGroupsHTML,
54 getGroupsMethodHTML, getGroupsNumberHTML, getLanguageByIndex, getPageSize,
55 goGroupsDate,
56 goGroupsSort,
57 setGroupMethod
58} from "./groups";
59
60export const openMenuPanel = (options: {
61 protyle: IProtyle,
62 blockElement: Element,
63 type: "select" | "properties" | "config" | "sorts" | "filters" | "edit" | "date" | "asset" | "switcher" | "relation" | "rollup",
64 colId?: string, // for edit, rollup
65 // 使用前端构造的数据
66 editData?: {
67 previousID: string,
68 colData: IAVColumn,
69 },
70 cellElements?: HTMLElement[], // for select & date & relation & asset
71 cb?: (avPanelElement: Element) => void
72}) => {
73 let avPanelElement = document.querySelector(".av__panel");
74 if (avPanelElement) {
75 avPanelElement.remove();
76 return;
77 }
78 const avID = options.blockElement.getAttribute("data-av-id");
79 const avPageSize = getPageSize(options.blockElement);
80 fetchPost("/api/av/renderAttributeView", {
81 id: avID,
82 query: (options.blockElement.querySelector('[data-type="av-search"]') as HTMLInputElement)?.value.trim() || "",
83 pageSize: avPageSize.unGroupPageSize,
84 groupPaging: avPageSize.groupPageSize,
85 viewID: options.blockElement.getAttribute(Constants.CUSTOM_SY_AV_VIEW)
86 }, (response) => {
87 avPanelElement = document.querySelector(".av__panel");
88 if (avPanelElement) {
89 avPanelElement.remove();
90 return;
91 }
92 window.siyuan.menus.menu.remove();
93 const blockID = options.blockElement.getAttribute("data-node-id");
94
95 const isCustomAttr = !options.blockElement.classList.contains("av");
96 let data = response.data as IAV;
97 let html;
98 let fields = getFieldsByData(data);
99 if (options.type === "config") {
100 html = getViewHTML(data);
101 } else if (options.type === "properties") {
102 html = getPropertiesHTML(fields);
103 } else if (options.type === "sorts") {
104 html = getSortsHTML(fields, data.view.sorts);
105 } else if (options.type === "switcher") {
106 html = getSwitcherHTML(data.views, data.viewID);
107 } else if (options.type === "filters") {
108 html = getFiltersHTML(data);
109 } else if (options.type === "select") {
110 html = getSelectHTML(fields, options.cellElements, true, options.blockElement);
111 } else if (options.type === "asset") {
112 html = getAssetHTML(options.cellElements);
113 } else if (options.type === "edit") {
114 if (options.editData) {
115 if (typeof options.editData.colData.wrap === "undefined") {
116 options.editData.colData.wrap = data.view.wrapField;
117 }
118 if (options.editData.previousID) {
119 fields.find((item, index) => {
120 if (item.id === options.editData.previousID) {
121 fields.splice(index + 1, 0, options.editData.colData);
122 return true;
123 }
124 });
125 } else {
126 if (data.viewType === "table") {
127 fields.splice(0, 0, options.editData.colData);
128 } else {
129 fields.push(options.editData.colData);
130 }
131 }
132 }
133 html = getEditHTML({protyle: options.protyle, data, colId: options.colId, isCustomAttr});
134 } else if (options.type === "date") {
135 html = getDateHTML(options.cellElements);
136 } else if (options.type === "rollup") {
137 html = `<div class="b3-menu__items">${getRollupHTML({data, cellElements: options.cellElements})}</div>`;
138 } else if (options.type === "relation") {
139 html = getRelationHTML(data, options.cellElements);
140 if (!html) {
141 openMenuPanel({
142 protyle: options.protyle,
143 blockElement: options.blockElement,
144 type: "edit",
145 colId: getColId(options.cellElements[0], data.viewType)
146 });
147 return;
148 }
149 }
150
151 document.body.insertAdjacentHTML("beforeend", `<div class="av__panel" style="z-index: ${++window.siyuan.zIndex};">
152 <div class="b3-dialog__scrim" data-type="close"></div>
153 <div class="b3-menu" ${["select", "date", "asset", "relation", "rollup"].includes(options.type) ? `style="min-width: 200px;${isMobile() ? "max-width: 90vw;" : "max-width: 50vw;"}"` : ""}>${html}</div>
154</div>`);
155 avPanelElement = document.querySelector(".av__panel");
156 let closeCB: () => void;
157 const menuElement = avPanelElement.lastElementChild as HTMLElement;
158 let tabRect = options.blockElement.querySelector(`.av__views, .av__row[data-col-id="${options.colId}"] > .block__logo`)?.getBoundingClientRect();
159 if (["select", "date", "asset", "relation", "rollup"].includes(options.type)) {
160 let lastElement = options.cellElements[options.cellElements.length - 1];
161 if (!options.blockElement.contains(lastElement)) {
162 // https://github.com/siyuan-note/siyuan/issues/15839
163 const rowID = getFieldIdByCellElement(lastElement, data.viewType);
164 if (data.viewType === "table") {
165 lastElement = options.blockElement.querySelector(`.av__row[data-id="${rowID}"] .av__cell[data-col-id="${lastElement.dataset.colId}"]`);
166 } else {
167 lastElement = options.blockElement.querySelector(`.av__gallery-item[data-id="${rowID}"] .av__cell[data-field-id="${lastElement.dataset.fieldId}"]`);
168 }
169 }
170 const cellRect = (lastElement || options.cellElements[options.cellElements.length - 1]).getBoundingClientRect();
171
172 if (options.type === "select") {
173 bindSelectEvent(options.protyle, data, menuElement, options.cellElements, options.blockElement);
174 } else if (options.type === "date") {
175 closeCB = bindDateEvent({
176 protyle: options.protyle,
177 data,
178 menuElement,
179 cellElements: options.cellElements,
180 blockElement: options.blockElement
181 });
182 } else if (options.type === "asset") {
183 bindAssetEvent({
184 protyle: options.protyle,
185 menuElement,
186 cellElements: options.cellElements,
187 blockElement: options.blockElement
188 });
189 setTimeout(() => {
190 setPosition(menuElement, cellRect.left, cellRect.bottom, cellRect.height);
191 }, Constants.TIMEOUT_LOAD); // 等待加载
192 } else if (options.type === "relation") {
193 bindRelationEvent({
194 menuElement,
195 cellElements: options.cellElements,
196 protyle: options.protyle,
197 blockElement: options.blockElement
198 });
199 } else if (options.type === "rollup") {
200 bindRollupData({protyle: options.protyle, data, menuElement});
201 }
202 if (["select", "date", "relation", "rollup"].includes(options.type)) {
203 const inputElement = menuElement.querySelector("input");
204 if (inputElement) {
205 inputElement.select();
206 inputElement.focus();
207 }
208 setPosition(menuElement, cellRect.left, cellRect.bottom, cellRect.height);
209 }
210 } else {
211 setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height);
212 if (options.type === "sorts") {
213 bindSortsEvent(options.protyle, menuElement, data, blockID);
214 } else if (options.type === "edit") {
215 bindEditEvent({protyle: options.protyle, data, menuElement, isCustomAttr, blockID});
216 } else if (options.type === "config") {
217 bindViewEvent({protyle: options.protyle, data, menuElement, blockElement: options.blockElement});
218 } else if (options.type === "switcher") {
219 bindSwitcherEvent({protyle: options.protyle, menuElement, blockElement: options.blockElement});
220 }
221 }
222 if (options.cb) {
223 options.cb(avPanelElement);
224 }
225 avPanelElement.addEventListener("dragstart", (event: DragEvent) => {
226 window.siyuan.dragElement = event.target as HTMLElement;
227 window.siyuan.dragElement.style.opacity = ".38";
228 return;
229 });
230 avPanelElement.addEventListener("drop", (event) => {
231 counter = 0;
232 if (!window.siyuan.dragElement) {
233 event.preventDefault();
234 event.stopPropagation();
235 return;
236 }
237 window.siyuan.dragElement.style.opacity = "";
238 const sourceElement = window.siyuan.dragElement;
239 window.siyuan.dragElement = undefined;
240 if (options.protyle && options.protyle.disabled) {
241 event.preventDefault();
242 event.stopPropagation();
243 return;
244 }
245 if (!options.protyle && window.siyuan.config.readonly) {
246 event.preventDefault();
247 event.stopPropagation();
248 return;
249 }
250 const targetElement = avPanelElement.querySelector(".dragover__bottom, .dragover__top") as HTMLElement;
251 if (!targetElement) {
252 return;
253 }
254 const isTop = targetElement.classList.contains("dragover__top");
255 const sourceId = sourceElement.dataset.id;
256 const targetId = targetElement.dataset.id;
257 if (targetElement.querySelector('[data-type="removeSort"]')) {
258 const changeData = data.view.sorts;
259 const oldData = Object.assign([], changeData);
260 let sortFilter: IAVSort;
261 changeData.find((sort, index: number) => {
262 if (sort.column === sourceId) {
263 sortFilter = changeData.splice(index, 1)[0];
264 return true;
265 }
266 });
267 changeData.find((sort, index: number) => {
268 if (sort.column === targetId) {
269 if (isTop) {
270 changeData.splice(index, 0, sortFilter);
271 } else {
272 changeData.splice(index + 1, 0, sortFilter);
273 }
274 return true;
275 }
276 });
277
278 transaction(options.protyle, [{
279 action: "setAttrViewSorts",
280 avID,
281 data: changeData,
282 blockID
283 }], [{
284 action: "setAttrViewSorts",
285 avID,
286 data: oldData,
287 blockID
288 }]);
289 menuElement.innerHTML = getSortsHTML(fields, data.view.sorts);
290 bindSortsEvent(options.protyle, menuElement, data, blockID);
291 return;
292 }
293 if (targetElement.querySelector('[data-type="removeFilter"]')) {
294 const changeData = data.view.filters;
295 const oldData = Object.assign([], changeData);
296 let targetFilter: IAVFilter;
297 changeData.find((filter, index: number) => {
298 if (filter.column === sourceId) {
299 targetFilter = changeData.splice(index, 1)[0];
300 return true;
301 }
302 });
303 changeData.find((filter, index: number) => {
304 if (filter.column === targetId) {
305 if (isTop) {
306 changeData.splice(index, 0, targetFilter);
307 } else {
308 changeData.splice(index + 1, 0, targetFilter);
309 }
310 return true;
311 }
312 });
313
314 transaction(options.protyle, [{
315 action: "setAttrViewFilters",
316 avID,
317 data: changeData,
318 blockID
319 }], [{
320 action: "setAttrViewFilters",
321 avID,
322 data: oldData,
323 blockID
324 }]);
325 menuElement.innerHTML = getFiltersHTML(data);
326 return;
327 }
328 if (targetElement.querySelector('[data-type="av-view-edit"]')) {
329 transaction(options.protyle, [{
330 action: "sortAttrViewView",
331 avID,
332 blockID,
333 id: sourceId,
334 previousID: isTop ? targetElement.previousElementSibling?.getAttribute("data-id") : targetElement.getAttribute("data-id")
335 }], [{
336 action: "sortAttrViewView",
337 avID,
338 blockID,
339 id: sourceId,
340 previousID: sourceElement.previousElementSibling?.getAttribute("data-id")
341 }]);
342 if (isTop) {
343 targetElement.before(sourceElement);
344 targetElement.classList.remove("dragover__top");
345 } else {
346 targetElement.after(sourceElement);
347 targetElement.classList.remove("dragover__bottom");
348 }
349 return;
350 }
351 if (targetElement.querySelector('[data-type="editAssetItem"]')) {
352 if (isTop) {
353 targetElement.before(sourceElement);
354 } else {
355 targetElement.after(sourceElement);
356 }
357 const replaceValue: IAVCellAssetValue[] = [];
358 Array.from(targetElement.parentElement.children).forEach((item: HTMLElement) => {
359 if (["image", "file"].includes(item.dataset.type)) {
360 replaceValue.push({
361 content: item.dataset.content,
362 name: item.dataset.name,
363 type: item.dataset.type as "image" | "file",
364 });
365 }
366 });
367 updateAssetCell({
368 protyle: options.protyle,
369 cellElements: options.cellElements,
370 replaceValue,
371 blockElement: options.blockElement
372 });
373 return;
374 }
375 if (targetElement.querySelector('[data-type="setColOption"]')) {
376 const colId = options.cellElements ? getColId(options.cellElements[0], data.viewType) : menuElement.querySelector(".b3-menu__item").getAttribute("data-col-id");
377 const changeData = fields.find((column) => column.id === colId).options;
378 const oldData = Object.assign([], changeData);
379 let targetOption: { name: string, color: string };
380 changeData.find((option, index: number) => {
381 if (option.name === sourceElement.dataset.name) {
382 targetOption = changeData.splice(index, 1)[0];
383 return true;
384 }
385 });
386 changeData.find((option, index: number) => {
387 if (option.name === targetElement.dataset.name) {
388 if (isTop) {
389 changeData.splice(index, 0, targetOption);
390 } else {
391 changeData.splice(index + 1, 0, targetOption);
392 }
393 return true;
394 }
395 });
396 transaction(options.protyle, [{
397 action: "updateAttrViewColOptions",
398 id: colId,
399 avID,
400 data: changeData,
401 }], [{
402 action: "updateAttrViewColOptions",
403 id: colId,
404 avID,
405 data: oldData,
406 }]);
407 const oldScroll = menuElement.querySelector(".b3-menu__items").scrollTop;
408 if (options.cellElements) {
409 menuElement.innerHTML = getSelectHTML(fields, options.cellElements, false, options.blockElement);
410 bindSelectEvent(options.protyle, data, menuElement, options.cellElements, options.blockElement);
411 } else {
412 menuElement.innerHTML = getEditHTML({
413 protyle: options.protyle,
414 data,
415 colId,
416 isCustomAttr
417 });
418 bindEditEvent({protyle: options.protyle, data, menuElement, isCustomAttr, blockID});
419 }
420 menuElement.querySelector(".b3-menu__items").scrollTop = oldScroll;
421 return;
422 }
423 if (targetElement.getAttribute("data-type") === "setRelationCell") {
424 if (isTop) {
425 targetElement.before(sourceElement);
426 } else {
427 targetElement.after(sourceElement);
428 }
429 targetElement.classList.remove("dragover__bottom", "dragover__top");
430 const blockIDs: string[] = [];
431 const contents: IAVCellValue[] = [];
432 targetElement.parentElement.querySelectorAll(".fn__grab").forEach(item => {
433 const dateElement = item.nextElementSibling as HTMLElement;
434 blockIDs.push(dateElement.parentElement.dataset.rowId);
435 contents.push({
436 isDetached: !dateElement.style.color,
437 type: "block",
438 block: {
439 content: dateElement.textContent,
440 id: dateElement.dataset.id
441 }
442 });
443 });
444 updateCellsValue(options.protyle, options.blockElement as HTMLElement, {
445 blockIDs,
446 contents,
447 }, options.cellElements);
448 return;
449 }
450 if (targetElement.getAttribute("data-type") === "editCol") {
451 const previousID = (isTop ? targetElement.previousElementSibling?.getAttribute("data-id") : targetElement.getAttribute("data-id")) || "";
452 const undoPreviousID = sourceElement.previousElementSibling?.getAttribute("data-id") || "";
453 if (previousID !== undoPreviousID && previousID !== sourceId) {
454 transaction(options.protyle, [{
455 action: "sortAttrViewCol",
456 avID,
457 previousID,
458 id: sourceId,
459 blockID,
460 }], [{
461 action: "sortAttrViewCol",
462 avID,
463 previousID: undoPreviousID,
464 id: sourceId,
465 blockID
466 }]);
467 let column: IAVColumn;
468 fields.find((item, index: number) => {
469 if (item.id === sourceId) {
470 column = fields.splice(index, 1)[0];
471 return true;
472 }
473 });
474 fields.find((item, index: number) => {
475 if (item.id === targetId) {
476 if (isTop) {
477 fields.splice(index, 0, column);
478 } else {
479 fields.splice(index + 1, 0, column);
480 }
481 return true;
482 }
483 });
484 }
485 menuElement.innerHTML = getPropertiesHTML(fields);
486 return;
487 }
488 if (targetElement.querySelector('[data-type="hideGroup"]')) {
489 const previousID = (isTop ? targetElement.previousElementSibling?.getAttribute("data-id") : targetElement.getAttribute("data-id")) || "";
490 const undoPreviousID = sourceElement.previousElementSibling?.getAttribute("data-id") || "";
491 if (previousID !== undoPreviousID && previousID !== sourceId) {
492 transaction(options.protyle, [{
493 action: "sortAttrViewGroup",
494 avID,
495 blockID,
496 previousID,
497 id: sourceId,
498 }], [{
499 action: "sortAttrViewGroup",
500 avID,
501 blockID,
502 previousID: undoPreviousID,
503 id: sourceId,
504 }]);
505 menuElement.querySelector('[data-type="goGroupsSort"] .b3-menu__accelerator').textContent = getLanguageByIndex(2, "sort");
506 data.view.group.order = 2;
507 data.view.groups.find((group, index) => {
508 if (group.id === sourceId) {
509 const groupData = data.view.groups.splice(index, 1)[0];
510 data.view.groups.find((item, index: number) => {
511 if (item.id === targetId) {
512 if (isTop) {
513 data.view.groups.splice(index, 0, groupData);
514 } else {
515 data.view.groups.splice(index + 1, 0, groupData);
516 }
517 return true;
518 }
519 });
520 return true;
521 }
522 });
523 if (isTop) {
524 targetElement.before(sourceElement);
525 } else {
526 targetElement.after(sourceElement);
527 }
528 }
529 targetElement.classList.remove("dragover__top", "dragover__bottom");
530 return;
531 }
532 });
533 let dragoverElement: HTMLElement;
534 avPanelElement.addEventListener("dragover", (event: DragEvent) => {
535 if (event.dataTransfer.types.includes("Files")) {
536 event.preventDefault();
537 return;
538 }
539 const target = event.target as HTMLElement;
540 let targetElement = hasClosestByAttribute(target, "draggable", "true");
541 if (!targetElement) {
542 targetElement = hasClosestByAttribute(document.elementFromPoint(event.clientX, event.clientY - 1), "draggable", "true");
543 }
544 if (!targetElement || targetElement === window.siyuan.dragElement) {
545 return;
546 }
547 event.preventDefault();
548 if (dragoverElement && targetElement === dragoverElement) {
549 const nodeRect = targetElement.getBoundingClientRect();
550 avPanelElement.querySelectorAll(".dragover__bottom, .dragover__top").forEach((item: HTMLElement) => {
551 item.classList.remove("dragover__bottom", "dragover__top");
552 });
553 if (event.clientY > nodeRect.top + nodeRect.height / 2) {
554 targetElement.classList.add("dragover__bottom");
555 } else {
556 targetElement.classList.add("dragover__top");
557 }
558 return;
559 }
560 dragoverElement = targetElement;
561 });
562 let counter = 0;
563 avPanelElement.addEventListener("dragleave", () => {
564 counter--;
565 if (counter === 0) {
566 avPanelElement.querySelectorAll(".dragover__bottom, .dragover__top").forEach((item: HTMLElement) => {
567 item.classList.remove("dragover__bottom", "dragover__top");
568 });
569 }
570 });
571 avPanelElement.addEventListener("dragenter", (event) => {
572 event.preventDefault();
573 counter++;
574 });
575 avPanelElement.addEventListener("dragend", () => {
576 if (window.siyuan.dragElement) {
577 window.siyuan.dragElement.style.opacity = "";
578 window.siyuan.dragElement = undefined;
579 }
580 });
581 avPanelElement.addEventListener("mousedown", (event: MouseEvent & { target: HTMLElement }) => {
582 if (event.button === 1 && !hasClosestByClassName(event.target, "b3-menu")) {
583 document.querySelector(".av__panel").dispatchEvent(new CustomEvent("click", {detail: "close"}));
584 }
585 });
586 avPanelElement.addEventListener("click", async (event: MouseEvent) => {
587 let type: string;
588 let target = event.target as HTMLElement;
589 if (typeof event.detail === "string") {
590 type = event.detail;
591 } else if (typeof event.detail === "object") {
592 type = (event.detail as { type: string }).type;
593 target = (event.detail as { target: HTMLElement }).target;
594 }
595 while (target && target !== avPanelElement || type) {
596 type = target?.dataset.type || type;
597 if (type === "close") {
598 if (!options.protyle.toolbar.subElement.classList.contains("fn__none")) {
599 // 优先关闭资源文件搜索
600 hideElements(["util"], options.protyle);
601 } else if (!window.siyuan.menus.menu.element.classList.contains("fn__none")) {
602 // 过滤面板先关闭过滤条件
603 window.siyuan.menus.menu.remove();
604 } else {
605 closeCB?.();
606 avPanelElement.remove();
607 focusBlock(options.blockElement);
608 }
609 window.siyuan.menus.menu.remove();
610 event.preventDefault();
611 event.stopPropagation();
612 break;
613 } else if (type === "go-config") {
614 menuElement.innerHTML = getViewHTML(data);
615 setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height);
616 bindViewEvent({protyle: options.protyle, data, menuElement, blockElement: options.blockElement});
617 window.siyuan.menus.menu.remove();
618 event.preventDefault();
619 event.stopPropagation();
620 break;
621 } else if (type === "go-properties") {
622 // 复制列后点击返回到属性面板,宽度不一致,需重新计算
623 tabRect = options.blockElement.querySelector(".av__views").getBoundingClientRect();
624 menuElement.innerHTML = getPropertiesHTML(fields);
625 setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height);
626 window.siyuan.menus.menu.remove();
627 event.preventDefault();
628 event.stopPropagation();
629 break;
630 } else if (type === "go-layout") {
631 menuElement.innerHTML = getLayoutHTML(data);
632 setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height);
633 bindLayoutEvent({protyle: options.protyle, data, menuElement, blockElement: options.blockElement});
634 window.siyuan.menus.menu.remove();
635 event.preventDefault();
636 event.stopPropagation();
637 break;
638 } else if (type === "goSorts") {
639 menuElement.innerHTML = getSortsHTML(fields, data.view.sorts);
640 bindSortsEvent(options.protyle, menuElement, data, blockID);
641 setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height);
642 window.siyuan.menus.menu.remove();
643 event.preventDefault();
644 event.stopPropagation();
645 break;
646 } else if (type === "removeSorts") {
647 transaction(options.protyle, [{
648 action: "setAttrViewSorts",
649 avID,
650 data: [],
651 blockID
652 }], [{
653 action: "setAttrViewSorts",
654 avID,
655 data: data.view.sorts,
656 blockID
657 }]);
658 data.view.sorts = [];
659 menuElement.innerHTML = getSortsHTML(fields, data.view.sorts);
660 bindSortsEvent(options.protyle, menuElement, data, blockID);
661 setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height);
662 event.preventDefault();
663 event.stopPropagation();
664 break;
665 } else if (type === "addSort") {
666 addSort({
667 data,
668 rect: target.getBoundingClientRect(),
669 menuElement,
670 tabRect,
671 avId: avID,
672 protyle: options.protyle,
673 blockID,
674 });
675 event.preventDefault();
676 event.stopPropagation();
677 break;
678 } else if (type === "removeSort") {
679 const oldSorts = Object.assign([], data.view.sorts);
680 data.view.sorts.find((item: IAVSort, index: number) => {
681 if (item.column === target.parentElement.dataset.id) {
682 data.view.sorts.splice(index, 1);
683 return true;
684 }
685 });
686 transaction(options.protyle, [{
687 action: "setAttrViewSorts",
688 avID,
689 data: data.view.sorts,
690 blockID
691 }], [{
692 action: "setAttrViewSorts",
693 avID,
694 data: oldSorts,
695 blockID
696 }]);
697 menuElement.innerHTML = getSortsHTML(fields, data.view.sorts);
698 bindSortsEvent(options.protyle, menuElement, data, blockID);
699 setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height);
700 event.preventDefault();
701 event.stopPropagation();
702 break;
703 } else if (type === "goFilters") {
704 menuElement.innerHTML = getFiltersHTML(data);
705 setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height);
706 window.siyuan.menus.menu.remove();
707 event.preventDefault();
708 event.stopPropagation();
709 break;
710 } else if (type === "removeFilters") {
711 transaction(options.protyle, [{
712 action: "setAttrViewFilters",
713 avID,
714 data: [],
715 blockID
716 }], [{
717 action: "setAttrViewFilters",
718 avID,
719 data: data.view.filters,
720 blockID
721 }]);
722 data.view.filters = [];
723 menuElement.innerHTML = getFiltersHTML(data);
724 setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height);
725 window.siyuan.menus.menu.remove();
726 event.preventDefault();
727 event.stopPropagation();
728 break;
729 } else if (type === "addFilter") {
730 addFilter({
731 data,
732 rect: target.getBoundingClientRect(),
733 menuElement,
734 tabRect,
735 avId: avID,
736 protyle: options.protyle,
737 blockElement: options.blockElement
738 });
739 event.preventDefault();
740 event.stopPropagation();
741 break;
742 } else if (type === "removeFilter") {
743 window.siyuan.menus.menu.remove();
744 const oldFilters = Object.assign([], data.view.filters);
745 data.view.filters.find((item: IAVFilter, index: number) => {
746 if (item.column === target.parentElement.dataset.id && item.value.type === target.parentElement.dataset.filterType) {
747 data.view.filters.splice(index, 1);
748 return true;
749 }
750 });
751 transaction(options.protyle, [{
752 action: "setAttrViewFilters",
753 avID,
754 data: data.view.filters,
755 blockID
756 }], [{
757 action: "setAttrViewFilters",
758 avID,
759 data: oldFilters,
760 blockID
761 }]);
762 menuElement.innerHTML = getFiltersHTML(data);
763 setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height);
764 event.preventDefault();
765 event.stopPropagation();
766 break;
767 } else if (type === "setFilter") {
768 data.view.filters.find((item: IAVFilter) => {
769 if (item.column === target.parentElement.parentElement.dataset.id && item.value.type === target.parentElement.parentElement.dataset.filterType) {
770 setFilter({
771 empty: false,
772 filter: item,
773 protyle: options.protyle,
774 data,
775 target,
776 blockElement: options.blockElement
777 });
778 return true;
779 }
780 });
781 event.preventDefault();
782 event.stopPropagation();
783 break;
784 } else if (type === "numberFormat") {
785 formatNumber({
786 avPanelElement,
787 element: target,
788 protyle: options.protyle,
789 oldFormat: target.dataset.format,
790 colId: menuElement.querySelector(".b3-menu__item").getAttribute("data-col-id"),
791 avID
792 });
793 event.preventDefault();
794 event.stopPropagation();
795 break;
796 } else if (type === "newCol") {
797 avPanelElement.remove();
798 const addMenu = addCol(options.protyle, options.blockElement);
799 addMenu.open({
800 x: tabRect.right,
801 y: tabRect.bottom,
802 h: tabRect.height,
803 isLeft: true
804 });
805 event.preventDefault();
806 event.stopPropagation();
807 break;
808 } else if (type === "update-view-icon") {
809 const rect = target.getBoundingClientRect();
810 openEmojiPanel("", "av", {
811 x: rect.left,
812 y: rect.bottom + 4,
813 h: rect.height,
814 w: rect.width
815 }, (unicode) => {
816 transaction(options.protyle, [{
817 action: "setAttrViewViewIcon",
818 avID,
819 id: data.viewID,
820 data: unicode,
821 }], [{
822 action: "setAttrViewViewIcon",
823 id: data.viewID,
824 avID,
825 data: target.dataset.icon,
826 }]);
827 target.innerHTML = unicode ? unicode2Emoji(unicode) : '<svg style="width: 14px;height: 14px;"><use xlink:href="#iconTable"></use></svg>';
828 target.dataset.icon = unicode;
829 }, target.querySelector("img"));
830 event.preventDefault();
831 event.stopPropagation();
832 break;
833 } else if (type === "set-page-size") {
834 setPageSize({
835 target,
836 protyle: options.protyle,
837 avID,
838 nodeElement: options.blockElement
839 });
840 event.preventDefault();
841 event.stopPropagation();
842 break;
843 } else if (type === "duplicate-view") {
844 const id = Lute.NewNodeID();
845 transaction(options.protyle, [{
846 action: "duplicateAttrViewView",
847 avID,
848 previousID: data.viewID,
849 id,
850 blockID
851 }], [{
852 action: "removeAttrViewView",
853 avID,
854 id,
855 blockID
856 }]);
857 avPanelElement.remove();
858 event.preventDefault();
859 event.stopPropagation();
860 break;
861 } else if (type === "delete-view") {
862 transaction(options.protyle, [{
863 action: "removeAttrViewView",
864 avID,
865 id: data.viewID,
866 blockID
867 }]);
868 avPanelElement.remove();
869 event.preventDefault();
870 event.stopPropagation();
871 break;
872 } else if (type === "update-icon") {
873 const rect = target.getBoundingClientRect();
874 openEmojiPanel("", "av", {
875 x: rect.left,
876 y: rect.bottom + 4,
877 h: rect.height,
878 w: rect.width
879 }, (unicode) => {
880 const colId = menuElement.querySelector(".b3-menu__item").getAttribute("data-col-id");
881 transaction(options.protyle, [{
882 action: "setAttrViewColIcon",
883 id: colId,
884 avID,
885 data: unicode,
886 }], [{
887 action: "setAttrViewColIcon",
888 id: colId,
889 avID,
890 data: target.dataset.icon,
891 }]);
892 target.innerHTML = unicode ? unicode2Emoji(unicode) : `<svg style="height: 14px;width: 14px"><use xlink:href="#${getColIconByType(target.dataset.colType as TAVCol)}"></use></svg>`;
893 if (isCustomAttr) {
894 const iconElement = options.blockElement.querySelector(`.av__row[data-col-id="${colId}"] .block__logoicon`);
895 iconElement.outerHTML = unicode ? unicode2Emoji(unicode, "block__logoicon", true) : `<svg class="block__logoicon"><use xlink:href="#${getColIconByType(iconElement.nextElementSibling.getAttribute("data-type") as TAVCol)}"></use></svg>`;
896 } else {
897 updateAttrViewCellAnimation(options.blockElement.querySelector(`.av__row--header .av__cell[data-col-id="${colId}"]`), undefined, {icon: unicode});
898 }
899 target.dataset.icon = unicode;
900 }, target.querySelector("img"));
901 event.preventDefault();
902 event.stopPropagation();
903 break;
904 } else if (type === "showAllCol") {
905 const doOperations: IOperation[] = [];
906 const undoOperations: IOperation[] = [];
907 fields.forEach((item: IAVColumn) => {
908 if (item.hidden) {
909 doOperations.push({
910 action: "setAttrViewColHidden",
911 id: item.id,
912 avID,
913 data: false,
914 blockID,
915 });
916 undoOperations.push({
917 action: "setAttrViewColHidden",
918 id: item.id,
919 avID,
920 data: true,
921 blockID
922 });
923 item.hidden = false;
924 }
925 });
926 if (doOperations.length > 0) {
927 transaction(options.protyle, doOperations, undoOperations);
928 menuElement.innerHTML = getPropertiesHTML(fields);
929 setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height);
930 }
931 event.preventDefault();
932 event.stopPropagation();
933 break;
934 } else if (type === "hideAllCol") {
935 const doOperations: IOperation[] = [];
936 const undoOperations: IOperation[] = [];
937 fields.forEach((item: IAVColumn) => {
938 if (!item.hidden && item.type !== "block") {
939 doOperations.push({
940 action: "setAttrViewColHidden",
941 id: item.id,
942 avID,
943 data: true,
944 blockID
945 });
946 undoOperations.push({
947 action: "setAttrViewColHidden",
948 id: item.id,
949 avID,
950 data: false,
951 blockID
952 });
953 item.hidden = true;
954 }
955 });
956 if (doOperations.length > 0) {
957 transaction(options.protyle, doOperations, undoOperations);
958 menuElement.innerHTML = getPropertiesHTML(fields);
959 setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height);
960 }
961 event.preventDefault();
962 event.stopPropagation();
963 break;
964 } else if (type === "editCol") {
965 menuElement.innerHTML = getEditHTML({
966 protyle: options.protyle,
967 data,
968 colId: target.dataset.id,
969 isCustomAttr
970 });
971 bindEditEvent({protyle: options.protyle, data, menuElement, isCustomAttr, blockID});
972 setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height);
973 event.preventDefault();
974 event.stopPropagation();
975 break;
976 } else if (type === "updateColType") {
977 const colId = options.colId || menuElement.querySelector(".b3-menu__item").getAttribute("data-col-id");
978 if (target.dataset.newType !== target.dataset.oldType) {
979 const nameElement = avPanelElement.querySelector('.b3-text-field[data-type="name"]') as HTMLInputElement;
980 const name = nameElement.value;
981 let newName = name;
982 fields.find((item: IAVColumn) => {
983 if (item.id === colId) {
984 item.type = target.dataset.newType as TAVCol;
985 if (getColNameByType(target.dataset.oldType as TAVCol) === name) {
986 newName = getColNameByType(target.dataset.newType as TAVCol);
987 item.name = newName;
988 }
989 return true;
990 }
991 });
992
993 transaction(options.protyle, [{
994 action: "updateAttrViewCol",
995 id: colId,
996 avID,
997 name: newName,
998 type: target.dataset.newType as TAVCol,
999 }], [{
1000 action: "updateAttrViewCol",
1001 id: colId,
1002 avID,
1003 name,
1004 type: target.dataset.oldType as TAVCol,
1005 }]);
1006
1007 // 需要取消行号列的筛选和排序
1008 if (target.dataset.newType === "lineNumber") {
1009 const sortExist = data.view.sorts.find((sort) => sort.column === colId);
1010 if (sortExist) {
1011 const oldSorts = Object.assign([], data.view.sorts);
1012 const newSorts = data.view.sorts.filter((sort) => sort.column !== colId);
1013
1014 transaction(options.protyle, [{
1015 action: "setAttrViewSorts",
1016 avID: data.id,
1017 data: newSorts,
1018 blockID,
1019 }], [{
1020 action: "setAttrViewSorts",
1021 avID: data.id,
1022 data: oldSorts,
1023 blockID,
1024 }]);
1025 }
1026
1027 const filterExist = data.view.filters.find((filter) => filter.column === colId);
1028 if (filterExist) {
1029 const oldFilters = JSON.parse(JSON.stringify(data.view.filters));
1030 const newFilters = data.view.filters.filter((filter) => filter.column !== colId);
1031
1032 transaction(options.protyle, [{
1033 action: "setAttrViewFilters",
1034 avID: data.id,
1035 data: newFilters,
1036 blockID
1037 }], [{
1038 action: "setAttrViewFilters",
1039 avID: data.id,
1040 data: oldFilters,
1041 blockID
1042 }]);
1043 }
1044 }
1045 }
1046 menuElement.innerHTML = getEditHTML({
1047 protyle: options.protyle,
1048 data,
1049 colId,
1050 isCustomAttr
1051 });
1052 bindEditEvent({protyle: options.protyle, data, menuElement, isCustomAttr, blockID});
1053 setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height);
1054 event.preventDefault();
1055 event.stopPropagation();
1056 break;
1057 } else if (type === "goUpdateColType") {
1058 const editMenuElement = hasClosestByClassName(target, "b3-menu");
1059 if (editMenuElement) {
1060 editMenuElement.firstElementChild.classList.add("fn__none");
1061 editMenuElement.lastElementChild.classList.remove("fn__none");
1062 }
1063 setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height);
1064 event.preventDefault();
1065 event.stopPropagation();
1066 break;
1067 } else if (type === "goSearchAV") {
1068 openSearchAV(avID, target, undefined, false);
1069 event.preventDefault();
1070 event.stopPropagation();
1071 break;
1072 } else if (type === "goSearchRollupCol") {
1073 goSearchRollupCol({
1074 target,
1075 data,
1076 isRelation: true,
1077 protyle: options.protyle,
1078 colId: options.colId || menuElement.querySelector(".b3-menu__item").getAttribute("data-col-id")
1079 });
1080 event.preventDefault();
1081 event.stopPropagation();
1082 break;
1083 } else if (type === "goSearchRollupTarget") {
1084 goSearchRollupCol({
1085 target,
1086 data,
1087 isRelation: false,
1088 protyle: options.protyle,
1089 colId: options.colId || menuElement.querySelector(".b3-menu__item").getAttribute("data-col-id")
1090 });
1091 event.preventDefault();
1092 event.stopPropagation();
1093 break;
1094 } else if (type === "goSearchRollupCalc") {
1095 openCalcMenu(options.protyle, target, {
1096 data,
1097 colId: options.colId || menuElement.querySelector(".b3-menu__item").getAttribute("data-col-id"),
1098 blockID
1099 });
1100 event.preventDefault();
1101 event.stopPropagation();
1102 break;
1103 } else if (type === "updateRelation") {
1104 updateRelation({
1105 protyle: options.protyle,
1106 avElement: avPanelElement,
1107 avID,
1108 colsData: fields,
1109 blockElement: options.blockElement,
1110 });
1111 event.preventDefault();
1112 event.stopPropagation();
1113 break;
1114 } else if (type === "goEditCol") {
1115 const editMenuElement = hasClosestByClassName(target, "b3-menu");
1116 if (editMenuElement) {
1117 editMenuElement.firstElementChild.classList.remove("fn__none");
1118 editMenuElement.lastElementChild.classList.add("fn__none");
1119 }
1120 setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height);
1121 event.preventDefault();
1122 event.stopPropagation();
1123 break;
1124 } else if (type === "hideCol") {
1125 const isEdit = menuElement.querySelector('[data-type="go-properties"]');
1126 const colId = isEdit ? menuElement.querySelector(".b3-menu__item").getAttribute("data-col-id") : target.parentElement.getAttribute("data-id");
1127 transaction(options.protyle, [{
1128 action: "setAttrViewColHidden",
1129 id: colId,
1130 avID,
1131 data: true,
1132 blockID
1133 }], [{
1134 action: "setAttrViewColHidden",
1135 id: colId,
1136 avID,
1137 data: false,
1138 blockID
1139 }]);
1140 fields.find((item: IAVColumn) => item.id === colId).hidden = true;
1141 if (isEdit) {
1142 menuElement.innerHTML = getEditHTML({
1143 protyle: options.protyle,
1144 data,
1145 colId,
1146 isCustomAttr
1147 });
1148 bindEditEvent({protyle: options.protyle, data, menuElement, isCustomAttr, blockID});
1149 } else {
1150 menuElement.innerHTML = getPropertiesHTML(fields);
1151 }
1152 setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height);
1153 event.preventDefault();
1154 event.stopPropagation();
1155 break;
1156 } else if (type === "showCol") {
1157 const isEdit = menuElement.querySelector('[data-type="go-properties"]');
1158 const colId = isEdit ? menuElement.querySelector(".b3-menu__item").getAttribute("data-col-id") : target.parentElement.getAttribute("data-id");
1159 transaction(options.protyle, [{
1160 action: "setAttrViewColHidden",
1161 id: colId,
1162 avID,
1163 data: false,
1164 blockID
1165 }], [{
1166 action: "setAttrViewColHidden",
1167 id: colId,
1168 avID,
1169 data: true,
1170 blockID
1171 }]);
1172 fields.find((item: IAVColumn) => item.id === colId).hidden = false;
1173 if (isEdit) {
1174 menuElement.innerHTML = getEditHTML({
1175 protyle: options.protyle,
1176 data,
1177 colId,
1178 isCustomAttr
1179 });
1180 bindEditEvent({protyle: options.protyle, data, menuElement, isCustomAttr, blockID});
1181 } else {
1182 menuElement.innerHTML = getPropertiesHTML(fields);
1183 }
1184 setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height);
1185 event.preventDefault();
1186 event.stopPropagation();
1187 break;
1188 } else if (type === "duplicateCol") {
1189 duplicateCol({
1190 blockElement: options.blockElement,
1191 protyle: options.protyle,
1192 colId: menuElement.querySelector(".b3-menu__item").getAttribute("data-col-id"),
1193 data,
1194 viewID: data.viewID,
1195 });
1196 event.preventDefault();
1197 event.stopPropagation();
1198 break;
1199 } else if (type === "removeCol") {
1200 if (!isCustomAttr) {
1201 tabRect = options.blockElement.querySelector(".av__views").getBoundingClientRect();
1202 }
1203 const colId = menuElement.querySelector(".b3-menu__item").getAttribute("data-col-id");
1204 const colData = fields.find((item: IAVColumn) => {
1205 if (item.id === colId) {
1206 return true;
1207 }
1208 });
1209 const isTwoWay = colData.type === "relation" && colData.relation?.isTwoWay;
1210 if (isCustomAttr || isTwoWay) {
1211 const dialog = new Dialog({
1212 title: isTwoWay ? window.siyuan.languages.removeColConfirm : window.siyuan.languages.deleteOpConfirm,
1213 content: `<div class="b3-dialog__content">
1214 ${isTwoWay ? window.siyuan.languages.confirmRemoveRelationField
1215 .replace("${x}", menuElement.querySelector("input").value || window.siyuan.languages._kernel[272])
1216 .replace("${y}", menuElement.querySelector('.b3-menu__item[data-type="goSearchAV"] .b3-menu__accelerator').textContent)
1217 .replace("${z}", (menuElement.querySelector('input[data-type="colName"]') as HTMLInputElement).value || window.siyuan.languages._kernel[272])
1218 : window.siyuan.languages.removeCol.replace("${x}", menuElement.querySelector("input").value || window.siyuan.languages._kernel[272])}
1219 <div class="fn__hr--b"></div>
1220 <button class="fn__block b3-button b3-button--remove" data-action="delete">${isTwoWay ? window.siyuan.languages.removeBothRelationField : window.siyuan.languages.delete}</button>
1221 <div class="fn__hr"></div>
1222 <button class="fn__block b3-button b3-button--remove${isTwoWay ? "" : " fn__none"}" data-action="keep-relation">${window.siyuan.languages.removeButKeepRelationField}</button>
1223 <div class="fn__hr"></div>
1224 <button class="fn__block b3-button b3-button--cancel">${window.siyuan.languages.cancel}</button>
1225</div>`,
1226 width: "520px",
1227 });
1228 dialog.element.addEventListener("click", (dialogEvent) => {
1229 let target = dialogEvent.target as HTMLElement;
1230 const isDispatch = typeof dialogEvent.detail === "string";
1231 while (target && target !== dialog.element || isDispatch) {
1232 const action = target.getAttribute("data-action");
1233 if (action === "delete" || (isDispatch && dialogEvent.detail === "Enter")) {
1234 removeCol({
1235 protyle: options.protyle,
1236 fields,
1237 avID,
1238 blockID,
1239 menuElement,
1240 isCustomAttr,
1241 blockElement: options.blockElement,
1242 avPanelElement,
1243 tabRect,
1244 isTwoWay: true
1245 });
1246 dialog.destroy();
1247 break;
1248 } else if (action === "keep-relation") {
1249 removeCol({
1250 protyle: options.protyle,
1251 fields,
1252 avID,
1253 blockID,
1254 menuElement,
1255 isCustomAttr,
1256 blockElement: options.blockElement,
1257 avPanelElement,
1258 tabRect,
1259 isTwoWay: false
1260 });
1261 dialog.destroy();
1262 break;
1263 } else if (target.classList.contains("b3-button--cancel") || (isDispatch && dialogEvent.detail === "Escape")) {
1264 dialog.destroy();
1265 break;
1266 }
1267 target = target.parentElement;
1268 }
1269 });
1270 dialog.element.setAttribute("data-key", Constants.DIALOG_CONFIRM);
1271 } else {
1272 removeCol({
1273 protyle: options.protyle,
1274 fields,
1275 avID,
1276 blockID,
1277 menuElement,
1278 isCustomAttr,
1279 blockElement: options.blockElement,
1280 avPanelElement,
1281 tabRect,
1282 isTwoWay: false
1283 });
1284 }
1285 event.preventDefault();
1286 event.stopPropagation();
1287 break;
1288 } else if (type === "setColOption") {
1289 setColOption(options.protyle, data, target, options.blockElement, isCustomAttr, options.cellElements);
1290 event.preventDefault();
1291 event.stopPropagation();
1292 break;
1293 } else if (type === "setRelationCell") {
1294 menuElement.querySelector(".b3-menu__item--current")?.classList.remove("b3-menu__item--current");
1295 target.classList.add("b3-menu__item--current");
1296 setRelationCell(options.protyle, options.blockElement as HTMLElement, target, options.cellElements);
1297 event.preventDefault();
1298 event.stopPropagation();
1299 break;
1300 } else if (type === "addColOptionOrCell") {
1301 menuElement.querySelector(".b3-menu__item--current")?.classList.remove("b3-menu__item--current");
1302 target.classList.add("b3-menu__item--current");
1303 if (target.querySelector(".b3-menu__checked")) {
1304 removeCellOption(options.protyle, options.cellElements, menuElement.querySelector(`.b3-chips .b3-chip[data-content="${escapeAttr(target.dataset.name)}"]`), options.blockElement);
1305 } else {
1306 addColOptionOrCell(options.protyle, data, options.cellElements, target, menuElement, options.blockElement);
1307 }
1308 window.siyuan.menus.menu.remove();
1309 event.preventDefault();
1310 event.stopPropagation();
1311 break;
1312 } else if (type === "removeCellOption") {
1313 removeCellOption(options.protyle, options.cellElements, target.parentElement, options.blockElement);
1314 event.preventDefault();
1315 event.stopPropagation();
1316 break;
1317 } else if (type === "addAssetLink") {
1318 addAssetLink(options.protyle, options.cellElements, target, options.blockElement);
1319 event.preventDefault();
1320 event.stopPropagation();
1321 break;
1322 } else if (type === "addAssetExist") {
1323 const rect = target.getBoundingClientRect();
1324 assetMenu(options.protyle, {
1325 x: rect.right,
1326 y: rect.bottom,
1327 w: target.parentElement.clientWidth + 8,
1328 h: rect.height
1329 }, (url, name) => {
1330 let value: IAVCellAssetValue;
1331 if (Constants.SIYUAN_ASSETS_IMAGE.includes(pathPosix().extname(url).toLowerCase())) {
1332 value = {
1333 type: "image",
1334 content: url,
1335 name: ""
1336 };
1337 } else {
1338 value = {
1339 type: "file",
1340 content: url,
1341 name
1342 };
1343 }
1344 updateAssetCell({
1345 protyle: options.protyle,
1346 cellElements: options.cellElements,
1347 addValue: [value],
1348 blockElement: options.blockElement
1349 });
1350 window.siyuan.menus.menu.remove();
1351 });
1352 event.preventDefault();
1353 event.stopPropagation();
1354 break;
1355 } else if (type === "openAssetItem") {
1356 const assetLink = target.parentElement.dataset.content;
1357 const suffix = pathPosix().extname(assetLink);
1358 /// #if !MOBILE
1359 if (isLocalPath(assetLink) && (
1360 [".pdf"].concat(Constants.SIYUAN_ASSETS_AUDIO).concat(Constants.SIYUAN_ASSETS_VIDEO).includes(suffix) && (
1361 suffix !== ".pdf" || (suffix === ".pdf" && !assetLink.startsWith("file://"))
1362 )
1363 )) {
1364 openAsset(options.protyle.app, assetLink.trim(), parseInt(getSearch("page", assetLink)), "right");
1365 } else if (Constants.SIYUAN_ASSETS_IMAGE.includes(suffix)) {
1366 previewAttrViewImages(assetLink, avID, options.blockElement.getAttribute(Constants.CUSTOM_SY_AV_VIEW),
1367 (options.blockElement.querySelector('[data-type="av-search"]') as HTMLInputElement)?.value.trim() || "");
1368 } else {
1369 window.open(assetLink);
1370 }
1371 /// #else
1372 if (Constants.SIYUAN_ASSETS_IMAGE.includes(suffix)) {
1373 previewAttrViewImages(assetLink, avID, options.blockElement.getAttribute(Constants.CUSTOM_SY_AV_VIEW),
1374 (options.blockElement.querySelector('[data-type="av-search"]') as HTMLInputElement)?.value.trim() || "");
1375 } else {
1376 window.open(assetLink);
1377 }
1378 /// #endif
1379 event.preventDefault();
1380 event.stopPropagation();
1381 break;
1382 } else if (type === "editAssetItem") {
1383 editAssetItem({
1384 protyle: options.protyle,
1385 cellElements: options.cellElements,
1386 blockElement: options.blockElement,
1387 content: target.parentElement.dataset.content,
1388 type: target.parentElement.dataset.type as "image" | "file",
1389 name: target.parentElement.dataset.name,
1390 index: parseInt(target.parentElement.dataset.index),
1391 rect: target.parentElement.getBoundingClientRect()
1392 });
1393 event.preventDefault();
1394 event.stopPropagation();
1395 break;
1396 } else if (type === "clearDate") {
1397 const colData = fields.find((item: IAVColumn) => {
1398 if (item.id === getColId(options.cellElements[0], data.viewType)) {
1399 return true;
1400 }
1401 });
1402 updateCellsValue(options.protyle, options.blockElement as HTMLElement, {
1403 isNotEmpty2: false,
1404 isNotEmpty: false,
1405 content: null,
1406 content2: null,
1407 hasEndDate: false,
1408 isNotTime: colData.date ? !colData.date.fillSpecificTime : true,
1409 }, options.cellElements);
1410 avPanelElement.remove();
1411 event.preventDefault();
1412 event.stopPropagation();
1413 break;
1414 } else if (type === "av-add") {
1415 window.siyuan.menus.menu.remove();
1416 addView(options.protyle, options.blockElement);
1417 avPanelElement.remove();
1418 event.preventDefault();
1419 event.stopPropagation();
1420 break;
1421 } else if (type === "av-view-switch") {
1422 if (!target.parentElement.classList.contains("b3-menu__item--current")) {
1423 avPanelElement.querySelector(".b3-menu__item--current")?.classList.remove("b3-menu__item--current");
1424 target.parentElement.classList.add("b3-menu__item--current");
1425 transaction(options.protyle, [{
1426 action: "setAttrViewBlockView",
1427 blockID,
1428 id: target.parentElement.dataset.id,
1429 avID
1430 }], [{
1431 action: "setAttrViewBlockView",
1432 blockID,
1433 id: options.blockElement.querySelector(".av__views .item--focus").getAttribute("data-id"),
1434 avID
1435 }]);
1436 }
1437 event.preventDefault();
1438 event.stopPropagation();
1439 break;
1440 } else if (type === "av-view-edit") {
1441 if (target.parentElement.classList.contains("b3-menu__item--current")) {
1442 openViewMenu({
1443 protyle: options.protyle,
1444 blockElement: options.blockElement as HTMLElement,
1445 element: target.parentElement
1446 });
1447 } else {
1448 avPanelElement.querySelector(".b3-menu__item--current")?.classList.remove("b3-menu__item--current");
1449 target.parentElement.classList.add("b3-menu__item--current");
1450 transaction(options.protyle, [{
1451 action: "setAttrViewBlockView",
1452 blockID,
1453 id: target.parentElement.dataset.id,
1454 avID,
1455 }], [{
1456 action: "setAttrViewBlockView",
1457 blockID,
1458 id: options.blockElement.querySelector(".av__views .item--focus").getAttribute("data-id"),
1459 avID,
1460 }]);
1461 window.siyuan.menus.menu.remove();
1462 openViewMenu({
1463 protyle: options.protyle,
1464 blockElement: options.blockElement as HTMLElement,
1465 element: target.parentElement
1466 });
1467 }
1468 event.preventDefault();
1469 event.stopPropagation();
1470 break;
1471 } else if (type === "set-gallery-cover") {
1472 setGalleryCover({
1473 target,
1474 protyle: options.protyle,
1475 nodeElement: options.blockElement,
1476 view: data.view as IAVGallery
1477 });
1478 event.preventDefault();
1479 event.stopPropagation();
1480 break;
1481 } else if (type === "set-gallery-size") {
1482 setGallerySize({
1483 target,
1484 protyle: options.protyle,
1485 nodeElement: options.blockElement,
1486 view: data.view as IAVGallery
1487 });
1488 event.preventDefault();
1489 event.stopPropagation();
1490 break;
1491 } else if (type === "set-gallery-ratio") {
1492 setGalleryRatio({
1493 target,
1494 protyle: options.protyle,
1495 nodeElement: options.blockElement,
1496 view: data.view as IAVGallery
1497 });
1498 event.preventDefault();
1499 event.stopPropagation();
1500 break;
1501 } else if (type === "set-layout") {
1502 data = await updateLayout({
1503 target,
1504 protyle: options.protyle,
1505 nodeElement: options.blockElement,
1506 data
1507 });
1508 fields = getFieldsByData(data);
1509 event.preventDefault();
1510 event.stopPropagation();
1511 break;
1512 } else if (type === "goGroupsDate") {
1513 goGroupsDate({
1514 target,
1515 menuElement,
1516 protyle: options.protyle,
1517 blockElement: options.blockElement,
1518 data
1519 });
1520 fields = getFieldsByData(data);
1521 event.stopPropagation();
1522 event.preventDefault();
1523 break;
1524 } else if (type === "goGroupsSort") {
1525 goGroupsSort({
1526 target,
1527 menuElement,
1528 protyle: options.protyle,
1529 blockElement: options.blockElement,
1530 data
1531 });
1532 fields = getFieldsByData(data);
1533 event.stopPropagation();
1534 event.preventDefault();
1535 break;
1536 } else if (type === "setGroupMethod") {
1537 setGroupMethod({
1538 protyle: options.protyle,
1539 fieldId: target.getAttribute("data-id"),
1540 data,
1541 menuElement,
1542 blockElement: options.blockElement,
1543 });
1544 event.preventDefault();
1545 event.stopPropagation();
1546 break;
1547 } else if (type === "goGroups") {
1548 if (menuElement.querySelector('[data-type="avGroupRange"]') && closeCB) {
1549 await closeCB();
1550 }
1551 closeCB = undefined;
1552 if ((data.view.group && data.view.group.field) || target.classList.contains("block__icon")) {
1553 menuElement.innerHTML = getGroupsHTML(fields, data.view);
1554 bindGroupsEvent({
1555 protyle: options.protyle,
1556 menuElement: menuElement,
1557 blockElement: options.blockElement,
1558 data
1559 });
1560 } else {
1561 menuElement.innerHTML = getGroupsMethodHTML(fields, data.view.group);
1562 }
1563 setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height);
1564 event.preventDefault();
1565 event.stopPropagation();
1566 break;
1567 } else if (type === "goGroupsMethod") {
1568 window.siyuan.menus.menu.remove();
1569 menuElement.innerHTML = getGroupsMethodHTML(fields, data.view.group);
1570 setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height);
1571 event.preventDefault();
1572 event.stopPropagation();
1573 break;
1574 } else if (type === "getGroupsNumber") {
1575 window.siyuan.menus.menu.remove();
1576 menuElement.innerHTML = getGroupsNumberHTML(data.view.group);
1577 setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height);
1578 closeCB = bindGroupsNumber({
1579 protyle: options.protyle,
1580 data,
1581 menuElement,
1582 blockElement: options.blockElement
1583 });
1584 event.preventDefault();
1585 event.stopPropagation();
1586 break;
1587 } else if (type === "hideGroup") {
1588 window.siyuan.menus.menu.remove();
1589 const useElement = target.firstElementChild;
1590 const isHide = useElement.getAttribute("xlink:href") !== "#iconEye";
1591 useElement.setAttribute("xlink:href", isHide ? "#iconEye" : "#iconEyeoff");
1592 let oldGroupHidden;
1593 let showCount = 0;
1594 data.view.groups.forEach((item) => {
1595 if (item.id === target.dataset.id) {
1596 oldGroupHidden = item.groupHidden;
1597 item.groupHidden = isHide ? 0 : 2;
1598 }
1599 if (item.groupHidden === 0) {
1600 showCount++;
1601 }
1602 });
1603 target.parentElement.classList[isHide ? "remove" : "add"]("b3-menu__item--hidden");
1604 menuElement.querySelector('[data-type="hideGroups"]').innerHTML = `${window.siyuan.languages[showCount === 0 ? "showAll" : "hideAll"]}
1605<span class="fn__space"></span>
1606<svg><use xlink:href="#iconEye${showCount === 0 ? "" : "off"}"></use></svg>`;
1607 transaction(options.protyle, [{
1608 action: "hideAttrViewGroup",
1609 avID: data.id,
1610 blockID,
1611 id: target.dataset.id,
1612 data: isHide ? 0 : 2,
1613 }], [{
1614 action: "hideAttrViewGroup",
1615 avID: data.id,
1616 blockID,
1617 id: target.dataset.id,
1618 data: oldGroupHidden
1619 }]);
1620 event.preventDefault();
1621 event.stopPropagation();
1622 break;
1623 } else if (type === "hideGroups") {
1624 window.siyuan.menus.menu.remove();
1625 const isShow = target.querySelector("use").getAttribute("xlink:href") === "#iconEyeoff";
1626 target.innerHTML = `${window.siyuan.languages[isShow ? "showAll" : "hideAll"]}
1627<span class="fn__space"></span>
1628<svg><use xlink:href="#iconEye${isShow ? "" : "off"}"></use></svg>`;
1629 data.view.groups.forEach((item) => {
1630 item.groupHidden = isShow ? 2 : 0;
1631 const itemElement = target.parentElement.parentElement.querySelector(`.b3-menu__item[data-id="${item.id}"]`);
1632 itemElement.classList[isShow ? "add" : "remove"]("b3-menu__item--hidden");
1633 itemElement.querySelector(".b3-menu__action use")?.setAttribute("xlink:href", `#iconEye${isShow ? "off" : ""}`);
1634 });
1635 transaction(options.protyle, [{
1636 action: "hideAttrViewAllGroups",
1637 avID: data.id,
1638 blockID,
1639 data: isShow,
1640 }], [{
1641 action: "hideAttrViewAllGroups",
1642 avID: data.id,
1643 blockID,
1644 data: !isShow
1645 }]);
1646 event.preventDefault();
1647 event.stopPropagation();
1648 break;
1649 } else if (type === "removeGroups") {
1650 window.siyuan.menus.menu.remove();
1651 transaction(options.protyle, [{
1652 action: "removeAttrViewGroup",
1653 avID: data.id,
1654 blockID,
1655 }], [{
1656 action: "setAttrViewGroup",
1657 avID: data.id,
1658 blockID,
1659 data: data.view.group
1660 }]);
1661 data.view.group = null;
1662 delete data.view.groups;
1663 menuElement.innerHTML = getGroupsHTML(fields, data.view);
1664 setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height);
1665 event.preventDefault();
1666 event.stopPropagation();
1667 break;
1668 }
1669 // 有错误日志,没找到重现步骤,需先判断一下
1670 if (!target || !target.parentElement) {
1671 break;
1672 }
1673 target = target.parentElement;
1674 }
1675 });
1676 });
1677};
1678
1679export const getPropertiesHTML = (fields: IAVColumn[]) => {
1680 let showHTML = "";
1681 let hideHTML = "";
1682 fields.forEach((item: IAVColumn) => {
1683 if (item.hidden) {
1684 hideHTML += `<button class="b3-menu__item" data-type="editCol" draggable="true" data-id="${item.id}">
1685 <svg class="b3-menu__icon fn__grab"><use xlink:href="#iconDrag"></use></svg>
1686 <div class="b3-menu__label fn__flex">
1687 ${item.icon ? unicode2Emoji(item.icon, "b3-menu__icon", true) : `<svg class="b3-menu__icon"><use xlink:href="#${getColIconByType(item.type)}"></use></svg>`}
1688 ${escapeHtml(item.name) || " "}
1689 </div>
1690 <svg class="b3-menu__action" data-type="showCol"><use xlink:href="#iconEye"></use></svg>
1691 <svg class="b3-menu__icon b3-menu__icon--small"><use xlink:href="#iconRight"></use></svg>
1692</button>`;
1693 } else {
1694 showHTML += `<button class="b3-menu__item" data-type="editCol" draggable="true" data-id="${item.id}">
1695 <svg class="b3-menu__icon fn__grab"><use xlink:href="#iconDrag"></use></svg>
1696 <div class="b3-menu__label fn__flex">
1697 ${item.icon ? unicode2Emoji(item.icon, "b3-menu__icon", true) : `<svg class="b3-menu__icon"><use xlink:href="#${getColIconByType(item.type)}"></use></svg>`}
1698 ${escapeHtml(item.name) || " "}
1699 </div>
1700 <svg class="b3-menu__action${item.type === "block" ? " fn__none" : ""}" data-type="hideCol"><use xlink:href="#iconEyeoff"></use></svg>
1701 <svg class="b3-menu__icon b3-menu__icon--small"><use xlink:href="#iconRight"></use></svg>
1702</button>`;
1703 }
1704 });
1705 if (hideHTML) {
1706 hideHTML = `<button class="b3-menu__separator"></button>
1707<button class="b3-menu__item" data-type="nobg">
1708 <span class="b3-menu__label">
1709 ${window.siyuan.languages.hideCol}
1710 </span>
1711 <span class="block__icon" data-type="showAllCol">
1712 ${window.siyuan.languages.showAll}
1713 <span class="fn__space"></span>
1714 <svg><use xlink:href="#iconEye"></use></svg>
1715 </span>
1716</button>
1717${hideHTML}`;
1718 }
1719 return `<div class="b3-menu__items">
1720<button class="b3-menu__item" data-type="nobg">
1721 <span class="block__icon" style="padding: 8px;margin-left: -4px;" data-type="go-config">
1722 <svg><use xlink:href="#iconLeft"></use></svg>
1723 </span>
1724 <span class="b3-menu__label ft__center">${window.siyuan.languages.fields}</span>
1725</button>
1726<button class="b3-menu__separator"></button>
1727<button class="b3-menu__item" data-type="nobg">
1728 <span class="b3-menu__label">
1729 ${window.siyuan.languages.showCol}
1730 </span>
1731 <span class="block__icon" data-type="hideAllCol">
1732 ${window.siyuan.languages.hideAll}
1733 <span class="fn__space"></span>
1734 <svg><use xlink:href="#iconEyeoff"></use></svg>
1735 </span>
1736</button>
1737${showHTML}
1738${hideHTML}
1739<button class="b3-menu__separator"></button>
1740<button class="b3-menu__item" data-type="newCol">
1741 <svg class="b3-menu__icon"><use xlink:href="#iconAdd"></use></svg>
1742 <span class="b3-menu__label">${window.siyuan.languages.new}</span>
1743</button>
1744</div>`;
1745};
1746