A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
1import {Menu} from "../../../plugin/Menu";
2import {getColIconByType} from "./col";
3import {transaction} from "../../wysiwyg/transaction";
4import {setPosition} from "../../../util/setPosition";
5import {unicode2Emoji} from "../../../emoji";
6import {getFieldsByData} from "./view";
7import {Constants} from "../../../constants";
8
9export const addSort = (options: {
10 data: IAV,
11 rect: DOMRect,
12 menuElement: HTMLElement,
13 tabRect: DOMRect,
14 avId: string,
15 protyle: IProtyle,
16 blockID: string,
17}) => {
18 const menu = new Menu(Constants.MENU_AV_ADD_SORT);
19 const fields = getFieldsByData(options.data);
20 fields.forEach((column) => {
21 let hasSort = false;
22
23 // 如果该列是行号类型列,不允许添加排序
24 if (column.type === "lineNumber") {
25 hasSort = true;
26 } else {
27 options.data.view.sorts.find((sort) => {
28 if (sort.column === column.id) {
29 hasSort = true;
30 return true;
31 }
32 });
33 }
34
35 if (!hasSort) {
36 menu.addItem({
37 label: column.name,
38 iconHTML: column.icon ? unicode2Emoji(column.icon, "b3-menu__icon", true) : `<svg class="b3-menu__icon"><use xlink:href="#${getColIconByType(column.type)}"></use></svg>`,
39 click: () => {
40 const oldSorts = Object.assign([], options.data.view.sorts);
41 options.data.view.sorts.push({
42 column: column.id,
43 order: "ASC",
44 });
45 transaction(options.protyle, [{
46 action: "setAttrViewSorts",
47 avID: options.data.id,
48 data: options.data.view.sorts,
49 blockID: options.blockID,
50 }], [{
51 action: "setAttrViewSorts",
52 avID: options.data.id,
53 data: oldSorts,
54 blockID: options.blockID,
55 }]);
56 options.menuElement.innerHTML = getSortsHTML(fields, options.data.view.sorts);
57 bindSortsEvent(options.protyle, options.menuElement, options.data, options.blockID);
58 setPosition(options.menuElement, options.tabRect.right - options.menuElement.clientWidth, options.tabRect.bottom, options.tabRect.height);
59 }
60 });
61 }
62 });
63 menu.open({
64 x: options.rect.left,
65 y: options.rect.bottom,
66 h: options.rect.height,
67 });
68};
69
70export const bindSortsEvent = (protyle: IProtyle, menuElement: HTMLElement, data: IAV, blockID: string) => {
71 menuElement.querySelectorAll("select").forEach((item: HTMLSelectElement) => {
72 item.addEventListener("change", () => {
73 const colId = item.parentElement.getAttribute("data-id");
74 const oldSort = JSON.parse(JSON.stringify(data.view.sorts));
75 if (item.previousElementSibling.classList.contains("b3-menu__icon")) {
76 data.view.sorts.find((sort: IAVSort) => {
77 if (sort.column === colId) {
78 sort.column = item.value;
79 item.parentElement.setAttribute("data-id", item.value);
80 return true;
81 }
82 });
83 } else {
84 data.view.sorts.find((sort: IAVSort) => sort.column === colId).order = item.value as "ASC" | "DESC";
85 }
86 transaction(protyle, [{
87 action: "setAttrViewSorts",
88 avID: data.id,
89 data: data.view.sorts,
90 blockID
91 }], [{
92 action: "setAttrViewSorts",
93 avID: data.id,
94 data: oldSort,
95 blockID
96 }]);
97 });
98 });
99};
100
101export const getSortsHTML = (columns: IAVColumn[], sorts: IAVSort[]) => {
102 let html = "";
103 const genSortItem = (id: string) => {
104 let sortHTML = "";
105 columns.forEach((item) => {
106 sortHTML += `<option value="${item.id}" ${item.id === id ? "selected" : ""}>${item.icon && unicode2Emoji(item.icon)}${item.name}</option>`;
107 });
108 return sortHTML;
109 };
110 sorts.forEach((item: IAVSort) => {
111 html += `<button draggable="true" class="b3-menu__item" data-id="${item.column}">
112 <svg class="b3-menu__icon fn__grab"><use xlink:href="#iconDrag"></use></svg>
113 <select class="b3-select fn__flex-1" style="margin: 4px 0">
114 ${genSortItem(item.column)}
115 </select>
116 <span class="fn__space"></span>
117 <select class="b3-select" style="margin: 4px 0">
118 <option value="ASC" ${item.order === "ASC" ? "selected" : ""}>${window.siyuan.languages.asc}</option>
119 <option value="DESC" ${item.order === "DESC" ? "selected" : ""}>${window.siyuan.languages.desc}</option>
120 </select>
121 <svg class="b3-menu__action" data-type="removeSort"><use xlink:href="#iconTrashcan"></use></svg>
122</button>`;
123 });
124 return `<div class="b3-menu__items">
125<button class="b3-menu__item" data-type="nobg">
126 <span class="block__icon" style="padding: 8px;margin-left: -4px;" data-type="go-config">
127 <svg><use xlink:href="#iconLeft"></use></svg>
128 </span>
129 <span class="b3-menu__label ft__center">${window.siyuan.languages.sort}</span>
130</button>
131<button class="b3-menu__separator"></button>
132${html}
133<button class="b3-menu__item${sorts.length === columns.length ? " fn__none" : ""}" data-type="addSort">
134 <svg class="b3-menu__icon"><use xlink:href="#iconAdd"></use></svg>
135 <span class="b3-menu__label">${window.siyuan.languages.addSort}</span>
136</button>
137<button class="b3-menu__item b3-menu__item--warning${html ? "" : " fn__none"}" data-type="removeSorts">
138 <svg class="b3-menu__icon"><use xlink:href="#iconTrashcan"></use></svg>
139 <span class="b3-menu__label">${window.siyuan.languages.removeSorts}</span>
140</button>
141</div>`;
142};