A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
1import {Constants} from "../constants";
2import {fetchPost} from "../util/fetch";
3/// #if !MOBILE
4import {exportLayout} from "../layout/util";
5/// #endif
6import {getAllEditor, getAllModels} from "../layout/getAll";
7import {getDockByType} from "../layout/tabUtil";
8import {Files} from "../layout/dock/Files";
9/// #if !BROWSER
10import {ipcRenderer} from "electron";
11/// #endif
12import {hideMessage, showMessage} from "./message";
13import {Dialog} from "./index";
14import {isMobile} from "../util/functions";
15import {confirmDialog} from "./confirmDialog";
16import {escapeHtml} from "../util/escape";
17import {getWorkspaceName} from "../util/noRelyPCFunction";
18import {needSubscribe} from "../util/needSubscribe";
19import {redirectToCheckAuth, setNoteBook} from "../util/pathName";
20import {reloadProtyle} from "../protyle/util/reload";
21import {Tab} from "../layout/Tab";
22import {setEmpty} from "../mobile/util/setEmpty";
23import {hideAllElements, hideElements} from "../protyle/ui/hideElements";
24import {App} from "../index";
25import {saveScroll} from "../protyle/scroll/saveScroll";
26import {isInAndroid, isInHarmony, isInIOS, setStorageVal} from "../protyle/util/compatibility";
27import {Plugin} from "../plugin";
28
29const updateTitle = (rootID: string, tab: Tab, protyle?: IProtyle) => {
30 fetchPost("/api/block/getDocInfo", {
31 id: rootID
32 }, (response) => {
33 tab.updateTitle(response.data.name);
34 if (protyle && protyle.title) {
35 protyle.title.setTitle(response.data.name);
36 }
37 });
38};
39
40export const reloadSync = (
41 app: App,
42 data: { upsertRootIDs: string[], removeRootIDs: string[] },
43 hideMsg = true,
44 // 同步的时候需要更新只读状态 https://github.com/siyuan-note/siyuan/issues/11517
45 // 调整大纲的时候需要使用现有状态 https://github.com/siyuan-note/siyuan/issues/11808
46 updateReadonly = true,
47 onlyUpdateDoc = false
48) => {
49 if (hideMsg) {
50 hideMessage();
51 }
52 /// #if MOBILE
53 if (window.siyuan.mobile.popEditor) {
54 if (data.removeRootIDs.includes(window.siyuan.mobile.popEditor.protyle.block.rootID)) {
55 hideElements(["dialog"]);
56 } else {
57 reloadProtyle(window.siyuan.mobile.popEditor.protyle, false, updateReadonly);
58 }
59 }
60 if (window.siyuan.mobile.editor) {
61 if (data.removeRootIDs.includes(window.siyuan.mobile.editor.protyle.block.rootID)) {
62 setEmpty(app);
63 } else {
64 reloadProtyle(window.siyuan.mobile.editor.protyle, false, updateReadonly);
65 fetchPost("/api/block/getDocInfo", {
66 id: window.siyuan.mobile.editor.protyle.block.rootID
67 }, (response) => {
68 setTitle(response.data.name);
69 window.siyuan.mobile.editor.protyle.title.setTitle(response.data.name);
70 });
71 }
72 }
73 setNoteBook(() => {
74 window.siyuan.mobile.docks.file.init(false);
75 });
76 /// #else
77 const allModels = getAllModels();
78 allModels.editor.forEach(item => {
79 if (data.upsertRootIDs.includes(item.editor.protyle.block.rootID)) {
80 fetchPost("/api/block/getDocInfo", {
81 id: item.editor.protyle.block.rootID,
82 }, (response) => {
83 item.editor.protyle.wysiwyg.renderCustom(response.data.ial);
84 reloadProtyle(item.editor.protyle, false, updateReadonly);
85 updateTitle(item.editor.protyle.block.rootID, item.parent, item.editor.protyle);
86 });
87 } else if (data.removeRootIDs.includes(item.editor.protyle.block.rootID)) {
88 item.parent.parent.removeTab(item.parent.id, false, false);
89 delete window.siyuan.storage[Constants.LOCAL_FILEPOSITION][item.editor.protyle.block.rootID];
90 setStorageVal(Constants.LOCAL_FILEPOSITION, window.siyuan.storage[Constants.LOCAL_FILEPOSITION]);
91 }
92 });
93 allModels.graph.forEach(item => {
94 if (item.type === "local" && data.removeRootIDs.includes(item.rootId)) {
95 item.parent.parent.removeTab(item.parent.id, false, false);
96 } else if (item.type !== "local" || data.upsertRootIDs.includes(item.rootId)) {
97 item.searchGraph(false);
98 if (item.type === "local") {
99 updateTitle(item.rootId, item.parent);
100 }
101 }
102 });
103 allModels.outline.forEach(item => {
104 if (item.type === "local" && data.removeRootIDs.includes(item.blockId)) {
105 item.parent.parent.removeTab(item.parent.id, false, false);
106 } else if (item.type !== "local" || data.upsertRootIDs.includes(item.blockId)) {
107 fetchPost("/api/outline/getDocOutline", {
108 id: item.blockId,
109 preview: item.isPreview
110 }, response => {
111 item.update(response);
112 });
113 if (item.type === "local") {
114 updateTitle(item.blockId, item.parent);
115 }
116 }
117 });
118 allModels.backlink.forEach(item => {
119 if (item.type === "local" && data.removeRootIDs.includes(item.rootId)) {
120 item.parent.parent.removeTab(item.parent.id, false, false);
121 } else {
122 item.refresh();
123 if (item.type === "local") {
124 updateTitle(item.rootId, item.parent);
125 }
126 }
127 });
128 if (!onlyUpdateDoc) {
129 allModels.files.forEach(item => {
130 setNoteBook(() => {
131 item.init(false);
132 });
133 });
134 }
135 allModels.bookmark.forEach(item => {
136 item.update();
137 });
138 allModels.tag.forEach(item => {
139 item.update();
140 });
141 // NOTE asset 无法获取推送地址,先不处理
142 allModels.search.forEach(item => {
143 item.parent.panelElement.querySelector("#searchInput").dispatchEvent(new CustomEvent("input"));
144 });
145 allModels.custom.forEach(item => {
146 if (item.update) {
147 item.update();
148 }
149 });
150 /// #endif
151};
152
153export const setRefDynamicText = (data: {
154 "blockID": string,
155 "defBlockID": string,
156 "refText": string,
157 "rootID": string
158}) => {
159 getAllEditor().forEach(editor => {
160 // 不能对比 rootId,否则嵌入块中的锚文本无法更新
161 editor.protyle.wysiwyg.element.querySelectorAll(`[data-node-id="${data.blockID}"] span[data-type~="block-ref"][data-subtype="d"][data-id="${data.defBlockID}"]`).forEach(item => {
162 item.innerHTML = data.refText;
163 });
164 });
165};
166
167export const setDefRefCount = (data: {
168 "blockID": string,
169 "refCount": number,
170 "rootRefCount": number,
171 "rootID": string
172}) => {
173 getAllEditor().forEach(editor => {
174 if (editor.protyle.block.rootID === data.rootID && editor.protyle.title) {
175 const attrElement = editor.protyle.title.element.querySelector(".protyle-attr");
176 const countElement = attrElement.querySelector(".protyle-attr--refcount");
177 if (countElement) {
178 if (data.rootRefCount === 0) {
179 countElement.remove();
180 } else {
181 countElement.textContent = data.rootRefCount.toString();
182 }
183 } else if (data.rootRefCount > 0) {
184 attrElement.insertAdjacentHTML("beforeend", `<div class="protyle-attr--refcount popover__block">${data.rootRefCount}</div>`);
185 }
186 }
187 if (data.rootID === data.blockID) {
188 return;
189 }
190 // 不能对比 rootId,否则嵌入块中的锚文本无法更新
191 editor.protyle.wysiwyg.element.querySelectorAll(`[data-node-id="${data.blockID}"]`).forEach(item => {
192 // 不能直接查询,否则列表中会获取到第一个列表项的 attr https://github.com/siyuan-note/siyuan/issues/12738
193 const countElement = item.lastElementChild.querySelector(".protyle-attr--refcount");
194 if (countElement) {
195 if (data.refCount === 0) {
196 countElement.remove();
197 } else {
198 countElement.textContent = data.refCount.toString();
199 }
200 } else if (data.refCount > 0) {
201 const attrElement = item.lastElementChild;
202 if (attrElement.childElementCount > 0) {
203 attrElement.lastElementChild.insertAdjacentHTML("afterend", `<div class="protyle-attr--refcount popover__block">${data.refCount}</div>`);
204 } else {
205 attrElement.innerHTML = `<div class="protyle-attr--refcount popover__block">${data.refCount}</div>${Constants.ZWSP}`;
206 }
207 }
208 if (data.refCount === 0) {
209 item.removeAttribute("refcount");
210 } else {
211 item.setAttribute("refcount", data.refCount.toString());
212 }
213 });
214 });
215
216 let liElement;
217 /// #if MOBILE
218 liElement = window.siyuan.mobile.docks.file.element.querySelector(`li[data-node-id="${data.rootID}"]`);
219 /// #else
220 liElement = (getDockByType("file").data.file as Files).element.querySelector(`li[data-node-id="${data.rootID}"]`);
221 /// #endif
222 if (liElement) {
223 const counterElement = liElement.querySelector(".counter");
224 if (counterElement) {
225 if (data.rootRefCount === 0) {
226 counterElement.remove();
227 } else {
228 counterElement.textContent = data.rootRefCount.toString();
229 }
230 } else if (data.rootRefCount > 0) {
231 liElement.insertAdjacentHTML("beforeend", `<span class="popover__block counter b3-tooltips b3-tooltips__nw" aria-label="${window.siyuan.languages.ref}">${data.rootRefCount}</span>`);
232 }
233 }
234};
235
236export const lockScreen = (app: App) => {
237 if (window.siyuan.config.readonly) {
238 return;
239 }
240 app.plugins.forEach(item => {
241 item.eventBus.emit("lock-screen");
242 });
243 /// #if BROWSER
244 fetchPost("/api/system/logoutAuth", {}, () => {
245 redirectToCheckAuth();
246 });
247 /// #else
248 ipcRenderer.send(Constants.SIYUAN_SEND_WINDOWS, {cmd: "lockscreen"});
249 /// #endif
250};
251
252export const kernelError = () => {
253 if (document.querySelector("#errorLog")) {
254 return;
255 }
256 let title = `💔 ${window.siyuan.languages.kernelFault0} <small>v${Constants.SIYUAN_VERSION}</small>`;
257 let body = `<div>${window.siyuan.languages.kernelFault1}</div><div class="fn__hr"></div><div>${window.siyuan.languages.kernelFault2}</div>`;
258 if (isInIOS()) {
259 title = `🍵 ${window.siyuan.languages.pleaseWait} <small>v${Constants.SIYUAN_VERSION}</small>`;
260 body = `<div>${window.siyuan.languages.reconnectPrompt}</div><div class="fn__hr"></div><div class="fn__flex"><div class="fn__flex-1"></div><button class="b3-button">${window.siyuan.languages.retry}</button></div>`;
261 }
262 const dialog = new Dialog({
263 disableClose: true,
264 title: title,
265 width: isMobile() ? "92vw" : "520px",
266 content: `<div class="b3-dialog__content">
267<div class="ft__breakword">
268 ${body}
269</div>
270</div>`
271 });
272 dialog.element.id = "errorLog";
273 dialog.element.setAttribute("data-key", Constants.DIALOG_KERNELFAULT);
274 const restartElement = dialog.element.querySelector(".b3-button");
275 if (restartElement) {
276 restartElement.addEventListener("click", () => {
277 dialog.destroy();
278 window.webkit.messageHandlers.startKernelFast.postMessage("startKernelFast");
279 });
280 }
281};
282
283export const exitSiYuan = async () => {
284 hideAllElements(["util"]);
285 /// #if MOBILE
286 if (window.siyuan.mobile.editor) {
287 await saveScroll(window.siyuan.mobile.editor.protyle);
288 }
289 /// #endif
290 fetchPost("/api/system/exit", {force: false}, (response) => {
291 if (response.code === 1) { // 同步执行失败
292 const msgId = showMessage(response.msg, response.data.closeTimeout, "error");
293 const buttonElement = document.querySelector(`#message [data-id="${msgId}"] button`);
294 if (buttonElement) {
295 buttonElement.addEventListener("click", () => {
296 fetchPost("/api/system/exit", {force: true}, () => {
297 /// #if !BROWSER
298 ipcRenderer.send(Constants.SIYUAN_QUIT, location.port);
299 /// #else
300 if (isInIOS() || isInAndroid() || isInHarmony()) {
301 window.location.href = "siyuan://api/system/exit";
302 }
303 /// #endif
304 });
305 });
306 }
307 } else if (response.code === 2) { // 提示新安装包
308 hideMessage();
309
310 if ("std" === window.siyuan.config.system.container) {
311 ipcRenderer.send(Constants.SIYUAN_SHOW_WINDOW);
312 }
313
314 confirmDialog(window.siyuan.languages.tip, response.msg, () => {
315 fetchPost("/api/system/exit", {
316 force: true,
317 execInstallPkg: 2 // 0:默认检查新版本,1:不执行新版本安装,2:执行新版本安装
318 }, () => {
319 /// #if !BROWSER
320 // 桌面端退出拉起更新安装时有时需要重启两次 https://github.com/siyuan-note/siyuan/issues/6544
321 // 这里先将主界面隐藏
322 setTimeout(() => {
323 ipcRenderer.send(Constants.SIYUAN_CMD, "hide");
324 }, 2000);
325 // 然后等待一段时间后再退出,避免界面主进程退出以后内核子进程被杀死
326 setTimeout(() => {
327 ipcRenderer.send(Constants.SIYUAN_QUIT, location.port);
328 }, 4000);
329 /// #endif
330 });
331 }, () => {
332 fetchPost("/api/system/exit", {
333 force: true,
334 execInstallPkg: 1 // 0:默认检查新版本,1:不执行新版本安装,2:执行新版本安装
335 }, () => {
336 /// #if !BROWSER
337 ipcRenderer.send(Constants.SIYUAN_QUIT, location.port);
338 /// #endif
339 });
340 });
341 } else { // 正常退出
342 /// #if !BROWSER
343 ipcRenderer.send(Constants.SIYUAN_QUIT, location.port);
344 /// #else
345 if (isInIOS() || isInAndroid() || isInHarmony()) {
346 window.location.href = "siyuan://api/system/exit";
347 }
348 /// #endif
349 }
350 });
351};
352
353export const transactionError = () => {
354 if (document.getElementById("transactionError")) {
355 return;
356 }
357 const dialog = new Dialog({
358 disableClose: true,
359 title: `${window.siyuan.languages.stateExcepted} v${Constants.SIYUAN_VERSION}`,
360 content: `<div class="b3-dialog__content" id="transactionError">${window.siyuan.languages.rebuildIndexTip}</div>
361<div class="b3-dialog__action">
362 <button class="b3-button b3-button--text">${window.siyuan.languages._kernel[97]}</button>
363 <div class="fn__space"></div>
364 <button class="b3-button">${window.siyuan.languages.rebuildIndex}</button>
365</div>`,
366 width: isMobile() ? "92vw" : "520px",
367 });
368 dialog.element.setAttribute("data-key", Constants.DIALOG_STATEEXCEPTED);
369 const btnsElement = dialog.element.querySelectorAll(".b3-button");
370 btnsElement[0].addEventListener("click", () => {
371 /// #if MOBILE
372 exitSiYuan();
373 /// #else
374 exportLayout({
375 errorExit: true,
376 cb: exitSiYuan
377 });
378 /// #endif
379 });
380 btnsElement[1].addEventListener("click", () => {
381 refreshFileTree();
382 dialog.destroy();
383 });
384};
385
386export const refreshFileTree = (cb?: () => void) => {
387 window.siyuan.storage[Constants.LOCAL_FILEPOSITION] = {};
388 setStorageVal(Constants.LOCAL_FILEPOSITION, window.siyuan.storage[Constants.LOCAL_FILEPOSITION]);
389 fetchPost("/api/system/rebuildDataIndex", {}, () => {
390 if (cb) {
391 cb();
392 }
393 });
394};
395
396let statusTimeout: number;
397export const progressStatus = (data: IWebSocketData) => {
398 const statusElement = document.querySelector("#status") as HTMLElement;
399 if (!statusElement) {
400 return;
401 }
402
403 if (isMobile()) {
404 if (!document.querySelector("#keyboardToolbar").classList.contains("fn__none")) {
405 return;
406 }
407 clearTimeout(statusTimeout);
408 statusElement.innerHTML = data.msg;
409 statusElement.style.bottom = "0";
410 statusTimeout = window.setTimeout(() => {
411 statusElement.style.bottom = "";
412 }, 12000);
413 } else {
414 const msgElement = statusElement.querySelector(".status__msg");
415 if (msgElement) {
416 clearTimeout(statusTimeout);
417 msgElement.innerHTML = data.msg;
418 statusTimeout = window.setTimeout(() => {
419 msgElement.innerHTML = "";
420 }, 12000);
421 }
422 }
423};
424
425export const progressLoading = (data: IWebSocketData) => {
426 let progressElement = document.getElementById("progress");
427 if (!progressElement) {
428 document.body.insertAdjacentHTML("beforeend", `<div id="progress" style="z-index: ${++window.siyuan.zIndex}"></div>`);
429 progressElement = document.getElementById("progress");
430 }
431 // code 0: 有进度;1: 无进度;2: 关闭
432 if (data.code === 2) {
433 progressElement.remove();
434 return;
435 }
436 if (data.code === 0) {
437 progressElement.innerHTML = `<div class="b3-dialog__scrim" style="opacity: 1"></div>
438<div class="b3-dialog__loading">
439 <div style="text-align: right">${data.data.current}/${data.data.total}</div>
440 <div style="margin: 8px 0;height: 8px;border-radius: var(--b3-border-radius);overflow: hidden;background-color:#fff;"><div style="width: ${data.data.current / data.data.total * 100}%;transition: var(--b3-transition);background-color: var(--b3-theme-primary);height: 8px;"></div></div>
441 <div class="ft__breakword">${data.msg}</div>
442</div>`;
443 } else if (data.code === 1) {
444 if (progressElement.lastElementChild) {
445 progressElement.lastElementChild.lastElementChild.innerHTML = data.msg;
446 } else {
447 progressElement.innerHTML = `<div class="b3-dialog__scrim" style="opacity: 1"></div>
448<div class="b3-dialog__loading">
449 <div style="margin: 8px 0;height: 8px;border-radius: var(--b3-border-radius);overflow: hidden;background-color:#fff;"><div style="background-color: var(--b3-theme-primary);height: 8px;background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.2) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0.2) 75%, transparent 75%, transparent);animation: stripMove 450ms linear infinite;background-size: 50px 50px;"></div></div>
450 <div class="ft__breakword">${data.msg}</div>
451</div>`;
452 }
453 }
454};
455
456export const progressBackgroundTask = (tasks: { action: string }[]) => {
457 const backgroundTaskElement = document.querySelector(".status__backgroundtask");
458 if (!backgroundTaskElement) {
459 return;
460 }
461 if (tasks.length === 0) {
462 backgroundTaskElement.classList.add("fn__none");
463 if (!window.siyuan.menus.menu.element.classList.contains("fn__none") &&
464 window.siyuan.menus.menu.element.getAttribute("data-name") === Constants.MENU_STATUS_BACKGROUND_TASK) {
465 window.siyuan.menus.menu.remove();
466 }
467 } else {
468 backgroundTaskElement.classList.remove("fn__none");
469 backgroundTaskElement.setAttribute("data-tasks", JSON.stringify(tasks));
470 backgroundTaskElement.innerHTML = tasks[0].action + "<div><div></div></div>";
471 }
472};
473
474export const bootSync = () => {
475 fetchPost("/api/sync/getBootSync", {}, response => {
476 if (response.code === 1) {
477 const dialog = new Dialog({
478 width: isMobile() ? "92vw" : "50vw",
479 title: "🌩️ " + window.siyuan.languages.bootSyncFailed,
480 content: `<div class="b3-dialog__content">${response.msg}</div>
481<div class="b3-dialog__action">
482 <button class="b3-button b3-button--cancel">${window.siyuan.languages.cancel}</button><div class="fn__space"></div>
483 <button class="b3-button b3-button--text">${window.siyuan.languages.syncNow}</button>
484</div>`
485 });
486 dialog.element.setAttribute("data-key", Constants.DIALOG_BOOTSYNCFAILED);
487 const btnsElement = dialog.element.querySelectorAll(".b3-button");
488 btnsElement[0].addEventListener("click", () => {
489 dialog.destroy();
490 });
491 btnsElement[1].addEventListener("click", () => {
492 if (btnsElement[1].getAttribute("disabled")) {
493 return;
494 }
495 btnsElement[1].setAttribute("disabled", "disabled");
496 fetchPost("/api/sync/performBootSync", {}, (syncResponse) => {
497 if (syncResponse.code === 0) {
498 dialog.destroy();
499 }
500 btnsElement[1].removeAttribute("disabled");
501 });
502 });
503 }
504 });
505};
506
507export const setTitle = (title: string) => {
508 const dragElement = document.getElementById("drag");
509 const workspaceName = getWorkspaceName();
510 if (title === window.siyuan.languages.siyuanNote) {
511 const versionTitle = `${workspaceName} - ${window.siyuan.languages.siyuanNote} v${Constants.SIYUAN_VERSION}`;
512 document.title = versionTitle;
513 if (dragElement) {
514 dragElement.textContent = versionTitle;
515 dragElement.setAttribute("title", versionTitle);
516 }
517 } else {
518 title = title || window.siyuan.languages.untitled;
519 document.title = `${title} - ${workspaceName} - ${window.siyuan.languages.siyuanNote} v${Constants.SIYUAN_VERSION}`;
520 if (!dragElement) {
521 return;
522 }
523 dragElement.setAttribute("title", title);
524 dragElement.innerHTML = escapeHtml(title);
525 }
526};
527
528export const downloadProgress = (data: { id: string, percent: number }) => {
529 const bazzarSideElement = document.querySelector("#configBazaarReadme .item__side");
530 if (!bazzarSideElement) {
531 return;
532 }
533 if (data.id !== JSON.parse(bazzarSideElement.getAttribute("data-obj")).repoURL) {
534 return;
535 }
536 const btnElement = bazzarSideElement.querySelector('[data-type="install"]') as HTMLElement;
537 if (btnElement) {
538 if (data.percent >= 1) {
539 btnElement.parentElement.classList.add("fn__none");
540 btnElement.parentElement.nextElementSibling.classList.add("fn__none");
541 } else {
542 btnElement.classList.add("b3-button--progress");
543 btnElement.parentElement.nextElementSibling.firstElementChild.classList.add("b3-button--progress");
544 btnElement.innerHTML = `<span style="width: ${data.percent * 100}%"></span>`;
545 btnElement.parentElement.nextElementSibling.firstElementChild.innerHTML = `<span style="width: ${data.percent * 100}%"></span>`;
546 }
547 }
548};
549
550export const processSync = (data?: IWebSocketData, plugins?: Plugin[]) => {
551 /// #if MOBILE
552 const menuSyncUseElement = document.querySelector("#menuSyncNow use");
553 const barSyncUseElement = document.querySelector("#toolbarSync use");
554 if (!data) {
555 if (!window.siyuan.config.sync.enabled || (0 === window.siyuan.config.sync.provider && needSubscribe(""))) {
556 menuSyncUseElement?.setAttribute("xlink:href", "#iconCloudOff");
557 barSyncUseElement.setAttribute("xlink:href", "#iconCloudOff");
558 } else {
559 menuSyncUseElement?.setAttribute("xlink:href", "#iconCloudSucc");
560 barSyncUseElement.setAttribute("xlink:href", "#iconCloudSucc");
561 }
562 return;
563 }
564 menuSyncUseElement?.parentElement.classList.remove("fn__rotate");
565 barSyncUseElement.parentElement.classList.remove("fn__rotate");
566 if (data.code === 0) { // syncing
567 menuSyncUseElement?.parentElement.classList.add("fn__rotate");
568 barSyncUseElement.parentElement.classList.add("fn__rotate");
569 menuSyncUseElement?.setAttribute("xlink:href", "#iconRefresh");
570 barSyncUseElement.setAttribute("xlink:href", "#iconRefresh");
571 } else if (data.code === 2) { // error
572 menuSyncUseElement?.setAttribute("xlink:href", "#iconCloudError");
573 barSyncUseElement.setAttribute("xlink:href", "#iconCloudError");
574 } else if (data.code === 1) { // success
575 menuSyncUseElement?.setAttribute("xlink:href", "#iconCloudSucc");
576 barSyncUseElement.setAttribute("xlink:href", "#iconCloudSucc");
577 }
578 /// #else
579 const iconElement = document.querySelector("#barSync");
580 if (!iconElement) {
581 return;
582 }
583 const useElement = iconElement.querySelector("use");
584 if (!data) {
585 iconElement.classList.remove("toolbar__item--active");
586 if (!window.siyuan.config.sync.enabled || (0 === window.siyuan.config.sync.provider && needSubscribe(""))) {
587 useElement.setAttribute("xlink:href", "#iconCloudOff");
588 } else {
589 useElement.setAttribute("xlink:href", "#iconCloudSucc");
590 }
591 return;
592 }
593 iconElement.firstElementChild.classList.remove("fn__rotate");
594 if (data.code === 0) { // syncing
595 iconElement.classList.add("toolbar__item--active");
596 iconElement.firstElementChild.classList.add("fn__rotate");
597 useElement.setAttribute("xlink:href", "#iconRefresh");
598 } else if (data.code === 2) { // error
599 iconElement.classList.remove("toolbar__item--active");
600 useElement.setAttribute("xlink:href", "#iconCloudError");
601 } else if (data.code === 1) { // success
602 iconElement.classList.remove("toolbar__item--active");
603 useElement.setAttribute("xlink:href", "#iconCloudSucc");
604 }
605 /// #endif
606 plugins.forEach((item) => {
607 if (data.code === 0) {
608 item.eventBus.emit("sync-start", data);
609 } else if (data.code === 1) {
610 item.eventBus.emit("sync-end", data);
611 } else if (data.code === 2) {
612 item.eventBus.emit("sync-fail", data);
613 }
614 });
615};