import {MenuItem} from "./Menu"; /// #if !BROWSER import {ipcRenderer} from "electron"; /// #endif import {openHistory} from "../history/history"; import {getOpenNotebookCount, originalPath, pathPosix, useShell} from "../util/pathName"; import {fetchNewDailyNote, mountHelp, newDailyNote} from "../util/mount"; import {fetchPost} from "../util/fetch"; import {Constants} from "../constants"; import { isInAndroid, isInHarmony, isInIOS, isIPad, setStorageVal, writeText } from "../protyle/util/compatibility"; import {openCard} from "../card/openCard"; import {openSetting} from "../config"; import {getAllDocks} from "../layout/getAll"; import {exportLayout, getAllLayout} from "../layout/util"; import {getDockByType} from "../layout/tabUtil"; import {exitSiYuan, lockScreen} from "../dialog/processSystem"; import {showMessage} from "../dialog/message"; import {unicode2Emoji} from "../emoji"; import {Dock} from "../layout/dock"; import {escapeHtml} from "../util/escape"; import {viewCards} from "../card/viewCards"; import {Dialog} from "../dialog"; import {hasClosestByClassName} from "../protyle/util/hasClosest"; import {confirmDialog} from "../dialog/confirmDialog"; import {App} from "../index"; import {isBrowser} from "../util/functions"; import {openRecentDocs} from "../business/openRecentDocs"; import * as dayjs from "dayjs"; import {upDownHint} from "../util/upDownHint"; const editLayout = (layoutName?: string) => { const dialog = new Dialog({ positionId: Constants.DIALOG_SAVEWORKSPACE, title: layoutName ? window.siyuan.languages.edit : window.siyuan.languages.save, content: `
`, width: "520px", }); dialog.element.setAttribute("data-key", Constants.DIALOG_SAVEWORKSPACE); const btnsElement = dialog.element.querySelectorAll(".b3-button"); const inputElement = dialog.element.querySelector("input"); inputElement.select(); inputElement.focus(); dialog.bindInput(inputElement, () => { btnsElement[3].dispatchEvent(new CustomEvent("click")); }); btnsElement[0].addEventListener("click", () => { window.siyuan.storage[Constants.LOCAL_LAYOUTS].find((layoutItem: ISaveLayout, index: number) => { if (layoutItem.name === layoutName) { window.siyuan.storage[Constants.LOCAL_LAYOUTS].splice(index, 1); setStorageVal(Constants.LOCAL_LAYOUTS, window.siyuan.storage[Constants.LOCAL_LAYOUTS]); return true; } }); dialog.destroy(); }); btnsElement[1].addEventListener("click", () => { dialog.destroy(); }); btnsElement[2].addEventListener("click", () => { const value = inputElement.value; if (!value) { showMessage(window.siyuan.languages["_kernel"]["142"]); return; } dialog.destroy(); window.siyuan.storage[Constants.LOCAL_LAYOUTS].find((layoutItem: ISaveLayout) => { if (layoutItem.name === layoutName) { layoutItem.name = value; layoutItem.time = new Date().getTime(); setStorageVal(Constants.LOCAL_LAYOUTS, window.siyuan.storage[Constants.LOCAL_LAYOUTS]); return true; } }); }); btnsElement[3].addEventListener("click", () => { const value = inputElement.value; if (!value) { showMessage(window.siyuan.languages["_kernel"]["142"]); return; } dialog.destroy(); if (layoutName) { window.siyuan.storage[Constants.LOCAL_LAYOUTS].find((layoutItem: ISaveLayout) => { if (layoutItem.name === layoutName) { layoutItem.name = value; layoutItem.time = new Date().getTime(); layoutItem.layout = getAllLayout(); layoutItem.filesPaths = window.siyuan.storage[Constants.LOCAL_FILESPATHS]; setStorageVal(Constants.LOCAL_LAYOUTS, window.siyuan.storage[Constants.LOCAL_LAYOUTS]); return true; } }); return; } const hadName = window.siyuan.storage[Constants.LOCAL_LAYOUTS].find((item: ISaveLayout) => { if (item.name === value) { confirmDialog(window.siyuan.languages.save, window.siyuan.languages.exportTplTip, () => { item.layout = getAllLayout(); item.time = new Date().getTime(); item.filesPaths = window.siyuan.storage[Constants.LOCAL_FILESPATHS]; setStorageVal(Constants.LOCAL_LAYOUTS, window.siyuan.storage[Constants.LOCAL_LAYOUTS]); }); return true; } }); if (hadName) { return; } window.siyuan.storage[Constants.LOCAL_LAYOUTS].push({ name: value, time: new Date().getTime(), layout: getAllLayout(), filesPaths: window.siyuan.storage[Constants.LOCAL_FILESPATHS] }); setStorageVal(Constants.LOCAL_LAYOUTS, window.siyuan.storage[Constants.LOCAL_LAYOUTS]); }); }; const togglePinDock = (id: string, dock: Dock, icon: string) => { return { id, label: `${dock.pin ? window.siyuan.languages.unpin : window.siyuan.languages.pin}`, icon, current: !dock.pin, click() { dock.togglePin(); } }; }; export const workspaceMenu = (app: App, rect: DOMRect) => { if (!window.siyuan.menus.menu.element.classList.contains("fn__none") && window.siyuan.menus.menu.element.getAttribute("data-name") === "barWorkspace") { window.siyuan.menus.menu.remove(); return; } fetchPost("/api/system/getWorkspaces", {}, (response) => { window.siyuan.menus.menu.remove(); window.siyuan.menus.menu.element.setAttribute("data-name", "barWorkspace"); if (!window.siyuan.config.readonly) { window.siyuan.menus.menu.append(new MenuItem({ id: "config", label: window.siyuan.languages.config, icon: "iconSettings", accelerator: window.siyuan.config.keymap.general.config.custom, click: () => { openSetting(app); } }).element); } const dockMenu: IMenu[] = []; getAllDocks().forEach(item => { dockMenu.push({ id: item.type, icon: item.icon, accelerator: item.hotkey, label: item.title, click() { getDockByType(item.type).toggleModel(item.type); } }); }); if (!window.siyuan.config.readonly) { dockMenu.push({id: "separator_1", type: "separator"}); dockMenu.push(togglePinDock("leftDock", window.siyuan.layout.leftDock, "iconLeftTop")); dockMenu.push(togglePinDock("rightDock", window.siyuan.layout.rightDock, "iconRightTop")); dockMenu.push(togglePinDock("bottomDock", window.siyuan.layout.bottomDock, "iconBottomLeft")); } window.siyuan.menus.menu.append(new MenuItem({ id: "panels", label: window.siyuan.languages.panels, icon: "iconDock", type: "submenu", submenu: dockMenu }).element); if (!window.siyuan.config.readonly) { let workspaceSubMenu: IMenu[]; /// #if !BROWSER workspaceSubMenu = [{ id: "newOrOpenBy", label: `${window.siyuan.languages.new} / ${window.siyuan.languages.openBy}`, iconHTML: "", click: async () => { const localPath = await ipcRenderer.invoke(Constants.SIYUAN_GET, { cmd: "showOpenDialog", defaultPath: window.siyuan.config.system.homeDir, properties: ["openDirectory", "createDirectory"], }); if (localPath.filePaths.length === 0) { return; } fetchPost("/api/system/checkWorkspaceDir", {path: localPath.filePaths[0]}, (response) => { if (response.data.isWorkspace) { openWorkspace(localPath.filePaths[0]); } else { confirmDialog("🏗️ " + window.siyuan.languages.createWorkspace, window.siyuan.languages.createWorkspaceTip + `

