A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
1import {fetchPost} from "../util/fetch";
2import {Dialog} from "../dialog";
3import {isMobile} from "../util/functions";
4import {hideMessage, showMessage} from "../dialog/message";
5import {confirmDialog} from "../dialog/confirmDialog";
6import {hideElements} from "../protyle/ui/hideElements";
7import {viewCards} from "./viewCards";
8import {Constants} from "../constants";
9import {escapeAttr, escapeHtml} from "../util/escape";
10import {transaction} from "../protyle/wysiwyg/transaction";
11import {App} from "../index";
12
13export const genCardItem = (item: ICardPackage) => {
14 return `<li data-id="${item.id}" data-name="${escapeAttr(item.name)}" class="b3-list-item b3-list-item--narrow${isMobile() ? "" : " b3-list-item--hide-action"}">
15<span class="b3-list-item__text">
16 <span>${escapeHtml(item.name)}</span>
17 <span class="b3-list-item__meta">${item.size}</span>
18</span>
19<span data-type="rename" class="b3-list-item__action b3-tooltips b3-tooltips__w" aria-label="${window.siyuan.languages.rename}">
20 <svg><use xlink:href="#iconEdit"></use></svg>
21</span>
22<span data-type="delete" class="b3-list-item__action b3-tooltips b3-tooltips__w" aria-label="${window.siyuan.languages.delete}">
23 <svg><use xlink:href="#iconTrashcan"></use></svg>
24</span>
25<span data-type="view" class="b3-list-item__action b3-tooltips b3-tooltips__w" aria-label="${window.siyuan.languages.cardPreview}">
26 <svg><use xlink:href="#iconEye"></use></svg>
27</span>
28<span data-type="remove" class="b3-list-item__action b3-list-item__action--warning b3-tooltips b3-tooltips__w" aria-label="${window.siyuan.languages.removeDeck}">
29 <svg><use xlink:href="#iconMin"></use></svg>
30</span>
31<span data-type="add" style="display: flex" class="b3-list-item__action b3-tooltips b3-tooltips__w" aria-label="${window.siyuan.languages.addDeck}">
32 <svg><use xlink:href="#iconAdd"></use></svg>
33</span>
34<span class="b3-list-item__meta${isMobile() ? " fn__none" : ""}">${item.updated}</span>
35</li>`;
36};
37
38export const makeCard = (app: App, ids: string[]) => {
39 window.siyuan.dialogs.find(item => {
40 if (item.element.getAttribute("data-key") === Constants.DIALOG_MAKECARD) {
41 hideElements(["dialog"]);
42 return true;
43 }
44 });
45 fetchPost("/api/riff/getRiffDecks", {}, (response) => {
46 let html = "";
47 response.data.forEach((item: ICardPackage) => {
48 html += genCardItem(item);
49 });
50 const dialog = new Dialog({
51 positionId: Constants.DIALOG_MAKECARD,
52 width: isMobile() ? "92vw" : "50vw",
53 height: "70vh",
54 title: window.siyuan.languages.riffCard,
55 content: `<div class="b3-dialog__content fn__flex-column" style="box-sizing: border-box;height: 100%">
56 <div class="fn__flex">
57 <input class="b3-text-field fn__flex-1">
58 <span class="fn__space"></span>
59 <span data-type="create" class="block__icon block__icon--show b3-tooltips b3-tooltips__w" aria-label="${window.siyuan.languages.createDeck}">
60 <svg><use xlink:href="#iconAdd"></use></svg>
61 </span>
62 <span class="fn__space"></span>
63 <span data-type="viewall" class="block__icon block__icon--show b3-tooltips b3-tooltips__w" aria-label="${window.siyuan.languages.cardPreview}">
64 <svg><use xlink:href="#iconEye"></use></svg>
65 </span>
66 </div>
67 <div class="fn__hr"></div>
68 <ul class="b3-list b3-list--background fn__flex-1">${html}</ul>
69</div>`,
70 });
71 dialog.element.setAttribute("data-key", Constants.DIALOG_MAKECARD);
72 dialog.element.addEventListener("click", (event) => {
73 let target = event.target as HTMLElement;
74 while (target && target !== dialog.element) {
75 const type = target.getAttribute("data-type");
76 if (type === "create") {
77 let msgId = "";
78 const inputElement = dialog.element.querySelector(".b3-text-field") as HTMLInputElement;
79 if (inputElement.value) {
80 if (msgId) {
81 hideMessage(msgId);
82 }
83 fetchPost("/api/riff/createRiffDeck", {name: inputElement.value}, (response) => {
84 dialog.element.querySelector(".b3-list").insertAdjacentHTML("afterbegin", genCardItem(response.data));
85 inputElement.value = "";
86 });
87 } else {
88 msgId = showMessage(window.siyuan.languages._kernel[142]);
89 inputElement.focus();
90 }
91 event.stopPropagation();
92 event.preventDefault();
93 break;
94 } else if (type === "add") {
95 fetchPost("/api/riff/addRiffCards", {
96 deckID: target.parentElement.getAttribute("data-id"),
97 blockIDs: ids
98 }, (addResponse) => {
99 target.parentElement.outerHTML = genCardItem(addResponse.data);
100 });
101 event.stopPropagation();
102 event.preventDefault();
103 break;
104 } else if (type === "remove") {
105 fetchPost("/api/riff/removeRiffCards", {
106 deckID: target.parentElement.getAttribute("data-id"),
107 blockIDs: ids
108 }, (removeResponse) => {
109 target.parentElement.outerHTML = genCardItem(removeResponse.data);
110 });
111 event.stopPropagation();
112 event.preventDefault();
113 break;
114 } else if (type === "delete") {
115 confirmDialog(window.siyuan.languages.deleteOpConfirm, `${window.siyuan.languages.confirmDelete} <b>${escapeHtml(target.parentElement.getAttribute("data-name"))}</b>?`, () => {
116 fetchPost("/api/riff/removeRiffDeck", {
117 deckID: target.parentElement.getAttribute("data-id"),
118 }, () => {
119 target.parentElement.remove();
120 });
121 }, undefined, true);
122 event.stopPropagation();
123 event.preventDefault();
124 break;
125 } else if (type === "view") {
126 viewCards(app, target.parentElement.getAttribute("data-id"), target.parentElement.getAttribute("data-name"), "", (removeResponse) => {
127 target.parentElement.outerHTML = genCardItem(removeResponse.data);
128 });
129 event.stopPropagation();
130 event.preventDefault();
131 break;
132 } else if (type === "viewall") {
133 viewCards(app, "", window.siyuan.languages.all, "");
134 event.stopPropagation();
135 event.preventDefault();
136 break;
137 } else if (type === "rename") {
138 const renameDialog = new Dialog({
139 title: window.siyuan.languages.rename,
140 content: `<div class="b3-dialog__content"><input class="b3-text-field fn__block" value=""></div>
141<div class="b3-dialog__action">
142 <button class="b3-button b3-button--cancel">${window.siyuan.languages.cancel}</button><div class="fn__space"></div>
143 <button class="b3-button b3-button--text">${window.siyuan.languages.confirm}</button>
144</div>`,
145 width: isMobile() ? "92vw" : "520px",
146 });
147 const inputElement = renameDialog.element.querySelector("input") as HTMLInputElement;
148 const btnsElement = renameDialog.element.querySelectorAll(".b3-button");
149 renameDialog.bindInput(inputElement, () => {
150 (btnsElement[1] as HTMLButtonElement).click();
151 });
152 inputElement.value = target.parentElement.getAttribute("data-name");
153 inputElement.focus();
154 inputElement.select();
155 btnsElement[0].addEventListener("click", () => {
156 renameDialog.destroy();
157 });
158 btnsElement[1].addEventListener("click", () => {
159 fetchPost("/api/riff/renameRiffDeck", {
160 name: inputElement.value,
161 deckID: target.parentElement.getAttribute("data-id"),
162 }, () => {
163 target.parentElement.querySelector(".b3-list-item__text span").textContent = inputElement.value;
164 target.parentElement.setAttribute("data-name", inputElement.value);
165 });
166 renameDialog.destroy();
167 });
168 event.stopPropagation();
169 event.preventDefault();
170 break;
171 }
172 target = target.parentElement;
173 }
174 });
175 });
176};
177
178export const quickMakeCard = (protyle: IProtyle, nodeElement: Element[]) => {
179 let isRemove = true;
180 const ids: string[] = [];
181 nodeElement.forEach(item => {
182 if (item.getAttribute("data-type") === "NodeThematicBreak") {
183 return;
184 }
185 item.classList.remove("protyle-wysiwyg--select");
186 ids.push(item.getAttribute("data-node-id"));
187 if ((item.getAttribute(Constants.CUSTOM_RIFF_DECKS) || "").indexOf(Constants.QUICK_DECK_ID) === -1) {
188 isRemove = false;
189 }
190 });
191 if (isRemove) {
192 transaction(protyle, [{
193 action: "removeFlashcards",
194 deckID: Constants.QUICK_DECK_ID,
195 blockIDs: ids
196 }], [{
197 action: "addFlashcards",
198 deckID: Constants.QUICK_DECK_ID,
199 blockIDs: ids
200 }]);
201 } else {
202 transaction(protyle, [{
203 action: "addFlashcards",
204 deckID: Constants.QUICK_DECK_ID,
205 blockIDs: ids
206 }], [{
207 action: "removeFlashcards",
208 deckID: Constants.QUICK_DECK_ID,
209 blockIDs: ids
210 }]);
211 }
212};
213
214
215