import {Dialog} from "../../dialog"; import {App} from "../../index"; import {upDownHint} from "../../util/upDownHint"; import {updateHotkeyTip} from "../../protyle/util/compatibility"; import {isMobile} from "../../util/functions"; import {Constants} from "../../constants"; import {Editor} from "../../editor"; /// #if !MOBILE import {getActiveTab, getDockByType} from "../../layout/tabUtil"; import {Custom} from "../../layout/dock/Custom"; import {getAllModels} from "../../layout/getAll"; import {Files} from "../../layout/dock/Files"; import {Search} from "../../search"; /// #endif import {addEditorToDatabase, addFilesToDatabase} from "../../protyle/render/av/addToDatabase"; import {hasClosestByClassName} from "../../protyle/util/hasClosest"; import {newDailyNote} from "../../util/mount"; import {getCurrentEditor} from "../../mobile/editor"; import {openDock} from "../../mobile/dock/util"; export const commandPanel = (app: App) => { const range = getSelection().getRangeAt(0); const dialog = new Dialog({ width: isMobile() ? "92vw" : "80vw", height: isMobile() ? "80vh" : "70vh", title: window.siyuan.languages.commandPanel, content: `
↑/↓ ${window.siyuan.languages.searchTip1} Enter/Click ${window.siyuan.languages.confirm} Esc ${window.siyuan.languages.close}
` }); dialog.element.setAttribute("data-key", Constants.DIALOG_COMMANDPANEL); const listElement = dialog.element.querySelector("#commands"); let html = ""; Object.keys(window.siyuan.config.keymap.general).forEach((key) => { if (["addToDatabase", "fileTree", "outline", "bookmark", "tag", "dailyNote", "inbox", "backlinks", "graphView", "globalGraph"].includes(key)) { html += `
  • ${window.siyuan.languages[key]} ${updateHotkeyTip(window.siyuan.config.keymap.general[key].custom)}
  • `; } }); listElement.insertAdjacentHTML("beforeend", html); app.plugins.forEach(plugin => { plugin.commands.forEach(command => { const liElement = document.createElement("li"); liElement.classList.add("b3-list-item"); liElement.innerHTML = `${plugin.displayName}: ${command.langText || plugin.i18n[command.langKey]} ${updateHotkeyTip(command.customHotkey)}`; liElement.addEventListener("click", () => { if (command.callback) { command.callback(); } else if (command.globalCallback) { command.globalCallback(); } dialog.destroy(); }); listElement.insertAdjacentElement("beforeend", liElement); }); }); if (listElement.childElementCount === 0) { const liElement = document.createElement("li"); liElement.classList.add("b3-list-item", "b3-list-item--focus"); liElement.innerHTML = `${window.siyuan.languages._kernel[122]}`; liElement.addEventListener("click", () => { dialog.destroy(); }); listElement.insertAdjacentElement("beforeend", liElement); } else { listElement.firstElementChild.classList.add("b3-list-item--focus"); } const inputElement = dialog.element.querySelector(".b3-text-field") as HTMLInputElement; inputElement.focus(); listElement.addEventListener("click", (event: KeyboardEvent) => { const liElement = hasClosestByClassName(event.target as HTMLElement, "b3-list-item"); if (liElement) { const command = liElement.getAttribute("data-command"); if (command) { execByCommand({command, app, previousRange: range}); dialog.destroy(); event.preventDefault(); event.stopPropagation(); } } }); inputElement.addEventListener("keydown", (event: KeyboardEvent) => { event.stopPropagation(); if (event.isComposing) { return; } upDownHint(listElement, event); if (event.key === "Enter") { const currentElement = listElement.querySelector(".b3-list-item--focus"); if (currentElement) { const command = currentElement.getAttribute("data-command"); if (command) { execByCommand({command, app, previousRange: range}); } else { currentElement.dispatchEvent(new CustomEvent("click")); } } dialog.destroy(); } else if (event.key === "Escape") { dialog.destroy(); } }); inputElement.addEventListener("compositionend", () => { filterList(inputElement, listElement); }); inputElement.addEventListener("input", (event: InputEvent) => { if (event.isComposing) { return; } event.stopPropagation(); filterList(inputElement, listElement); }); }; const filterList = (inputElement: HTMLInputElement, listElement: Element) => { const inputValue = inputElement.value.toLowerCase(); listElement.querySelector(".b3-list-item--focus")?.classList.remove("b3-list-item--focus"); let hasFocus = false; Array.from(listElement.children).forEach((element: HTMLElement) => { const elementValue = element.querySelector(".b3-list-item__text").textContent.toLowerCase(); if (inputValue.indexOf(elementValue) > -1 || elementValue.indexOf(inputValue) > -1) { if (!hasFocus) { element.classList.add("b3-list-item--focus"); } hasFocus = true; element.classList.remove("fn__none"); } else { element.classList.add("fn__none"); } }); }; export const execByCommand = (options: { command: string, app: App, previousRange?: Range, protyle?: IProtyle, fileLiElements?: Element[] }) => { /// #if MOBILE switch (options.command) { case "fileTree": openDock("file"); return; case "outline": case "bookmark": case "tag": case "inbox": openDock(options.command); return; case "backlinks": openDock("backlink"); return; } /// #else switch (options.command) { case "fileTree": getDockByType("file").toggleModel("file"); return; case "outline": getDockByType("outline").toggleModel("outline"); return; case "bookmark": getDockByType("bookmark").toggleModel("bookmark"); return; case "tag": getDockByType("tag").toggleModel("tag"); return; case "inbox": getDockByType("inbox").toggleModel("inbox"); return; case "backlinks": getDockByType("backlink").toggleModel("backlink"); return; case "graphView": getDockByType("graph").toggleModel("graph"); return; case "globalGraph": getDockByType("globalGraph").toggleModel("globalGraph"); return; } /// #endif switch (options.command) { case "dailyNote": newDailyNote(options.app); return; } const isFileFocus = document.querySelector(".layout__tab--active")?.classList.contains("sy__file"); let protyle = options.protyle; /// #if MOBILE if (!protyle) { protyle = getCurrentEditor().protyle; options.previousRange = protyle.toolbar.range; } /// #endif const range: Range = options.previousRange || getSelection().getRangeAt(0); let fileLiElements = options.fileLiElements; if (!isFileFocus && !protyle) { if (range) { window.siyuan.dialogs.find(item => { if (item.editors) { Object.keys(item.editors).find(key => { if (item.editors[key].protyle.element.contains(range.startContainer)) { protyle = item.editors[key].protyle; return true; } }); if (protyle) { return true; } } }); } const activeTab = getActiveTab(); if (!protyle && activeTab) { if (activeTab.model instanceof Editor) { protyle = activeTab.model.editor.protyle; } else if (activeTab.model instanceof Search) { if (activeTab.model.element.querySelector("#searchUnRefPanel").classList.contains("fn__none")) { protyle = activeTab.model.editors.edit.protyle; } else { protyle = activeTab.model.editors.unRefEdit.protyle; } } else if (activeTab.model instanceof Custom && activeTab.model.editors?.length > 0) { if (range) { activeTab.model.editors.find(item => { if (item.protyle.element.contains(range.startContainer)) { protyle = item.protyle; return true; } }); } } if (!protyle) { return; } } else if (!protyle) { if (!protyle && range) { window.siyuan.blockPanels.find(item => { item.editors.find(editorItem => { if (editorItem.protyle.element.contains(range.startContainer)) { protyle = editorItem.protyle; return true; } }); if (protyle) { return true; } }); } const models = getAllModels(); if (!protyle) { models.backlink.find(item => { if (item.element.classList.contains("layout__tab--active")) { if (range) { item.editors.find(editor => { if (editor.protyle.element.contains(range.startContainer)) { protyle = editor.protyle; return true; } }); } if (!protyle && item.editors.length > 0) { protyle = item.editors[0].protyle; } return true; } }); } if (!protyle) { models.editor.find(item => { if (item.parent.headElement.classList.contains("item--focus")) { protyle = item.editor.protyle; return true; } }); } if (!protyle) { return false; } } } if (isFileFocus && !fileLiElements) { const dockFile = getDockByType("file"); if (!dockFile) { return false; } const files = dockFile.data.file as Files; fileLiElements = Array.from(files.element.querySelectorAll(".b3-list-item--focus")); } switch (options.command) { case "addToDatabase": if (!isFileFocus) { addEditorToDatabase(protyle, range); } else { addFilesToDatabase(fileLiElements); } break; } };