From c0535ffb98394ff3fd5f9accac9c347f22fe6aa4 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Wed, 30 Aug 2023 16:32:54 +0800 Subject: [PATCH] :recycle: https://github.com/siyuan-note/siyuan/issues/9032 --- app/src/boot/globalEvent/click.ts | 74 ++ app/src/boot/globalEvent/event.ts | 51 + app/src/boot/globalEvent/keydown.ts | 1304 +++++++++++++++++++ app/src/boot/globalEvent/keyup.ts | 118 ++ app/src/boot/globalEvent/mousemove.ts | 197 +++ app/src/boot/globalShortcut.ts | 1703 ------------------------- app/src/boot/onGetConfig.ts | 4 +- app/src/protyle/wysiwyg/index.ts | 2 +- app/src/types/index.d.ts | 9 +- app/src/window/init.ts | 4 +- 10 files changed, 1754 insertions(+), 1712 deletions(-) create mode 100644 app/src/boot/globalEvent/click.ts create mode 100644 app/src/boot/globalEvent/event.ts create mode 100644 app/src/boot/globalEvent/keydown.ts create mode 100644 app/src/boot/globalEvent/keyup.ts create mode 100644 app/src/boot/globalEvent/mousemove.ts delete mode 100644 app/src/boot/globalShortcut.ts diff --git a/app/src/boot/globalEvent/click.ts b/app/src/boot/globalEvent/click.ts new file mode 100644 index 000000000..199b6f91a --- /dev/null +++ b/app/src/boot/globalEvent/click.ts @@ -0,0 +1,74 @@ +import {getAllModels} from "../../layout/getAll"; +import {hasClosestByAttribute, hasClosestByClassName, hasTopClosestByClassName} from "../../protyle/util/hasClosest"; +import {hideAllElements} from "../../protyle/ui/hideElements"; +import {isWindow} from "../../util/functions"; +import {writeText} from "../../protyle/util/compatibility"; +import {showMessage} from "../../dialog/message"; + +export const globalClick = (event: MouseEvent & { target: HTMLElement }) => { + if (!window.siyuan.menus.menu.element.contains(event.target) && !hasClosestByAttribute(event.target, "data-menu", "true")) { + if (getSelection().rangeCount > 0 && window.siyuan.menus.menu.element.contains(getSelection().getRangeAt(0).startContainer) && + window.siyuan.menus.menu.element.contains(document.activeElement)) { + // https://ld246.com/article/1654567749834/comment/1654589171218#comments + } else { + window.siyuan.menus.menu.remove(); + } + } + // protyle.toolbar 点击空白处时进行隐藏 + if (!hasClosestByClassName(event.target, "protyle-toolbar")) { + hideAllElements(["toolbar"]); + } + if (!hasClosestByClassName(event.target, "pdf__outer")) { + hideAllElements(["pdfutil"]); + } + // dock float 时,点击空白处,隐藏 dock + const floatDockLayoutElement = hasClosestByClassName(event.target, "layout--float", true); + if (floatDockLayoutElement && window.siyuan.layout.leftDock) { + if (!floatDockLayoutElement.isSameNode(window.siyuan.layout.bottomDock.layout.element)) { + window.siyuan.layout.bottomDock.hideDock(); + } + if (!floatDockLayoutElement.isSameNode(window.siyuan.layout.leftDock.layout.element)) { + window.siyuan.layout.leftDock.hideDock(); + } + if (!floatDockLayoutElement.isSameNode(window.siyuan.layout.rightDock.layout.element)) { + window.siyuan.layout.rightDock.hideDock(); + } + } else if (!hasClosestByClassName(event.target, "dock") && !isWindow() && window.siyuan.layout.leftDock) { + window.siyuan.layout.bottomDock.hideDock(); + window.siyuan.layout.leftDock.hideDock(); + window.siyuan.layout.rightDock.hideDock(); + } + const copyElement = hasTopClosestByClassName(event.target, "protyle-action__copy"); + if (copyElement) { + writeText(copyElement.parentElement.nextElementSibling.textContent.trimEnd()); + showMessage(window.siyuan.languages.copied, 2000); + event.preventDefault(); + } + + // 点击空白,pdf 搜索、更多消失 + if (hasClosestByAttribute(event.target, "id", "secondaryToolbarToggle") || + hasClosestByAttribute(event.target, "id", "viewFind") || + hasClosestByAttribute(event.target, "id", "findbar")) { + return; + } + let currentPDFViewerObject: any; + getAllModels().asset.find(item => { + if (item.pdfObject && + !item.pdfObject.appConfig.appContainer.classList.contains("fn__none")) { + currentPDFViewerObject = item.pdfObject; + return true; + } + }); + if (!currentPDFViewerObject) { + return; + } + if (currentPDFViewerObject.secondaryToolbar.isOpen) { + currentPDFViewerObject.secondaryToolbar.close(); + } + if ( + !currentPDFViewerObject.supportsIntegratedFind && + currentPDFViewerObject.findBar.opened + ) { + currentPDFViewerObject.findBar.close(); + } +} diff --git a/app/src/boot/globalEvent/event.ts b/app/src/boot/globalEvent/event.ts new file mode 100644 index 000000000..85a206f49 --- /dev/null +++ b/app/src/boot/globalEvent/event.ts @@ -0,0 +1,51 @@ +import {App} from "../../index"; +import {windowMouseMove} from "./mousemove"; +import {Dialog} from "../../dialog"; +import {windowKeyUp} from "./keyup"; +import {windowKeyDown} from "./keydown"; +import {globalClick} from "./click"; +import {goBack, goForward} from "../../util/backForward"; + +export const initWindowEvent = (app: App) => { + document.body.addEventListener("mouseleave", () => { + if (window.siyuan.layout.leftDock) { + window.siyuan.layout.leftDock.hideDock(); + window.siyuan.layout.rightDock.hideDock(); + window.siyuan.layout.bottomDock.hideDock(); + } + }); + + window.addEventListener("mousemove", (event: MouseEvent & { target: HTMLElement }) => { + windowMouseMove(event); + }); + + window.addEventListener("mouseup", (event) => { + if (event.button === 3) { + event.preventDefault(); + goBack(app); + } else if (event.button === 4) { + event.preventDefault(); + goForward(app); + } + }); + + let switchDialog: Dialog; + + window.addEventListener("keyup", (event) => { + windowKeyUp(app, event, switchDialog); + }); + + window.addEventListener("keydown", (event) => { + windowKeyDown(app, event, switchDialog); + }); + + window.addEventListener("blur", () => { + window.siyuan.ctrlIsPressed = false; + window.siyuan.shiftIsPressed = false; + window.siyuan.altIsPressed = false; + }); + + window.addEventListener("click", (event: MouseEvent & { target: HTMLElement }) => { + globalClick(event); + }); +}; diff --git a/app/src/boot/globalEvent/keydown.ts b/app/src/boot/globalEvent/keydown.ts new file mode 100644 index 000000000..a3203e88f --- /dev/null +++ b/app/src/boot/globalEvent/keydown.ts @@ -0,0 +1,1304 @@ +import {isCtrl, isMac, updateHotkeyTip} from "../../protyle/util/compatibility"; +import {matchHotKey} from "../../protyle/util/hotKey"; +import {openSearch} from "../../search/spread"; +import { + hasClosestBlock, + hasClosestByAttribute, + hasClosestByClassName, + hasTopClosestByTag, +} from "../../protyle/util/hasClosest"; +import {newFile} from "../../util/newFile"; +import {Constants} from "../../constants"; +import {openSetting} from "../../config"; +import {getDockByType, getInstanceById} from "../../layout/util"; +import {Tab} from "../../layout/Tab"; +import {Editor} from "../../editor"; +import {setEditMode} from "../../protyle/util/setEditMode"; +import {rename} from "../../editor/rename"; +import {Files} from "../../layout/dock/Files"; +import {newDailyNote} from "../../util/mount"; +import {hideElements} from "../../protyle/ui/hideElements"; +import {fetchPost} from "../../util/fetch"; +import {goBack, goForward} from "../../util/backForward"; +import {onGet} from "../../protyle/util/onGet"; +import {getDisplayName, getNotebookName, getTopPaths, movePathTo, moveToPath} from "../../util/pathName"; +import {openFileById} from "../../editor/util"; +import {getAllDocks, getAllModels, getAllTabs} from "../../layout/getAll"; +import {openGlobalSearch} from "../../search/util"; +import {getColIndex} from "../../protyle/util/table"; +import {focusBlock, focusByRange} from "../../protyle/util/selection"; +import {initFileMenu, initNavigationMenu} from "../../menus/navigation"; +import {bindMenuKeydown} from "../../menus/Menu"; +import {showMessage} from "../../dialog/message"; +import {Dialog} from "../../dialog"; +import {unicode2Emoji} from "../../emoji"; +import {deleteFiles} from "../../editor/deleteFile"; +import {escapeHtml} from "../../util/escape"; +import {syncGuide} from "../../sync/syncGuide"; +import {showPopover} from "../../block/popover"; +import {getStartEndElement} from "../../protyle/wysiwyg/commonHotkey"; +import {getNextFileLi, getPreviousFileLi} from "../../protyle/wysiwyg/getBlock"; +import {editor} from "../../config/editor"; +import {hintMoveBlock} from "../../protyle/hint/extend"; +import {Backlink} from "../../layout/dock/Backlink"; +/// #if !BROWSER +import {setZoom} from "../../layout/topBar"; +/// #endif +import {openHistory} from "../../history/history"; +import {openCard, openCardByData} from "../../card/openCard"; +import {lockScreen} from "../../dialog/processSystem"; +import {isWindow} from "../../util/functions"; +import {reloadProtyle} from "../../protyle/util/reload"; +import {fullscreen} from "../../protyle/breadcrumb/action"; +import {setPadding} from "../../protyle/ui/initUI"; +import {openRecentDocs} from "../../business/openRecentDocs"; +import {App} from "../../index"; +import {commandPanel} from "../../plugin/commandPanel"; +import {toggleDockBar} from "../../layout/dock/util"; +import {workspaceMenu} from "../../menus/workspace"; + + +const switchDialogEvent = (app: App, event: MouseEvent, switchDialog: Dialog) => { + event.preventDefault(); + let target = event.target as HTMLElement; + while (!target.isSameNode(switchDialog.element)) { + if (target.classList.contains("b3-list-item")) { + const currentType = target.getAttribute("data-type"); + if (currentType) { + if (currentType === "riffCard") { + openCard(app); + } else { + getDockByType(currentType).toggleModel(currentType, true); + } + } else { + const currentId = target.getAttribute("data-id"); + getAllTabs().find(item => { + if (item.id === currentId) { + item.parent.switchTab(item.headElement); + item.parent.showHeading(); + return true; + } + }); + } + switchDialog.destroy(); + switchDialog = undefined; + break; + } + target = target.parentElement; + } +}; + +const dialogArrow = (app: App, element: HTMLElement, event: KeyboardEvent) => { + let currentLiElement = element.querySelector(".b3-list-item--focus"); + if (currentLiElement) { + currentLiElement.classList.remove("b3-list-item--focus"); + if (event.key === "ArrowUp") { + if (currentLiElement.previousElementSibling) { + currentLiElement.previousElementSibling.classList.add("b3-list-item--focus"); + } else { + currentLiElement.parentElement.lastElementChild.classList.add("b3-list-item--focus"); + } + } else if (event.key === "ArrowDown") { + if (currentLiElement.nextElementSibling) { + currentLiElement.nextElementSibling.classList.add("b3-list-item--focus"); + } else { + currentLiElement.parentElement.firstElementChild.classList.add("b3-list-item--focus"); + } + } else if (event.key === "ArrowLeft" || event.key === "ArrowRight") { + if (isWindow()) { + currentLiElement.classList.add("b3-list-item--focus"); + } else { + const sideElement = currentLiElement.parentElement.previousElementSibling || currentLiElement.parentElement.nextElementSibling; + (sideElement.querySelector(`[data-index="${currentLiElement.getAttribute("data-index")}"]`) || sideElement.lastElementChild).classList.add("b3-list-item--focus"); + } + } else if (event.key === "Enter") { + const currentType = currentLiElement.getAttribute("data-type"); + if (currentType) { + if (currentType === "riffCard") { + openCard(app); + } else { + getDockByType(currentType).toggleModel(currentType, true); + } + } else { + openFileById({ + app, + id: currentLiElement.getAttribute("data-node-id"), + action: [Constants.CB_GET_SCROLL] + }); + } + hideElements(["dialog"]); + return; + } + currentLiElement = element.querySelector(".b3-list-item--focus"); + const rootId = currentLiElement.getAttribute("data-node-id"); + if (rootId) { + fetchPost("/api/filetree/getFullHPathByID", { + id: rootId + }, (response) => { + currentLiElement.parentElement.parentElement.nextElementSibling.innerHTML = escapeHtml(response.data); + }); + } else { + currentLiElement.parentElement.parentElement.nextElementSibling.innerHTML = currentLiElement.querySelector(".b3-list-item__text").innerHTML; + } + const currentRect = currentLiElement.getBoundingClientRect(); + const currentParentRect = currentLiElement.parentElement.getBoundingClientRect(); + if (currentRect.top < currentParentRect.top) { + currentLiElement.scrollIntoView(true); + } else if (currentRect.bottom > currentParentRect.bottom) { + currentLiElement.scrollIntoView(false); + } + } +}; + +const editKeydown = (app: App, event: KeyboardEvent) => { + const activeTabElement = document.querySelector(".layout__wnd--active .item--focus"); + let protyle: IProtyle; + if (activeTabElement) { + const tab = getInstanceById(activeTabElement.getAttribute("data-id")) as Tab; + if (!(tab.model instanceof Editor)) { + return false; + } + protyle = tab.model.editor.protyle; + } else { + const editor = getAllModels().editor.find(item => { + if (item.parent.headElement.classList.contains("item--focus")) { + return true; + } + }); + if (!editor) { + return false; + } + protyle = editor.editor.protyle; + } + const activePanelElement = document.querySelector(".layout__tab--active"); + let isFileFocus = false; + if (activePanelElement && activePanelElement.classList.contains("sy__file")) { + isFileFocus = true; + } + let searchKey = ""; + if (matchHotKey(window.siyuan.config.keymap.general.replace.custom, event)) { + searchKey = window.siyuan.config.keymap.general.replace.custom; + } else if (matchHotKey(window.siyuan.config.keymap.general.search.custom, event)) { + searchKey = window.siyuan.config.keymap.general.search.custom; + } + if (!isFileFocus && searchKey) { + let range: Range; + if (getSelection().rangeCount > 0) { + range = getSelection().getRangeAt(0); + } + if (range && protyle.element.contains(range.startContainer)) { + openSearch({ + app, + hotkey: searchKey, + key: range.toString(), + notebookId: protyle.notebookId, + searchPath: protyle.path + }); + } else { + openSearch({ + app, + hotkey: searchKey, + }); + } + event.preventDefault(); + return true; + } + if (!isFileFocus && matchHotKey(window.siyuan.config.keymap.editor.general.spaceRepetition.custom, event)) { + fetchPost("/api/riff/getTreeRiffDueCards", {rootID: protyle.block.rootID}, (response) => { + openCardByData(app, response.data, "doc", protyle.block.rootID, protyle.title.editElement.textContent || "Untitled"); + }); + event.preventDefault(); + return true; + } + if (!isFileFocus && matchHotKey(window.siyuan.config.keymap.general.move.custom, event)) { + let range: Range; + let nodeElement: false | HTMLElement; + if (getSelection().rangeCount > 0) { + range = getSelection().getRangeAt(0); + nodeElement = hasClosestBlock(range.startContainer); + } + if (protyle.title?.editElement.contains(range.startContainer)) { + movePathTo((toPath, toNotebook) => { + moveToPath([protyle.path], toNotebook[0], toPath[0]); + }, [protyle.path], range); + } else if (nodeElement && range && protyle.element.contains(range.startContainer)) { + let selectElements = Array.from(protyle.wysiwyg.element.querySelectorAll(".protyle-wysiwyg--select")); + if (selectElements.length === 0) { + selectElements = [nodeElement]; + } + movePathTo((toPath) => { + hintMoveBlock(toPath[0], selectElements, protyle); + }); + } + event.preventDefault(); + return true; + } + const target = event.target as HTMLElement; + if (target.tagName !== "TABLE" && ( + target.tagName === "INPUT" || target.tagName === "TEXTAREA" || hasClosestByAttribute(target, "contenteditable", null) + )) { + return false; + } + if (matchHotKey(window.siyuan.config.keymap.editor.general.refresh.custom, event)) { + reloadProtyle(protyle, true); + event.preventDefault(); + return true; + } + if (matchHotKey(window.siyuan.config.keymap.editor.general.fullscreen.custom, event)) { + fullscreen(protyle.element); + setPadding(protyle); + event.preventDefault(); + return true; + } + if (matchHotKey(window.siyuan.config.keymap.editor.general.preview.custom, event)) { + setEditMode(protyle, "preview"); + event.preventDefault(); + return true; + } + if (matchHotKey(window.siyuan.config.keymap.editor.general.wysiwyg.custom, event) && !protyle.options.backlinkData) { + setEditMode(protyle, "wysiwyg"); + protyle.scroll.lastScrollTop = 0; + fetchPost("/api/filetree/getDoc", { + id: protyle.block.parentID, + size: window.siyuan.config.editor.dynamicLoadBlocks, + }, getResponse => { + onGet({data: getResponse, protyle}); + }); + event.preventDefault(); + return true; + } + // 没有光标时,无法撤销 https://ld246.com/article/1624021111567 + if (matchHotKey(window.siyuan.config.keymap.editor.general.undo.custom, event)) { + protyle.undo.undo(protyle); + event.preventDefault(); + return true; + } + if (matchHotKey(window.siyuan.config.keymap.editor.general.redo.custom, event)) { + protyle.undo.redo(protyle); + event.preventDefault(); + return true; + } + return false; +}; + +const fileTreeKeydown = (app: App, event: KeyboardEvent) => { + const dockFile = getDockByType("file"); + if (!dockFile) { + return false; + } + const files = dockFile.data.file as Files; + + if (matchHotKey(window.siyuan.config.keymap.general.selectOpen1.custom, event)) { + event.preventDefault(); + const element = document.querySelector(".layout__wnd--active > .fn__flex > .layout-tab-bar > .item--focus") || + document.querySelector(".layout-tab-bar > .item--focus"); + if (element) { + const tab = getInstanceById(element.getAttribute("data-id")) as Tab; + if (tab && tab.model instanceof Editor) { + tab.model.editor.protyle.wysiwyg.element.blur(); + tab.model.editor.protyle.title.editElement.blur(); + files.selectItem(tab.model.editor.protyle.notebookId, tab.model.editor.protyle.path); + } + } + dockFile.toggleModel("file", true); + return; + } + + if (!files.element.parentElement.classList.contains("layout__tab--active")) { + return false; + } + + let matchCommand = false; + app.plugins.find(item => { + item.commands.find(command => { + if (command.fileTreeCallback && matchHotKey(command.customHotkey, event)) { + matchCommand = true; + command.fileTreeCallback(files); + return true; + } + }); + if (matchCommand) { + return true; + } + }); + if (matchCommand) { + return true; + } + + const liElements = Array.from(files.element.querySelectorAll(".b3-list-item--focus")); + if (liElements.length === 0) { + if (event.key.startsWith("Arrow") && !isCtrl(event)) { + const liElement = files.element.querySelector(".b3-list-item"); + if (liElement) { + liElement.classList.add("b3-list-item--focus"); + } + event.preventDefault(); + } + return false; + } + const topULElement = hasTopClosestByTag(liElements[0], "UL"); + if (!topULElement) { + return false; + } + const notebookId = topULElement.getAttribute("data-url"); + const pathString = liElements[0].getAttribute("data-path"); + const isFile = liElements[0].getAttribute("data-type") === "navigation-file"; + + if (matchHotKey(window.siyuan.config.keymap.editor.general.spaceRepetition.custom, event)) { + if (isFile) { + const id = liElements[0].getAttribute("data-node-id"); + fetchPost("/api/riff/getTreeRiffDueCards", {rootID: id}, (response) => { + openCardByData(app, response.data, "doc", id, getDisplayName(liElements[0].getAttribute("data-name"), false, true)); + }); + } else { + fetchPost("/api/riff/getNotebookRiffDueCards", {notebook: notebookId}, (response) => { + openCardByData(app, response.data, "notebook", notebookId, getNotebookName(notebookId)); + }); + } + } + + if (matchHotKey(window.siyuan.config.keymap.editor.general.rename.custom, event)) { + window.siyuan.menus.menu.remove(); + rename({ + notebookId, + path: pathString, + name: isFile ? getDisplayName(liElements[0].getAttribute("data-name"), false, true) : getNotebookName(notebookId), + type: isFile ? "file" : "notebook", + }); + event.preventDefault(); + return true; + } + + if (matchHotKey("⌘/", event)) { + const liRect = liElements[0].getBoundingClientRect(); + if (isFile) { + initFileMenu(app, notebookId, pathString, liElements[0]).popup({ + x: liRect.right - 15, + y: liRect.top + 15 + }); + } else { + initNavigationMenu(app, liElements[0] as HTMLElement).popup({x: liRect.right - 15, y: liRect.top + 15}); + } + return true; + } + + if (isFile && matchHotKey(window.siyuan.config.keymap.general.move.custom, event)) { + window.siyuan.menus.menu.remove(); + const pathes = getTopPaths(liElements); + movePathTo((toPath, toNotebook) => { + moveToPath(pathes, toNotebook[0], toPath[0]); + }, pathes); + event.preventDefault(); + return true; + } + + if (isFile && matchHotKey(window.siyuan.config.keymap.editor.general.insertRight.custom, event)) { + window.siyuan.menus.menu.remove(); + openFileById({ + app, + id: liElements[0].getAttribute("data-node-id"), + action: [Constants.CB_GET_FOCUS], + position: "right", + }); + event.preventDefault(); + return true; + } + + let searchKey = ""; + if (matchHotKey(window.siyuan.config.keymap.general.replace.custom, event)) { + searchKey = window.siyuan.config.keymap.general.replace.custom; + } else if (matchHotKey(window.siyuan.config.keymap.general.search.custom, event)) { + searchKey = window.siyuan.config.keymap.general.search.custom; + } + if (searchKey) { + window.siyuan.menus.menu.remove(); + if (isFile) { + openSearch({ + app, + hotkey: searchKey, + notebookId: notebookId, + searchPath: getDisplayName(pathString, false, true) + }); + } else { + openSearch({ + app, + hotkey: searchKey, + notebookId: notebookId, + }); + } + event.preventDefault(); + return true; + } + const target = event.target as HTMLElement; + if (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || + hasClosestByAttribute(target, "contenteditable", null) || + hasClosestByClassName(target, "protyle", true)) { + return false; + } + if (!window.siyuan.menus.menu.element.classList.contains("fn__none") && + (event.code.startsWith("Arrow") || event.code === "Enter") && + !event.altKey && !event.shiftKey && !isCtrl(event)) { + event.preventDefault(); + return true; + } + if (event.shiftKey) { + if (event.key === "ArrowUp") { + const startEndElement = getStartEndElement(liElements); + let previousElement: Element; + if (startEndElement.startElement.getBoundingClientRect().top >= startEndElement.endElement.getBoundingClientRect().top) { + previousElement = getPreviousFileLi(startEndElement.endElement) as Element; + if (previousElement) { + previousElement.classList.add("b3-list-item--focus"); + previousElement.setAttribute("select-end", "true"); + startEndElement.endElement.removeAttribute("select-end"); + } + } else { + startEndElement.endElement.classList.remove("b3-list-item--focus"); + startEndElement.endElement.removeAttribute("select-end"); + previousElement = getPreviousFileLi(startEndElement.endElement) as Element; + if (previousElement) { + previousElement.setAttribute("select-end", "true"); + } + } + if (previousElement) { + const previousRect = previousElement.getBoundingClientRect(); + const fileRect = files.element.getBoundingClientRect(); + if (previousRect.top < fileRect.top || previousRect.bottom > fileRect.bottom) { + previousElement.scrollIntoView(previousRect.top < fileRect.top); + } + } + } else if (event.key === "ArrowDown") { + const startEndElement = getStartEndElement(liElements); + let nextElement: Element; + if (startEndElement.startElement.getBoundingClientRect().top <= startEndElement.endElement.getBoundingClientRect().top) { + nextElement = getNextFileLi(startEndElement.endElement) as Element; + if (nextElement) { + nextElement.classList.add("b3-list-item--focus"); + nextElement.setAttribute("select-end", "true"); + startEndElement.endElement.removeAttribute("select-end"); + } + } else { + startEndElement.endElement.classList.remove("b3-list-item--focus"); + startEndElement.endElement.removeAttribute("select-end"); + nextElement = getNextFileLi(startEndElement.endElement) as Element; + if (nextElement) { + nextElement.setAttribute("select-end", "true"); + } + } + if (nextElement) { + const nextRect = nextElement.getBoundingClientRect(); + const fileRect = files.element.getBoundingClientRect(); + if (nextRect.top < fileRect.top || nextRect.bottom > fileRect.bottom) { + nextElement.scrollIntoView(nextRect.top < fileRect.top); + } + } + } + return; + } else if (!isCtrl(event)) { + files.element.querySelector('[select-end="true"]')?.removeAttribute("select-end"); + files.element.querySelector('[select-start="true"]')?.removeAttribute("select-start"); + if ((event.key === "ArrowRight" && !liElements[0].querySelector(".b3-list-item__arrow--open") && !liElements[0].querySelector(".b3-list-item__toggle").classList.contains("fn__hidden")) || + (event.key === "ArrowLeft" && liElements[0].querySelector(".b3-list-item__arrow--open"))) { + files.getLeaf(liElements[0], notebookId); + liElements.forEach((item, index) => { + if (index !== 0) { + item.classList.remove("b3-list-item--focus"); + } + }); + event.preventDefault(); + return true; + } + if (event.key === "ArrowLeft") { + let parentElement = liElements[0].parentElement.previousElementSibling; + if (parentElement) { + if (parentElement.tagName !== "LI") { + parentElement = files.element.querySelector(".b3-list-item"); + } + liElements.forEach((item) => { + item.classList.remove("b3-list-item--focus"); + }); + parentElement.classList.add("b3-list-item--focus"); + const parentRect = parentElement.getBoundingClientRect(); + const fileRect = files.element.getBoundingClientRect(); + if (parentRect.top < fileRect.top || parentRect.bottom > fileRect.bottom) { + parentElement.scrollIntoView(parentRect.top < fileRect.top); + } + } + event.preventDefault(); + return true; + } + if (event.key === "ArrowDown" || event.key === "ArrowRight") { + let nextElement = liElements[0]; + while (nextElement) { + if (nextElement.nextElementSibling) { + if (nextElement.nextElementSibling.tagName === "UL") { + nextElement = nextElement.nextElementSibling.firstElementChild; + } else { + nextElement = nextElement.nextElementSibling; + } + break; + } else { + if (nextElement.parentElement.classList.contains("fn__flex-1")) { + break; + } else { + nextElement = nextElement.parentElement; + } + } + } + if (nextElement.classList.contains("b3-list-item")) { + liElements.forEach((item) => { + item.classList.remove("b3-list-item--focus"); + }); + nextElement.classList.add("b3-list-item--focus"); + const nextRect = nextElement.getBoundingClientRect(); + const fileRect = files.element.getBoundingClientRect(); + if (nextRect.top < fileRect.top || nextRect.bottom > fileRect.bottom) { + nextElement.scrollIntoView(nextRect.top < fileRect.top); + } + } + event.preventDefault(); + return true; + } + if (event.key === "ArrowUp") { + let previousElement = liElements[0]; + while (previousElement) { + if (previousElement.previousElementSibling) { + if (previousElement.previousElementSibling.tagName === "LI") { + previousElement = previousElement.previousElementSibling; + } else { + const liElements = previousElement.previousElementSibling.querySelectorAll(".b3-list-item"); + previousElement = liElements[liElements.length - 1]; + } + break; + } else { + if (previousElement.parentElement.classList.contains("fn__flex-1")) { + break; + } else { + previousElement = previousElement.parentElement; + } + } + } + if (previousElement.classList.contains("b3-list-item")) { + liElements.forEach((item) => { + item.classList.remove("b3-list-item--focus"); + }); + previousElement.classList.add("b3-list-item--focus"); + const previousRect = previousElement.getBoundingClientRect(); + const fileRect = files.element.getBoundingClientRect(); + if (previousRect.top < fileRect.top || previousRect.bottom > fileRect.bottom) { + previousElement.scrollIntoView(previousRect.top < fileRect.top); + } + } + event.preventDefault(); + return true; + } + } + if (event.key === "Delete" || (event.key === "Backspace" && isMac())) { + window.siyuan.menus.menu.remove(); + deleteFiles(liElements); + return true; + } + if (event.key === "Enter") { + window.siyuan.menus.menu.remove(); + liElements.forEach(item => { + if (item.getAttribute("data-type") === "navigation-file") { + openFileById({app, id: item.getAttribute("data-node-id"), action: [Constants.CB_GET_FOCUS]}); + } else { + const itemTopULElement = hasTopClosestByTag(item, "UL"); + if (itemTopULElement) { + files.getLeaf(item, itemTopULElement.getAttribute("data-url")); + } + } + }); + return true; + } +}; + +const panelTreeKeydown = (app: App, event: KeyboardEvent) => { + // 面板折叠展开操作 + const target = event.target as HTMLElement; + if (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || + hasClosestByAttribute(target, "contenteditable", null) || + hasClosestByClassName(target, "protyle", true)) { + return false; + } + + let activePanelElement = document.querySelector(".layout__tab--active"); + if (!activePanelElement) { + Array.from(document.querySelectorAll(".layout__wnd--active .layout-tab-container > div")).find(item => { + if (!item.classList.contains("fn__none") && item.className.indexOf("sy__") > -1) { + activePanelElement = item; + return true; + } + }); + } + if (!activePanelElement) { + return false; + } + if (activePanelElement.className.indexOf("sy__") === -1) { + return false; + } + + let matchCommand = false; + app.plugins.find(item => { + item.commands.find(command => { + if (command.dockCallback && matchHotKey(command.customHotkey, event)) { + matchCommand = true; + command.dockCallback(activePanelElement as HTMLElement); + return true; + } + }); + if (matchCommand) { + return true; + } + }); + if (matchCommand) { + return true; + } + if (!matchHotKey(window.siyuan.config.keymap.editor.general.collapse.custom, event) && + !matchHotKey(window.siyuan.config.keymap.editor.general.expand.custom, event) && + !event.key.startsWith("Arrow") && event.key !== "Enter") { + return false; + } + if (!event.repeat && matchHotKey(window.siyuan.config.keymap.editor.general.collapse.custom, event)) { + const collapseElement = activePanelElement.querySelector('.block__icon[data-type="collapse"]'); + if (collapseElement) { + collapseElement.dispatchEvent(new CustomEvent("click")); + event.preventDefault(); + return true; + } + } + if (!event.repeat && matchHotKey(window.siyuan.config.keymap.editor.general.expand.custom, event)) { + const expandElement = activePanelElement.querySelector('.block__icon[data-type="expand"]'); + if (expandElement) { + expandElement.dispatchEvent(new CustomEvent("click")); + event.preventDefault(); + return true; + } + } + if (activePanelElement.classList.contains("sy__inbox") || + activePanelElement.classList.contains("sy__globalGraph") || + activePanelElement.classList.contains("sy__graph")) { + return false; + } + const model = (getInstanceById(activePanelElement.getAttribute("data-id"), window.siyuan.layout.layout) as Tab)?.model; + if (!model) { + return false; + } + let activeItemElement = activePanelElement.querySelector(".b3-list-item--focus"); + if (!activeItemElement) { + activeItemElement = activePanelElement.querySelector(".b3-list .b3-list-item"); + if (activeItemElement) { + activeItemElement.classList.add("b3-list-item--focus"); + } + return false; + } + + let tree = (model as Backlink).tree; + if (activeItemElement.parentElement.parentElement.classList.contains("backlinkMList")) { + tree = (model as Backlink).mTree; + } + if (!tree) { + return false; + } + if (event.key === "Enter") { + tree.click(activeItemElement); + event.preventDefault(); + return true; + } + const arrowElement = activeItemElement.querySelector(".b3-list-item__arrow"); + if ((event.key === "ArrowRight" && !arrowElement.classList.contains("b3-list-item__arrow--open") && !arrowElement.parentElement.classList.contains("fn__hidden")) || + (event.key === "ArrowLeft" && arrowElement.classList.contains("b3-list-item__arrow--open") && !arrowElement.parentElement.classList.contains("fn__hidden"))) { + tree.toggleBlocks(activeItemElement); + event.preventDefault(); + return true; + } + const ulElement = hasClosestByClassName(activeItemElement, "b3-list"); + if (!ulElement) { + return false; + } + if (event.key === "ArrowLeft") { + let parentElement = activeItemElement.parentElement.previousElementSibling; + if (parentElement) { + if (parentElement.tagName !== "LI") { + parentElement = ulElement.querySelector(".b3-list-item"); + } + activeItemElement.classList.remove("b3-list-item--focus"); + parentElement.classList.add("b3-list-item--focus"); + const parentRect = parentElement.getBoundingClientRect(); + const scrollRect = ulElement.parentElement.getBoundingClientRect(); + if (parentRect.top < scrollRect.top || parentRect.bottom > scrollRect.bottom) { + parentElement.scrollIntoView(parentRect.top < scrollRect.top); + } + } + event.preventDefault(); + return true; + } + if (event.key === "ArrowDown" || event.key === "ArrowRight") { + let nextElement = activeItemElement; + while (nextElement) { + if (nextElement.nextElementSibling) { + if (nextElement.nextElementSibling.tagName === "UL") { + if (nextElement.nextElementSibling.classList.contains("fn__none")) { // 遇到折叠内容 + if (nextElement.nextElementSibling.nextElementSibling) { + nextElement = nextElement.nextElementSibling.nextElementSibling; + } + } else { + nextElement = nextElement.nextElementSibling.firstElementChild; + } + } else if (nextElement.nextElementSibling.classList.contains("protyle")) { // backlink + if (nextElement.nextElementSibling.nextElementSibling) { + nextElement = nextElement.nextElementSibling.nextElementSibling; + } + } else { + nextElement = nextElement.nextElementSibling; + } + break; + } else { + if (nextElement.parentElement.classList.contains("fn__flex-1")) { + break; + } else { + nextElement = nextElement.parentElement; + } + } + } + if (nextElement.classList.contains("b3-list-item") && !nextElement.classList.contains("b3-list-item--focus")) { + activeItemElement.classList.remove("b3-list-item--focus"); + nextElement.classList.add("b3-list-item--focus"); + const nextRect = nextElement.getBoundingClientRect(); + const scrollRect = ulElement.parentElement.getBoundingClientRect(); + if (nextRect.top < scrollRect.top || nextRect.bottom > scrollRect.bottom) { + nextElement.scrollIntoView(nextRect.top < scrollRect.top); + } + } + event.preventDefault(); + return true; + } + if (event.key === "ArrowUp") { + let previousElement = activeItemElement; + while (previousElement) { + if (previousElement.previousElementSibling) { + if (previousElement.previousElementSibling.tagName === "LI") { + previousElement = previousElement.previousElementSibling; + } else if (previousElement.previousElementSibling.classList.contains("protyle")) { + if (previousElement.previousElementSibling.previousElementSibling) { + previousElement = previousElement.previousElementSibling.previousElementSibling; + } + } else if (previousElement.previousElementSibling.tagName === "UL" && previousElement.previousElementSibling.classList.contains("fn__none")) { // 遇到折叠内容 + if (previousElement.previousElementSibling.previousElementSibling) { + previousElement = previousElement.previousElementSibling.previousElementSibling; + } + } else { + const liElements = previousElement.previousElementSibling.querySelectorAll(".b3-list-item"); + previousElement = liElements[liElements.length - 1]; + } + break; + } else { + if (previousElement.parentElement.classList.contains("fn__flex-1")) { + break; + } else { + previousElement = previousElement.parentElement; + } + } + } + if (previousElement.classList.contains("b3-list-item") && !previousElement.classList.contains("b3-list-item--focus")) { + activeItemElement.classList.remove("b3-list-item--focus"); + previousElement.classList.add("b3-list-item--focus"); + const previousRect = previousElement.getBoundingClientRect(); + const scrollRect = ulElement.parentElement.getBoundingClientRect(); + if (previousRect.top < scrollRect.top || previousRect.bottom > scrollRect.bottom) { + previousElement.scrollIntoView(previousRect.top < scrollRect.top); + } + } + event.preventDefault(); + return true; + } + return false; +}; + +export const windowKeyDown = (app: App, event: KeyboardEvent, switchDialog:Dialog) => { + + if (document.querySelector(".av__mask") || document.getElementById("errorLog") || event.isComposing) { + return; + } + const target = event.target as HTMLElement; + if (!event.ctrlKey && !event.metaKey && !event.shiftKey && !event.altKey && + !["INPUT", "TEXTAREA"].includes(target.tagName) && + ["0", "1", "2", "3", "4", "j", "k", "l", ";", "s", " ", "p"].includes(event.key.toLowerCase())) { + let cardElement: Element; + window.siyuan.dialogs.find(item => { + if (item.element.getAttribute("data-key") === window.siyuan.config.keymap.general.riffCard.custom) { + cardElement = item.element; + return true; + } + }); + if (!cardElement) { + cardElement = document.querySelector(`.layout__wnd--active div[data-key="${window.siyuan.config.keymap.general.riffCard.custom}"]:not(.fn__none)`); + } + if (cardElement) { + event.preventDefault(); + cardElement.dispatchEvent(new CustomEvent("click", {detail: event.key.toLowerCase()})); + return; + } + } + + // 仅处理以下快捷键操作 + if (!event.ctrlKey && !isCtrl(event) && event.key !== "Escape" && !event.shiftKey && !event.altKey && + !/^F\d{1,2}$/.test(event.key) && event.key.indexOf("Arrow") === -1 && event.key !== "Enter" && event.key !== "Backspace" && event.key !== "Delete") { + return; + } + + if (!event.altKey && !event.shiftKey && isCtrl(event)) { + if (event.key === "Meta" || event.key === "Control" || event.ctrlKey || event.metaKey) { + window.siyuan.ctrlIsPressed = true; + if ((event.key === "Meta" || event.key === "Control") && + window.siyuan.config.editor.floatWindowMode === 1 && !event.repeat) { + showPopover(app); + } + } else { + window.siyuan.ctrlIsPressed = false; + } + } + + if (!event.altKey && event.shiftKey && !isCtrl(event)) { + if (event.key === "Shift") { + window.siyuan.shiftIsPressed = true; + if (!event.repeat) { + showPopover(app, true); + } + } else { + window.siyuan.shiftIsPressed = false; + } + } + + if (event.altKey && !event.shiftKey && !isCtrl(event)) { + if (event.key === "Alt") { + window.siyuan.altIsPressed = true; + } else { + window.siyuan.altIsPressed = false; + } + } + + if (switchDialog && event.ctrlKey && !event.metaKey && event.key.startsWith("Arrow")) { + dialogArrow(app, switchDialog.element, event); + return; + } + + const isTabWindow = isWindow(); + if (event.ctrlKey && !event.metaKey && event.key === "Tab") { + if (switchDialog && switchDialog.element.parentElement) { + return; + } + let tabHtml = ""; + let currentTabElement = document.querySelector(".layout__wnd--active .layout-tab-bar > .item--focus"); + if (!currentTabElement) { + currentTabElement = document.querySelector(".layout-tab-bar > .item--focus"); + } + if (currentTabElement) { + const currentId = currentTabElement.getAttribute("data-id"); + getAllTabs().sort((itemA, itemB) => { + return itemA.headElement.getAttribute("data-activetime") > itemB.headElement.getAttribute("data-activetime") ? -1 : 1; + }).forEach((item, index) => { + let icon = ``; + let rootId = ""; + const initData = item.headElement.getAttribute("data-initdata"); + if (item.model instanceof Editor) { + rootId = ` data-node-id="${item.model.editor.protyle.block.rootID}"`; + icon = unicode2Emoji(item.docIcon || Constants.SIYUAN_IMAGE_FILE, "b3-list-item__graphic", true); + } else if (initData) { + const initDataObj = JSON.parse(initData); + if (initDataObj.instance === "Editor") { + rootId = ` data-node-id="${initDataObj.rootId}"`; + icon = unicode2Emoji(item.docIcon || Constants.SIYUAN_IMAGE_FILE, "b3-list-item__graphic", true); + } + } + tabHtml += `
  • ${icon}${escapeHtml(item.title)}
  • `; + }); + } + let dockHtml = ""; + if (!isTabWindow) { + dockHtml = `"; + } + hideElements(["dialog"]); + switchDialog = new Dialog({ + title: window.siyuan.languages.switchTab, + content: `
    +
    +
    ${dockHtml} + ${tabHtml} +
    +
    +
    `, + }); + // 需移走光标,否则编辑器会继续监听并执行按键操作 + switchDialog.element.querySelector("input").focus(); + if (isMac()) { + switchDialog.element.addEventListener("contextmenu", (event) => { + switchDialogEvent(app, event, switchDialog); + }); + } + switchDialog.element.addEventListener("click", (event) => { + switchDialogEvent(app, event, switchDialog); + }); + return; + } + + if (!event.ctrlKey && !event.metaKey && !event.shiftKey && !event.altKey && + (event.key.startsWith("Arrow") || event.key === "Enter")) { + const openRecentDocsDialog = window.siyuan.dialogs.find(item => { + if (item.element.getAttribute("data-key") === window.siyuan.config.keymap.general.recentDocs.custom) { + return true; + } + }); + if (openRecentDocsDialog) { + event.preventDefault(); + dialogArrow(app, openRecentDocsDialog.element, event); + return; + } + } + + if (matchHotKey(window.siyuan.config.keymap.general.recentDocs.custom, event)) { + const openRecentDocsDialog = window.siyuan.dialogs.find(item => { + if (item.element.getAttribute("data-key") === window.siyuan.config.keymap.general.recentDocs.custom) { + return true; + } + }); + if (openRecentDocsDialog) { + hideElements(["dialog"]); + return; + } + openRecentDocs(); + event.preventDefault(); + return; + } + + if (bindMenuKeydown(event)) { + event.preventDefault(); + return; + } + + if (event.key === "ArrowUp" || event.key === "ArrowDown") { + const viewCardsDialog = window.siyuan.dialogs.find(item => { + if (item.element.getAttribute("data-key") === "viewCards") { + return true; + } + }); + if (viewCardsDialog) { + viewCardsDialog.element.dispatchEvent(new CustomEvent("click", {detail: event.key.toLowerCase()})); + event.preventDefault(); + return; + } + } + + /// #if !BROWSER + if (matchHotKey("⌘=", event) && !hasClosestByClassName(target, "pdf__outer")) { + setZoom("zoomIn"); + event.preventDefault(); + return; + } + if (matchHotKey("⌘0", event)) { + setZoom("restore"); + event.preventDefault(); + return; + } + if (matchHotKey("⌘-", event) && !hasClosestByClassName(target, "pdf__outer")) { + setZoom("zoomOut"); + event.preventDefault(); + return; + } + /// #endif + + if (!isTabWindow && matchHotKey(window.siyuan.config.keymap.general.syncNow.custom, event)) { + event.preventDefault(); + syncGuide(app); + return; + } + if (matchHotKey(window.siyuan.config.keymap.general.commandPanel.custom, event)) { + event.preventDefault(); + commandPanel(app); + return; + } + if (matchHotKey(window.siyuan.config.keymap.general.editMode.custom, event)) { + event.preventDefault(); + editor.setReadonly(); + return; + } + if (matchHotKey(window.siyuan.config.keymap.general.lockScreen.custom, event)) { + lockScreen(); + event.preventDefault(); + return; + } + if (!isTabWindow && matchHotKey(window.siyuan.config.keymap.general.dataHistory.custom, event)) { + if (!window.siyuan.config.readonly) { + openHistory(app); + } + event.preventDefault(); + return; + } + if (!isTabWindow && matchHotKey(window.siyuan.config.keymap.general.toggleDock.custom, event)) { + toggleDockBar(document.querySelector("#barDock use")); + event.preventDefault(); + return; + } + if (!isTabWindow && !window.siyuan.config.readonly && matchHotKey(window.siyuan.config.keymap.general.config.custom, event)) { + openSetting(app); + event.preventDefault(); + return; + } + if (matchHotKey("⌘A", event) && target.tagName !== "INPUT" && target.tagName !== "TEXTAREA") { + event.preventDefault(); + return; + } + const matchDock = getAllDocks().find(item => { + if (matchHotKey(item.hotkey, event)) { + getDockByType(item.type).toggleModel(item.type); + event.preventDefault(); + return true; + } + }); + if (matchDock) { + return; + } + if (!isTabWindow && matchHotKey(window.siyuan.config.keymap.general.riffCard.custom, event)) { + openCard(app); + if (document.activeElement) { + (document.activeElement as HTMLElement).blur(); + } + event.preventDefault(); + return; + } + if (!isTabWindow && matchHotKey(window.siyuan.config.keymap.general.dailyNote.custom, event)) { + newDailyNote(); + event.stopPropagation(); + event.preventDefault(); + return; + } + if (matchHotKey(window.siyuan.config.keymap.general.newFile.custom, event)) { + newFile(app, undefined, undefined, undefined, true); + event.preventDefault(); + return; + } + // https://github.com/siyuan-note/siyuan/issues/8913#issuecomment-1679720605 + const confirmElement = document.querySelector("#confirmDialogConfirmBtn"); + if (confirmElement) { + if (event.key === "Enter") { + confirmElement.dispatchEvent(new CustomEvent("click")); + event.preventDefault(); + return; + } else if (event.key === "Escape") { + confirmElement.previousElementSibling.previousElementSibling.dispatchEvent(new CustomEvent("click")); + event.preventDefault(); + return; + } + } + + if (event.key === "Escape" && !event.isComposing) { + const imgPreviewElement = document.querySelector(".protyle-img"); + if (imgPreviewElement) { + imgPreviewElement.remove(); + return; + } + if (!window.siyuan.menus.menu.element.classList.contains("fn__none")) { + window.siyuan.menus.menu.remove(); + return; + } + if (window.siyuan.dialogs.length > 0) { + hideElements(["dialog"]); + return; + } + + // remove blockpopover + const maxEditLevels: { [key: string]: number } = {oid: 0}; + window.siyuan.blockPanels.forEach((item) => { + if ((item.targetElement || typeof item.x === "number") && item.element.getAttribute("data-pin") === "true") { + const level = parseInt(item.element.getAttribute("data-level")); + const oid = item.element.getAttribute("data-oid"); + if (maxEditLevels[oid]) { + if (level > maxEditLevels[oid]) { + maxEditLevels[oid] = level; + } + } else { + maxEditLevels[oid] = 1; + } + } + }); + let destroyBlock = false; + for (let i = 0; i < window.siyuan.blockPanels.length; i++) { + const item = window.siyuan.blockPanels[i]; + if ((item.targetElement || typeof item.x === "number") && item.element.getAttribute("data-pin") === "false" && + parseInt(item.element.getAttribute("data-level")) > (maxEditLevels[item.element.getAttribute("data-oid")] || 0)) { + item.destroy(); + destroyBlock = true; + i--; + } + } + if (destroyBlock) { + return; + } + + // 光标在文档树等面板中,按 Esc 回到编辑器中 https://github.com/siyuan-note/siyuan/issues/4289 + let range; + if (getSelection().rangeCount > 0) { + range = getSelection().getRangeAt(0); + const protypleElement = hasClosestByClassName(range.startContainer, "protyle-content", true); + if (protypleElement) { + focusByRange(range); + return; + } + } else { + range = document.createRange(); + } + const lastBackStack = window.siyuan.backStack[window.siyuan.backStack.length - 1]; + if (lastBackStack && lastBackStack.protyle.toolbar.range) { + focusByRange(lastBackStack.protyle.toolbar.range); + } else { + const editor = getAllModels().editor[0]; + if (editor) { + focusBlock(editor.editor.protyle.wysiwyg.element.firstElementChild); + } + } + event.preventDefault(); + return; + } + + if (!isTabWindow && matchHotKey(window.siyuan.config.keymap.general.mainMenu.custom, event)) { + workspaceMenu(app, document.querySelector("#barWorkspace").getBoundingClientRect()); + event.preventDefault(); + return; + } + + if (matchHotKey(window.siyuan.config.keymap.general.goForward.custom, event)) { + goForward(app); + event.preventDefault(); + return; + } + + if (matchHotKey(window.siyuan.config.keymap.general.goBack.custom, event)) { + goBack(app); + event.preventDefault(); + return; + } + + // close tab + if (matchHotKey(window.siyuan.config.keymap.general.closeTab.custom, event) && !event.repeat) { + event.preventDefault(); + let activeTabElement = document.querySelector(".layout__tab--active"); + if (activeTabElement && activeTabElement.getBoundingClientRect().width > 0) { + let type = ""; + Array.from(activeTabElement.classList).find(item => { + if (item.startsWith("sy__")) { + type = item.replace("sy__", ""); + return true; + } + }); + if (type) { + getDockByType(type)?.toggleModel(type, false, true); + } + return; + } + activeTabElement = document.querySelector(".layout__wnd--active .item--focus"); + if (activeTabElement) { + const tab = getInstanceById(activeTabElement.getAttribute("data-id")) as Tab; + tab.parent.removeTab(tab.id); + return; + } + getAllTabs().find(item => { + if (item.headElement?.classList.contains("item--focus")) { + item.parent.removeTab(item.id); + return true; + } + }); + return; + } + + if (matchHotKey(window.siyuan.config.keymap.general.stickSearch.custom, event)) { + if (getSelection().rangeCount > 0) { + const range = getSelection().getRangeAt(0); + openGlobalSearch(app, range.toString(), false); + } else { + openGlobalSearch(app, "", false); + } + event.preventDefault(); + return; + } + + if (editKeydown(app, event)) { + return; + } + + // 文件树的操作 + if (!isTabWindow && fileTreeKeydown(app, event)) { + return; + } + + // 面板的操作 + if (!isTabWindow && panelTreeKeydown(app, event)) { + return; + } + + let matchCommand = false; + app.plugins.find(item => { + item.commands.find(command => { + if (command.callback && + !command.fileTreeCallback && !command.editorCallback && !command.dockCallback && !command.globalCallback + && matchHotKey(command.customHotkey, event)) { + matchCommand = true; + command.callback(); + return true; + } + }); + if (matchCommand) { + return true; + } + }); + if (matchCommand) { + event.stopPropagation(); + event.preventDefault(); + return true; + } + + let searchKey = ""; + if (matchHotKey(window.siyuan.config.keymap.general.replace.custom, event)) { + searchKey = window.siyuan.config.keymap.general.replace.custom; + } else if (!hasClosestByClassName(target, "pdf__outer") && matchHotKey(window.siyuan.config.keymap.general.search.custom, event)) { + searchKey = window.siyuan.config.keymap.general.search.custom; + } else if (matchHotKey(window.siyuan.config.keymap.general.globalSearch.custom, event)) { + searchKey = window.siyuan.config.keymap.general.globalSearch.custom; + } + if (searchKey) { + if (getSelection().rangeCount > 0) { + const range = getSelection().getRangeAt(0); + openSearch({ + app, + hotkey: searchKey, + key: range.toString(), + }); + } else { + openSearch({ + app, + hotkey: searchKey, + }); + } + event.preventDefault(); + return; + } + + // https://github.com/siyuan-note/insider/issues/445 + if (matchHotKey("⌘S", event)) { + event.preventDefault(); + return true; + } +}; diff --git a/app/src/boot/globalEvent/keyup.ts b/app/src/boot/globalEvent/keyup.ts new file mode 100644 index 000000000..1c0e72857 --- /dev/null +++ b/app/src/boot/globalEvent/keyup.ts @@ -0,0 +1,118 @@ +import {Dialog} from "../../dialog"; +import {fetchPost} from "../../util/fetch"; +import {escapeHtml} from "../../util/escape"; +import {openCard} from "../../card/openCard"; +import {getDockByType} from "../../layout/util"; +import {getAllTabs} from "../../layout/getAll"; +import {App} from "../../index"; + +export const windowKeyUp = (app: App,event:KeyboardEvent, switchDialog:Dialog) => { + window.siyuan.ctrlIsPressed = false; + window.siyuan.shiftIsPressed = false; + window.siyuan.altIsPressed = false; + if (switchDialog && switchDialog.element.parentElement) { + if (event.key === "Tab") { + let currentLiElement = switchDialog.element.querySelector(".b3-list-item--focus"); + currentLiElement.classList.remove("b3-list-item--focus"); + if (event.shiftKey) { + if (currentLiElement.previousElementSibling) { + currentLiElement.previousElementSibling.classList.add("b3-list-item--focus"); + } else if (currentLiElement.getAttribute("data-original")) { + currentLiElement.parentElement.lastElementChild.classList.add("b3-list-item--focus"); + currentLiElement.removeAttribute("data-original"); + } else if (currentLiElement.parentElement.nextElementSibling) { + if (currentLiElement.parentElement.nextElementSibling.lastElementChild) { + currentLiElement.parentElement.nextElementSibling.lastElementChild.classList.add("b3-list-item--focus"); + } else { + currentLiElement.parentElement.lastElementChild.classList.add("b3-list-item--focus"); + } + } else if (currentLiElement.parentElement.previousElementSibling) { + currentLiElement.parentElement.previousElementSibling.lastElementChild.classList.add("b3-list-item--focus"); + } + } else { + if (currentLiElement.nextElementSibling) { + currentLiElement.nextElementSibling.classList.add("b3-list-item--focus"); + } else if (currentLiElement.getAttribute("data-original")) { + currentLiElement.parentElement.firstElementChild.classList.add("b3-list-item--focus"); + currentLiElement.removeAttribute("data-original"); + } else if (currentLiElement.parentElement.nextElementSibling) { + if (currentLiElement.parentElement.nextElementSibling.firstElementChild) { + currentLiElement.parentElement.nextElementSibling.firstElementChild.classList.add("b3-list-item--focus"); + } else { + currentLiElement.parentElement.firstElementChild.classList.add("b3-list-item--focus"); + } + } else if (currentLiElement.parentElement.previousElementSibling) { + currentLiElement.parentElement.previousElementSibling.firstElementChild.classList.add("b3-list-item--focus"); + } + } + currentLiElement = switchDialog.element.querySelector(".b3-list-item--focus"); + if (currentLiElement) { + const rootId = currentLiElement.getAttribute("data-node-id"); + if (rootId) { + fetchPost("/api/filetree/getFullHPathByID", { + id: rootId + }, (response) => { + currentLiElement.parentElement.parentElement.nextElementSibling.innerHTML = escapeHtml(response.data); + }); + } else { + currentLiElement.parentElement.parentElement.nextElementSibling.innerHTML = currentLiElement.querySelector(".b3-list-item__text").innerHTML; + } + const currentRect = currentLiElement.getBoundingClientRect(); + const currentParentRect = currentLiElement.parentElement.getBoundingClientRect(); + if (currentRect.top < currentParentRect.top) { + currentLiElement.scrollIntoView(true); + } else if (currentRect.bottom > currentParentRect.bottom) { + currentLiElement.scrollIntoView(false); + } + } + const originalElement = switchDialog.element.querySelector('[data-original="true"]'); + if (originalElement) { + originalElement.removeAttribute("data-original"); + } + } else if (event.key === "Control") { + let currentLiElement = switchDialog.element.querySelector(".b3-list-item--focus"); + // 快速切换时,不触发 Tab + if (currentLiElement.getAttribute("data-original")) { + currentLiElement.classList.remove("b3-list-item--focus"); + if (event.shiftKey) { + if (currentLiElement.previousElementSibling) { + currentLiElement.previousElementSibling.classList.add("b3-list-item--focus"); + } else { + currentLiElement.parentElement.lastElementChild.classList.add("b3-list-item--focus"); + currentLiElement.removeAttribute("data-original"); + } + } else { + if (currentLiElement.nextElementSibling) { + currentLiElement.nextElementSibling.classList.add("b3-list-item--focus"); + } else { + currentLiElement.parentElement.firstElementChild.classList.add("b3-list-item--focus"); + } + } + currentLiElement.removeAttribute("data-original"); + currentLiElement = switchDialog.element.querySelector(".b3-list-item--focus"); + } + const currentType = currentLiElement.getAttribute("data-type"); + if (currentType) { + if (currentType === "riffCard") { + openCard(app); + } else { + getDockByType(currentType).toggleModel(currentType, true); + } + if (document.activeElement) { + (document.activeElement as HTMLElement).blur(); + } + } else { + const currentId = currentLiElement.getAttribute("data-id"); + getAllTabs().find(item => { + if (item.id === currentId) { + item.parent.switchTab(item.headElement); + item.parent.showHeading(); + return true; + } + }); + } + switchDialog.destroy(); + switchDialog = undefined; + } + } +} diff --git a/app/src/boot/globalEvent/mousemove.ts b/app/src/boot/globalEvent/mousemove.ts new file mode 100644 index 000000000..e18dc63c8 --- /dev/null +++ b/app/src/boot/globalEvent/mousemove.ts @@ -0,0 +1,197 @@ +import {getAllModels} from "../../layout/getAll"; +import {isWindow} from "../../util/functions"; +import {hasClosestBlock, hasClosestByClassName, hasClosestByMatchTag} from "../../protyle/util/hasClosest"; +import {getColIndex} from "../../protyle/util/table"; + +const getRightBlock = (element: HTMLElement, x: number, y: number) => { + let index = 1; + let nodeElement = element; + while (nodeElement && (nodeElement.classList.contains("list") || nodeElement.classList.contains("li"))) { + nodeElement = document.elementFromPoint(x + 73 * index, y) as HTMLElement; + nodeElement = hasClosestBlock(nodeElement) as HTMLElement; + index++; + } + return nodeElement; +}; + +export const windowMouseMove = (event: MouseEvent & { target: HTMLElement }) => { + // https://github.com/siyuan-note/siyuan/pull/8793 + const coordinates = window.siyuan.coordinates ?? (window.siyuan.coordinates = { + pageX: 0, + pageY: 0, + clientX: 0, + clientY: 0, + screenX: 0, + screenY: 0, + }); + coordinates.pageX = event.pageX; + coordinates.pageY = event.pageY; + coordinates.clientX = event.clientX; + coordinates.clientY = event.clientY; + coordinates.screenX = event.screenX; + coordinates.screenY = event.screenY; + + if (window.siyuan.hideBreadcrumb) { + document.querySelectorAll(".protyle-breadcrumb__bar--hide").forEach(item => { + item.classList.remove("protyle-breadcrumb__bar--hide"); + }); + window.siyuan.hideBreadcrumb = false; + getAllModels().editor.forEach(item => { + item.editor.protyle.breadcrumb.render(item.editor.protyle, true); + }); + } + if (event.buttons === 0 && // 鼠标按键被按下时不触发 + window.siyuan.layout.bottomDock && + !isWindow() && !hasClosestByClassName(event.target, "b3-dialog") && !hasClosestByClassName(event.target, "b3-menu")) { + if (event.clientX < 43) { + if (!window.siyuan.layout.leftDock.pin && window.siyuan.layout.leftDock.layout.element.clientWidth > 0 && + // 隐藏停靠栏会导致点击两侧内容触发浮动面板弹出,因此需减小鼠标范围 + (window.siyuan.layout.leftDock.element.clientWidth > 0 || (window.siyuan.layout.leftDock.element.clientWidth === 0 && event.clientX < 8))) { + if (event.clientY > document.getElementById("toolbar").clientHeight && + event.clientY < window.innerHeight - document.getElementById("status").clientHeight - document.getElementById("dockBottom").clientHeight) { + if (!hasClosestByClassName(event.target, "b3-menu") && + !hasClosestByClassName(event.target, "layout--float")) { + window.siyuan.layout.leftDock.showDock(); + } + } else { + window.siyuan.layout.leftDock.hideDock(); + } + } + } else if (event.clientX > window.innerWidth - 41) { + if (!window.siyuan.layout.rightDock.pin && window.siyuan.layout.rightDock.layout.element.clientWidth > 0 && + (window.siyuan.layout.rightDock.element.clientWidth > 0 || (window.siyuan.layout.rightDock.element.clientWidth === 0 && event.clientX > window.innerWidth - 8))) { + if (event.clientY > document.getElementById("toolbar").clientHeight && + event.clientY < window.innerHeight - document.getElementById("status").clientHeight - document.getElementById("dockBottom").clientHeight) { + if (!hasClosestByClassName(event.target, "layout--float")) { + window.siyuan.layout.rightDock.showDock(); + } + } else { + window.siyuan.layout.rightDock.hideDock(); + } + } + } + + if (event.clientY > window.innerHeight - 73) { + window.siyuan.layout.bottomDock.showDock(); + } + } + const eventPath0 = event.composedPath()[0] as HTMLElement; + if (eventPath0 && eventPath0.nodeType !== 3 && eventPath0.classList.contains("protyle-wysiwyg") && eventPath0.style.paddingLeft) { + // 光标在编辑器右边也需要进行显示 + const mouseElement = document.elementFromPoint(eventPath0.getBoundingClientRect().left + parseInt(eventPath0.style.paddingLeft) + 13, event.clientY); + const blockElement = hasClosestBlock(mouseElement); + if (blockElement) { + const targetBlockElement = getRightBlock(blockElement, blockElement.getBoundingClientRect().left + 1, event.clientY); + if (!targetBlockElement) { + return; + } + const allModels = getAllModels(); + let findNode = false; + allModels.editor.find(item => { + if (item.editor.protyle.wysiwyg.element.isSameNode(eventPath0)) { + item.editor.protyle.gutter.render(item.editor.protyle, targetBlockElement, item.editor.protyle.wysiwyg.element); + findNode = true; + return true; + } + }); + if (!findNode) { + window.siyuan.blockPanels.find(item => { + item.editors.find(eItem => { + if (eItem.protyle.wysiwyg.element.contains(eventPath0)) { + eItem.protyle.gutter.render(eItem.protyle, targetBlockElement, eItem.protyle.wysiwyg.element); + findNode = true; + return true; + } + }); + if (findNode) { + return true; + } + }); + } + if (!findNode) { + allModels.backlink.find(item => { + item.editors.find(eItem => { + if (eItem.protyle.wysiwyg.element.isSameNode(eventPath0)) { + eItem.protyle.gutter.render(eItem.protyle, targetBlockElement, eItem.protyle.wysiwyg.element); + findNode = true; + return true; + } + }); + if (findNode) { + return true; + } + }); + } + } + return; + } + if (eventPath0 && eventPath0.nodeType !== 3 && (eventPath0.classList.contains("li") || eventPath0.classList.contains("list"))) { + // 光标在列表下部应显示右侧的元素,而不是列表本身 + const targetBlockElement = getRightBlock(eventPath0, eventPath0.getBoundingClientRect().left + 1, event.clientY); + if (!targetBlockElement) { + return; + } + const allModels = getAllModels(); + let findNode = false; + allModels.editor.find(item => { + if (item.editor.protyle.wysiwyg.element.contains(eventPath0)) { + item.editor.protyle.gutter.render(item.editor.protyle, targetBlockElement, item.editor.protyle.wysiwyg.element); + findNode = true; + return true; + } + }); + if (!findNode) { + window.siyuan.blockPanels.find(item => { + item.editors.find(eItem => { + if (eItem.protyle.wysiwyg.element.contains(eventPath0)) { + eItem.protyle.gutter.render(eItem.protyle, targetBlockElement, eItem.protyle.wysiwyg.element); + findNode = true; + return true; + } + }); + if (findNode) { + return true; + } + }); + } + if (!findNode) { + allModels.backlink.find(item => { + item.editors.find(eItem => { + if (eItem.protyle.wysiwyg.element.contains(eventPath0)) { + eItem.protyle.gutter.render(eItem.protyle, targetBlockElement, eItem.protyle.wysiwyg.element); + findNode = true; + return true; + } + }); + if (findNode) { + return true; + } + }); + } + return; + } + + const target = event.target as Element; + const blockElement = hasClosestByClassName(target, "table"); + if (blockElement && blockElement.style.cursor !== "col-resize" && !hasClosestByClassName(blockElement, "protyle-wysiwyg__embed")) { + const cellElement = (hasClosestByMatchTag(target, "TH") || hasClosestByMatchTag(target, "TD")) as HTMLTableCellElement; + if (cellElement) { + const tableElement = blockElement.querySelector("table"); + const tableHeight = blockElement.querySelector("table").clientHeight; + const resizeElement = blockElement.querySelector(".table__resize"); + if (blockElement.style.textAlign === "center" || blockElement.style.textAlign === "right") { + resizeElement.parentElement.style.left = tableElement.offsetLeft + "px"; + } else { + resizeElement.parentElement.style.left = ""; + } + const rect = cellElement.getBoundingClientRect(); + if (rect.right - event.clientX < 3 && rect.right - event.clientX > 0) { + resizeElement.setAttribute("data-col-index", (getColIndex(cellElement) + cellElement.colSpan - 1).toString()); + resizeElement.setAttribute("style", `height:${tableHeight}px;left: ${Math.round(cellElement.offsetWidth + cellElement.offsetLeft - blockElement.firstElementChild.scrollLeft - 3)}px;display:block`); + } else if (event.clientX - rect.left < 3 && event.clientX - rect.left > 0 && cellElement.previousElementSibling) { + resizeElement.setAttribute("data-col-index", (getColIndex(cellElement) - 1).toString()); + resizeElement.setAttribute("style", `height:${tableHeight}px;left: ${Math.round(cellElement.offsetLeft - blockElement.firstElementChild.scrollLeft - 3)}px;display:block`); + } + } + } +}; diff --git a/app/src/boot/globalShortcut.ts b/app/src/boot/globalShortcut.ts deleted file mode 100644 index 3ee05b6e0..000000000 --- a/app/src/boot/globalShortcut.ts +++ /dev/null @@ -1,1703 +0,0 @@ -import {isCtrl, isMac, updateHotkeyTip, writeText} from "../protyle/util/compatibility"; -import {matchHotKey} from "../protyle/util/hotKey"; -import {openSearch} from "../search/spread"; -import { - hasClosestBlock, - hasClosestByAttribute, - hasClosestByClassName, hasClosestByMatchTag, - hasTopClosestByClassName, - hasTopClosestByTag, -} from "../protyle/util/hasClosest"; -import {newFile} from "../util/newFile"; -import {Constants} from "../constants"; -import {openSetting} from "../config"; -import {getDockByType, getInstanceById} from "../layout/util"; -import {Tab} from "../layout/Tab"; -import {Editor} from "../editor"; -import {setEditMode} from "../protyle/util/setEditMode"; -import {rename} from "../editor/rename"; -import {Files} from "../layout/dock/Files"; -import {newDailyNote} from "../util/mount"; -import {hideAllElements, hideElements} from "../protyle/ui/hideElements"; -import {fetchPost} from "../util/fetch"; -import {goBack, goForward} from "../util/backForward"; -import {onGet} from "../protyle/util/onGet"; -import {getDisplayName, getNotebookName, getTopPaths, movePathTo, moveToPath} from "../util/pathName"; -import {openFileById} from "../editor/util"; -import {getAllDocks, getAllModels, getAllTabs} from "../layout/getAll"; -import {openGlobalSearch} from "../search/util"; -import {getColIndex} from "../protyle/util/table"; -import {focusBlock, focusByRange} from "../protyle/util/selection"; -import {initFileMenu, initNavigationMenu} from "../menus/navigation"; -import {bindMenuKeydown} from "../menus/Menu"; -import {showMessage} from "../dialog/message"; -import {Dialog} from "../dialog"; -import {unicode2Emoji} from "../emoji"; -import {deleteFiles} from "../editor/deleteFile"; -import {escapeHtml} from "../util/escape"; -import {syncGuide} from "../sync/syncGuide"; -import {showPopover} from "../block/popover"; -import {getStartEndElement} from "../protyle/wysiwyg/commonHotkey"; -import {getNextFileLi, getPreviousFileLi} from "../protyle/wysiwyg/getBlock"; -import {editor} from "../config/editor"; -import {hintMoveBlock} from "../protyle/hint/extend"; -import {Backlink} from "../layout/dock/Backlink"; -/// #if !BROWSER -import {setZoom} from "../layout/topBar"; -/// #endif -import {openHistory} from "../history/history"; -import {openCard, openCardByData} from "../card/openCard"; -import {lockScreen} from "../dialog/processSystem"; -import {isWindow} from "../util/functions"; -import {reloadProtyle} from "../protyle/util/reload"; -import {fullscreen} from "../protyle/breadcrumb/action"; -import {setPadding} from "../protyle/ui/initUI"; -import {openRecentDocs} from "../business/openRecentDocs"; -import {App} from "../index"; -import {commandPanel} from "../plugin/commandPanel"; -import {toggleDockBar} from "../layout/dock/util"; -import {workspaceMenu} from "../menus/workspace"; - -const getRightBlock = (element: HTMLElement, x: number, y: number) => { - let index = 1; - let nodeElement = element; - while (nodeElement && (nodeElement.classList.contains("list") || nodeElement.classList.contains("li"))) { - nodeElement = document.elementFromPoint(x + 73 * index, y) as HTMLElement; - nodeElement = hasClosestBlock(nodeElement) as HTMLElement; - index++; - } - return nodeElement; -}; - -const switchDialogEvent = (app: App, event: MouseEvent, switchDialog: Dialog) => { - event.preventDefault(); - let target = event.target as HTMLElement; - while (!target.isSameNode(switchDialog.element)) { - if (target.classList.contains("b3-list-item")) { - const currentType = target.getAttribute("data-type"); - if (currentType) { - if (currentType === "riffCard") { - openCard(app); - } else { - getDockByType(currentType).toggleModel(currentType, true); - } - } else { - const currentId = target.getAttribute("data-id"); - getAllTabs().find(item => { - if (item.id === currentId) { - item.parent.switchTab(item.headElement); - item.parent.showHeading(); - return true; - } - }); - } - switchDialog.destroy(); - switchDialog = undefined; - break; - } - target = target.parentElement; - } -}; - -export const globalShortcut = (app: App) => { - document.body.addEventListener("mouseleave", () => { - if (window.siyuan.layout.leftDock) { - window.siyuan.layout.leftDock.hideDock(); - window.siyuan.layout.rightDock.hideDock(); - window.siyuan.layout.bottomDock.hideDock(); - } - }); - window.addEventListener("mousemove", (event: MouseEvent & { target: HTMLElement }) => { - // https://github.com/siyuan-note/siyuan/pull/8793 - const coordinates = window.siyuan.coordinates ?? (window.siyuan.coordinates = { - pageX: 0, - pageY: 0, - clientX: 0, - clientY: 0, - screenX: 0, - screenY: 0, - }); - coordinates.pageX = event.pageX; - coordinates.pageY = event.pageY; - coordinates.clientX = event.clientX; - coordinates.clientY = event.clientY; - coordinates.screenX = event.screenX; - coordinates.screenY = event.screenY; - - if (window.siyuan.hideBreadcrumb) { - document.querySelectorAll(".protyle-breadcrumb__bar--hide").forEach(item => { - item.classList.remove("protyle-breadcrumb__bar--hide"); - }); - window.siyuan.hideBreadcrumb = false; - getAllModels().editor.forEach(item => { - item.editor.protyle.breadcrumb.render(item.editor.protyle, true); - }); - } - if (event.buttons === 0 && // 鼠标按键被按下时不触发 - window.siyuan.layout.bottomDock && - !isWindow() && !hasClosestByClassName(event.target, "b3-dialog") && !hasClosestByClassName(event.target, "b3-menu")) { - if (event.clientX < 43) { - if (!window.siyuan.layout.leftDock.pin && window.siyuan.layout.leftDock.layout.element.clientWidth > 0 && - // 隐藏停靠栏会导致点击两侧内容触发浮动面板弹出,因此需减小鼠标范围 - (window.siyuan.layout.leftDock.element.clientWidth > 0 || (window.siyuan.layout.leftDock.element.clientWidth === 0 && event.clientX < 8))) { - if (event.clientY > document.getElementById("toolbar").clientHeight && - event.clientY < window.innerHeight - document.getElementById("status").clientHeight - document.getElementById("dockBottom").clientHeight) { - if (!hasClosestByClassName(event.target, "b3-menu") && - !hasClosestByClassName(event.target, "layout--float")) { - window.siyuan.layout.leftDock.showDock(); - } - } else { - window.siyuan.layout.leftDock.hideDock(); - } - } - } else if (event.clientX > window.innerWidth - 41) { - if (!window.siyuan.layout.rightDock.pin && window.siyuan.layout.rightDock.layout.element.clientWidth > 0 && - (window.siyuan.layout.rightDock.element.clientWidth > 0 || (window.siyuan.layout.rightDock.element.clientWidth === 0 && event.clientX > window.innerWidth - 8))) { - if (event.clientY > document.getElementById("toolbar").clientHeight && - event.clientY < window.innerHeight - document.getElementById("status").clientHeight - document.getElementById("dockBottom").clientHeight) { - if (!hasClosestByClassName(event.target, "layout--float")) { - window.siyuan.layout.rightDock.showDock(); - } - } else { - window.siyuan.layout.rightDock.hideDock(); - } - } - } - - if (event.clientY > window.innerHeight - 73) { - window.siyuan.layout.bottomDock.showDock(); - } - } - const eventPath0 = event.composedPath()[0] as HTMLElement; - if (eventPath0 && eventPath0.nodeType !== 3 && eventPath0.classList.contains("protyle-wysiwyg") && eventPath0.style.paddingLeft) { - // 光标在编辑器右边也需要进行显示 - const mouseElement = document.elementFromPoint(eventPath0.getBoundingClientRect().left + parseInt(eventPath0.style.paddingLeft) + 13, event.clientY); - const blockElement = hasClosestBlock(mouseElement); - if (blockElement) { - const targetBlockElement = getRightBlock(blockElement, blockElement.getBoundingClientRect().left + 1, event.clientY); - if (!targetBlockElement) { - return; - } - const allModels = getAllModels(); - let findNode = false; - allModels.editor.find(item => { - if (item.editor.protyle.wysiwyg.element.isSameNode(eventPath0)) { - item.editor.protyle.gutter.render(item.editor.protyle, targetBlockElement, item.editor.protyle.wysiwyg.element); - findNode = true; - return true; - } - }); - if (!findNode) { - window.siyuan.blockPanels.find(item => { - item.editors.find(eItem => { - if (eItem.protyle.wysiwyg.element.contains(eventPath0)) { - eItem.protyle.gutter.render(eItem.protyle, targetBlockElement, eItem.protyle.wysiwyg.element); - findNode = true; - return true; - } - }); - if (findNode) { - return true; - } - }); - } - if (!findNode) { - allModels.backlink.find(item => { - item.editors.find(eItem => { - if (eItem.protyle.wysiwyg.element.isSameNode(eventPath0)) { - eItem.protyle.gutter.render(eItem.protyle, targetBlockElement, eItem.protyle.wysiwyg.element); - findNode = true; - return true; - } - }); - if (findNode) { - return true; - } - }); - } - } - return; - } - if (eventPath0 && eventPath0.nodeType !== 3 && (eventPath0.classList.contains("li") || eventPath0.classList.contains("list"))) { - // 光标在列表下部应显示右侧的元素,而不是列表本身 - const targetBlockElement = getRightBlock(eventPath0, eventPath0.getBoundingClientRect().left + 1, event.clientY); - if (!targetBlockElement) { - return; - } - const allModels = getAllModels(); - let findNode = false; - allModels.editor.find(item => { - if (item.editor.protyle.wysiwyg.element.contains(eventPath0)) { - item.editor.protyle.gutter.render(item.editor.protyle, targetBlockElement, item.editor.protyle.wysiwyg.element); - findNode = true; - return true; - } - }); - if (!findNode) { - window.siyuan.blockPanels.find(item => { - item.editors.find(eItem => { - if (eItem.protyle.wysiwyg.element.contains(eventPath0)) { - eItem.protyle.gutter.render(eItem.protyle, targetBlockElement, eItem.protyle.wysiwyg.element); - findNode = true; - return true; - } - }); - if (findNode) { - return true; - } - }); - } - if (!findNode) { - allModels.backlink.find(item => { - item.editors.find(eItem => { - if (eItem.protyle.wysiwyg.element.contains(eventPath0)) { - eItem.protyle.gutter.render(eItem.protyle, targetBlockElement, eItem.protyle.wysiwyg.element); - findNode = true; - return true; - } - }); - if (findNode) { - return true; - } - }); - } - return; - } - - const target = event.target as Element; - const blockElement = hasClosestByClassName(target, "table"); - if (blockElement && blockElement.style.cursor !== "col-resize" && !hasClosestByClassName(blockElement, "protyle-wysiwyg__embed")) { - const cellElement = (hasClosestByMatchTag(target, "TH") || hasClosestByMatchTag(target, "TD")) as HTMLTableCellElement; - if (cellElement) { - const tableElement = blockElement.querySelector("table"); - const tableHeight = blockElement.querySelector("table").clientHeight; - const resizeElement = blockElement.querySelector(".table__resize"); - if (blockElement.style.textAlign === "center" || blockElement.style.textAlign === "right") { - resizeElement.parentElement.style.left = tableElement.offsetLeft + "px"; - } else { - resizeElement.parentElement.style.left = ""; - } - const rect = cellElement.getBoundingClientRect(); - if (rect.right - event.clientX < 3 && rect.right - event.clientX > 0) { - resizeElement.setAttribute("data-col-index", (getColIndex(cellElement) + cellElement.colSpan - 1).toString()); - resizeElement.setAttribute("style", `height:${tableHeight}px;left: ${Math.round(cellElement.offsetWidth + cellElement.offsetLeft - blockElement.firstElementChild.scrollLeft - 3)}px;display:block`); - } else if (event.clientX - rect.left < 3 && event.clientX - rect.left > 0 && cellElement.previousElementSibling) { - resizeElement.setAttribute("data-col-index", (getColIndex(cellElement) - 1).toString()); - resizeElement.setAttribute("style", `height:${tableHeight}px;left: ${Math.round(cellElement.offsetLeft - blockElement.firstElementChild.scrollLeft - 3)}px;display:block`); - } - } - } - }); - - window.addEventListener("mouseup", (event) => { - if (event.button === 3) { - event.preventDefault(); - goBack(app); - } else if (event.button === 4) { - event.preventDefault(); - goForward(app); - } - }); - - let switchDialog: Dialog; - - window.addEventListener("keyup", (event) => { - window.siyuan.ctrlIsPressed = false; - window.siyuan.shiftIsPressed = false; - window.siyuan.altIsPressed = false; - if (switchDialog && switchDialog.element.parentElement) { - if (event.key === "Tab") { - let currentLiElement = switchDialog.element.querySelector(".b3-list-item--focus"); - currentLiElement.classList.remove("b3-list-item--focus"); - if (event.shiftKey) { - if (currentLiElement.previousElementSibling) { - currentLiElement.previousElementSibling.classList.add("b3-list-item--focus"); - } else if (currentLiElement.getAttribute("data-original")) { - currentLiElement.parentElement.lastElementChild.classList.add("b3-list-item--focus"); - currentLiElement.removeAttribute("data-original"); - } else if (currentLiElement.parentElement.nextElementSibling) { - if (currentLiElement.parentElement.nextElementSibling.lastElementChild) { - currentLiElement.parentElement.nextElementSibling.lastElementChild.classList.add("b3-list-item--focus"); - } else { - currentLiElement.parentElement.lastElementChild.classList.add("b3-list-item--focus"); - } - } else if (currentLiElement.parentElement.previousElementSibling) { - currentLiElement.parentElement.previousElementSibling.lastElementChild.classList.add("b3-list-item--focus"); - } - } else { - if (currentLiElement.nextElementSibling) { - currentLiElement.nextElementSibling.classList.add("b3-list-item--focus"); - } else if (currentLiElement.getAttribute("data-original")) { - currentLiElement.parentElement.firstElementChild.classList.add("b3-list-item--focus"); - currentLiElement.removeAttribute("data-original"); - } else if (currentLiElement.parentElement.nextElementSibling) { - if (currentLiElement.parentElement.nextElementSibling.firstElementChild) { - currentLiElement.parentElement.nextElementSibling.firstElementChild.classList.add("b3-list-item--focus"); - } else { - currentLiElement.parentElement.firstElementChild.classList.add("b3-list-item--focus"); - } - } else if (currentLiElement.parentElement.previousElementSibling) { - currentLiElement.parentElement.previousElementSibling.firstElementChild.classList.add("b3-list-item--focus"); - } - } - currentLiElement = switchDialog.element.querySelector(".b3-list-item--focus"); - if (currentLiElement) { - const rootId = currentLiElement.getAttribute("data-node-id"); - if (rootId) { - fetchPost("/api/filetree/getFullHPathByID", { - id: rootId - }, (response) => { - currentLiElement.parentElement.parentElement.nextElementSibling.innerHTML = escapeHtml(response.data); - }); - } else { - currentLiElement.parentElement.parentElement.nextElementSibling.innerHTML = currentLiElement.querySelector(".b3-list-item__text").innerHTML; - } - const currentRect = currentLiElement.getBoundingClientRect(); - const currentParentRect = currentLiElement.parentElement.getBoundingClientRect(); - if (currentRect.top < currentParentRect.top) { - currentLiElement.scrollIntoView(true); - } else if (currentRect.bottom > currentParentRect.bottom) { - currentLiElement.scrollIntoView(false); - } - } - const originalElement = switchDialog.element.querySelector('[data-original="true"]'); - if (originalElement) { - originalElement.removeAttribute("data-original"); - } - } else if (event.key === "Control") { - let currentLiElement = switchDialog.element.querySelector(".b3-list-item--focus"); - // 快速切换时,不触发 Tab - if (currentLiElement.getAttribute("data-original")) { - currentLiElement.classList.remove("b3-list-item--focus"); - if (event.shiftKey) { - if (currentLiElement.previousElementSibling) { - currentLiElement.previousElementSibling.classList.add("b3-list-item--focus"); - } else { - currentLiElement.parentElement.lastElementChild.classList.add("b3-list-item--focus"); - currentLiElement.removeAttribute("data-original"); - } - } else { - if (currentLiElement.nextElementSibling) { - currentLiElement.nextElementSibling.classList.add("b3-list-item--focus"); - } else { - currentLiElement.parentElement.firstElementChild.classList.add("b3-list-item--focus"); - } - } - currentLiElement.removeAttribute("data-original"); - currentLiElement = switchDialog.element.querySelector(".b3-list-item--focus"); - } - const currentType = currentLiElement.getAttribute("data-type"); - if (currentType) { - if (currentType === "riffCard") { - openCard(app); - } else { - getDockByType(currentType).toggleModel(currentType, true); - } - if (document.activeElement) { - (document.activeElement as HTMLElement).blur(); - } - } else { - const currentId = currentLiElement.getAttribute("data-id"); - getAllTabs().find(item => { - if (item.id === currentId) { - item.parent.switchTab(item.headElement); - item.parent.showHeading(); - return true; - } - }); - } - switchDialog.destroy(); - switchDialog = undefined; - } - } - }); - - window.addEventListener("keydown", (event) => { - if (document.querySelector(".av__mask") || document.getElementById("errorLog") || event.isComposing) { - return; - } - const target = event.target as HTMLElement; - if (!event.ctrlKey && !event.metaKey && !event.shiftKey && !event.altKey && - !["INPUT", "TEXTAREA"].includes(target.tagName) && - ["0", "1", "2", "3", "4", "j", "k", "l", ";", "s", " ", "p"].includes(event.key.toLowerCase())) { - let cardElement: Element; - window.siyuan.dialogs.find(item => { - if (item.element.getAttribute("data-key") === window.siyuan.config.keymap.general.riffCard.custom) { - cardElement = item.element; - return true; - } - }); - if (!cardElement) { - cardElement = document.querySelector(`.layout__wnd--active div[data-key="${window.siyuan.config.keymap.general.riffCard.custom}"]:not(.fn__none)`); - } - if (cardElement) { - event.preventDefault(); - cardElement.dispatchEvent(new CustomEvent("click", {detail: event.key.toLowerCase()})); - return; - } - } - - // 仅处理以下快捷键操作 - if (!event.ctrlKey && !isCtrl(event) && event.key !== "Escape" && !event.shiftKey && !event.altKey && - !/^F\d{1,2}$/.test(event.key) && event.key.indexOf("Arrow") === -1 && event.key !== "Enter" && event.key !== "Backspace" && event.key !== "Delete") { - return; - } - - if (!event.altKey && !event.shiftKey && isCtrl(event)) { - if (event.key === "Meta" || event.key === "Control" || event.ctrlKey || event.metaKey) { - window.siyuan.ctrlIsPressed = true; - if ((event.key === "Meta" || event.key === "Control") && - window.siyuan.config.editor.floatWindowMode === 1 && !event.repeat) { - showPopover(app); - } - } else { - window.siyuan.ctrlIsPressed = false; - } - } - - if (!event.altKey && event.shiftKey && !isCtrl(event)) { - if (event.key === "Shift") { - window.siyuan.shiftIsPressed = true; - if (!event.repeat) { - showPopover(app, true); - } - } else { - window.siyuan.shiftIsPressed = false; - } - } - - if (event.altKey && !event.shiftKey && !isCtrl(event)) { - if (event.key === "Alt") { - window.siyuan.altIsPressed = true; - } else { - window.siyuan.altIsPressed = false; - } - } - - if (switchDialog && event.ctrlKey && !event.metaKey && event.key.startsWith("Arrow")) { - dialogArrow(app, switchDialog.element, event); - return; - } - - const isTabWindow = isWindow(); - if (event.ctrlKey && !event.metaKey && event.key === "Tab") { - if (switchDialog && switchDialog.element.parentElement) { - return; - } - let tabHtml = ""; - let currentTabElement = document.querySelector(".layout__wnd--active .layout-tab-bar > .item--focus"); - if (!currentTabElement) { - currentTabElement = document.querySelector(".layout-tab-bar > .item--focus"); - } - if (currentTabElement) { - const currentId = currentTabElement.getAttribute("data-id"); - getAllTabs().sort((itemA, itemB) => { - return itemA.headElement.getAttribute("data-activetime") > itemB.headElement.getAttribute("data-activetime") ? -1 : 1; - }).forEach((item, index) => { - let icon = ``; - let rootId = ""; - const initData = item.headElement.getAttribute("data-initdata"); - if (item.model instanceof Editor) { - rootId = ` data-node-id="${item.model.editor.protyle.block.rootID}"`; - icon = unicode2Emoji(item.docIcon || Constants.SIYUAN_IMAGE_FILE, "b3-list-item__graphic", true); - } else if (initData) { - const initDataObj = JSON.parse(initData); - if (initDataObj.instance === "Editor") { - rootId = ` data-node-id="${initDataObj.rootId}"`; - icon = unicode2Emoji(item.docIcon || Constants.SIYUAN_IMAGE_FILE, "b3-list-item__graphic", true); - } - } - tabHtml += `
  • ${icon}${escapeHtml(item.title)}
  • `; - }); - } - let dockHtml = ""; - if (!isTabWindow) { - dockHtml = `"; - } - hideElements(["dialog"]); - switchDialog = new Dialog({ - title: window.siyuan.languages.switchTab, - content: `
    -
    -
    ${dockHtml} - ${tabHtml} -
    -
    -
    `, - }); - // 需移走光标,否则编辑器会继续监听并执行按键操作 - switchDialog.element.querySelector("input").focus(); - if (isMac()) { - switchDialog.element.addEventListener("contextmenu", (event) => { - switchDialogEvent(app, event, switchDialog); - }); - } - switchDialog.element.addEventListener("click", (event) => { - switchDialogEvent(app, event, switchDialog); - }); - return; - } - - if (!event.ctrlKey && !event.metaKey && !event.shiftKey && !event.altKey && - (event.key.startsWith("Arrow") || event.key === "Enter")) { - const openRecentDocsDialog = window.siyuan.dialogs.find(item => { - if (item.element.getAttribute("data-key") === window.siyuan.config.keymap.general.recentDocs.custom) { - return true; - } - }); - if (openRecentDocsDialog) { - event.preventDefault(); - dialogArrow(app, openRecentDocsDialog.element, event); - return; - } - } - - if (matchHotKey(window.siyuan.config.keymap.general.recentDocs.custom, event)) { - const openRecentDocsDialog = window.siyuan.dialogs.find(item => { - if (item.element.getAttribute("data-key") === window.siyuan.config.keymap.general.recentDocs.custom) { - return true; - } - }); - if (openRecentDocsDialog) { - hideElements(["dialog"]); - return; - } - openRecentDocs(); - event.preventDefault(); - return; - } - - if (bindMenuKeydown(event)) { - event.preventDefault(); - return; - } - - if (event.key === "ArrowUp" || event.key === "ArrowDown") { - const viewCardsDialog = window.siyuan.dialogs.find(item => { - if (item.element.getAttribute("data-key") === "viewCards") { - return true; - } - }); - if (viewCardsDialog) { - viewCardsDialog.element.dispatchEvent(new CustomEvent("click", {detail: event.key.toLowerCase()})); - event.preventDefault(); - return; - } - } - - /// #if !BROWSER - if (matchHotKey("⌘=", event) && !hasClosestByClassName(target, "pdf__outer")) { - setZoom("zoomIn"); - event.preventDefault(); - return; - } - if (matchHotKey("⌘0", event)) { - setZoom("restore"); - event.preventDefault(); - return; - } - if (matchHotKey("⌘-", event) && !hasClosestByClassName(target, "pdf__outer")) { - setZoom("zoomOut"); - event.preventDefault(); - return; - } - /// #endif - - if (!isTabWindow && matchHotKey(window.siyuan.config.keymap.general.syncNow.custom, event)) { - event.preventDefault(); - syncGuide(app); - return; - } - if (matchHotKey(window.siyuan.config.keymap.general.commandPanel.custom, event)) { - event.preventDefault(); - commandPanel(app); - return; - } - if (matchHotKey(window.siyuan.config.keymap.general.editMode.custom, event)) { - event.preventDefault(); - editor.setReadonly(); - return; - } - if (matchHotKey(window.siyuan.config.keymap.general.lockScreen.custom, event)) { - lockScreen(); - event.preventDefault(); - return; - } - if (!isTabWindow && matchHotKey(window.siyuan.config.keymap.general.dataHistory.custom, event)) { - if (!window.siyuan.config.readonly) { - openHistory(app); - } - event.preventDefault(); - return; - } - if (!isTabWindow && matchHotKey(window.siyuan.config.keymap.general.toggleDock.custom, event)) { - toggleDockBar(document.querySelector("#barDock use")); - event.preventDefault(); - return; - } - if (!isTabWindow && !window.siyuan.config.readonly && matchHotKey(window.siyuan.config.keymap.general.config.custom, event)) { - openSetting(app); - event.preventDefault(); - return; - } - if (matchHotKey("⌘A", event) && target.tagName !== "INPUT" && target.tagName !== "TEXTAREA") { - event.preventDefault(); - return; - } - const matchDock = getAllDocks().find(item => { - if (matchHotKey(item.hotkey, event)) { - getDockByType(item.type).toggleModel(item.type); - event.preventDefault(); - return true; - } - }); - if (matchDock) { - return; - } - if (!isTabWindow && matchHotKey(window.siyuan.config.keymap.general.riffCard.custom, event)) { - openCard(app); - if (document.activeElement) { - (document.activeElement as HTMLElement).blur(); - } - event.preventDefault(); - return; - } - if (!isTabWindow && matchHotKey(window.siyuan.config.keymap.general.dailyNote.custom, event)) { - newDailyNote(); - event.stopPropagation(); - event.preventDefault(); - return; - } - if (matchHotKey(window.siyuan.config.keymap.general.newFile.custom, event)) { - newFile(app, undefined, undefined, undefined, true); - event.preventDefault(); - return; - } - // https://github.com/siyuan-note/siyuan/issues/8913#issuecomment-1679720605 - const confirmElement = document.querySelector("#confirmDialogConfirmBtn"); - if (confirmElement) { - if (event.key === "Enter") { - confirmElement.dispatchEvent(new CustomEvent("click")); - event.preventDefault(); - return; - } else if (event.key === "Escape") { - confirmElement.previousElementSibling.previousElementSibling.dispatchEvent(new CustomEvent("click")); - event.preventDefault(); - return; - } - } - - if (event.key === "Escape" && !event.isComposing) { - const imgPreviewElement = document.querySelector(".protyle-img"); - if (imgPreviewElement) { - imgPreviewElement.remove(); - return; - } - if (!window.siyuan.menus.menu.element.classList.contains("fn__none")) { - window.siyuan.menus.menu.remove(); - return; - } - if (window.siyuan.dialogs.length > 0) { - hideElements(["dialog"]); - return; - } - - // remove blockpopover - const maxEditLevels: { [key: string]: number } = {oid: 0}; - window.siyuan.blockPanels.forEach((item) => { - if ((item.targetElement || typeof item.x === "number") && item.element.getAttribute("data-pin") === "true") { - const level = parseInt(item.element.getAttribute("data-level")); - const oid = item.element.getAttribute("data-oid"); - if (maxEditLevels[oid]) { - if (level > maxEditLevels[oid]) { - maxEditLevels[oid] = level; - } - } else { - maxEditLevels[oid] = 1; - } - } - }); - let destroyBlock = false; - for (let i = 0; i < window.siyuan.blockPanels.length; i++) { - const item = window.siyuan.blockPanels[i]; - if ((item.targetElement || typeof item.x === "number") && item.element.getAttribute("data-pin") === "false" && - parseInt(item.element.getAttribute("data-level")) > (maxEditLevels[item.element.getAttribute("data-oid")] || 0)) { - item.destroy(); - destroyBlock = true; - i--; - } - } - if (destroyBlock) { - return; - } - - // 光标在文档树等面板中,按 Esc 回到编辑器中 https://github.com/siyuan-note/siyuan/issues/4289 - let range; - if (getSelection().rangeCount > 0) { - range = getSelection().getRangeAt(0); - const protypleElement = hasClosestByClassName(range.startContainer, "protyle-content", true); - if (protypleElement) { - focusByRange(range); - return; - } - } else { - range = document.createRange(); - } - const lastBackStack = window.siyuan.backStack[window.siyuan.backStack.length - 1]; - if (lastBackStack && lastBackStack.protyle.toolbar.range) { - focusByRange(lastBackStack.protyle.toolbar.range); - } else { - const editor = getAllModels().editor[0]; - if (editor) { - focusBlock(editor.editor.protyle.wysiwyg.element.firstElementChild); - } - } - event.preventDefault(); - return; - } - - if (!isTabWindow && matchHotKey(window.siyuan.config.keymap.general.mainMenu.custom, event)) { - workspaceMenu(app, document.querySelector("#barWorkspace").getBoundingClientRect()); - event.preventDefault(); - return; - } - - if (matchHotKey(window.siyuan.config.keymap.general.goForward.custom, event)) { - goForward(app); - event.preventDefault(); - return; - } - - if (matchHotKey(window.siyuan.config.keymap.general.goBack.custom, event)) { - goBack(app); - event.preventDefault(); - return; - } - - // close tab - if (matchHotKey(window.siyuan.config.keymap.general.closeTab.custom, event) && !event.repeat) { - event.preventDefault(); - let activeTabElement = document.querySelector(".layout__tab--active"); - if (activeTabElement && activeTabElement.getBoundingClientRect().width > 0) { - let type = ""; - Array.from(activeTabElement.classList).find(item => { - if (item.startsWith("sy__")) { - type = item.replace("sy__", ""); - return true; - } - }); - if (type) { - getDockByType(type)?.toggleModel(type, false, true); - } - return; - } - activeTabElement = document.querySelector(".layout__wnd--active .item--focus"); - if (activeTabElement) { - const tab = getInstanceById(activeTabElement.getAttribute("data-id")) as Tab; - tab.parent.removeTab(tab.id); - return; - } - getAllTabs().find(item => { - if (item.headElement?.classList.contains("item--focus")) { - item.parent.removeTab(item.id); - return true; - } - }); - return; - } - - if (matchHotKey(window.siyuan.config.keymap.general.stickSearch.custom, event)) { - if (getSelection().rangeCount > 0) { - const range = getSelection().getRangeAt(0); - openGlobalSearch(app, range.toString(), false); - } else { - openGlobalSearch(app, "", false); - } - event.preventDefault(); - return; - } - - if (editKeydown(app, event)) { - return; - } - - // 文件树的操作 - if (!isTabWindow && fileTreeKeydown(app, event)) { - return; - } - - // 面板的操作 - if (!isTabWindow && panelTreeKeydown(app, event)) { - return; - } - - let matchCommand = false; - app.plugins.find(item => { - item.commands.find(command => { - if (command.callback && - !command.fileTreeCallback && !command.editorCallback && !command.dockCallback - && matchHotKey(command.customHotkey, event)) { - matchCommand = true; - command.callback(); - return true; - } - }); - if (matchCommand) { - return true; - } - }); - if (matchCommand) { - event.stopPropagation(); - event.preventDefault(); - return true; - } - - let searchKey = ""; - if (matchHotKey(window.siyuan.config.keymap.general.replace.custom, event)) { - searchKey = window.siyuan.config.keymap.general.replace.custom; - } else if (!hasClosestByClassName(target, "pdf__outer") && matchHotKey(window.siyuan.config.keymap.general.search.custom, event)) { - searchKey = window.siyuan.config.keymap.general.search.custom; - } else if (matchHotKey(window.siyuan.config.keymap.general.globalSearch.custom, event)) { - searchKey = window.siyuan.config.keymap.general.globalSearch.custom; - } - if (searchKey) { - if (getSelection().rangeCount > 0) { - const range = getSelection().getRangeAt(0); - openSearch({ - app, - hotkey: searchKey, - key: range.toString(), - }); - } else { - openSearch({ - app, - hotkey: searchKey, - }); - } - event.preventDefault(); - return; - } - - // https://github.com/siyuan-note/insider/issues/445 - if (matchHotKey("⌘S", event)) { - event.preventDefault(); - return true; - } - }); - - window.addEventListener("blur", () => { - window.siyuan.ctrlIsPressed = false; - window.siyuan.shiftIsPressed = false; - window.siyuan.altIsPressed = false; - }); - - window.addEventListener("click", (event: MouseEvent & { target: HTMLElement }) => { - if (!window.siyuan.menus.menu.element.contains(event.target) && !hasClosestByAttribute(event.target, "data-menu", "true")) { - if (getSelection().rangeCount > 0 && window.siyuan.menus.menu.element.contains(getSelection().getRangeAt(0).startContainer) && - window.siyuan.menus.menu.element.contains(document.activeElement)) { - // https://ld246.com/article/1654567749834/comment/1654589171218#comments - } else { - window.siyuan.menus.menu.remove(); - } - } - // protyle.toolbar 点击空白处时进行隐藏 - if (!hasClosestByClassName(event.target, "protyle-toolbar")) { - hideAllElements(["toolbar"]); - } - if (!hasClosestByClassName(event.target, "pdf__outer")) { - hideAllElements(["pdfutil"]); - } - // dock float 时,点击空白处,隐藏 dock - const floatDockLayoutElement = hasClosestByClassName(event.target, "layout--float", true); - if (floatDockLayoutElement && window.siyuan.layout.leftDock) { - if (!floatDockLayoutElement.isSameNode(window.siyuan.layout.bottomDock.layout.element)) { - window.siyuan.layout.bottomDock.hideDock(); - } - if (!floatDockLayoutElement.isSameNode(window.siyuan.layout.leftDock.layout.element)) { - window.siyuan.layout.leftDock.hideDock(); - } - if (!floatDockLayoutElement.isSameNode(window.siyuan.layout.rightDock.layout.element)) { - window.siyuan.layout.rightDock.hideDock(); - } - } else if (!hasClosestByClassName(event.target, "dock") && !isWindow() && window.siyuan.layout.leftDock) { - window.siyuan.layout.bottomDock.hideDock(); - window.siyuan.layout.leftDock.hideDock(); - window.siyuan.layout.rightDock.hideDock(); - } - const copyElement = hasTopClosestByClassName(event.target, "protyle-action__copy"); - if (copyElement) { - writeText(copyElement.parentElement.nextElementSibling.textContent.trimEnd()); - showMessage(window.siyuan.languages.copied, 2000); - event.preventDefault(); - } - - // 点击空白,pdf 搜索、更多消失 - if (hasClosestByAttribute(event.target, "id", "secondaryToolbarToggle") || - hasClosestByAttribute(event.target, "id", "viewFind") || - hasClosestByAttribute(event.target, "id", "findbar")) { - return; - } - let currentPDFViewerObject: any; - getAllModels().asset.find(item => { - if (item.pdfObject && - !item.pdfObject.appConfig.appContainer.classList.contains("fn__none")) { - currentPDFViewerObject = item.pdfObject; - return true; - } - }); - if (!currentPDFViewerObject) { - return; - } - if (currentPDFViewerObject.secondaryToolbar.isOpen) { - currentPDFViewerObject.secondaryToolbar.close(); - } - if ( - !currentPDFViewerObject.supportsIntegratedFind && - currentPDFViewerObject.findBar.opened - ) { - currentPDFViewerObject.findBar.close(); - } - }); -}; - -const dialogArrow = (app: App, element: HTMLElement, event: KeyboardEvent) => { - let currentLiElement = element.querySelector(".b3-list-item--focus"); - if (currentLiElement) { - currentLiElement.classList.remove("b3-list-item--focus"); - if (event.key === "ArrowUp") { - if (currentLiElement.previousElementSibling) { - currentLiElement.previousElementSibling.classList.add("b3-list-item--focus"); - } else { - currentLiElement.parentElement.lastElementChild.classList.add("b3-list-item--focus"); - } - } else if (event.key === "ArrowDown") { - if (currentLiElement.nextElementSibling) { - currentLiElement.nextElementSibling.classList.add("b3-list-item--focus"); - } else { - currentLiElement.parentElement.firstElementChild.classList.add("b3-list-item--focus"); - } - } else if (event.key === "ArrowLeft" || event.key === "ArrowRight") { - if (isWindow()) { - currentLiElement.classList.add("b3-list-item--focus"); - } else { - const sideElement = currentLiElement.parentElement.previousElementSibling || currentLiElement.parentElement.nextElementSibling; - (sideElement.querySelector(`[data-index="${currentLiElement.getAttribute("data-index")}"]`) || sideElement.lastElementChild).classList.add("b3-list-item--focus"); - } - } else if (event.key === "Enter") { - const currentType = currentLiElement.getAttribute("data-type"); - if (currentType) { - if (currentType === "riffCard") { - openCard(app); - } else { - getDockByType(currentType).toggleModel(currentType, true); - } - } else { - openFileById({ - app, - id: currentLiElement.getAttribute("data-node-id"), - action: [Constants.CB_GET_SCROLL] - }); - } - hideElements(["dialog"]); - return; - } - currentLiElement = element.querySelector(".b3-list-item--focus"); - const rootId = currentLiElement.getAttribute("data-node-id"); - if (rootId) { - fetchPost("/api/filetree/getFullHPathByID", { - id: rootId - }, (response) => { - currentLiElement.parentElement.parentElement.nextElementSibling.innerHTML = escapeHtml(response.data); - }); - } else { - currentLiElement.parentElement.parentElement.nextElementSibling.innerHTML = currentLiElement.querySelector(".b3-list-item__text").innerHTML; - } - const currentRect = currentLiElement.getBoundingClientRect(); - const currentParentRect = currentLiElement.parentElement.getBoundingClientRect(); - if (currentRect.top < currentParentRect.top) { - currentLiElement.scrollIntoView(true); - } else if (currentRect.bottom > currentParentRect.bottom) { - currentLiElement.scrollIntoView(false); - } - } -}; - -const editKeydown = (app: App, event: KeyboardEvent) => { - const activeTabElement = document.querySelector(".layout__wnd--active .item--focus"); - let protyle: IProtyle; - if (activeTabElement) { - const tab = getInstanceById(activeTabElement.getAttribute("data-id")) as Tab; - if (!(tab.model instanceof Editor)) { - return false; - } - protyle = tab.model.editor.protyle; - } else { - const editor = getAllModels().editor.find(item => { - if (item.parent.headElement.classList.contains("item--focus")) { - return true; - } - }); - if (!editor) { - return false; - } - protyle = editor.editor.protyle; - } - const activePanelElement = document.querySelector(".layout__tab--active"); - let isFileFocus = false; - if (activePanelElement && activePanelElement.classList.contains("sy__file")) { - isFileFocus = true; - } - let searchKey = ""; - if (matchHotKey(window.siyuan.config.keymap.general.replace.custom, event)) { - searchKey = window.siyuan.config.keymap.general.replace.custom; - } else if (matchHotKey(window.siyuan.config.keymap.general.search.custom, event)) { - searchKey = window.siyuan.config.keymap.general.search.custom; - } - if (!isFileFocus && searchKey) { - let range: Range; - if (getSelection().rangeCount > 0) { - range = getSelection().getRangeAt(0); - } - if (range && protyle.element.contains(range.startContainer)) { - openSearch({ - app, - hotkey: searchKey, - key: range.toString(), - notebookId: protyle.notebookId, - searchPath: protyle.path - }); - } else { - openSearch({ - app, - hotkey: searchKey, - }); - } - event.preventDefault(); - return true; - } - if (!isFileFocus && matchHotKey(window.siyuan.config.keymap.editor.general.spaceRepetition.custom, event)) { - fetchPost("/api/riff/getTreeRiffDueCards", {rootID: protyle.block.rootID}, (response) => { - openCardByData(app, response.data, "doc", protyle.block.rootID, protyle.title.editElement.textContent || "Untitled"); - }); - event.preventDefault(); - return true; - } - if (!isFileFocus && matchHotKey(window.siyuan.config.keymap.general.move.custom, event)) { - let range: Range; - let nodeElement: false | HTMLElement; - if (getSelection().rangeCount > 0) { - range = getSelection().getRangeAt(0); - nodeElement = hasClosestBlock(range.startContainer); - } - if (protyle.title?.editElement.contains(range.startContainer)) { - movePathTo((toPath, toNotebook) => { - moveToPath([protyle.path], toNotebook[0], toPath[0]); - }, [protyle.path], range); - } else if (nodeElement && range && protyle.element.contains(range.startContainer)) { - let selectElements = Array.from(protyle.wysiwyg.element.querySelectorAll(".protyle-wysiwyg--select")); - if (selectElements.length === 0) { - selectElements = [nodeElement]; - } - movePathTo((toPath) => { - hintMoveBlock(toPath[0], selectElements, protyle); - }); - } - event.preventDefault(); - return true; - } - const target = event.target as HTMLElement; - if (target.tagName !== "TABLE" && ( - target.tagName === "INPUT" || target.tagName === "TEXTAREA" || hasClosestByAttribute(target, "contenteditable", null) - )) { - return false; - } - if (matchHotKey(window.siyuan.config.keymap.editor.general.refresh.custom, event)) { - reloadProtyle(protyle, true); - event.preventDefault(); - return true; - } - if (matchHotKey(window.siyuan.config.keymap.editor.general.fullscreen.custom, event)) { - fullscreen(protyle.element); - setPadding(protyle); - event.preventDefault(); - return true; - } - if (matchHotKey(window.siyuan.config.keymap.editor.general.preview.custom, event)) { - setEditMode(protyle, "preview"); - event.preventDefault(); - return true; - } - if (matchHotKey(window.siyuan.config.keymap.editor.general.wysiwyg.custom, event) && !protyle.options.backlinkData) { - setEditMode(protyle, "wysiwyg"); - protyle.scroll.lastScrollTop = 0; - fetchPost("/api/filetree/getDoc", { - id: protyle.block.parentID, - size: window.siyuan.config.editor.dynamicLoadBlocks, - }, getResponse => { - onGet({data: getResponse, protyle}); - }); - event.preventDefault(); - return true; - } - // 没有光标时,无法撤销 https://ld246.com/article/1624021111567 - if (matchHotKey(window.siyuan.config.keymap.editor.general.undo.custom, event)) { - protyle.undo.undo(protyle); - event.preventDefault(); - return true; - } - if (matchHotKey(window.siyuan.config.keymap.editor.general.redo.custom, event)) { - protyle.undo.redo(protyle); - event.preventDefault(); - return true; - } - return false; -}; - -const fileTreeKeydown = (app: App, event: KeyboardEvent) => { - const dockFile = getDockByType("file"); - if (!dockFile) { - return false; - } - const files = dockFile.data.file as Files; - - if (matchHotKey(window.siyuan.config.keymap.general.selectOpen1.custom, event)) { - event.preventDefault(); - const element = document.querySelector(".layout__wnd--active > .fn__flex > .layout-tab-bar > .item--focus") || - document.querySelector(".layout-tab-bar > .item--focus"); - if (element) { - const tab = getInstanceById(element.getAttribute("data-id")) as Tab; - if (tab && tab.model instanceof Editor) { - tab.model.editor.protyle.wysiwyg.element.blur(); - tab.model.editor.protyle.title.editElement.blur(); - files.selectItem(tab.model.editor.protyle.notebookId, tab.model.editor.protyle.path); - } - } - dockFile.toggleModel("file", true); - return; - } - - if (!files.element.parentElement.classList.contains("layout__tab--active")) { - return false; - } - - let matchCommand = false; - app.plugins.find(item => { - item.commands.find(command => { - if (command.fileTreeCallback && matchHotKey(command.customHotkey, event)) { - matchCommand = true; - command.fileTreeCallback(files); - return true; - } - }); - if (matchCommand) { - return true; - } - }); - if (matchCommand) { - return true; - } - - const liElements = Array.from(files.element.querySelectorAll(".b3-list-item--focus")); - if (liElements.length === 0) { - if (event.key.startsWith("Arrow") && !isCtrl(event)) { - const liElement = files.element.querySelector(".b3-list-item"); - if (liElement) { - liElement.classList.add("b3-list-item--focus"); - } - event.preventDefault(); - } - return false; - } - const topULElement = hasTopClosestByTag(liElements[0], "UL"); - if (!topULElement) { - return false; - } - const notebookId = topULElement.getAttribute("data-url"); - const pathString = liElements[0].getAttribute("data-path"); - const isFile = liElements[0].getAttribute("data-type") === "navigation-file"; - - if (matchHotKey(window.siyuan.config.keymap.editor.general.spaceRepetition.custom, event)) { - if (isFile) { - const id = liElements[0].getAttribute("data-node-id"); - fetchPost("/api/riff/getTreeRiffDueCards", {rootID: id}, (response) => { - openCardByData(app, response.data, "doc", id, getDisplayName(liElements[0].getAttribute("data-name"), false, true)); - }); - } else { - fetchPost("/api/riff/getNotebookRiffDueCards", {notebook: notebookId}, (response) => { - openCardByData(app, response.data, "notebook", notebookId, getNotebookName(notebookId)); - }); - } - } - - if (matchHotKey(window.siyuan.config.keymap.editor.general.rename.custom, event)) { - window.siyuan.menus.menu.remove(); - rename({ - notebookId, - path: pathString, - name: isFile ? getDisplayName(liElements[0].getAttribute("data-name"), false, true) : getNotebookName(notebookId), - type: isFile ? "file" : "notebook", - }); - event.preventDefault(); - return true; - } - - if (matchHotKey("⌘/", event)) { - const liRect = liElements[0].getBoundingClientRect(); - if (isFile) { - initFileMenu(app, notebookId, pathString, liElements[0]).popup({ - x: liRect.right - 15, - y: liRect.top + 15 - }); - } else { - initNavigationMenu(app, liElements[0] as HTMLElement).popup({x: liRect.right - 15, y: liRect.top + 15}); - } - return true; - } - - if (isFile && matchHotKey(window.siyuan.config.keymap.general.move.custom, event)) { - window.siyuan.menus.menu.remove(); - const pathes = getTopPaths(liElements); - movePathTo((toPath, toNotebook) => { - moveToPath(pathes, toNotebook[0], toPath[0]); - }, pathes); - event.preventDefault(); - return true; - } - - if (isFile && matchHotKey(window.siyuan.config.keymap.editor.general.insertRight.custom, event)) { - window.siyuan.menus.menu.remove(); - openFileById({ - app, - id: liElements[0].getAttribute("data-node-id"), - action: [Constants.CB_GET_FOCUS], - position: "right", - }); - event.preventDefault(); - return true; - } - - let searchKey = ""; - if (matchHotKey(window.siyuan.config.keymap.general.replace.custom, event)) { - searchKey = window.siyuan.config.keymap.general.replace.custom; - } else if (matchHotKey(window.siyuan.config.keymap.general.search.custom, event)) { - searchKey = window.siyuan.config.keymap.general.search.custom; - } - if (searchKey) { - window.siyuan.menus.menu.remove(); - if (isFile) { - openSearch({ - app, - hotkey: searchKey, - notebookId: notebookId, - searchPath: getDisplayName(pathString, false, true) - }); - } else { - openSearch({ - app, - hotkey: searchKey, - notebookId: notebookId, - }); - } - event.preventDefault(); - return true; - } - const target = event.target as HTMLElement; - if (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || - hasClosestByAttribute(target, "contenteditable", null) || - hasClosestByClassName(target, "protyle", true)) { - return false; - } - if (!window.siyuan.menus.menu.element.classList.contains("fn__none") && - (event.code.startsWith("Arrow") || event.code === "Enter") && - !event.altKey && !event.shiftKey && !isCtrl(event)) { - event.preventDefault(); - return true; - } - if (event.shiftKey) { - if (event.key === "ArrowUp") { - const startEndElement = getStartEndElement(liElements); - let previousElement: Element; - if (startEndElement.startElement.getBoundingClientRect().top >= startEndElement.endElement.getBoundingClientRect().top) { - previousElement = getPreviousFileLi(startEndElement.endElement) as Element; - if (previousElement) { - previousElement.classList.add("b3-list-item--focus"); - previousElement.setAttribute("select-end", "true"); - startEndElement.endElement.removeAttribute("select-end"); - } - } else { - startEndElement.endElement.classList.remove("b3-list-item--focus"); - startEndElement.endElement.removeAttribute("select-end"); - previousElement = getPreviousFileLi(startEndElement.endElement) as Element; - if (previousElement) { - previousElement.setAttribute("select-end", "true"); - } - } - if (previousElement) { - const previousRect = previousElement.getBoundingClientRect(); - const fileRect = files.element.getBoundingClientRect(); - if (previousRect.top < fileRect.top || previousRect.bottom > fileRect.bottom) { - previousElement.scrollIntoView(previousRect.top < fileRect.top); - } - } - } else if (event.key === "ArrowDown") { - const startEndElement = getStartEndElement(liElements); - let nextElement: Element; - if (startEndElement.startElement.getBoundingClientRect().top <= startEndElement.endElement.getBoundingClientRect().top) { - nextElement = getNextFileLi(startEndElement.endElement) as Element; - if (nextElement) { - nextElement.classList.add("b3-list-item--focus"); - nextElement.setAttribute("select-end", "true"); - startEndElement.endElement.removeAttribute("select-end"); - } - } else { - startEndElement.endElement.classList.remove("b3-list-item--focus"); - startEndElement.endElement.removeAttribute("select-end"); - nextElement = getNextFileLi(startEndElement.endElement) as Element; - if (nextElement) { - nextElement.setAttribute("select-end", "true"); - } - } - if (nextElement) { - const nextRect = nextElement.getBoundingClientRect(); - const fileRect = files.element.getBoundingClientRect(); - if (nextRect.top < fileRect.top || nextRect.bottom > fileRect.bottom) { - nextElement.scrollIntoView(nextRect.top < fileRect.top); - } - } - } - return; - } else if (!isCtrl(event)) { - files.element.querySelector('[select-end="true"]')?.removeAttribute("select-end"); - files.element.querySelector('[select-start="true"]')?.removeAttribute("select-start"); - if ((event.key === "ArrowRight" && !liElements[0].querySelector(".b3-list-item__arrow--open") && !liElements[0].querySelector(".b3-list-item__toggle").classList.contains("fn__hidden")) || - (event.key === "ArrowLeft" && liElements[0].querySelector(".b3-list-item__arrow--open"))) { - files.getLeaf(liElements[0], notebookId); - liElements.forEach((item, index) => { - if (index !== 0) { - item.classList.remove("b3-list-item--focus"); - } - }); - event.preventDefault(); - return true; - } - if (event.key === "ArrowLeft") { - let parentElement = liElements[0].parentElement.previousElementSibling; - if (parentElement) { - if (parentElement.tagName !== "LI") { - parentElement = files.element.querySelector(".b3-list-item"); - } - liElements.forEach((item) => { - item.classList.remove("b3-list-item--focus"); - }); - parentElement.classList.add("b3-list-item--focus"); - const parentRect = parentElement.getBoundingClientRect(); - const fileRect = files.element.getBoundingClientRect(); - if (parentRect.top < fileRect.top || parentRect.bottom > fileRect.bottom) { - parentElement.scrollIntoView(parentRect.top < fileRect.top); - } - } - event.preventDefault(); - return true; - } - if (event.key === "ArrowDown" || event.key === "ArrowRight") { - let nextElement = liElements[0]; - while (nextElement) { - if (nextElement.nextElementSibling) { - if (nextElement.nextElementSibling.tagName === "UL") { - nextElement = nextElement.nextElementSibling.firstElementChild; - } else { - nextElement = nextElement.nextElementSibling; - } - break; - } else { - if (nextElement.parentElement.classList.contains("fn__flex-1")) { - break; - } else { - nextElement = nextElement.parentElement; - } - } - } - if (nextElement.classList.contains("b3-list-item")) { - liElements.forEach((item) => { - item.classList.remove("b3-list-item--focus"); - }); - nextElement.classList.add("b3-list-item--focus"); - const nextRect = nextElement.getBoundingClientRect(); - const fileRect = files.element.getBoundingClientRect(); - if (nextRect.top < fileRect.top || nextRect.bottom > fileRect.bottom) { - nextElement.scrollIntoView(nextRect.top < fileRect.top); - } - } - event.preventDefault(); - return true; - } - if (event.key === "ArrowUp") { - let previousElement = liElements[0]; - while (previousElement) { - if (previousElement.previousElementSibling) { - if (previousElement.previousElementSibling.tagName === "LI") { - previousElement = previousElement.previousElementSibling; - } else { - const liElements = previousElement.previousElementSibling.querySelectorAll(".b3-list-item"); - previousElement = liElements[liElements.length - 1]; - } - break; - } else { - if (previousElement.parentElement.classList.contains("fn__flex-1")) { - break; - } else { - previousElement = previousElement.parentElement; - } - } - } - if (previousElement.classList.contains("b3-list-item")) { - liElements.forEach((item) => { - item.classList.remove("b3-list-item--focus"); - }); - previousElement.classList.add("b3-list-item--focus"); - const previousRect = previousElement.getBoundingClientRect(); - const fileRect = files.element.getBoundingClientRect(); - if (previousRect.top < fileRect.top || previousRect.bottom > fileRect.bottom) { - previousElement.scrollIntoView(previousRect.top < fileRect.top); - } - } - event.preventDefault(); - return true; - } - } - if (event.key === "Delete" || (event.key === "Backspace" && isMac())) { - window.siyuan.menus.menu.remove(); - deleteFiles(liElements); - return true; - } - if (event.key === "Enter") { - window.siyuan.menus.menu.remove(); - liElements.forEach(item => { - if (item.getAttribute("data-type") === "navigation-file") { - openFileById({app, id: item.getAttribute("data-node-id"), action: [Constants.CB_GET_FOCUS]}); - } else { - const itemTopULElement = hasTopClosestByTag(item, "UL"); - if (itemTopULElement) { - files.getLeaf(item, itemTopULElement.getAttribute("data-url")); - } - } - }); - return true; - } -}; - -const panelTreeKeydown = (app: App, event: KeyboardEvent) => { - // 面板折叠展开操作 - const target = event.target as HTMLElement; - if (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || - hasClosestByAttribute(target, "contenteditable", null) || - hasClosestByClassName(target, "protyle", true)) { - return false; - } - - let activePanelElement = document.querySelector(".layout__tab--active"); - if (!activePanelElement) { - Array.from(document.querySelectorAll(".layout__wnd--active .layout-tab-container > div")).find(item => { - if (!item.classList.contains("fn__none") && item.className.indexOf("sy__") > -1) { - activePanelElement = item; - return true; - } - }); - } - if (!activePanelElement) { - return false; - } - if (activePanelElement.className.indexOf("sy__") === -1) { - return false; - } - - let matchCommand = false; - app.plugins.find(item => { - item.commands.find(command => { - if (command.dockCallback && matchHotKey(command.customHotkey, event)) { - matchCommand = true; - command.dockCallback(activePanelElement as HTMLElement); - return true; - } - }); - if (matchCommand) { - return true; - } - }); - if (matchCommand) { - return true; - } - if (!matchHotKey(window.siyuan.config.keymap.editor.general.collapse.custom, event) && - !matchHotKey(window.siyuan.config.keymap.editor.general.expand.custom, event) && - !event.key.startsWith("Arrow") && event.key !== "Enter") { - return false; - } - if (!event.repeat && matchHotKey(window.siyuan.config.keymap.editor.general.collapse.custom, event)) { - const collapseElement = activePanelElement.querySelector('.block__icon[data-type="collapse"]'); - if (collapseElement) { - collapseElement.dispatchEvent(new CustomEvent("click")); - event.preventDefault(); - return true; - } - } - if (!event.repeat && matchHotKey(window.siyuan.config.keymap.editor.general.expand.custom, event)) { - const expandElement = activePanelElement.querySelector('.block__icon[data-type="expand"]'); - if (expandElement) { - expandElement.dispatchEvent(new CustomEvent("click")); - event.preventDefault(); - return true; - } - } - if (activePanelElement.classList.contains("sy__inbox") || - activePanelElement.classList.contains("sy__globalGraph") || - activePanelElement.classList.contains("sy__graph")) { - return false; - } - const model = (getInstanceById(activePanelElement.getAttribute("data-id"), window.siyuan.layout.layout) as Tab)?.model; - if (!model) { - return false; - } - let activeItemElement = activePanelElement.querySelector(".b3-list-item--focus"); - if (!activeItemElement) { - activeItemElement = activePanelElement.querySelector(".b3-list .b3-list-item"); - if (activeItemElement) { - activeItemElement.classList.add("b3-list-item--focus"); - } - return false; - } - - let tree = (model as Backlink).tree; - if (activeItemElement.parentElement.parentElement.classList.contains("backlinkMList")) { - tree = (model as Backlink).mTree; - } - if (!tree) { - return false; - } - if (event.key === "Enter") { - tree.click(activeItemElement); - event.preventDefault(); - return true; - } - const arrowElement = activeItemElement.querySelector(".b3-list-item__arrow"); - if ((event.key === "ArrowRight" && !arrowElement.classList.contains("b3-list-item__arrow--open") && !arrowElement.parentElement.classList.contains("fn__hidden")) || - (event.key === "ArrowLeft" && arrowElement.classList.contains("b3-list-item__arrow--open") && !arrowElement.parentElement.classList.contains("fn__hidden"))) { - tree.toggleBlocks(activeItemElement); - event.preventDefault(); - return true; - } - const ulElement = hasClosestByClassName(activeItemElement, "b3-list"); - if (!ulElement) { - return false; - } - if (event.key === "ArrowLeft") { - let parentElement = activeItemElement.parentElement.previousElementSibling; - if (parentElement) { - if (parentElement.tagName !== "LI") { - parentElement = ulElement.querySelector(".b3-list-item"); - } - activeItemElement.classList.remove("b3-list-item--focus"); - parentElement.classList.add("b3-list-item--focus"); - const parentRect = parentElement.getBoundingClientRect(); - const scrollRect = ulElement.parentElement.getBoundingClientRect(); - if (parentRect.top < scrollRect.top || parentRect.bottom > scrollRect.bottom) { - parentElement.scrollIntoView(parentRect.top < scrollRect.top); - } - } - event.preventDefault(); - return true; - } - if (event.key === "ArrowDown" || event.key === "ArrowRight") { - let nextElement = activeItemElement; - while (nextElement) { - if (nextElement.nextElementSibling) { - if (nextElement.nextElementSibling.tagName === "UL") { - if (nextElement.nextElementSibling.classList.contains("fn__none")) { // 遇到折叠内容 - if (nextElement.nextElementSibling.nextElementSibling) { - nextElement = nextElement.nextElementSibling.nextElementSibling; - } - } else { - nextElement = nextElement.nextElementSibling.firstElementChild; - } - } else if (nextElement.nextElementSibling.classList.contains("protyle")) { // backlink - if (nextElement.nextElementSibling.nextElementSibling) { - nextElement = nextElement.nextElementSibling.nextElementSibling; - } - } else { - nextElement = nextElement.nextElementSibling; - } - break; - } else { - if (nextElement.parentElement.classList.contains("fn__flex-1")) { - break; - } else { - nextElement = nextElement.parentElement; - } - } - } - if (nextElement.classList.contains("b3-list-item") && !nextElement.classList.contains("b3-list-item--focus")) { - activeItemElement.classList.remove("b3-list-item--focus"); - nextElement.classList.add("b3-list-item--focus"); - const nextRect = nextElement.getBoundingClientRect(); - const scrollRect = ulElement.parentElement.getBoundingClientRect(); - if (nextRect.top < scrollRect.top || nextRect.bottom > scrollRect.bottom) { - nextElement.scrollIntoView(nextRect.top < scrollRect.top); - } - } - event.preventDefault(); - return true; - } - if (event.key === "ArrowUp") { - let previousElement = activeItemElement; - while (previousElement) { - if (previousElement.previousElementSibling) { - if (previousElement.previousElementSibling.tagName === "LI") { - previousElement = previousElement.previousElementSibling; - } else if (previousElement.previousElementSibling.classList.contains("protyle")) { - if (previousElement.previousElementSibling.previousElementSibling) { - previousElement = previousElement.previousElementSibling.previousElementSibling; - } - } else if (previousElement.previousElementSibling.tagName === "UL" && previousElement.previousElementSibling.classList.contains("fn__none")) { // 遇到折叠内容 - if (previousElement.previousElementSibling.previousElementSibling) { - previousElement = previousElement.previousElementSibling.previousElementSibling; - } - } else { - const liElements = previousElement.previousElementSibling.querySelectorAll(".b3-list-item"); - previousElement = liElements[liElements.length - 1]; - } - break; - } else { - if (previousElement.parentElement.classList.contains("fn__flex-1")) { - break; - } else { - previousElement = previousElement.parentElement; - } - } - } - if (previousElement.classList.contains("b3-list-item") && !previousElement.classList.contains("b3-list-item--focus")) { - activeItemElement.classList.remove("b3-list-item--focus"); - previousElement.classList.add("b3-list-item--focus"); - const previousRect = previousElement.getBoundingClientRect(); - const scrollRect = ulElement.parentElement.getBoundingClientRect(); - if (previousRect.top < scrollRect.top || previousRect.bottom > scrollRect.bottom) { - previousElement.scrollIntoView(previousRect.top < scrollRect.top); - } - } - event.preventDefault(); - return true; - } - return false; -}; - diff --git a/app/src/boot/onGetConfig.ts b/app/src/boot/onGetConfig.ts index 8a30b281c..0063fb70e 100644 --- a/app/src/boot/onGetConfig.ts +++ b/app/src/boot/onGetConfig.ts @@ -10,7 +10,6 @@ import {onWindowsMsg} from "../window/onWindowsMsg"; /// #endif import {Constants} from "../constants"; import {appearance} from "../config/appearance"; -import {globalShortcut} from "../boot/globalShortcut"; import {fetchPost, fetchSyncPost} from "../util/fetch"; import {addGA, initAssets, setInlineStyle} from "../util/assets"; import {renderSnippet} from "../config/util/snippets"; @@ -27,6 +26,7 @@ import {setProxy} from "../config/util/about"; import {openChangelog} from "./openChangelog"; import {getIdFromSYProtocol, isSYProtocol} from "../util/pathName"; import {App} from "../index"; +import {initWindowEvent} from "./globalEvent/event"; const matchKeymap = (keymap: Record, key1: "general" | "editor", key2?: "general" | "insert" | "heading" | "list" | "table") => { if (key1 === "general") { @@ -131,7 +131,7 @@ export const onGetConfig = (isStart: boolean, app: App) => { if (!window.siyuan.config.uiLayout || (window.siyuan.config.uiLayout && !window.siyuan.config.uiLayout.left)) { window.siyuan.config.uiLayout = Constants.SIYUAN_EMPTY_LAYOUT; } - globalShortcut(app); + initWindowEvent(app); fetchPost("/api/system/getEmojiConf", {}, response => { window.siyuan.emojis = response.data as IEmoji[]; try { diff --git a/app/src/protyle/wysiwyg/index.ts b/app/src/protyle/wysiwyg/index.ts index fa2539635..51ad76df1 100644 --- a/app/src/protyle/wysiwyg/index.ts +++ b/app/src/protyle/wysiwyg/index.ts @@ -1410,7 +1410,7 @@ export class WYSIWYG { } const nodeElement = hasClosestBlock(event.target); if (nodeElement && (nodeElement.classList.contains("list") || nodeElement.classList.contains("li"))) { - // 光标在列表下部应显示右侧的元素,而不是列表本身。放在 globalShortcut 中的 mousemove 下处理 + // 光标在列表下部应显示右侧的元素,而不是列表本身。放在 windowEvent 中的 mousemove 下处理 return; } if (nodeElement) { diff --git a/app/src/types/index.d.ts b/app/src/types/index.d.ts index eb776486b..12d9793e7 100644 --- a/app/src/types/index.d.ts +++ b/app/src/types/index.d.ts @@ -407,10 +407,11 @@ interface ICommand { langText?: string, // 显示的文本, 指定后不再使用 langKey 对应的 i18n 文本 hotkey: string, customHotkey?: string, - callback?: () => void - fileTreeCallback?: (file: import("../layout/dock/Files").Files) => void - editorCallback?: (protyle: IProtyle) => void - dockCallback?: (element: HTMLElement) => void + callback?: () => void // 其余回调存在时将不会触 + globalCallback?: () => void // 焦点不在应用内时执行的回调 + fileTreeCallback?: (file: import("../layout/dock/Files").Files) => void // 焦点在文档树上时执行的回调 + editorCallback?: (protyle: IProtyle) => void // 焦点在编辑器上时执行的回调 + dockCallback?: (element: HTMLElement) => void // 焦点在 dock 上时执行的回调 } interface IPluginData { diff --git a/app/src/window/init.ts b/app/src/window/init.ts index c2d438823..45a7e379a 100644 --- a/app/src/window/init.ts +++ b/app/src/window/init.ts @@ -1,6 +1,5 @@ import {Constants} from "../constants"; import {webFrame} from "electron"; -import {globalShortcut} from "../boot/globalShortcut"; import {fetchPost} from "../util/fetch"; import {getInstanceById, JSONToCenter, resizeTabs} from "../layout/util"; import {initStatus} from "../layout/status"; @@ -12,10 +11,11 @@ import {initWindow} from "../boot/onGetConfig"; import {App} from "../index"; import {afterLoadPlugin} from "../plugin/loader"; import {Tab} from "../layout/Tab"; +import {initWindowEvent} from "../boot/globalEvent/event"; export const init = (app: App) => { webFrame.setZoomFactor(window.siyuan.storage[Constants.LOCAL_ZOOM]); - globalShortcut(app); + initWindowEvent(app); fetchPost("/api/system/getEmojiConf", {}, response => { window.siyuan.emojis = response.data as IEmoji[];