${localPath.filePaths[0]}`, () => { openWorkspace(localPath.filePaths[0]); }); } }); } }]; workspaceSubMenu.push({id: "separator_1", type: "separator"}); response.data.forEach((item: IWorkspace) => { workspaceSubMenu.push(workspaceItem(item) as IMenu); }); /// #else workspaceSubMenu = [{ id: "new", label: window.siyuan.languages.new, iconHTML: "", click() { const createWorkspaceDialog = new Dialog({ title: window.siyuan.languages.new, content: `
`, width: "520px", }); createWorkspaceDialog.element.setAttribute("data-key", Constants.DIALOG_CREATEWORKSPACE); const inputElement = createWorkspaceDialog.element.querySelector("input"); inputElement.focus(); const btnsElement = createWorkspaceDialog.element.querySelectorAll(".b3-button"); btnsElement[0].addEventListener("click", () => { createWorkspaceDialog.destroy(); }); btnsElement[1].addEventListener("click", () => { fetchPost("/api/system/createWorkspaceDir", { path: pathPosix().join(pathPosix().dirname(window.siyuan.config.system.workspaceDir), inputElement.value) }, () => { createWorkspaceDialog.destroy(); }); }); } }, { id: "openBy", label: `${window.siyuan.languages.openBy}...`, iconHTML: "", click() { fetchPost("/api/system/getMobileWorkspaces", {}, (response) => { let selectHTML = ""; response.data.forEach((item: string, index: number) => { selectHTML += ``; }); const openWorkspaceDialog = new Dialog({ title: window.siyuan.languages.openBy, content: `
`, width: "520px", }); openWorkspaceDialog.element.setAttribute("data-key", Constants.DIALOG_OPENWORKSPACE); const btnsElement = openWorkspaceDialog.element.querySelectorAll(".b3-button"); btnsElement[0].addEventListener("click", () => { openWorkspaceDialog.destroy(); }); btnsElement[1].addEventListener("click", () => { const openPath = openWorkspaceDialog.element.querySelector("select").value; if (openPath === window.siyuan.config.system.workspaceDir) { openWorkspaceDialog.destroy(); return; } confirmDialog(window.siyuan.languages.confirm, `${pathPosix().basename(window.siyuan.config.system.workspaceDir)} -> ${pathPosix().basename(openPath)}?`, () => { fetchPost("/api/system/setWorkspaceDir", { path: openPath }, () => { exitSiYuan(); }); }); }); }); } }]; workspaceSubMenu.push({id: "separator_1", type: "separator"}); response.data.forEach((item: IWorkspace) => { workspaceSubMenu.push({ iconHTML: "", action: "iconCloseRound", current: window.siyuan.config.system.workspaceDir === item.path, label: pathPosix().basename(item.path), bind(menuElement) { menuElement.addEventListener("click", (event) => { if (hasClosestByClassName(event.target as Element, "b3-menu__action")) { event.preventDefault(); event.stopPropagation(); fetchPost("/api/system/removeWorkspaceDir", {path: item.path}, () => { confirmDialog(window.siyuan.languages.deleteOpConfirm, window.siyuan.languages.removeWorkspacePhysically.replace("${x}", item.path), () => { fetchPost("/api/system/removeWorkspaceDirPhysically", {path: item.path}); }, undefined, true); }); return; } confirmDialog(window.siyuan.languages.confirm, `${pathPosix().basename(window.siyuan.config.system.workspaceDir)} -> ${pathPosix().basename(item.path)}?`, () => { fetchPost("/api/system/setWorkspaceDir", { path: item.path }, () => { exitSiYuan(); }); }); }); } }); }); /// #endif if (!isBrowser() || isInIOS() || isInAndroid() || isInHarmony()) { window.siyuan.menus.menu.append(new MenuItem({ id: "workspaceList", label: window.siyuan.languages.workspaceList, icon: "iconWorkspace", type: "submenu", submenu: workspaceSubMenu, }).element); } } const layoutSubMenu: IMenu[] = [{ id: "save", iconHTML: "", label: window.siyuan.languages.save, click() { editLayout(); } }]; if (window.siyuan.storage[Constants.LOCAL_LAYOUTS].length > 0) { layoutSubMenu.push({id: "separator_1", type: "separator"}); layoutSubMenu.push({ iconHTML: "", type: "empty", label: `
`, bind(menuElement) { const genListHTML = () => { let html = ""; window.siyuan.storage[Constants.LOCAL_LAYOUTS].sort((a: ISaveLayout, b: ISaveLayout) => { return a.name.localeCompare(b.name, undefined, {numeric: true}); }).forEach((item: ISaveLayout) => { if (inputElement.value === "" || item.name.toLowerCase().indexOf(inputElement.value.toLowerCase()) > -1) { html += `
${item.name}
${item.time ? dayjs(item.time).format("YYYY-MM-DD HH:mm") : ""}
`; } }); return html; }; const inputElement = menuElement.querySelector(".b3-text-field") as HTMLInputElement; const listElement = menuElement.querySelector(".b3-list"); inputElement.addEventListener("keydown", (event) => { event.stopPropagation(); if (event.isComposing) { return; } upDownHint(listElement, event); if (event.key === "Escape") { window.siyuan.menus.menu.remove(); } else if (event.key === "Enter") { const currentElement = listElement.querySelector(".b3-list-item--focus"); if (currentElement) { listElement.dispatchEvent(new CustomEvent("click", {detail: currentElement.getAttribute("data-name")})); } } }); inputElement.addEventListener("compositionend", () => { listElement.innerHTML = genListHTML(); }); inputElement.addEventListener("input", (event: InputEvent) => { if (event.isComposing) { return; } event.stopPropagation(); listElement.innerHTML = genListHTML(); }); listElement.addEventListener("click", (event: MouseEvent) => { if (window.siyuan.config.readonly) { return; } const actionElement = hasClosestByClassName(event.target as Element, "b3-list-item__action"); if (actionElement) { event.preventDefault(); event.stopPropagation(); editLayout(actionElement.parentElement.dataset.name); window.siyuan.menus.menu.remove(); return; } const liElement = hasClosestByClassName(event.target as Element, "b3-list-item"); if (liElement || event.detail) { const itemData: ISaveLayout = window.siyuan.storage[Constants.LOCAL_LAYOUTS].find((item: ISaveLayout) => { if (typeof event.detail === "string") { return item.name === event.detail; } else if (liElement) { return item.name === liElement.dataset.name; } }); if (itemData) { fetchPost("/api/system/setUILayout", {layout: itemData.layout}, () => { if (itemData.filesPaths) { window.siyuan.storage[Constants.LOCAL_FILESPATHS] = itemData.filesPaths; setStorageVal(Constants.LOCAL_FILESPATHS, itemData.filesPaths, () => { window.location.reload(); }); } else { window.location.reload(); } }); } event.preventDefault(); event.stopPropagation(); } }); listElement.innerHTML = genListHTML(); } }); } if (!window.siyuan.config.readonly) { window.siyuan.menus.menu.append(new MenuItem({ id: "layout", label: window.siyuan.languages.layout, icon: "iconLayout", type: "submenu", submenu: layoutSubMenu }).element); } window.siyuan.menus.menu.append(new MenuItem({id: "separator_1", type: "separator"}).element); if (!window.siyuan.config.readonly) { if (getOpenNotebookCount() < 2) { window.siyuan.menus.menu.append(new MenuItem({ id: "dailyNote", label: window.siyuan.languages.dailyNote, icon: "iconCalendar", accelerator: window.siyuan.config.keymap.general.dailyNote.custom, click: () => { newDailyNote(app); } }).element); } else { const submenu: IMenu[] = []; window.siyuan.notebooks.forEach(item => { if (!item.closed) { submenu.push({ label: escapeHtml(item.name), iconHTML: unicode2Emoji(item.icon || window.siyuan.storage[Constants.LOCAL_IMAGES].note, "b3-menu__icon", true), accelerator: window.siyuan.storage[Constants.LOCAL_DAILYNOTEID] === item.id ? window.siyuan.config.keymap.general.dailyNote.custom : "", click: () => { fetchNewDailyNote(app, item.id); window.siyuan.storage[Constants.LOCAL_DAILYNOTEID] = item.id; setStorageVal(Constants.LOCAL_DAILYNOTEID, window.siyuan.storage[Constants.LOCAL_DAILYNOTEID]); } }); } }); window.siyuan.menus.menu.append(new MenuItem({ id: "dailyNote", label: window.siyuan.languages.dailyNote, icon: "iconCalendar", type: "submenu", submenu }).element); } if (!window.siyuan.config.readonly) { window.siyuan.menus.menu.append(new MenuItem({ id: "riffCard", label: window.siyuan.languages.riffCard, type: "submenu", icon: "iconRiffCard", submenu: [{ id: "spaceRepetition", iconHTML: "", label: window.siyuan.languages.spaceRepetition, accelerator: window.siyuan.config.keymap.general.riffCard.custom, click: () => { openCard(app); } }, { id: "manage", iconHTML: "", label: window.siyuan.languages.manage, click: () => { viewCards(app, "", window.siyuan.languages.all, ""); } }], }).element); } window.siyuan.menus.menu.append(new MenuItem({ id: "recentDocs", label: window.siyuan.languages.recentDocs, icon: "iconFile", accelerator: window.siyuan.config.keymap.general.recentDocs.custom, click: () => { openRecentDocs(); } }).element); window.siyuan.menus.menu.append(new MenuItem({ id: "lockScreen", label: window.siyuan.languages.lockScreen, icon: "iconLock", accelerator: window.siyuan.config.keymap.general.lockScreen.custom, click: () => { lockScreen(app); } }).element); window.siyuan.menus.menu.append(new MenuItem({ id: "dataHistory", label: window.siyuan.languages.dataHistory, icon: "iconHistory", accelerator: window.siyuan.config.keymap.general.dataHistory.custom, click: () => { openHistory(app); } }).element); window.siyuan.menus.menu.append(new MenuItem({id: "separator_2", type: "separator"}).element); } window.siyuan.menus.menu.append(new MenuItem({ id: "userGuide", label: window.siyuan.languages.userGuide, icon: "iconHelp", ignore: isIPad() || window.siyuan.config.readonly, click: () => { mountHelp(); } }).element); window.siyuan.menus.menu.append(new MenuItem({ id: "feedback", label: window.siyuan.languages.feedback, icon: "iconFeedback", click: () => { if ("zh_CN" === window.siyuan.config.lang || "zh_CHT" === window.siyuan.config.lang) { window.open("https://ld246.com/article/1649901726096"); } else { window.open("https://liuyun.io/article/1686530886208"); } } }).element); /// #if !BROWSER window.siyuan.menus.menu.append(new MenuItem({ id: "debug", label: window.siyuan.languages.debug, icon: "iconBug", click: () => { ipcRenderer.send(Constants.SIYUAN_CMD, "openDevTools"); } }).element); /// #endif if (isIPad() || isInAndroid() || isInHarmony() || !isBrowser()) { window.siyuan.menus.menu.append(new MenuItem({id: "separator_3", type: "separator"}).element); window.siyuan.menus.menu.append(new MenuItem({ id: "safeQuit", label: window.siyuan.languages.safeQuit, icon: "iconQuit", warning: true, click: () => { exportLayout({ errorExit: true, cb: exitSiYuan, }); } }).element); } window.siyuan.menus.menu.popup({x: rect.left, y: rect.bottom}); }); }; const openWorkspace = (workspace: string) => { /// #if !BROWSER if (workspace === window.siyuan.config.system.workspaceDir) { return; } fetchPost("/api/system/setWorkspaceDir", { path: workspace }, () => { ipcRenderer.send(Constants.SIYUAN_OPEN_WORKSPACE, { workspace, lang: window.siyuan.config.appearance.lang }); }); /// #endif }; const workspaceItem = (item: IWorkspace) => { /// #if !BROWSER const submenu = [{ id: "showInFolder", icon: "iconFolder", label: window.siyuan.languages.showInFolder, click() { useShell("showItemInFolder", item.path); } }, { id: "copyPath", icon: "iconCopy", label: window.siyuan.languages.copyPath, click() { writeText(item.path); showMessage(window.siyuan.languages.copied); } }]; if (item.path !== window.siyuan.config.system.workspaceDir) { submenu.splice(0, 0, { id: "openBy", icon: "iconOpenWindow", label: window.siyuan.languages.openBy, click() { openWorkspace(item.path); } }); if (item.closed) { submenu.push({ id: "removeWorkspaceTip", icon: "iconTrashcan", label: window.siyuan.languages.removeWorkspaceTip, click() { fetchPost("/api/system/removeWorkspaceDir", {path: item.path}); } }); } } return { label: `
${originalPath().basename(item.path)}
`, current: !item.closed, iconHTML: "", type: "submenu", submenu, click() { openWorkspace(item.path); }, }; /// #endif };