From 54022ed92ade1d9821f113337650ab4bde3ff9f0 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Thu, 18 May 2023 19:27:21 +0800 Subject: [PATCH] :recycle: https://github.com/siyuan-note/siyuan/issues/5066 click block menu --- app/src/asset/index.ts | 5 +- app/src/block/Panel.ts | 6 +- app/src/block/popover.ts | 12 +-- app/src/boot/globalShortcut.ts | 98 ++++++++++++++++--------- app/src/boot/onGetConfig.ts | 5 +- app/src/card/makeCard.ts | 7 +- app/src/card/newCardTab.ts | 4 + app/src/card/openCard.ts | 12 ++- app/src/card/viewCards.ts | 5 +- app/src/dialog/processSystem.ts | 5 +- app/src/editor/index.ts | 5 +- app/src/editor/util.ts | 10 ++- app/src/history/diff.ts | 13 ++-- app/src/history/history.ts | 13 ++-- app/src/index.ts | 16 ++-- app/src/layout/Model.ts | 6 +- app/src/layout/Wnd.ts | 7 +- app/src/layout/dock/Backlink.ts | 11 ++- app/src/layout/dock/Bookmark.ts | 8 +- app/src/layout/dock/Custom.ts | 4 +- app/src/layout/dock/Files.ts | 18 ++++- app/src/layout/dock/Graph.ts | 14 +++- app/src/layout/dock/Inbox.ts | 5 +- app/src/layout/dock/Outline.ts | 4 + app/src/layout/dock/Tag.ts | 6 +- app/src/layout/dock/index.ts | 28 ++++--- app/src/layout/dock/util.ts | 10 ++- app/src/layout/topBar.ts | 9 ++- app/src/layout/util.ts | 38 +++++++--- app/src/menus/commonMenuItem.ts | 5 +- app/src/menus/index.ts | 4 +- app/src/menus/navigation.ts | 58 ++++++++++----- app/src/menus/protyle.ts | 27 ++++--- app/src/menus/workspace.ts | 6 +- app/src/mobile/dock/MobileBacklinks.ts | 7 +- app/src/mobile/dock/MobileBookmarks.ts | 5 +- app/src/mobile/dock/MobileFiles.ts | 12 +-- app/src/mobile/dock/MobileOutline.ts | 5 +- app/src/mobile/dock/MobileTags.ts | 5 +- app/src/mobile/editor.ts | 5 +- app/src/mobile/index.ts | 19 +++-- app/src/mobile/menu/getRecentDocs.ts | 5 +- app/src/mobile/menu/index.ts | 11 +-- app/src/mobile/menu/search.ts | 11 +-- app/src/mobile/util/initFramework.ts | 22 +++--- app/src/mobile/util/onMessage.ts | 9 ++- app/src/mobile/util/setEmpty.ts | 13 ++-- app/src/mobile/util/touch.ts | 9 ++- app/src/plugin/index.ts | 4 + app/src/protyle/breadcrumb/index.ts | 4 +- app/src/protyle/gutter/index.ts | 21 ++++-- app/src/protyle/header/Background.ts | 7 +- app/src/protyle/header/Title.ts | 22 +++--- app/src/protyle/hint/index.ts | 10 ++- app/src/protyle/index.ts | 26 ++++--- app/src/protyle/preview/index.ts | 5 +- app/src/protyle/toolbar/Link.ts | 5 +- app/src/protyle/toolbar/index.ts | 20 ++--- app/src/protyle/wysiwyg/commonClick.ts | 11 +-- app/src/protyle/wysiwyg/commonHotkey.ts | 9 ++- app/src/protyle/wysiwyg/index.ts | 40 ++++++---- app/src/protyle/wysiwyg/keydown.ts | 17 +++-- app/src/search/index.ts | 6 +- app/src/search/spread.ts | 47 +++++++----- app/src/search/util.ts | 19 +++-- app/src/types/index.d.ts | 3 +- app/src/util/backForward.ts | 16 ++-- app/src/util/newFile.ts | 21 +++--- app/src/window/index.ts | 17 +++-- app/src/window/init.ts | 2 +- 70 files changed, 604 insertions(+), 350 deletions(-) diff --git a/app/src/asset/index.ts b/app/src/asset/index.ts index 02eeade04..bbe4b54f4 100644 --- a/app/src/asset/index.ts +++ b/app/src/asset/index.ts @@ -13,6 +13,7 @@ import {webViewerPageNumberChanged} from "./pdf/app"; /// #endif import {fetchPost} from "../util/fetch"; import {setStorageVal, updateHotkeyTip} from "../protyle/util/compatibility"; +import {App} from "../index"; export class Asset extends Model { public path: string; @@ -21,8 +22,8 @@ export class Asset extends Model { private pdfPage: number; public pdfObject: any; - constructor(options: { tab: Tab, path: string, page?: number | string }) { - super({id: options.tab.id}); + constructor(options: { app: App, tab: Tab, path: string, page?: number | string }) { + super({app: options.app, id: options.tab.id}); if (window.siyuan.config.fileTree.openFilesUseCurrentTab) { options.tab.headElement.classList.add("item--unupdate"); } diff --git a/app/src/block/Panel.ts b/app/src/block/Panel.ts index e0237e671..87c6dce51 100644 --- a/app/src/block/Panel.ts +++ b/app/src/block/Panel.ts @@ -11,6 +11,7 @@ import {openNewWindowById} from "../window/openNewWindow"; import {disabledProtyle} from "../protyle/util/onGet"; import {fetchPost} from "../util/fetch"; import {showMessage} from "../dialog/message"; +import {App} from "../index"; export class BlockPanel { public element: HTMLElement; @@ -19,11 +20,13 @@ export class BlockPanel { public defIds: string[] = []; public id: string; private stmt: string; + private app: App; public editors: Protyle[] = []; public esc: () => void; // stmt 非空且 id 为空为查询嵌入 constructor(options: { + app: App, targetElement: HTMLElement, nodeIds?: string[], defIds?: string[], @@ -36,6 +39,7 @@ export class BlockPanel { this.nodeIds = options.nodeIds; this.defIds = options.defIds || []; this.esc = options.esc; + this.app = options.app; this.element = document.createElement("div"); this.element.classList.add("block__popover", "block__popover--move", "block__popover--top"); @@ -259,7 +263,7 @@ export class BlockPanel { this.targetElement.classList.contains("counter")) { action.push(Constants.CB_GET_BACKLINK); } - const editor = new Protyle(editorElement, { + const editor = new Protyle(this.app, editorElement, { blockId: this.nodeIds[index], defId: this.defIds[index] || this.defIds[0] || "", action, diff --git a/app/src/block/popover.ts b/app/src/block/popover.ts index 33d50a219..d4b50746d 100644 --- a/app/src/block/popover.ts +++ b/app/src/block/popover.ts @@ -3,9 +3,10 @@ import {hasClosestBlock, hasClosestByAttribute, hasClosestByClassName} from "../ import {fetchSyncPost} from "../util/fetch"; import {hideTooltip, showTooltip} from "../dialog/tooltip"; import {getIdFromSYProtocol} from "../util/pathName"; +import {App} from "../index"; let popoverTargetElement: HTMLElement; -export const initBlockPopover = () => { +export const initBlockPopover = (app: App) => { let timeout: number; let timeoutHide: number; // 编辑器内容块引用/backlinks/tag/bookmark/套娃中使用 @@ -50,10 +51,10 @@ export const initBlockPopover = () => { } if (window.siyuan.ctrlIsPressed) { clearTimeout(timeoutHide); - showPopover(); + showPopover(app); } else if (window.siyuan.shiftIsPressed) { clearTimeout(timeoutHide); - showPopover(true); + showPopover(app, true); } return; } @@ -73,7 +74,7 @@ export const initBlockPopover = () => { return; } clearTimeout(timeoutHide); - showPopover(); + showPopover(app); }, 620); }); }; @@ -177,7 +178,7 @@ const getTarget = (event: MouseEvent & { target: HTMLElement }, aElement: false return true; }; -export const showPopover = async (showRef = false) => { +export const showPopover = async (app: App, showRef = false) => { if (!popoverTargetElement) { return; } @@ -241,6 +242,7 @@ export const showPopover = async (showRef = false) => { popoverTargetElement.parentElement.style.opacity !== "0.1" // 反向面板图标拖拽时不应该弹层 ) { window.siyuan.blockPanels.push(new BlockPanel({ + app, targetElement: popoverTargetElement, nodeIds: ids, defIds, diff --git a/app/src/boot/globalShortcut.ts b/app/src/boot/globalShortcut.ts index 1a70e65c6..979561ae8 100644 --- a/app/src/boot/globalShortcut.ts +++ b/app/src/boot/globalShortcut.ts @@ -66,7 +66,7 @@ const getRightBlock = (element: HTMLElement, x: number, y: number) => { return nodeElement; }; -const switchDialogEvent = (event: MouseEvent, switchDialog: Dialog) => { +const switchDialogEvent = (app: App, event: MouseEvent, switchDialog: Dialog) => { event.preventDefault(); let target = event.target as HTMLElement; while (!target.isSameNode(switchDialog.element)) { @@ -74,7 +74,7 @@ const switchDialogEvent = (event: MouseEvent, switchDialog: Dialog) => { const currentType = target.getAttribute("data-type"); if (currentType) { if (currentType === "riffCard") { - openCard(); + openCard(app); } else { getDockByType(currentType).toggleModel(currentType, true); } @@ -270,10 +270,10 @@ export const globalShortcut = (app: App) => { window.addEventListener("mouseup", (event) => { if (event.button === 3) { event.preventDefault(); - goBack(); + goBack(app); } else if (event.button === 4) { event.preventDefault(); - goForward(); + goForward(app); } }); @@ -367,7 +367,7 @@ export const globalShortcut = (app: App) => { const currentType = currentLiElement.getAttribute("data-type"); if (currentType) { if (currentType === "riffCard") { - openCard(); + openCard(app); } else { getDockByType(currentType).toggleModel(currentType, true); } @@ -425,7 +425,7 @@ export const globalShortcut = (app: App) => { if (event.key === "Meta" || event.key === "Control" || event.ctrlKey || event.metaKey) { window.siyuan.ctrlIsPressed = true; if (window.siyuan.config.editor.floatWindowMode === 1 && !event.repeat) { - showPopover(); + showPopover(app); } } else { window.siyuan.ctrlIsPressed = false; @@ -436,7 +436,7 @@ export const globalShortcut = (app: App) => { if (event.key === "Shift") { window.siyuan.shiftIsPressed = true; if (!event.repeat) { - showPopover(true); + showPopover(app,true); } } else { window.siyuan.shiftIsPressed = false; @@ -452,7 +452,7 @@ export const globalShortcut = (app: App) => { } if (switchDialog && event.ctrlKey && !event.metaKey && event.key.startsWith("Arrow")) { - dialogArrow(switchDialog.element, event); + dialogArrow(app, switchDialog.element, event); return; } @@ -525,11 +525,11 @@ export const globalShortcut = (app: App) => { switchDialog.element.querySelector("input").focus(); if (isMac()) { switchDialog.element.addEventListener("contextmenu", (event) => { - switchDialogEvent(event, switchDialog); + switchDialogEvent(app, event, switchDialog); }); } switchDialog.element.addEventListener("click", (event) => { - switchDialogEvent(event, switchDialog); + switchDialogEvent(app, event, switchDialog); }); return; } @@ -543,7 +543,7 @@ export const globalShortcut = (app: App) => { }); if (openRecentDocsDialog) { event.preventDefault(); - dialogArrow(openRecentDocsDialog.element, event); + dialogArrow(app, openRecentDocsDialog.element, event); return; } } @@ -611,7 +611,7 @@ export const globalShortcut = (app: App) => { } if (!isTabWindow && matchHotKey(window.siyuan.config.keymap.general.dataHistory.custom, event)) { if (!window.siyuan.config.readonly) { - openHistory(); + openHistory(app); } event.preventDefault(); return; @@ -639,7 +639,7 @@ export const globalShortcut = (app: App) => { return; } if (!isTabWindow && matchHotKey(window.siyuan.config.keymap.general.riffCard.custom, event)) { - openCard(); + openCard(app); if (document.activeElement) { (document.activeElement as HTMLElement).blur(); } @@ -653,7 +653,7 @@ export const globalShortcut = (app: App) => { return; } if (matchHotKey(window.siyuan.config.keymap.general.newFile.custom, event)) { - newFile(undefined, undefined, undefined, true); + newFile(app, undefined, undefined, undefined, true); event.preventDefault(); return; } @@ -731,13 +731,13 @@ export const globalShortcut = (app: App) => { } if (matchHotKey(window.siyuan.config.keymap.general.goForward.custom, event)) { - goForward(); + goForward(app); event.preventDefault(); return; } if (matchHotKey(window.siyuan.config.keymap.general.goBack.custom, event)) { - goBack(); + goBack(app); event.preventDefault(); return; } @@ -784,20 +784,20 @@ export const globalShortcut = (app: App) => { if (matchHotKey(window.siyuan.config.keymap.general.stickSearch.custom, event)) { if (getSelection().rangeCount > 0) { const range = getSelection().getRangeAt(0); - openGlobalSearch(range.toString(), false); + openGlobalSearch(app, range.toString(), false); } else { - openGlobalSearch("", false); + openGlobalSearch(app, "", false); } event.preventDefault(); return; } - if (editKeydown(event)) { + if (editKeydown(app, event)) { return; } // 文件树的操作 - if (!isTabWindow && fileTreeKeydown(event)) { + if (!isTabWindow && fileTreeKeydown(app, event)) { return; } @@ -817,9 +817,16 @@ export const globalShortcut = (app: App) => { if (searchKey) { if (getSelection().rangeCount > 0) { const range = getSelection().getRangeAt(0); - openSearch(searchKey, range.toString()); + openSearch({ + app, + hotkey: searchKey, + key: range.toString(), + }); } else { - openSearch(searchKey); + openSearch({ + app, + hotkey: searchKey, + }); } event.preventDefault(); return; @@ -906,7 +913,7 @@ export const globalShortcut = (app: App) => { }); }; -const dialogArrow = (element: HTMLElement, event: KeyboardEvent) => { +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"); @@ -933,12 +940,13 @@ const dialogArrow = (element: HTMLElement, event: KeyboardEvent) => { const currentType = currentLiElement.getAttribute("data-type"); if (currentType) { if (currentType === "riffCard") { - openCard(); + openCard(app); } else { getDockByType(currentType).toggleModel(currentType, true); } } else { openFileById({ + app, id: currentLiElement.getAttribute("data-node-id"), action: [Constants.CB_GET_SCROLL] }); @@ -967,7 +975,7 @@ const dialogArrow = (element: HTMLElement, event: KeyboardEvent) => { } }; -const editKeydown = (event: KeyboardEvent) => { +const editKeydown = (app: App, event: KeyboardEvent) => { const activeTabElement = document.querySelector(".layout__wnd--active .item--focus"); let protyle: IProtyle; if (activeTabElement) { @@ -1004,16 +1012,25 @@ const editKeydown = (event: KeyboardEvent) => { range = getSelection().getRangeAt(0); } if (range && protyle.element.contains(range.startContainer)) { - openSearch(searchKey, range.toString(), protyle.notebookId, protyle.path); + openSearch({ + app, + hotkey: searchKey, + key: range.toString(), + notebookId: protyle.notebookId, + searchPath: protyle.path + }); } else { - openSearch(searchKey); + 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(response.data, "doc", protyle.block.rootID, protyle.title.editElement.textContent || "Untitled"); + openCardByData(app, response.data, "doc", protyle.block.rootID, protyle.title.editElement.textContent || "Untitled"); }); event.preventDefault(); return true; @@ -1088,7 +1105,7 @@ const editKeydown = (event: KeyboardEvent) => { return false; }; -const fileTreeKeydown = (event: KeyboardEvent) => { +const fileTreeKeydown = (app: App, event: KeyboardEvent) => { const dockFile = getDockByType("file"); if (!dockFile) { return false; @@ -1135,11 +1152,11 @@ const fileTreeKeydown = (event: KeyboardEvent) => { if (isFile) { const id = liElements[0].getAttribute("data-node-id"); fetchPost("/api/riff/getTreeRiffDueCards", {rootID: id}, (response) => { - openCardByData(response.data, "doc", id, getDisplayName(liElements[0].getAttribute("data-name"), false, true)); + openCardByData(app, response.data, "doc", id, getDisplayName(liElements[0].getAttribute("data-name"), false, true)); }); } else { fetchPost("/api/riff/getNotebookRiffDueCards", {notebook: notebookId}, (response) => { - openCardByData(response.data, "notebook", notebookId, getNotebookName(notebookId)); + openCardByData(app, response.data, "notebook", notebookId, getNotebookName(notebookId)); }); } } @@ -1158,12 +1175,12 @@ const fileTreeKeydown = (event: KeyboardEvent) => { if (matchHotKey("⌘/", event)) { const liRect = liElements[0].getBoundingClientRect(); if (isFile) { - initFileMenu(notebookId, pathString, liElements[0]).popup({ + initFileMenu(app, notebookId, pathString, liElements[0]).popup({ x: liRect.right - 15, y: liRect.top + 15 }); } else { - initNavigationMenu(liElements[0] as HTMLElement).popup({x: liRect.right - 15, y: liRect.top + 15}); + initNavigationMenu(app, liElements[0] as HTMLElement).popup({x: liRect.right - 15, y: liRect.top + 15}); } return true; } @@ -1185,9 +1202,18 @@ const fileTreeKeydown = (event: KeyboardEvent) => { if (searchKey) { window.siyuan.menus.menu.remove(); if (isFile) { - openSearch(searchKey, undefined, notebookId, getDisplayName(pathString, false, true)); + openSearch({ + app, + hotkey: searchKey, + notebookId: notebookId, + searchPath: getDisplayName(pathString, false, true) + }); } else { - openSearch(searchKey, undefined, notebookId); + openSearch({ + app, + hotkey: searchKey, + notebookId: notebookId, + }); } event.preventDefault(); return true; @@ -1363,7 +1389,7 @@ const fileTreeKeydown = (event: KeyboardEvent) => { window.siyuan.menus.menu.remove(); liElements.forEach(item => { if (item.getAttribute("data-type") === "navigation-file") { - openFileById({id: item.getAttribute("data-node-id"), action: [Constants.CB_GET_FOCUS]}); + openFileById({app, id: item.getAttribute("data-node-id"), action: [Constants.CB_GET_FOCUS]}); } else { const itemTopULElement = hasTopClosestByTag(item, "UL"); if (itemTopULElement) { diff --git a/app/src/boot/onGetConfig.ts b/app/src/boot/onGetConfig.ts index 14f492ff3..90f979c23 100644 --- a/app/src/boot/onGetConfig.ts +++ b/app/src/boot/onGetConfig.ts @@ -144,7 +144,7 @@ export const onGetConfig = (isStart: boolean, app: App) => { initBar(app); setProxy(); initStatus(); - initWindow(); + initWindow(app); appearance.onSetappearance(window.siyuan.config.appearance); initAssets(); renderSnippet(); @@ -160,7 +160,7 @@ export const onGetConfig = (isStart: boolean, app: App) => { addGA(); }; -export const initWindow = () => { +export const initWindow = (app: App) => { /// #if !BROWSER const winOnFocus = () => { if (getSelection().rangeCount > 0) { @@ -256,6 +256,7 @@ export const initWindow = () => { fetchPost("/api/block/checkBlockExist", {id}, existResponse => { if (existResponse.data) { openFileById({ + app, id, action: [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT], zoomIn: getSearch("focus", url) === "1" diff --git a/app/src/card/makeCard.ts b/app/src/card/makeCard.ts index 20e07546e..bf7e44290 100644 --- a/app/src/card/makeCard.ts +++ b/app/src/card/makeCard.ts @@ -8,6 +8,7 @@ import {viewCards} from "./viewCards"; import {Constants} from "../constants"; import {escapeAttr, escapeHtml} from "../util/escape"; import {transaction} from "../protyle/wysiwyg/transaction"; +import {App} from "../index"; export const genCardItem = (item: ICardPackage) => { return `
  • @@ -34,7 +35,7 @@ export const genCardItem = (item: ICardPackage) => {
  • `; }; -export const makeCard = (ids: string[]) => { +export const makeCard = (app: App, ids: string[]) => { window.siyuan.dialogs.find(item => { if (item.element.getAttribute("data-key") === "makeCard") { hideElements(["dialog"]); @@ -122,14 +123,14 @@ export const makeCard = (ids: string[]) => { event.preventDefault(); break; } else if (type === "view") { - viewCards(target.parentElement.getAttribute("data-id"), target.parentElement.getAttribute("data-name"), "", (removeResponse) => { + viewCards(app, target.parentElement.getAttribute("data-id"), target.parentElement.getAttribute("data-name"), "", (removeResponse) => { target.parentElement.outerHTML = genCardItem(removeResponse.data); }); event.stopPropagation(); event.preventDefault(); break; } else if (type === "viewall") { - viewCards("", window.siyuan.languages.all, ""); + viewCards(app, "", window.siyuan.languages.all, ""); event.stopPropagation(); event.preventDefault(); break; diff --git a/app/src/card/newCardTab.ts b/app/src/card/newCardTab.ts index a8d8e8982..2e34078b3 100644 --- a/app/src/card/newCardTab.ts +++ b/app/src/card/newCardTab.ts @@ -4,8 +4,10 @@ import {bindCardEvent, genCardHTML} from "./openCard"; import {fetchPost} from "../util/fetch"; import {Protyle} from "../protyle"; import {setPanelFocus} from "../layout/util"; +import {App} from "../index"; export const newCardModel = (options: { + app: App, tab: Tab, data: { cardType: TCardType, @@ -15,6 +17,7 @@ export const newCardModel = (options: { }) => { let editor: Protyle; const customObj = new Custom({ + app: options.app, type: "siyuan-card", tab: options.tab, data: options.data, @@ -33,6 +36,7 @@ export const newCardModel = (options: { }); editor = bindCardEvent({ + app: options.app, element: this.element, id: this.data.id, title: this.data.title, diff --git a/app/src/card/openCard.ts b/app/src/card/openCard.ts index ec2754094..edb85ccd5 100644 --- a/app/src/card/openCard.ts +++ b/app/src/card/openCard.ts @@ -15,6 +15,7 @@ import {openFile} from "../editor/util"; import {newCardModel} from "./newCardTab"; /// #endif import {getDisplayName, movePathTo} from "../util/pathName"; +import {App} from "../index"; export const genCardHTML = (options: { id: string, @@ -110,6 +111,7 @@ export const genCardHTML = (options: { }; export const bindCardEvent = (options: { + app: App, element: Element, title?: string, blocks: ICard[], @@ -118,7 +120,7 @@ export const bindCardEvent = (options: { dialog?: Dialog, }) => { let index = 0; - const editor = new Protyle(options.element.querySelector("[data-type='render']") as HTMLElement, { + const editor = new Protyle(options.app, options.element.querySelector("[data-type='render']") as HTMLElement, { blockId: "", action: [Constants.CB_GET_ALL], render: { @@ -205,6 +207,7 @@ export const bindCardEvent = (options: { const sticktabElement = hasClosestByAttribute(target, "data-type", "sticktab"); if (sticktabElement) { openFile({ + app: options.app, position: "right", custom: { icon: "iconRiffCard", @@ -399,13 +402,13 @@ export const bindCardEvent = (options: { return editor; }; -export const openCard = () => { +export const openCard = (app: App) => { fetchPost("/api/riff/getRiffDueCards", {deckID: ""}, (cardsResponse) => { - openCardByData(cardsResponse.data, "all"); + openCardByData(app, cardsResponse.data, "all"); }); }; -export const openCardByData = (cardsData: { +export const openCardByData = (app: App, cardsData: { cards: ICard[], unreviewedCount: number }, cardType: TCardType, id?: string, title?: string) => { @@ -435,6 +438,7 @@ export const openCardByData = (cardsData: { (dialog.element.querySelector(".b3-dialog__scrim") as HTMLElement).style.backgroundColor = "var(--b3-theme-background)"; (dialog.element.querySelector(".b3-dialog__container") as HTMLElement).style.maxWidth = "1024px"; const editor = bindCardEvent({ + app, element: dialog.element, blocks: cardsData.cards, title, diff --git a/app/src/card/viewCards.ts b/app/src/card/viewCards.ts index 7128f2ae4..f8478ad65 100644 --- a/app/src/card/viewCards.ts +++ b/app/src/card/viewCards.ts @@ -9,8 +9,9 @@ import {unicode2Emoji} from "../emoji"; import {addLoading} from "../protyle/ui/initUI"; import {Constants} from "../constants"; import {disabledProtyle, onGet} from "../protyle/util/onGet"; +import {App} from "../index"; -export const viewCards = (deckID: string, title: string, deckType: "Tree" | "" | "Notebook", cb?: (response: IWebSocketData) => void) => { +export const viewCards = (app: App, deckID: string, title: string, deckType: "Tree" | "" | "Notebook", cb?: (response: IWebSocketData) => void) => { let pageIndex = 1; let edit: Protyle; fetchPost(`/api/riff/get${deckType}RiffCards`, { @@ -55,7 +56,7 @@ export const viewCards = (deckID: string, title: string, deckType: "Tree" | "" | } }); if (response.data.blocks.length > 0) { - edit = new Protyle(dialog.element.querySelector("#cardPreview") as HTMLElement, { + edit = new Protyle(app, dialog.element.querySelector("#cardPreview") as HTMLElement, { blockId: "", render: { gutter: true, diff --git a/app/src/dialog/processSystem.ts b/app/src/dialog/processSystem.ts index 78d18aa25..5a6b49b3d 100644 --- a/app/src/dialog/processSystem.ts +++ b/app/src/dialog/processSystem.ts @@ -20,6 +20,7 @@ import {reloadProtyle} from "../protyle/util/reload"; import {Tab} from "../layout/Tab"; import {setEmpty} from "../mobile/util/setEmpty"; import {hideElements} from "../protyle/ui/hideElements"; +import {App} from "../index"; const updateTitle = (rootID: string, tab: Tab) => { fetchPost("/api/block/getDocInfo", { @@ -29,7 +30,7 @@ const updateTitle = (rootID: string, tab: Tab) => { }); }; -export const reloadSync = (data: { upsertRootIDs: string[], removeRootIDs: string[] }) => { +export const reloadSync = (app: App, data: { upsertRootIDs: string[], removeRootIDs: string[] }) => { hideMessage(); /// #if MOBILE if (window.siyuan.mobile.popEditor) { @@ -42,7 +43,7 @@ export const reloadSync = (data: { upsertRootIDs: string[], removeRootIDs: strin } if (window.siyuan.mobile.editor) { if (data.removeRootIDs.includes(window.siyuan.mobile.editor.protyle.block.rootID)) { - setEmpty(); + setEmpty(app); } else { reloadProtyle(window.siyuan.mobile.editor.protyle, false); fetchPost("/api/block/getDocInfo", { diff --git a/app/src/editor/index.ts b/app/src/editor/index.ts index dc5156f08..e4a62c362 100644 --- a/app/src/editor/index.ts +++ b/app/src/editor/index.ts @@ -8,6 +8,7 @@ import {getAllModels} from "../layout/getAll"; import {setModelsHash} from "../window/setHeader"; /// #endif import {countBlockWord} from "../layout/status"; +import {App} from "../index"; export class Editor extends Model { public element: HTMLElement; @@ -15,6 +16,7 @@ export class Editor extends Model { public headElement: HTMLElement; constructor(options: { + app: App, tab: Tab, blockId: string, mode?: TEditorMode, @@ -22,6 +24,7 @@ export class Editor extends Model { scrollAttr?: IScrollAttr }) { super({ + app: options.app, id: options.tab.id, }); if (window.siyuan.config.fileTree.openFilesUseCurrentTab) { @@ -38,7 +41,7 @@ export class Editor extends Model { mode?: TEditorMode, scrollAttr?: IScrollAttr }) { - this.editor = new Protyle(this.element, { + this.editor = new Protyle(this.app, this.element, { action: options.action || [], blockId: options.blockId, mode: options.mode, diff --git a/app/src/editor/util.ts b/app/src/editor/util.ts index 98c4d8e55..ddc8b8041 100644 --- a/app/src/editor/util.ts +++ b/app/src/editor/util.ts @@ -27,8 +27,10 @@ import {showMessage} from "../dialog/message"; import {objEquals} from "../util/functions"; import {resize} from "../protyle/util/resize"; import {Search} from "../search"; +import {App} from "../index"; export const openFileById = async (options: { + app: App, id: string, position?: string, mode?: TEditorMode, @@ -47,6 +49,7 @@ export const openFileById = async (options: { options.removeCurrentTab = true; } openFile({ + app: options.app, fileName: data.data.rootTitle, rootIcon: data.data.rootIcon, rootID: data.data.rootID, @@ -62,12 +65,13 @@ export const openFileById = async (options: { }); }; -export const openAsset = (assetPath: string, page: number | string, position?: string) => { +export const openAsset = (app: App, assetPath: string, page: number | string, position?: string) => { const suffix = pathPosix().extname(assetPath.split("?page")[0]); if (!Constants.SIYUAN_ASSETS_EXTS.includes(suffix)) { return; } openFile({ + app, assetPath, page, position, @@ -379,6 +383,7 @@ const newTab = (options: IOpenFileOptions) => { title: getDisplayName(options.assetPath), callback(tab) { tab.addModel(new Asset({ + app: options.app, tab, path: options.assetPath, page: options.page, @@ -405,6 +410,7 @@ const newTab = (options: IOpenFileOptions) => { title: window.siyuan.languages.search, callback(tab) { tab.addModel(new Search({ + app: options.app, tab, config: options.searchData })); @@ -419,12 +425,14 @@ const newTab = (options: IOpenFileOptions) => { let editor; if (options.zoomIn) { editor = new Editor({ + app: options.app, tab, blockId: options.id, action: [Constants.CB_GET_ALL, Constants.CB_GET_FOCUS], }); } else { editor = new Editor({ + app: options.app, tab, blockId: options.id, mode: options.mode, diff --git a/app/src/history/diff.ts b/app/src/history/diff.ts index ca0aaee51..b5057eefe 100644 --- a/app/src/history/diff.ts +++ b/app/src/history/diff.ts @@ -7,6 +7,7 @@ import {hasClosestByClassName} from "../protyle/util/hasClosest"; import {escapeHtml} from "../util/escape"; import * as dayjs from "dayjs"; import {isMobile} from "../util/functions"; +import {App} from "../index"; const genItem = (data: [], data2?: { title: string, fileID: string }[]) => { if (!data || data.length === 0) { @@ -27,7 +28,7 @@ const genItem = (data: [], data2?: { title: string, fileID: string }[]) => { let leftEditor: Protyle; let rightEditor: Protyle; -const renderCompare = (element: HTMLElement) => { +const renderCompare = (app: App, element: HTMLElement) => { const listElement = hasClosestByClassName(element, "history__diff"); if (!listElement) { return; @@ -35,7 +36,7 @@ const renderCompare = (element: HTMLElement) => { const leftElement = listElement.nextElementSibling.firstElementChild; const rightElement = listElement.nextElementSibling.lastElementChild; if (!leftEditor) { - leftEditor = new Protyle(leftElement.lastElementChild as HTMLElement, { + leftEditor = new Protyle(app, leftElement.lastElementChild as HTMLElement, { blockId: "", action: [Constants.CB_GET_HISTORY], render: { @@ -48,7 +49,7 @@ const renderCompare = (element: HTMLElement) => { typewriterMode: false }); disabledProtyle(leftEditor.protyle); - rightEditor = new Protyle(rightElement.lastElementChild as HTMLElement, { + rightEditor = new Protyle(app, rightElement.lastElementChild as HTMLElement, { blockId: "", action: [Constants.CB_GET_HISTORY], render: { @@ -98,7 +99,7 @@ const renderCompare = (element: HTMLElement) => { } }; -export const showDiff = (data: { id: string, time: string }[]) => { +export const showDiff = (app: App, data: { id: string, time: string }[]) => { if (data.length !== 2) { return; } @@ -137,7 +138,7 @@ export const showDiff = (data: { id: string, time: string }[]) => { } dialog.element.querySelector(".history__diff .b3-list-item--focus")?.classList.remove("b3-list-item--focus"); target.classList.add("b3-list-item--focus"); - renderCompare(target); + renderCompare(app, target); event.preventDefault(); event.stopPropagation(); break; @@ -159,7 +160,7 @@ export const showDiff = (data: { id: string, time: string }[]) => { genHTML(left, right, dialog, "left"); }; -const genHTML = (left: string, right: string, dialog: Dialog, direct:string) => { +const genHTML = (left: string, right: string, dialog: Dialog, direct: string) => { leftEditor = undefined; rightEditor = undefined; const isPhone = isMobile(); diff --git a/app/src/history/history.ts b/app/src/history/history.ts index 483ed04a5..d27b77cbd 100644 --- a/app/src/history/history.ts +++ b/app/src/history/history.ts @@ -13,6 +13,7 @@ import {showDiff} from "./diff"; import {setStorageVal} from "../protyle/util/compatibility"; import {openModel} from "../mobile/menu/model"; import {closeModel} from "../mobile/util/closePanel"; +import {App} from "../index"; let historyEditor: Protyle; @@ -288,7 +289,7 @@ const renderRmNotebook = (element: HTMLElement) => { }); }; -export const openHistory = () => { +export const openHistory = (app: App) => { if (window.siyuan.config.readonly) { return; } @@ -403,7 +404,7 @@ export const openHistory = () => { icon: "iconHistory", title: window.siyuan.languages.dataHistory, bindEvent(element) { - bindEvent(element.firstElementChild); + bindEvent(app, element.firstElementChild); } }); } else { @@ -415,11 +416,11 @@ export const openHistory = () => { historyEditor = undefined; } }); - bindEvent(dialog.element, dialog); + bindEvent(app, dialog.element, dialog); } }; -const bindEvent = (element: Element, dialog?: Dialog) => { +const bindEvent = (app: App, element: Element, dialog?: Dialog) => { const firstPanelElement = element.querySelector("#historyContainer [data-type=doc]") as HTMLElement; firstPanelElement.querySelectorAll(".b3-select").forEach((itemElement) => { itemElement.addEventListener("change", () => { @@ -439,7 +440,7 @@ const bindEvent = (element: Element, dialog?: Dialog) => { const assetElement = firstPanelElement.querySelector('.history__text[data-type="assetPanel"]'); const mdElement = firstPanelElement.querySelector('.history__text[data-type="mdPanel"]') as HTMLTextAreaElement; renderDoc(firstPanelElement, 1); - historyEditor = new Protyle(docElement, { + historyEditor = new Protyle(app, docElement, { blockId: "", action: [Constants.CB_GET_HISTORY], render: { @@ -750,7 +751,7 @@ const bindEvent = (element: Element, dialog?: Dialog) => { event.preventDefault(); break; } else if (type === "compare" && !target.getAttribute("disabled")) { - showDiff(JSON.parse(target.getAttribute("data-ids") || "[]")); + showDiff(app, JSON.parse(target.getAttribute("data-ids") || "[]")); event.stopPropagation(); event.preventDefault(); break; diff --git a/app/src/index.ts b/app/src/index.ts index 11f6d3628..7f39bf6b7 100644 --- a/app/src/index.ts +++ b/app/src/index.ts @@ -51,6 +51,7 @@ export class App { ctrlIsPressed: false, altIsPressed: false, ws: new Model({ + app: this, id: genUUID(), type: "main", msgCallback: (data) => { @@ -60,7 +61,7 @@ export class App { if (data) { switch (data.cmd) { case "syncMergeResult": - reloadSync(data.data); + reloadSync(this, data.data); break; case "readonly": window.siyuan.config.editor.readOnly = data.data; @@ -135,10 +136,10 @@ export class App { } break; case "createdailynote": - openFileById({id: data.data.id, action: [Constants.CB_GET_FOCUS]}); + openFileById({app: this, id: data.data.id, action: [Constants.CB_GET_FOCUS]}); break; case "openFileById": - openFileById({id: data.data.id, action: [Constants.CB_GET_FOCUS]}); + openFileById({app: this, id: data.data.id, action: [Constants.CB_GET_FOCUS]}); break; } } @@ -166,12 +167,12 @@ export class App { getLocalStorage(() => { fetchGet(`/appearance/langs/${window.siyuan.config.appearance.lang}.json?v=${Constants.SIYUAN_VERSION}`, (lauguages) => { window.siyuan.languages = lauguages; - window.siyuan.menus = new Menus(siyuanApp); + window.siyuan.menus = new Menus(this); bootSync(); fetchPost("/api/setting/getCloudUser", {}, userResponse => { window.siyuan.user = userResponse.data; - loadPlugins(siyuanApp); - onGetConfig(response.data.start, siyuanApp); + loadPlugins(this); + onGetConfig(response.data.start, this); account.onSetaccount(); resizeDrag(); setTitle(window.siyuan.languages.siyuanNote); @@ -181,7 +182,7 @@ export class App { }); }); setNoteBook(); - initBlockPopover(); + initBlockPopover(this); promiseTransactions(); } } @@ -192,6 +193,7 @@ window.openFileByURL = (openURL) => { if (openURL && isSYProtocol(openURL)) { const isZoomIn = getSearch("focus", openURL) === "1"; openFileById({ + app: siyuanApp, id: getIdFromSYProtocol(openURL), action: isZoomIn ? [Constants.CB_GET_ALL, Constants.CB_GET_FOCUS] : [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT], zoomIn: isZoomIn diff --git a/app/src/layout/Model.ts b/app/src/layout/Model.ts index 6943efbf9..130e9a2c1 100644 --- a/app/src/layout/Model.ts +++ b/app/src/layout/Model.ts @@ -4,6 +4,7 @@ import {Tab} from "./Tab"; /// #endif import {processMessage} from "../util/processMessage"; import {kernelError, reloadSync} from "../dialog/processSystem"; +import {App} from "../index"; export class Model { public ws: WebSocket; @@ -14,13 +15,16 @@ export class Model { // @ts-ignore public parent: any; /// #endif + public app: App; constructor(options: { + app: App, id: string, type?: TWS, callback?: () => void, msgCallback?: (data: IWebSocketData) => void }) { + this.app = options.app; if (options.msgCallback) { this.connect(options); } @@ -41,7 +45,7 @@ export class Model { const logElement = document.getElementById("errorLog"); if (logElement) { // 内核中断后无法 catch fetch 请求错误,重连会导致无法执行 transactionsTimeout - reloadSync({upsertRootIDs: [], removeRootIDs: []}); + reloadSync(this.app, {upsertRootIDs: [], removeRootIDs: []}); window.siyuan.dialogs.find(item =>{ if (item.element.id === "errorLog") { item.destroy(); diff --git a/app/src/layout/Wnd.ts b/app/src/layout/Wnd.ts index 5b54237e5..bc17bc958 100644 --- a/app/src/layout/Wnd.ts +++ b/app/src/layout/Wnd.ts @@ -100,7 +100,7 @@ export class Wnd { while (target && !target.isEqualNode(this.headersElement)) { if (target.classList.contains("block__icon") && target.getAttribute("data-type") === "new") { setPanelFocus(this.headersElement.parentElement.parentElement); - newFile(undefined, undefined, undefined, true); + newFile(app, undefined, undefined, undefined, true); break; } else if (target.classList.contains("block__icon") && target.getAttribute("data-type") === "more") { this.renderTabList(target); @@ -211,6 +211,7 @@ export class Wnd { event.dataTransfer.getData(Constants.SIYUAN_DROP_FILE).split(",").forEach(item => { if (item) { openFileById({ + app, id: item, action: [Constants.CB_GET_FOCUS, Constants.CB_GET_SCROLL] }); @@ -435,6 +436,7 @@ export class Wnd { if (initData) { const json = JSON.parse(initData); currentTab.addModel(new Editor({ + app: this.app, tab: currentTab, blockId: json.blockId, mode: json.mode, @@ -476,6 +478,7 @@ export class Wnd { scrollCenter(currentTab.model.editor.protyle, nodeElement, true); } else { openFileById({ + app: this.app, id: keepCursorId, action: [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT] }); @@ -767,7 +770,7 @@ export class Wnd { /// #endif const wnd = new Wnd(this.app); window.siyuan.layout.centerLayout.addWnd(wnd); - wnd.addTab(newCenterEmptyTab()); + wnd.addTab(newCenterEmptyTab(this.app)); } } /// #if !BROWSER diff --git a/app/src/layout/dock/Backlink.ts b/app/src/layout/dock/Backlink.ts index edf96668f..4489d5679 100644 --- a/app/src/layout/dock/Backlink.ts +++ b/app/src/layout/dock/Backlink.ts @@ -8,6 +8,7 @@ import {updateHotkeyTip} from "../../protyle/util/compatibility"; import {openFileById} from "../../editor/util"; import {Protyle} from "../../protyle"; import {MenuItem} from "../../menus/Menu"; +import {App} from "../../index"; export class Backlink extends Model { public element: HTMLElement; @@ -32,12 +33,14 @@ export class Backlink extends Model { } = {}; constructor(options: { + app: App, tab: Tab, blockId: string, rootId?: string, type: "pin" | "local" }) { super({ + app: options.app, id: options.tab.id, callback() { if (this.type === "local") { @@ -156,6 +159,7 @@ export class Backlink extends Model { }, ctrlClick: (element) => { openFileById({ + app: options.app, id: element.getAttribute("data-node-id"), action: [Constants.CB_GET_CONTEXT] }); @@ -163,6 +167,7 @@ export class Backlink extends Model { }, altClick(element) { openFileById({ + app: options.app, id: element.getAttribute("data-node-id"), position: "right", action: [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT] @@ -171,6 +176,7 @@ export class Backlink extends Model { }, shiftClick(element) { openFileById({ + app: options.app, id: element.getAttribute("data-node-id"), position: "bottom", action: [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT] @@ -193,6 +199,7 @@ export class Backlink extends Model { }, ctrlClick(element) { openFileById({ + app: options.app, id: element.getAttribute("data-node-id"), action: [Constants.CB_GET_CONTEXT] }); @@ -200,6 +207,7 @@ export class Backlink extends Model { }, altClick(element) { openFileById({ + app: options.app, id: element.getAttribute("data-node-id"), position: "right", action: [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT] @@ -208,6 +216,7 @@ export class Backlink extends Model { }, shiftClick(element) { openFileById({ + app: options.app, id: element.getAttribute("data-node-id"), position: "bottom", action: [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT] @@ -431,7 +440,7 @@ export class Backlink extends Model { editorElement.setAttribute("data-defid", this.blockId); editorElement.setAttribute("data-ismention", isMention ? "true" : "false"); liElement.after(editorElement); - const editor = new Protyle(editorElement, { + const editor = new Protyle(this.app, editorElement, { blockId: docId, backlinkData: isMention ? response.data.backmentions : response.data.backlinks, render: { diff --git a/app/src/layout/dock/Bookmark.ts b/app/src/layout/dock/Bookmark.ts index 2d54983e7..a5a64802e 100644 --- a/app/src/layout/dock/Bookmark.ts +++ b/app/src/layout/dock/Bookmark.ts @@ -8,14 +8,16 @@ import {openFileById} from "../../editor/util"; import {Constants} from "../../constants"; import {hasClosestByClassName} from "../../protyle/util/hasClosest"; import {openBookmarkMenu} from "../../menus/bookmark"; +import {App} from "../../index"; export class Bookmark extends Model { private openNodes: string[]; public tree: Tree; private element: Element; - constructor(tab: Tab) { + constructor(app: App, tab: Tab) { super({ + app, id: tab.id, msgCallback(data) { if (data) { @@ -85,6 +87,7 @@ export class Bookmark extends Model { if (id) { fetchPost("/api/block/checkBlockFold", {id}, (foldResponse) => { openFileById({ + app, id, action: foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL] : [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT], zoomIn: foldResponse.data @@ -97,6 +100,7 @@ export class Bookmark extends Model { }, ctrlClick(element: HTMLElement) { openFileById({ + app, id: element.getAttribute("data-node-id"), keepCursor: true, action: [Constants.CB_GET_CONTEXT] @@ -104,6 +108,7 @@ export class Bookmark extends Model { }, altClick(element: HTMLElement) { openFileById({ + app, id: element.getAttribute("data-node-id"), position: "right", action: [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT] @@ -111,6 +116,7 @@ export class Bookmark extends Model { }, shiftClick(element: HTMLElement) { openFileById({ + app, id: element.getAttribute("data-node-id"), position: "bottom", action: [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT] diff --git a/app/src/layout/dock/Custom.ts b/app/src/layout/dock/Custom.ts index e5c7bfde5..f2a8de4b2 100644 --- a/app/src/layout/dock/Custom.ts +++ b/app/src/layout/dock/Custom.ts @@ -1,5 +1,6 @@ import {Tab} from "../Tab"; import {Model} from "../Model"; +import {App} from "../../index"; export class Custom extends Model { public element: Element; @@ -11,6 +12,7 @@ export class Custom extends Model { public update: () => void; constructor(options: { + app: App, type: string, tab: Tab, data: any, @@ -19,7 +21,7 @@ export class Custom extends Model { update?: () => void, init: () => void }) { - super({id: options.tab.id}); + super({app: options.app, id: options.tab.id}); this.type = options.type; if (window.siyuan.config.fileTree.openFilesUseCurrentTab) { options.tab.headElement.classList.add("item--unupdate"); diff --git a/app/src/layout/dock/Files.ts b/app/src/layout/dock/Files.ts index 2e2ea03e4..cad8c7901 100644 --- a/app/src/layout/dock/Files.ts +++ b/app/src/layout/dock/Files.ts @@ -17,6 +17,7 @@ import {updateHotkeyTip} from "../../protyle/util/compatibility"; import {openFileById} from "../../editor/util"; import {hasClosestByAttribute, hasClosestByTag, hasTopClosestByTag} from "../../protyle/util/hasClosest"; import {isTouchDevice} from "../../util/functions"; +import {App} from "../../index"; export class Files extends Model { public element: HTMLElement; @@ -24,8 +25,9 @@ export class Files extends Model { private actionsElement: HTMLElement; public closeElement: HTMLElement; - constructor(options: { tab: Tab }) { + constructor(options: { tab: Tab, app: App }) { super({ + app: options.app, type: "filetree", id: options.tab.id, msgCallback(data) { @@ -198,6 +200,7 @@ export class Files extends Model { if (target.tagName === "LI" && !target.getAttribute("data-opening")) { target.setAttribute("data-opening", "true"); openFileById({ + app: options.app, removeCurrentTab: false, id: target.getAttribute("data-node-id"), action: [Constants.CB_GET_FOCUS, Constants.CB_GET_SCROLL], @@ -240,13 +243,16 @@ export class Files extends Model { const pathString = target.parentElement.getAttribute("data-path"); if (!window.siyuan.config.readonly) { if (type === "new") { - newFile(notebookId, pathString); + newFile(options.app, notebookId, pathString); } else if (type === "more-root") { - initNavigationMenu(target.parentElement).popup({x: event.clientX, y: event.clientY}); + initNavigationMenu(options.app, target.parentElement).popup({ + x: event.clientX, + y: event.clientY + }); } } if (type === "more-file") { - initFileMenu(notebookId, pathString, target.parentElement).popup({ + initFileMenu(options.app, notebookId, pathString, target.parentElement).popup({ x: event.clientX, y: event.clientY }); @@ -267,6 +273,7 @@ export class Files extends Model { target.setAttribute("data-opening", "true"); if (event.altKey && !event.metaKey && !event.ctrlKey && !event.shiftKey) { openFileById({ + app: options.app, id: target.getAttribute("data-node-id"), position: "right", action: [Constants.CB_GET_FOCUS, Constants.CB_GET_SCROLL], @@ -276,6 +283,7 @@ export class Files extends Model { }); } else if (!event.altKey && !event.metaKey && !event.ctrlKey && event.shiftKey) { openFileById({ + app: options.app, id: target.getAttribute("data-node-id"), position: "bottom", action: [Constants.CB_GET_FOCUS, Constants.CB_GET_SCROLL], @@ -286,6 +294,7 @@ export class Files extends Model { } else if (window.siyuan.config.fileTree.openFilesUseCurrentTab && event.altKey && (event.metaKey || event.ctrlKey) && !event.shiftKey) { openFileById({ + app: options.app, removeCurrentTab: false, id: target.getAttribute("data-node-id"), action: [Constants.CB_GET_FOCUS, Constants.CB_GET_SCROLL], @@ -295,6 +304,7 @@ export class Files extends Model { }); } else { openFileById({ + app: options.app, id: target.getAttribute("data-node-id"), action: [Constants.CB_GET_FOCUS, Constants.CB_GET_SCROLL], afterOpen() { diff --git a/app/src/layout/dock/Graph.ts b/app/src/layout/dock/Graph.ts index 4b1d8ce25..ad926cc9e 100644 --- a/app/src/layout/dock/Graph.ts +++ b/app/src/layout/dock/Graph.ts @@ -9,6 +9,7 @@ import {fetchPost} from "../../util/fetch"; import {isCurrentEditor, openFileById} from "../../editor/util"; import {updateHotkeyTip} from "../../protyle/util/compatibility"; import {openGlobalSearch} from "../../search/util"; +import {App} from "../../index"; declare const vis: any; @@ -29,12 +30,14 @@ export class Graph extends Model { public type: "local" | "pin" | "global"; constructor(options: { + app: App tab: Tab blockId?: string rootId?: string type: "local" | "pin" | "global" }) { super({ + app: options.app, id: options.tab.id, callback() { if (this.type === "local") { @@ -635,28 +638,35 @@ export class Graph extends Model { return; } if (node.type === "textmark tag") { - openGlobalSearch(`#${node.id}#`, !window.siyuan.ctrlIsPressed); + openGlobalSearch(this.app, `#${node.id}#`, !window.siyuan.ctrlIsPressed); return; } if (window.siyuan.shiftIsPressed) { openFileById({ + app: this.app, id: node.id, position: "bottom", action: [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT] }); } else if (window.siyuan.altIsPressed) { openFileById({ + app: this.app, id: node.id, position: "right", action: [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT] }); } else if (window.siyuan.ctrlIsPressed) { window.siyuan.blockPanels.push(new BlockPanel({ + app: this.app, targetElement: this.inputElement, nodeIds: [node.id], })); } else { - openFileById({id: node.id, action: [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT]}); + openFileById({ + app: this.app, + id: node.id, + action: [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT] + }); } }); }, 1000); diff --git a/app/src/layout/dock/Inbox.ts b/app/src/layout/dock/Inbox.ts index 6df669526..b4c96a694 100644 --- a/app/src/layout/dock/Inbox.ts +++ b/app/src/layout/dock/Inbox.ts @@ -10,6 +10,7 @@ import {MenuItem} from "../../menus/Menu"; import {confirmDialog} from "../../dialog/confirmDialog"; import {replaceFileName} from "../../editor/rename"; import {getDisplayName, movePathTo, pathPosix} from "../../util/pathName"; +import {App} from "../../index"; export class Inbox extends Model { private element: Element; @@ -18,8 +19,8 @@ export class Inbox extends Model { private pageCount = 1; private data: { [key: string]: IInbox } = {}; - constructor(tab: Tab | Element) { - super({id: tab.id}); + constructor(app: App, tab: Tab | Element) { + super({app, id: tab.id}); if (tab instanceof Element) { this.element = tab; } else { diff --git a/app/src/layout/dock/Outline.ts b/app/src/layout/dock/Outline.ts index 8e8156c2d..b1cd9c600 100644 --- a/app/src/layout/dock/Outline.ts +++ b/app/src/layout/dock/Outline.ts @@ -12,6 +12,7 @@ import {escapeHtml} from "../../util/escape"; import {unicode2Emoji} from "../../emoji"; import {onGet} from "../../protyle/util/onGet"; import {getPreviousBlock} from "../../protyle/wysiwyg/getBlock"; +import {App} from "../../index"; export class Outline extends Model { public tree: Tree; @@ -22,11 +23,13 @@ export class Outline extends Model { private openNodes: { [key: string]: string[] } = {}; constructor(options: { + app: App, tab: Tab, blockId: string, type: "pin" | "local" }) { super({ + app: options.app, id: options.tab.id, callback() { if (this.type === "local") { @@ -101,6 +104,7 @@ export class Outline extends Model { const id = element.getAttribute("data-node-id"); fetchPost("/api/attr/getBlockAttrs", {id}, (attrResponse) => { openFileById({ + app: options.app, id, action: attrResponse.data["heading-fold"] === "1" ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL, Constants.CB_GET_HTML] : [Constants.CB_GET_FOCUS, Constants.CB_GET_SETID, Constants.CB_GET_CONTEXT, Constants.CB_GET_HTML], }); diff --git a/app/src/layout/dock/Tag.ts b/app/src/layout/dock/Tag.ts index 8bcb3e9b0..8be62e26a 100644 --- a/app/src/layout/dock/Tag.ts +++ b/app/src/layout/dock/Tag.ts @@ -9,14 +9,16 @@ import {MenuItem} from "../../menus/Menu"; import {confirmDialog} from "../../dialog/confirmDialog"; import {escapeHtml} from "../../util/escape"; import {renameTag} from "../../util/noRelyPCFunction"; +import {App} from "../../index"; export class Tag extends Model { private openNodes: string[]; public tree: Tree; private element: Element; - constructor(tab: Tab) { + constructor(app: App, tab: Tab) { super({ + app, id: tab.id, msgCallback(data) { if (data) { @@ -78,7 +80,7 @@ export class Tag extends Model { element: this.element.lastElementChild as HTMLElement, data: null, click(element: HTMLElement) { - openGlobalSearch(`#${element.getAttribute("data-label")}#`, !window.siyuan.ctrlIsPressed); + openGlobalSearch(app, `#${element.getAttribute("data-label")}#`, !window.siyuan.ctrlIsPressed); }, rightClick: (element: HTMLElement, event: MouseEvent) => { const labelName = element.getAttribute("data-label"); diff --git a/app/src/layout/dock/index.ts b/app/src/layout/dock/index.ts index b703c3a66..b10e116e4 100644 --- a/app/src/layout/dock/index.ts +++ b/app/src/layout/dock/index.ts @@ -328,29 +328,30 @@ export class Dock { switch (type) { case "file": tab = new Tab({ - callback(tab: Tab) { - tab.addModel(new Files({tab})); + callback: (tab: Tab) => { + tab.addModel(new Files({tab, app: this.app})); } }); break; case "bookmark": tab = new Tab({ - callback(tab: Tab) { - tab.addModel(new Bookmark(tab)); + callback: (tab: Tab) => { + tab.addModel(new Bookmark(this.app, tab)); } }); break; case "tag": tab = new Tab({ - callback(tab: Tab) { - tab.addModel(new Tag(tab)); + callback: (tab: Tab) => { + tab.addModel(new Tag(this.app, tab)); } }); break; case "outline": tab = new Tab({ - callback(tab: Tab) { + callback: (tab: Tab) => { const outline = new Outline({ + app: this.app, type: "pin", tab, blockId: editor?.protyle?.block?.rootID, @@ -364,8 +365,9 @@ export class Dock { break; case "graph": tab = new Tab({ - callback(tab: Tab) { + callback: (tab: Tab) => { tab.addModel(new Graph({ + app: this.app, tab, blockId: editor?.protyle?.block?.rootID, type: "pin" @@ -375,8 +377,9 @@ export class Dock { break; case "globalGraph": tab = new Tab({ - callback(tab: Tab) { + callback: (tab: Tab) => { tab.addModel(new Graph({ + app: this.app, tab, type: "global" })); @@ -385,8 +388,9 @@ export class Dock { break; case "backlink": tab = new Tab({ - callback(tab: Tab) { + callback: (tab: Tab) => { tab.addModel(new Backlink({ + app: this.app, type: "pin", tab, blockId: editor?.protyle?.block?.rootID, @@ -396,8 +400,8 @@ export class Dock { break; case "inbox": tab = new Tab({ - callback(tab: Tab) { - tab.addModel(new Inbox(tab)); + callback: (tab: Tab) => { + tab.addModel(new Inbox(this.app, tab)); } }); break; diff --git a/app/src/layout/dock/util.ts b/app/src/layout/dock/util.ts index bf75911b0..8271fb573 100644 --- a/app/src/layout/dock/util.ts +++ b/app/src/layout/dock/util.ts @@ -4,8 +4,9 @@ import {Graph} from "./Graph"; import {Outline} from "./Outline"; import {switchWnd} from "../util"; import {Backlink} from "./Backlink"; +import {App} from "../../index"; -export const openBacklink = (protyle: IProtyle) => { +export const openBacklink = (app: App, protyle: IProtyle) => { const backlink = getAllModels().backlink.find(item => { if (item.blockId === protyle.block.id && item.type === "local") { item.parent.parent.removeTab(item.parent.id); @@ -21,6 +22,7 @@ export const openBacklink = (protyle: IProtyle) => { title: protyle.title.editElement.textContent || "Untitled", callback(tab: Tab) { tab.addModel(new Backlink({ + app, type: "local", tab, // 通过搜索打开的包含上下文,但不是缩放,因此需要传 rootID https://ld246.com/article/1666786639708 @@ -32,7 +34,7 @@ export const openBacklink = (protyle: IProtyle) => { newWnd.addTab(tab); }; -export const openGraph = (protyle: IProtyle) => { +export const openGraph = (app: App, protyle: IProtyle) => { const graph = getAllModels().graph.find(item => { if (item.blockId === protyle.block.id && item.type === "local") { item.parent.parent.removeTab(item.parent.id); @@ -48,6 +50,7 @@ export const openGraph = (protyle: IProtyle) => { title: protyle.title.editElement.textContent || "Untitled", callback(tab: Tab) { tab.addModel(new Graph({ + app, type: "local", tab, blockId: protyle.block.id, @@ -58,7 +61,7 @@ export const openGraph = (protyle: IProtyle) => { wnd.addTab(tab); }; -export const openOutline = (protyle: IProtyle) => { +export const openOutline = (app: App,protyle: IProtyle) => { const outlinePanel = getAllModels().outline.find(item => { if (item.blockId === protyle.block.rootID && item.type === "local") { item.parent.parent.removeTab(item.parent.id); @@ -74,6 +77,7 @@ export const openOutline = (protyle: IProtyle) => { title: protyle.title.editElement.textContent || "Untitled", callback(tab: Tab) { tab.addModel(new Outline({ + app, type: "local", tab, blockId: protyle.block.rootID, diff --git a/app/src/layout/topBar.ts b/app/src/layout/topBar.ts index 0312ce774..c5ebf46ad 100644 --- a/app/src/layout/topBar.ts +++ b/app/src/layout/topBar.ts @@ -65,11 +65,11 @@ export const initBar = (app: App) => { let target = event.target as HTMLElement; while (!target.classList.contains("toolbar")) { if (target.id === "barBack") { - goBack(); + goBack(app); event.stopPropagation(); break; } else if (target.id === "barForward") { - goForward(); + goForward(app); event.stopPropagation(); break; } else if (target.id === "barSync") { @@ -128,7 +128,10 @@ export const initBar = (app: App) => { event.stopPropagation(); break; } else if (target.id === "barSearch") { - openSearch(window.siyuan.config.keymap.general.globalSearch.custom); + openSearch({ + app, + hotkey: window.siyuan.config.keymap.general.globalSearch.custom + }); event.stopPropagation(); break; } else if (target.id === "barZoom") { diff --git a/app/src/layout/util.ts b/app/src/layout/util.ts index 9e69c5ee5..0ab6ba7e7 100644 --- a/app/src/layout/util.ts +++ b/app/src/layout/util.ts @@ -324,7 +324,7 @@ export const JSONToCenter = (app: App, json: ILayoutJSON, layout?: Layout | Wnd } } else if (json.instance === "Tab") { if (!json.title) { - child = newCenterEmptyTab(); + child = newCenterEmptyTab(app); } else { let title = json.title; if (json.lang) { @@ -358,25 +358,29 @@ export const JSONToCenter = (app: App, json: ILayoutJSON, layout?: Layout | Wnd (layout as Tab).headElement.setAttribute("data-initdata", JSON.stringify(json)); } else if (json.instance === "Asset") { (layout as Tab).addModel(new Asset({ + app, tab: (layout as Tab), path: json.path, page: json.page, })); } else if (json.instance === "Backlink") { (layout as Tab).addModel(new Backlink({ + app, tab: (layout as Tab), blockId: json.blockId, rootId: json.rootId, type: json.type as "pin" | "local", })); } else if (json.instance === "Bookmark") { - (layout as Tab).addModel(new Bookmark((layout as Tab))); + (layout as Tab).addModel(new Bookmark(app, (layout as Tab))); } else if (json.instance === "Files") { (layout as Tab).addModel(new Files({ + app, tab: (layout as Tab), })); } else if (json.instance === "Graph") { (layout as Tab).addModel(new Graph({ + app, tab: (layout as Tab), blockId: json.blockId, rootId: json.rootId, @@ -384,20 +388,23 @@ export const JSONToCenter = (app: App, json: ILayoutJSON, layout?: Layout | Wnd })); } else if (json.instance === "Outline") { (layout as Tab).addModel(new Outline({ + app, tab: (layout as Tab), blockId: json.blockId, type: json.type as "pin" | "local", })); } else if (json.instance === "Tag") { - (layout as Tab).addModel(new Tag((layout as Tab))); + (layout as Tab).addModel(new Tag(app, (layout as Tab))); } else if (json.instance === "Search") { (layout as Tab).addModel(new Search({ + app, tab: (layout as Tab), config: json.config })); } else if (json.instance === "Custom") { if (json.customModelType === "siyuan-card") { (layout as Tab).addModel(newCardModel({ + app, tab: (layout as Tab), data: json.customModelData })); @@ -454,6 +461,7 @@ export const JSONToLayout = (app: App, isStart: boolean) => { // 启动时 layout 中有该文档,该文档还原会在此之后,因此需有延迟 if (idZoomIn.id) { openFileById({ + app, id: idZoomIn.id, action: idZoomIn.isZoomIn ? [Constants.CB_GET_ALL, Constants.CB_GET_FOCUS] : [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT], zoomIn: idZoomIn.isZoomIn @@ -654,17 +662,20 @@ export const copyTab = (app: App, tab: Tab) => { let model: Model; if (tab.model instanceof Editor) { model = new Editor({ + app, tab: newTab, blockId: tab.model.editor.protyle.block.id, scrollAttr: saveScroll(tab.model.editor.protyle, true) }); } else if (tab.model instanceof Asset) { model = new Asset({ + app, tab: newTab, path: tab.model.path }); } else if (tab.model instanceof Graph) { model = new Graph({ + app, tab: newTab, blockId: tab.model.blockId, rootId: tab.model.rootId, @@ -672,27 +683,31 @@ export const copyTab = (app: App, tab: Tab) => { }); } else if (tab.model instanceof Files) { model = new Files({ + app, tab: newTab }); } else if (tab.model instanceof Outline) { model = new Outline({ + app, tab: newTab, blockId: tab.model.blockId, type: tab.model.type }); } else if (tab.model instanceof Backlink) { model = new Backlink({ + app, tab: newTab, blockId: tab.model.blockId, rootId: tab.model.rootId, type: tab.model.type }); } else if (tab.model instanceof Bookmark) { - model = new Bookmark(newTab); + model = new Bookmark(app, newTab); } else if (tab.model instanceof Tag) { - model = new Tag(newTab); + model = new Tag(app, newTab); } else if (tab.model instanceof Search) { model = new Search({ + app, tab: newTab, config: tab.model.config }); @@ -700,6 +715,7 @@ export const copyTab = (app: App, tab: Tab) => { const custom = tab.model as Custom; if (custom.type === "siyuan-card") { model = newCardModel({ + app, tab: newTab, data: custom.data }); @@ -720,6 +736,7 @@ export const copyTab = (app: App, tab: Tab) => { initData.scrollAttr.rootId = initData.rootId; } model = new Editor({ + app, tab: newTab, blockId: initData.blockId, mode: initData.mode, @@ -882,7 +899,7 @@ export const addResize = (obj: Layout | Wnd) => { resizeWnd(resizeElement, obj.resize); }; -export const newCenterEmptyTab = () => { +export const newCenterEmptyTab = (app: App) => { return new Tab({ panel: `
    @@ -927,7 +944,10 @@ export const newCenterEmptyTab = () => { let target = event.target as HTMLElement; while (target && !target.isEqualNode(tab.panelElement)) { if (target.id === "editorEmptySearch") { - openSearch(window.siyuan.config.keymap.general.globalSearch.custom); + openSearch( { + app, + hotkey: window.siyuan.config.keymap.general.globalSearch.custom, + }); event.stopPropagation(); event.preventDefault(); break; @@ -946,12 +966,12 @@ export const newCenterEmptyTab = () => { event.preventDefault(); break; } else if (target.id === "editorEmptyHistory") { - openHistory(); + openHistory(app); event.stopPropagation(); event.preventDefault(); break; } else if (target.id === "editorEmptyFile") { - newFile(undefined, undefined, undefined, true); + newFile(app, undefined, undefined, undefined, true); event.stopPropagation(); event.preventDefault(); break; diff --git a/app/src/menus/commonMenuItem.ts b/app/src/menus/commonMenuItem.ts index a1c101527..f42d9c425 100644 --- a/app/src/menus/commonMenuItem.ts +++ b/app/src/menus/commonMenuItem.ts @@ -24,6 +24,7 @@ import {matchHotKey} from "../protyle/util/hotKey"; import * as dayjs from "dayjs"; import {Constants} from "../constants"; import {exportImage} from "../protyle/export/util"; +import {App} from "../index"; const bindAttrInput = (inputElement: HTMLInputElement, confirmElement: Element) => { inputElement.addEventListener("keydown", (event) => { @@ -741,7 +742,7 @@ export const exportMd = (id: string) => { }).element; }; -export const openMenu = (src: string, onlyMenu: boolean, showAccelerator: boolean) => { +export const openMenu = (app: App, src: string, onlyMenu: boolean, showAccelerator: boolean) => { const submenu = []; if (isLocalPath(src)) { if (Constants.SIYUAN_ASSETS_EXTS.includes(pathPosix().extname(src)) && @@ -753,7 +754,7 @@ export const openMenu = (src: string, onlyMenu: boolean, showAccelerator: boolea label: window.siyuan.languages.insertRight, accelerator: showAccelerator ? "Click" : "", click() { - openAsset(src.trim(), parseInt(getSearch("page", src)), "right"); + openAsset(app, src.trim(), parseInt(getSearch("page", src)), "right"); } }); /// #endif diff --git a/app/src/menus/index.ts b/app/src/menus/index.ts index bdd89f46e..e881ba325 100644 --- a/app/src/menus/index.ts +++ b/app/src/menus/index.ts @@ -38,7 +38,7 @@ export class Menus { } this.unselect(); // navigation 根上:新建文档/文件夹/取消挂在/打开文件位置 - initNavigationMenu(target).popup({x: event.clientX, y: event.clientY}); + initNavigationMenu(app, target).popup({x: event.clientX, y: event.clientY}); event.stopPropagation(); break; } @@ -46,7 +46,7 @@ export class Menus { if (dataType === "navigation-file") { this.unselect(); // navigation 文件上:删除/重命名/打开文件位置/导出 - initFileMenu(this.getDir(target), target.getAttribute("data-path"), target).popup({ + initFileMenu(app, this.getDir(target), target.getAttribute("data-path"), target).popup({ x: event.clientX, y: event.clientY }); diff --git a/app/src/menus/navigation.ts b/app/src/menus/navigation.ts index c3f4b2661..38910d0c3 100644 --- a/app/src/menus/navigation.ts +++ b/app/src/menus/navigation.ts @@ -31,6 +31,7 @@ import {Files} from "../layout/dock/Files"; import {openNewWindowById} from "../window/openNewWindow"; import {openCardByData} from "../card/openCard"; import {viewCards} from "../card/viewCards"; +import {App} from "../index"; const initMultiMenu = (selectItemElements: NodeListOf) => { const fileItemElement = Array.from(selectItemElements).find(item => { @@ -55,7 +56,7 @@ const initMultiMenu = (selectItemElements: NodeListOf) => { return window.siyuan.menus.menu; }; -export const initNavigationMenu = (liElement: HTMLElement) => { +export const initNavigationMenu = (app: App, liElement: HTMLElement) => { window.siyuan.menus.menu.remove(); const fileElement = hasClosestByTag(liElement, "DIV"); if (!fileElement) { @@ -133,7 +134,7 @@ export const initNavigationMenu = (liElement: HTMLElement) => { accelerator: window.siyuan.config.keymap.editor.general.spaceRepetition.custom, click: () => { fetchPost("/api/riff/getNotebookRiffDueCards", {notebook: notebookId}, (response) => { - openCardByData(response.data, "notebook", notebookId, name); + openCardByData(app, response.data, "notebook", notebookId, name); }); /// #if MOBILE closePanel(); @@ -143,7 +144,7 @@ export const initNavigationMenu = (liElement: HTMLElement) => { iconHTML: Constants.ZWSP, label: window.siyuan.languages.mgmt, click: () => { - viewCards(notebookId, name, "Notebook"); + viewCards(app, notebookId, name, "Notebook"); /// #if MOBILE closePanel(); /// #endif @@ -157,7 +158,7 @@ export const initNavigationMenu = (liElement: HTMLElement) => { click() { /// #if MOBILE const localData = window.siyuan.storage[Constants.LOCAL_SEARCHDATA]; - popSearch({ + popSearch(app, { removed: localData.removed, sort: localData.sort, group: localData.group, @@ -171,7 +172,11 @@ export const initNavigationMenu = (liElement: HTMLElement) => { types: Object.assign({}, localData.types) }); /// #else - openSearch(window.siyuan.config.keymap.general.search.custom, undefined, notebookId); + openSearch({ + app, + hotkey: window.siyuan.config.keymap.general.search.custom, + notebookId, + }); /// #endif } }).element); @@ -183,7 +188,7 @@ export const initNavigationMenu = (liElement: HTMLElement) => { click() { /// #if MOBILE const localData = window.siyuan.storage[Constants.LOCAL_SEARCHDATA]; - popSearch({ + popSearch(app, { removed: localData.removed, sort: localData.sort, group: localData.group, @@ -197,7 +202,11 @@ export const initNavigationMenu = (liElement: HTMLElement) => { types: Object.assign({}, localData.types) }); /// #else - openSearch(window.siyuan.config.keymap.general.replace.custom, undefined, notebookId); + openSearch({ + app, + hotkey: window.siyuan.config.keymap.general.replace.custom, + notebookId, + }); /// #endif } }).element); @@ -267,7 +276,7 @@ export const initNavigationMenu = (liElement: HTMLElement) => { return window.siyuan.menus.menu; }; -export const initFileMenu = (notebookId: string, pathString: string, liElement: Element) => { +export const initFileMenu = (app: App, notebookId: string, pathString: string, liElement: Element) => { window.siyuan.menus.menu.remove(); const fileElement = hasClosestByTag(liElement, "DIV"); if (!fileElement) { @@ -303,7 +312,7 @@ export const initFileMenu = (notebookId: string, pathString: string, liElement: paths.push(item.getAttribute("data-path")); } }); - newFile(notebookId, pathPosix().dirname(pathString), paths); + newFile(app, notebookId, pathPosix().dirname(pathString), paths); } }).element); window.siyuan.menus.menu.append(new MenuItem({ @@ -319,7 +328,7 @@ export const initFileMenu = (notebookId: string, pathString: string, liElement: } } }); - newFile(notebookId, pathPosix().dirname(pathString), paths); + newFile(app, notebookId, pathPosix().dirname(pathString), paths); } }).element); window.siyuan.menus.menu.append(new MenuItem({type: "separator"}).element); @@ -376,7 +385,7 @@ export const initFileMenu = (notebookId: string, pathString: string, liElement: accelerator: window.siyuan.config.keymap.editor.general.spaceRepetition.custom, click: () => { fetchPost("/api/riff/getTreeRiffDueCards", {rootID: id}, (response) => { - openCardByData(response.data, "doc", id, name); + openCardByData(app, response.data, "doc", id, name); }); /// #if MOBILE closePanel(); @@ -389,7 +398,7 @@ export const initFileMenu = (notebookId: string, pathString: string, liElement: fetchPost("/api/filetree/getHPathByID", { id }, (response) => { - viewCards(id, pathPosix().join(getNotebookName(notebookId), response.data), "Tree"); + viewCards(app, id, pathPosix().join(getNotebookName(notebookId), response.data), "Tree"); }); /// #if MOBILE closePanel(); @@ -409,7 +418,7 @@ export const initFileMenu = (notebookId: string, pathString: string, liElement: path: searchPath + ".sy" }); const localData = window.siyuan.storage[Constants.LOCAL_SEARCHDATA]; - popSearch({ + popSearch(app, { removed: localData.removed, sort: localData.sort, group: localData.group, @@ -423,7 +432,12 @@ export const initFileMenu = (notebookId: string, pathString: string, liElement: types: Object.assign({}, localData.types) }); /// #else - openSearch(window.siyuan.config.keymap.general.search.custom, undefined, notebookId, searchPath); + openSearch({ + app, + hotkey: window.siyuan.config.keymap.general.search.custom, + notebookId, + searchPath + }); /// #endif } }).element); @@ -439,7 +453,7 @@ export const initFileMenu = (notebookId: string, pathString: string, liElement: path: searchPath + ".sy" }); const localData = window.siyuan.storage[Constants.LOCAL_SEARCHDATA]; - popSearch({ + popSearch(app, { removed: localData.removed, sort: localData.sort, group: localData.group, @@ -453,7 +467,12 @@ export const initFileMenu = (notebookId: string, pathString: string, liElement: types: Object.assign({}, localData.types) }); /// #else - openSearch(window.siyuan.config.keymap.general.replace.custom, undefined, notebookId, searchPath); + openSearch({ + app, + hotkey: window.siyuan.config.keymap.general.replace.custom, + notebookId, + searchPath + }); /// #endif } }).element); @@ -465,14 +484,14 @@ export const initFileMenu = (notebookId: string, pathString: string, liElement: label: window.siyuan.languages.insertRight, accelerator: "⌥Click", click: () => { - openFileById({id, position: "right", action: [Constants.CB_GET_FOCUS]}); + openFileById({app, id, position: "right", action: [Constants.CB_GET_FOCUS]}); } }, { icon: "iconLayoutBottom", label: window.siyuan.languages.insertBottom, accelerator: "⇧Click", click: () => { - openFileById({id, position: "bottom", action: [Constants.CB_GET_FOCUS]}); + openFileById({app, id, position: "bottom", action: [Constants.CB_GET_FOCUS]}); } }]; if (window.siyuan.config.fileTree.openFilesUseCurrentTab) { @@ -481,6 +500,7 @@ export const initFileMenu = (notebookId: string, pathString: string, liElement: accelerator: "⌥⌘Click", click: () => { openFileById({ + app, id, action: [Constants.CB_GET_FOCUS], removeCurrentTab: false }); @@ -501,7 +521,7 @@ export const initFileMenu = (notebookId: string, pathString: string, liElement: icon: "iconPreview", label: window.siyuan.languages.preview, click: () => { - openFileById({id, mode: "preview"}); + openFileById({app, id, mode: "preview"}); } }); /// #if !BROWSER diff --git a/app/src/menus/protyle.ts b/app/src/menus/protyle.ts index b1fd81867..6d66ee6a7 100644 --- a/app/src/menus/protyle.ts +++ b/app/src/menus/protyle.ts @@ -42,8 +42,9 @@ import {removeLink} from "../protyle/toolbar/Link"; import {alignImgCenter, alignImgLeft} from "../protyle/wysiwyg/commonHotkey"; import {renameTag} from "../util/noRelyPCFunction"; import {hideElements} from "../protyle/ui/hideElements"; +import {App} from "../index"; -export const refMenu = (protyle: IProtyle, element: HTMLElement) => { +export const refMenu = (app: App, protyle: IProtyle, element: HTMLElement) => { const nodeElement = hasClosestBlock(element); if (!nodeElement) { return; @@ -99,6 +100,7 @@ export const refMenu = (protyle: IProtyle, element: HTMLElement) => { click() { fetchPost("/api/block/checkBlockFold", {id: refBlockId}, (foldResponse) => { openFileById({ + app, id: refBlockId, action: foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL] : [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT], zoomIn: foldResponse.data @@ -112,6 +114,7 @@ export const refMenu = (protyle: IProtyle, element: HTMLElement) => { click() { fetchPost("/api/block/checkBlockFold", {id: refBlockId}, (foldResponse) => { openFileById({ + app, id: refBlockId, action: foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL] : [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT], keepCursor: true, @@ -127,6 +130,7 @@ export const refMenu = (protyle: IProtyle, element: HTMLElement) => { click() { fetchPost("/api/block/checkBlockFold", {id: refBlockId}, (foldResponse) => { openFileById({ + app, id: refBlockId, position: "right", action: foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL] : [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT], @@ -142,6 +146,7 @@ export const refMenu = (protyle: IProtyle, element: HTMLElement) => { click() { fetchPost("/api/block/checkBlockFold", {id: refBlockId}, (foldResponse) => { openFileById({ + app, id: refBlockId, position: "bottom", action: foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL] : [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT], @@ -501,7 +506,7 @@ export const zoomOut = (protyle: IProtyle, id: string, focusId?: string, isPushB }); }; -export const imgMenu = (protyle: IProtyle, range: Range, assetElement: HTMLElement, position: { +export const imgMenu = (app: App, protyle: IProtyle, range: Range, assetElement: HTMLElement, position: { clientX: number, clientY: number }) => { @@ -703,7 +708,7 @@ export const imgMenu = (protyle: IProtyle, range: Range, assetElement: HTMLEleme const imgSrc = imgElement.getAttribute("src"); if (imgSrc) { window.siyuan.menus.menu.append(new MenuItem({type: "separator"}).element); - openMenu(imgSrc, false, false); + openMenu(app, imgSrc, false, false); } window.siyuan.menus.menu.popup({x: position.clientX, y: position.clientY}); const textElements = window.siyuan.menus.menu.element.querySelectorAll("textarea"); @@ -722,7 +727,7 @@ export const imgMenu = (protyle: IProtyle, range: Range, assetElement: HTMLEleme }; }; -export const linkMenu = (protyle: IProtyle, linkElement: HTMLElement, focusText = false) => { +export const linkMenu = (app: App, protyle: IProtyle, linkElement: HTMLElement, focusText = false) => { window.siyuan.menus.menu.remove(); const nodeElement = hasClosestBlock(linkElement); if (!nodeElement) { @@ -815,7 +820,7 @@ export const linkMenu = (protyle: IProtyle, linkElement: HTMLElement, focusText } }).element); if (linkAddress) { - openMenu(linkAddress, false, true); + openMenu(app, linkAddress, false, true); } if (linkAddress?.startsWith("siyuan://blocks/")) { window.siyuan.menus.menu.append(new MenuItem({ @@ -897,7 +902,7 @@ export const linkMenu = (protyle: IProtyle, linkElement: HTMLElement, focusText }; }; -export const tagMenu = (protyle: IProtyle, tagElement: HTMLElement) => { +export const tagMenu = (app: App, protyle: IProtyle, tagElement: HTMLElement) => { window.siyuan.menus.menu.remove(); const nodeElement = hasClosestBlock(tagElement); if (!nodeElement) { @@ -953,7 +958,7 @@ export const tagMenu = (protyle: IProtyle, tagElement: HTMLElement) => { accelerator: "Click", icon: "iconSearch", click() { - openGlobalSearch(`#${tagElement.textContent}#`, false); + openGlobalSearch(app, `#${tagElement.textContent}#`, false); } }).element); /// #endif @@ -1017,7 +1022,7 @@ const genImageWidthMenu = (label: string, assetElement: HTMLElement, imgElement: }; }; -export const iframeMenu = (protyle: IProtyle, nodeElement: Element) => { +export const iframeMenu = (app: App, protyle: IProtyle, nodeElement: Element) => { const id = nodeElement.getAttribute("data-node-id"); const iframeElement = nodeElement.querySelector("iframe"); let html = nodeElement.outerHTML; @@ -1076,12 +1081,12 @@ export const iframeMenu = (protyle: IProtyle, nodeElement: Element) => { subMenus.push({ type: "separator" }); - return subMenus.concat(openMenu(iframeSrc, true, false) as IMenu[]); + return subMenus.concat(openMenu(app, iframeSrc, true, false) as IMenu[]); } return subMenus; }; -export const videoMenu = (protyle: IProtyle, nodeElement: Element, type: string) => { +export const videoMenu = (app: App, protyle: IProtyle, nodeElement: Element, type: string) => { const id = nodeElement.getAttribute("data-node-id"); const videoElement = nodeElement.querySelector(type === "NodeVideo" ? "video" : "audio"); let html = nodeElement.outerHTML; @@ -1113,7 +1118,7 @@ export const videoMenu = (protyle: IProtyle, nodeElement: Element, type: string) /// #endif const VideoSrc = videoElement.getAttribute("src"); if (VideoSrc) { - return subMenus.concat(openMenu(VideoSrc, true, false) as IMenu[]); + return subMenus.concat(openMenu(app, VideoSrc, true, false) as IMenu[]); } return subMenus; }; diff --git a/app/src/menus/workspace.ts b/app/src/menus/workspace.ts index 6e99fc3f3..62fee5590 100644 --- a/app/src/menus/workspace.ts +++ b/app/src/menus/workspace.ts @@ -242,13 +242,13 @@ export const workspaceMenu = (app:App, rect: DOMRect) => { label: window.siyuan.languages.spaceRepetition, accelerator: window.siyuan.config.keymap.general.riffCard.custom, click: () => { - openCard(); + openCard(app); } }, { iconHTML: Constants.ZWSP, label: window.siyuan.languages.mgmt, click: () => { - viewCards("", window.siyuan.languages.all, ""); + viewCards(app, "", window.siyuan.languages.all, ""); } }], }).element); @@ -265,7 +265,7 @@ export const workspaceMenu = (app:App, rect: DOMRect) => { icon: "iconHistory", accelerator: window.siyuan.config.keymap.general.dataHistory.custom, click: () => { - openHistory(); + openHistory(app); } }).element); window.siyuan.menus.menu.append(new MenuItem({type: "separator"}).element); diff --git a/app/src/mobile/dock/MobileBacklinks.ts b/app/src/mobile/dock/MobileBacklinks.ts index 2f3c1ea54..d2f257a92 100644 --- a/app/src/mobile/dock/MobileBacklinks.ts +++ b/app/src/mobile/dock/MobileBacklinks.ts @@ -2,6 +2,7 @@ import {Tree} from "../../util/Tree"; import {fetchPost} from "../../util/fetch"; import {Constants} from "../../constants"; import {openMobileFileById} from "../editor"; +import {App} from "../../index"; export class MobileBacklinks { public element: HTMLElement; @@ -10,7 +11,7 @@ export class MobileBacklinks { private mTree: Tree; public beforeLen = 10; - constructor() { + constructor(app: App) { this.element = document.querySelector('#sidebar [data-type="sidebar-backlink"]'); this.element.innerHTML = `
    @@ -43,14 +44,14 @@ export class MobileBacklinks { element: this.element.querySelector(".backlinkList") as HTMLElement, data: null, click(element: HTMLElement) { - openMobileFileById(element.getAttribute("data-node-id"), [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT]); + openMobileFileById(app, element.getAttribute("data-node-id"), [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT]); } }); this.mTree = new Tree({ element: this.element.querySelector(".backlinkMList") as HTMLElement, data: null, click: (element) => { - openMobileFileById(element.getAttribute("data-node-id"), [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT]); + openMobileFileById(app, element.getAttribute("data-node-id"), [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT]); }, }); this.element.addEventListener("click", (event) => { diff --git a/app/src/mobile/dock/MobileBookmarks.ts b/app/src/mobile/dock/MobileBookmarks.ts index 39a0dca08..71d0830fc 100644 --- a/app/src/mobile/dock/MobileBookmarks.ts +++ b/app/src/mobile/dock/MobileBookmarks.ts @@ -4,13 +4,14 @@ import {Constants} from "../../constants"; import {hasClosestByClassName} from "../../protyle/util/hasClosest"; import {openMobileFileById} from "../editor"; import {openBookmarkMenu} from "../../menus/bookmark"; +import {App} from "../../index"; export class MobileBookmarks { public element: HTMLElement; private tree: Tree; private openNodes: string[]; - constructor() { + constructor(app: App) { this.element = document.querySelector('#sidebar [data-type="sidebar-bookmark"]'); this.element.innerHTML = `
    @@ -38,7 +39,7 @@ export class MobileBookmarks { } } fetchPost("/api/block/checkBlockFold", {id}, (foldResponse) => { - openMobileFileById(id, foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL, Constants.CB_GET_HTML] : [Constants.CB_GET_FOCUS, Constants.CB_GET_SETID, Constants.CB_GET_CONTEXT, Constants.CB_GET_HTML]); + openMobileFileById(app, id, foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL, Constants.CB_GET_HTML] : [Constants.CB_GET_FOCUS, Constants.CB_GET_SETID, Constants.CB_GET_CONTEXT, Constants.CB_GET_HTML]); }); }, blockExtHTML: '', diff --git a/app/src/mobile/dock/MobileFiles.ts b/app/src/mobile/dock/MobileFiles.ts index 541be9dee..6291cd44b 100644 --- a/app/src/mobile/dock/MobileFiles.ts +++ b/app/src/mobile/dock/MobileFiles.ts @@ -13,14 +13,16 @@ import {mountHelp, newNotebook} from "../../util/mount"; import {confirmDialog} from "../../dialog/confirmDialog"; import {newFile} from "../../util/newFile"; import {MenuItem} from "../../menus/Menu"; +import {App} from "../../index"; export class MobileFiles extends Model { public element: HTMLElement; private actionsElement: HTMLElement; private closeElement: HTMLElement; - constructor() { + constructor(app: App) { super({ + app, id: genUUID(), type: "filetree", msgCallback(data) { @@ -177,15 +179,15 @@ export class MobileFiles extends Model { const notebookId = ulElement.getAttribute("data-url"); if (!window.siyuan.config.readonly) { if (type === "new") { - newFile(notebookId, pathString); + newFile(app, notebookId, pathString); } else if (type === "more-root") { - initNavigationMenu(target.parentElement); + initNavigationMenu(app, target.parentElement); window.siyuan.menus.menu.fullscreen("bottom"); window.siyuan.menus.menu.element.style.zIndex = "310"; } } if (type === "more-file") { - initFileMenu(notebookId, pathString, target.parentElement); + initFileMenu(app, notebookId, pathString, target.parentElement); window.siyuan.menus.menu.fullscreen("bottom"); window.siyuan.menus.menu.element.style.zIndex = "310"; } @@ -196,7 +198,7 @@ export class MobileFiles extends Model { } else if (target.tagName === "LI") { this.setCurrent(target); if (target.getAttribute("data-type") === "navigation-file") { - openMobileFileById(target.getAttribute("data-node-id")); + openMobileFileById(app, target.getAttribute("data-node-id")); } else if (target.getAttribute("data-type") === "navigation-root") { const ulElement = hasTopClosestByTag(target, "UL"); if (ulElement) { diff --git a/app/src/mobile/dock/MobileOutline.ts b/app/src/mobile/dock/MobileOutline.ts index 3635ed512..a7fd55933 100644 --- a/app/src/mobile/dock/MobileOutline.ts +++ b/app/src/mobile/dock/MobileOutline.ts @@ -3,13 +3,14 @@ import {fetchPost} from "../../util/fetch"; import {openMobileFileById} from "../editor"; import {Constants} from "../../constants"; import {getEventName} from "../../protyle/util/compatibility"; +import {App} from "../../index"; export class MobileOutline { private tree: Tree; private openNodes: { [key: string]: string[] } = {}; private element: Element; - constructor() { + constructor(app: App) { this.element = document.querySelector('#sidebar [data-type="sidebar-outline"]'); this.element.innerHTML = `
    @@ -28,7 +29,7 @@ export class MobileOutline { click: (element: HTMLElement) => { const id = element.getAttribute("data-node-id"); fetchPost("/api/block/checkBlockFold", {id}, (foldResponse) => { - openMobileFileById(id, foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL, Constants.CB_GET_HTML] : [Constants.CB_GET_FOCUS, Constants.CB_GET_SETID, Constants.CB_GET_CONTEXT, Constants.CB_GET_HTML]); + openMobileFileById(app, id, foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL, Constants.CB_GET_HTML] : [Constants.CB_GET_FOCUS, Constants.CB_GET_SETID, Constants.CB_GET_CONTEXT, Constants.CB_GET_HTML]); }); } }); diff --git a/app/src/mobile/dock/MobileTags.ts b/app/src/mobile/dock/MobileTags.ts index 1548fb6c0..a70f0ad33 100644 --- a/app/src/mobile/dock/MobileTags.ts +++ b/app/src/mobile/dock/MobileTags.ts @@ -7,13 +7,14 @@ import {confirmDialog} from "../../dialog/confirmDialog"; import {escapeHtml} from "../../util/escape"; import {popSearch} from "../menu/search"; import {Constants} from "../../constants"; +import {App} from "../../index"; export class MobileTags { public element: HTMLElement; private tree: Tree; private openNodes: string[]; - constructor() { + constructor(app: App) { this.element = document.querySelector('#sidebar [data-type="sidebar-tag"]'); this.element.innerHTML = `
    @@ -67,7 +68,7 @@ export class MobileTags { } } else { const searchOption = window.siyuan.storage[Constants.LOCAL_SEARCHDATA]; - popSearch({ + popSearch(app, { removed: searchOption.removed, sort: searchOption.sort, group: searchOption.group, diff --git a/app/src/mobile/editor.ts b/app/src/mobile/editor.ts index 95c87f242..0337e133f 100644 --- a/app/src/mobile/editor.ts +++ b/app/src/mobile/editor.ts @@ -13,12 +13,13 @@ import {pushBack} from "./util/MobileBackFoward"; import {setStorageVal} from "../protyle/util/compatibility"; import {showMessage} from "../dialog/message"; import {saveScroll} from "../protyle/scroll/saveScroll"; +import {App} from "../index"; export const getCurrentEditor = () => { return window.siyuan.mobile.popEditor || window.siyuan.mobile.editor; }; -export const openMobileFileById = (id: string, action = [Constants.CB_GET_HL]) => { +export const openMobileFileById = (app: App, id: string, action = [Constants.CB_GET_HL]) => { window.siyuan.storage[Constants.LOCAL_DOCINFO] = {id, action}; setStorageVal(Constants.LOCAL_DOCINFO, window.siyuan.storage[Constants.LOCAL_DOCINFO]); if (window.siyuan.mobile.editor) { @@ -62,7 +63,7 @@ export const openMobileFileById = (id: string, action = [Constants.CB_GET_HL]) = }); window.siyuan.mobile.editor.protyle.undo.clear(); } else { - window.siyuan.mobile.editor = new Protyle(document.getElementById("editor"), { + window.siyuan.mobile.editor = new Protyle(app, document.getElementById("editor"), { blockId: id, action, render: { diff --git a/app/src/mobile/index.ts b/app/src/mobile/index.ts index abb133184..40e8f9b62 100644 --- a/app/src/mobile/index.ts +++ b/app/src/mobile/index.ts @@ -42,13 +42,14 @@ class App { blockPanels: [], mobile: {}, ws: new Model({ + app: this, id: genUUID(), type: "main", - msgCallback: (data)=> { + msgCallback: (data) => { this.plugins.forEach((plugin) => { plugin.eventBus.emit("ws-main", data); }); - onMessage(data); + onMessage(this, data); } }) }; @@ -64,7 +65,7 @@ class App { getLocalStorage(() => { fetchGet(`/appearance/langs/${window.siyuan.config.appearance.lang}.json?v=${Constants.SIYUAN_VERSION}`, (lauguages) => { window.siyuan.languages = lauguages; - window.siyuan.menus = new Menus(siyuanApp); + window.siyuan.menus = new Menus(this); document.title = window.siyuan.languages.siyuanNote; bootSync(); loadAssets(confResponse.data.conf.appearance); @@ -74,9 +75,9 @@ class App { window.siyuan.user = userResponse.data; fetchPost("/api/system/getEmojiConf", {}, emojiResponse => { window.siyuan.emojis = emojiResponse.data as IEmoji[]; - initFramework(siyuanApp); - initRightMenu(); - loadPlugins(siyuanApp); + initFramework(this); + initRightMenu(this); + loadPlugins(this); openChangelog(); }); }); @@ -85,7 +86,9 @@ class App { }); document.addEventListener("touchstart", handleTouchStart, false); document.addEventListener("touchmove", handleTouchMove, false); - document.addEventListener("touchend", handleTouchEnd, false); + document.addEventListener("touchend", (event) => { + handleTouchEnd(this, event); + }, false); }); setNoteBook(); promiseTransactions(); @@ -102,7 +105,7 @@ window.showKeyboardToolbar = (height) => { window.hideKeyboardToolbar = hideKeyboardToolbar; window.openFileByURL = (openURL) => { if (openURL && isSYProtocol(openURL)) { - openMobileFileById(getIdFromSYProtocol(openURL), + openMobileFileById(siyuanApp, getIdFromSYProtocol(openURL), getSearch("focus", openURL) === "1" ? [Constants.CB_GET_ALL, Constants.CB_GET_FOCUS] : [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT]); return true; } diff --git a/app/src/mobile/menu/getRecentDocs.ts b/app/src/mobile/menu/getRecentDocs.ts index b876a5eaf..651e1e7d7 100644 --- a/app/src/mobile/menu/getRecentDocs.ts +++ b/app/src/mobile/menu/getRecentDocs.ts @@ -5,8 +5,9 @@ import {escapeHtml} from "../../util/escape"; import {hasClosestByClassName} from "../../protyle/util/hasClosest"; import {openModel} from "./model"; import {openMobileFileById} from "../editor"; +import {App} from "../../index"; -export const getRecentDocs = () => { +export const getRecentDocs = (app: App) => { fetchPost("/api/storage/getRecentDocs", {}, (response) => { let html = ""; response.data.forEach((item: any, index: number) => { @@ -23,7 +24,7 @@ ${unicode2Emoji(item.icon || Constants.SIYUAN_IMAGE_FILE, false, "b3-list-item__ element.firstElementChild.addEventListener("click", (event) => { const liElement = hasClosestByClassName(event.target as HTMLElement, "b3-list-item"); if (liElement) { - openMobileFileById(liElement.dataset.nodeId, [Constants.CB_GET_SCROLL]); + openMobileFileById(app, liElement.dataset.nodeId, [Constants.CB_GET_SCROLL]); } }); } diff --git a/app/src/mobile/menu/index.ts b/app/src/mobile/menu/index.ts index b7278b7a9..2fab5b1d5 100644 --- a/app/src/mobile/menu/index.ts +++ b/app/src/mobile/menu/index.ts @@ -15,6 +15,7 @@ import {openModel} from "./model"; import {initAbout} from "../settings/about"; import {getRecentDocs} from "./getRecentDocs"; import {initEditor} from "../settings/editor"; +import {App} from "../../index"; export const popMenu = () => { activeBlur(); @@ -22,7 +23,7 @@ export const popMenu = () => { document.getElementById("menu").style.transform = "translateX(0px)"; }; -export const initRightMenu = () => { +export const initRightMenu = (app: App) => { const menuElement = document.getElementById("menu"); let accountHTML = ""; if (window.siyuan.user && !window.siyuan.config.readonly) { @@ -118,12 +119,12 @@ export const initRightMenu = () => { event.stopPropagation(); break; } else if (target.id === "menuSearch") { - popSearch(); + popSearch(app); event.preventDefault(); event.stopPropagation(); break; } else if (target.id === "menuRecent") { - getRecentDocs(); + getRecentDocs(app); event.preventDefault(); event.stopPropagation(); break; @@ -164,7 +165,7 @@ export const initRightMenu = () => { event.stopPropagation(); break; } else if (target.id === "menuCard") { - openCard(); + openCard(app); closePanel(); event.preventDefault(); event.stopPropagation(); @@ -204,7 +205,7 @@ export const initRightMenu = () => { event.stopPropagation(); break; } else if (target.id === "menuHistory") { - openHistory(); + openHistory(app); event.preventDefault(); event.stopPropagation(); break; diff --git a/app/src/mobile/menu/search.ts b/app/src/mobile/menu/search.ts index e5300565c..1d947b1d0 100644 --- a/app/src/mobile/menu/search.ts +++ b/app/src/mobile/menu/search.ts @@ -14,6 +14,7 @@ import {newFileByName} from "../../util/newFile"; import {showMessage} from "../../dialog/message"; import {reloadProtyle} from "../../protyle/util/reload"; import {activeBlur, hideKeyboardToolbar} from "../util/keyboardToolbar"; +import {App} from "../../index"; const replace = (element: Element, config: ISearchOption, isAll: boolean) => { if (config.method === 1 || config.method === 2) { @@ -245,7 +246,7 @@ const updateSearchResult = (config: ISearchOption, element: Element) => { }, Constants.TIMEOUT_INPUT); }; -const initSearchEvent = (element: Element, config: ISearchOption) => { +const initSearchEvent = (app: App, element: Element, config: ISearchOption) => { const searchInputElement = document.getElementById("toolbarSearch") as HTMLInputElement; searchInputElement.value = config.k || ""; searchInputElement.addEventListener("compositionend", (event: InputEvent) => { @@ -494,14 +495,14 @@ const initSearchEvent = (element: Element, config: ISearchOption) => { break; } else if (target.classList.contains("b3-list-item")) { if (target.getAttribute("data-type") === "search-new") { - newFileByName(searchInputElement.value); + newFileByName(app, searchInputElement.value); } else if (target.getAttribute("data-type") === "search-item") { const id = target.getAttribute("data-node-id"); if (window.siyuan.mobile.editor.protyle) { preventScroll(window.siyuan.mobile.editor.protyle); } fetchPost("/api/block/checkBlockFold", {id}, (foldResponse) => { - openMobileFileById(id, foldResponse.data ? [Constants.CB_GET_ALL, Constants.CB_GET_HL] : [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT]); + openMobileFileById(app, id, foldResponse.data ? [Constants.CB_GET_ALL, Constants.CB_GET_HL] : [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT]); }); closePanel(); } else if (target.querySelector(".b3-list-item__toggle")) { @@ -517,7 +518,7 @@ const initSearchEvent = (element: Element, config: ISearchOption) => { }, false); }; -export const popSearch = (config = window.siyuan.storage[Constants.LOCAL_SEARCHDATA] as ISearchOption) => { +export const popSearch = (app: App, config = window.siyuan.storage[Constants.LOCAL_SEARCHDATA] as ISearchOption) => { activeBlur(); hideKeyboardToolbar(); let includeChild = true; @@ -575,7 +576,7 @@ export const popSearch = (config = window.siyuan.storage[Constants.LOCAL_SEARCHD
    `, bindEvent(element) { - initSearchEvent(element.firstElementChild, config); + initSearchEvent(app, element.firstElementChild, config); updateSearchResult(config, element); } }); diff --git a/app/src/mobile/util/initFramework.ts b/app/src/mobile/util/initFramework.ts index fa099bba5..b16aee4b5 100644 --- a/app/src/mobile/util/initFramework.ts +++ b/app/src/mobile/util/initFramework.ts @@ -52,30 +52,30 @@ export const initFramework = (app: App) => { if (itemType === type) { if (type === "sidebar-outline-tab") { if (!outline) { - outline = new MobileOutline(); + outline = new MobileOutline(app); } else { outline.update(); } } else if (type === "sidebar-backlink-tab") { if (!backlink) { - backlink = new MobileBacklinks(); + backlink = new MobileBacklinks(app); } else { backlink.update(); } } else if (type === "sidebar-bookmark-tab") { if (!bookmark) { - bookmark = new MobileBookmarks(); + bookmark = new MobileBookmarks(app); } else { backlink.update(); } } else if (type === "sidebar-tag-tab") { if (!tag) { - tag = new MobileTags(); + tag = new MobileTags(app); } else { tag.update(); } } else if (type === "sidebar-inbox-tab" && !inbox) { - inbox = new Inbox(document.querySelector('#sidebar [data-type="sidebar-inbox"]')); + inbox = new Inbox(app, document.querySelector('#sidebar [data-type="sidebar-inbox"]')); } svgElement.classList.add("toolbar__icon--active"); sidebarElement.lastElementChild.querySelector(`[data-type="${itemType.replace("-tab", "")}"]`).classList.remove("fn__none"); @@ -85,7 +85,7 @@ export const initFramework = (app: App) => { } }); }); - window.siyuan.mobile.files = new MobileFiles(); + window.siyuan.mobile.files = new MobileFiles(app); document.getElementById("toolbarFile").addEventListener("click", () => { hideKeyboardToolbar(); activeBlur(); @@ -144,27 +144,27 @@ export const initFramework = (app: App) => { } const idZoomIn = getIdZoomInByPath(); if (idZoomIn.id) { - openMobileFileById(idZoomIn.id, + openMobileFileById(app, idZoomIn.id, idZoomIn.isZoomIn ? [Constants.CB_GET_ALL, Constants.CB_GET_FOCUS] : [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT]); return; } const localDoc = window.siyuan.storage[Constants.LOCAL_DOCINFO]; fetchPost("/api/block/checkBlockExist", {id: localDoc.id}, existResponse => { if (existResponse.data) { - openMobileFileById(localDoc.id, localDoc.action); + openMobileFileById(app, localDoc.id, localDoc.action); } else { fetchPost("/api/block/getRecentUpdatedBlocks", {}, (response) => { if (response.data.length !== 0) { - openMobileFileById(response.data[0].id, [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT]); + openMobileFileById(app, response.data[0].id, [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT]); } else { - setEmpty(); + setEmpty(app); } }); } }); return; } - setEmpty(); + setEmpty(app); }; const initEditorName = () => { diff --git a/app/src/mobile/util/onMessage.ts b/app/src/mobile/util/onMessage.ts index 54e62ff56..1b7ea53f1 100644 --- a/app/src/mobile/util/onMessage.ts +++ b/app/src/mobile/util/onMessage.ts @@ -1,6 +1,7 @@ import {openMobileFileById} from "../editor"; import {processSync, progressLoading, progressStatus, reloadSync, transactionError} from "../../dialog/processSystem"; import {Constants} from "../../constants"; +import {App} from "../../index"; const processReadonly = () => { const inputElement = document.getElementById("toolbarName") as HTMLInputElement; @@ -14,11 +15,11 @@ const processReadonly = () => { } }; -export const onMessage = (data: IWebSocketData) => { +export const onMessage = (app: App, data: IWebSocketData) => { if (data) { switch (data.cmd) { case "syncMergeResult": - reloadSync(data.data); + reloadSync(app, data.data); break; case "readonly": window.siyuan.config.editor.readOnly = data.data; @@ -34,10 +35,10 @@ export const onMessage = (data: IWebSocketData) => { } break; case "createdailynote": - openMobileFileById(data.data.id); + openMobileFileById(app, data.data.id); break; case "openFileById": - openMobileFileById(data.data.id, [Constants.CB_GET_FOCUS]); + openMobileFileById(app, data.data.id, [Constants.CB_GET_FOCUS]); break; case"txerr": transactionError(); diff --git a/app/src/mobile/util/setEmpty.ts b/app/src/mobile/util/setEmpty.ts index 625359cf0..80fd7b7bd 100644 --- a/app/src/mobile/util/setEmpty.ts +++ b/app/src/mobile/util/setEmpty.ts @@ -4,8 +4,9 @@ import {getOpenNotebookCount} from "../../util/pathName"; import {popSearch} from "../menu/search"; import {getRecentDocs} from "../menu/getRecentDocs"; import {openHistory} from "../../history/history"; +import {App} from "../../index"; -export const setEmpty = () => { +export const setEmpty = (app: App) => { document.getElementById("toolbarName").classList.add("fn__hidden"); document.getElementById("toolbarEdit").classList.add("fn__hidden"); document.getElementById("editor").classList.add("fn__none"); @@ -37,27 +38,27 @@ export const setEmpty = () => { let target = event.target as HTMLElement; while (target && !target.isEqualNode(emptyElement)) { if (target.id === "emptySearch") { - popSearch(); + popSearch(app); event.stopPropagation(); event.preventDefault(); break; } else if (target.id === "emptyRecent") { - getRecentDocs(); + getRecentDocs(app); event.stopPropagation(); event.preventDefault(); break; } else if (target.id === "emptyHistory") { - openHistory(); + openHistory(app); event.stopPropagation(); event.preventDefault(); break; } else if (target.id === "emptyNewFile") { if (window.siyuan.mobile.editor) { - newFile(window.siyuan.mobile.editor.protyle.notebookId, window.siyuan.mobile.editor.protyle.path, undefined, true); + newFile(app, window.siyuan.mobile.editor.protyle.notebookId, window.siyuan.mobile.editor.protyle.path, undefined, true); } else { window.siyuan.notebooks.find(item => { if (!item.closed) { - newFile(item.id, "/", undefined, true); + newFile(app, item.id, "/", undefined, true); return true; } }); diff --git a/app/src/mobile/util/touch.ts b/app/src/mobile/util/touch.ts index 86c009720..d2efa5a5c 100644 --- a/app/src/mobile/util/touch.ts +++ b/app/src/mobile/util/touch.ts @@ -4,6 +4,7 @@ import {popMenu} from "../menu"; import {activeBlur, hideKeyboardToolbar} from "./keyboardToolbar"; import {getCurrentEditor} from "../editor"; import {linkMenu, refMenu, tagMenu} from "../../menus/protyle"; +import {App} from "../../index"; let clientX: number; let clientY: number; @@ -23,7 +24,7 @@ const popSide = (render = true) => { } }; -export const handleTouchEnd = (event: TouchEvent) => { +export const handleTouchEnd = (app: App, event: TouchEvent) => { const editor = getCurrentEditor(); if (editor) { document.querySelectorAll(".protyle-breadcrumb__bar--hide").forEach(item => { @@ -44,13 +45,13 @@ export const handleTouchEnd = (event: TouchEvent) => { return; } if (types.includes("block-ref")) { - refMenu(editor.protyle, target); + refMenu(app, editor.protyle, target); } else if (types.includes("file-annotation-ref")) { editor.protyle.toolbar.showFileAnnotationRef(editor.protyle, target); } else if (types.includes("tag")) { - tagMenu(editor.protyle, target); + tagMenu(app, editor.protyle, target); } else if (types.includes("a")) { - linkMenu(editor.protyle, target); + linkMenu(app, editor.protyle, target); } return; } diff --git a/app/src/plugin/index.ts b/app/src/plugin/index.ts index 5c462c771..67a4cc67e 100644 --- a/app/src/plugin/index.ts +++ b/app/src/plugin/index.ts @@ -10,6 +10,7 @@ import {getDockByType, setPanelFocus} from "../layout/util"; import {hasClosestByAttribute} from "../protyle/util/hasClosest"; export class Plugin { + private app: App; public i18n: IObject; public eventBus: EventBus; public data: any = {}; @@ -34,6 +35,7 @@ export class Plugin { name: string, i18n: IObject }) { + this.app = options.app; this.i18n = options.i18n; this.name = options.name; this.eventBus = new EventBus(options.name); @@ -141,6 +143,7 @@ export class Plugin { const type2 = this.name + options.type; this.models[type2] = (arg: { data: any, tab: Tab }) => { const customObj = new Custom({ + app: this.app, tab: arg.tab, type: type2, data: arg.data, @@ -173,6 +176,7 @@ export class Plugin { config: options.config, model: (arg: { tab: Tab }) => { const customObj = new Custom({ + app: this.app, tab: arg.tab, type: type2, data: options.data, diff --git a/app/src/protyle/breadcrumb/index.ts b/app/src/protyle/breadcrumb/index.ts index 17dae65a1..b442646a2 100644 --- a/app/src/protyle/breadcrumb/index.ts +++ b/app/src/protyle/breadcrumb/index.ts @@ -25,6 +25,7 @@ import {hideElements} from "../ui/hideElements"; import {confirmDialog} from "../../dialog/confirmDialog"; import {reloadProtyle} from "../util/reload"; import {deleteFile} from "../../editor/deleteFile"; +import {App} from "../../index"; export class Breadcrumb { public element: HTMLElement; @@ -32,7 +33,7 @@ export class Breadcrumb { private id: string; private messageId: string; - constructor(protyle: IProtyle) { + constructor(app: App, protyle: IProtyle) { const element = document.createElement("div"); element.className = "protyle-breadcrumb"; const isFocus = protyle.options.action.includes(Constants.CB_GET_ALL) && !isMobile(); @@ -50,6 +51,7 @@ export class Breadcrumb { if (protyle.options.render.breadcrumbDocName && window.siyuan.ctrlIsPressed) { /// #if !MOBILE openFileById({ + app, id, action: id === protyle.block.rootID ? [Constants.CB_GET_FOCUS] : [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL] }); diff --git a/app/src/protyle/gutter/index.ts b/app/src/protyle/gutter/index.ts index 07a910468..6020217f0 100644 --- a/app/src/protyle/gutter/index.ts +++ b/app/src/protyle/gutter/index.ts @@ -38,11 +38,14 @@ import {isMobile} from "../../util/functions"; import {AIActions} from "../../ai/actions"; import {activeBlur} from "../../mobile/util/keyboardToolbar"; import {hideTooltip} from "../../dialog/tooltip"; +import {App} from "../../index"; export class Gutter { public element: HTMLElement; + private app: App; - constructor(protyle: IProtyle) { + constructor(app: App, protyle: IProtyle) { + this.app = app; this.element = document.createElement("div"); this.element.className = "protyle-gutters"; if (/Mac/.test(navigator.platform) || navigator.platform === "iPhone") { @@ -701,7 +704,7 @@ export class Gutter { } ids.push(item.getAttribute("data-node-id")); }); - makeCard(ids); + makeCard(this.app, ids); } }).element); } @@ -1202,7 +1205,7 @@ export class Gutter { type: "submenu", icon: type === "NodeVideo" ? "iconVideo" : "iconRecord", label: window.siyuan.languages.assets, - submenu: videoMenu(protyle, nodeElement, type) + submenu: videoMenu(this.app, protyle, nodeElement, type) }).element); } else if (type === "NodeIFrame" && !protyle.disabled) { window.siyuan.menus.menu.append(new MenuItem({type: "separator"}).element); @@ -1211,7 +1214,7 @@ export class Gutter { type: "submenu", icon: "iconLanguage", label: window.siyuan.languages.assets, - submenu: iframeMenu(protyle, nodeElement) + submenu: iframeMenu(this.app, protyle, nodeElement) }).element); } else if (type === "NodeHTMLBlock" && !protyle.disabled) { window.siyuan.menus.menu.append(new MenuItem({type: "separator"}).element); @@ -1369,14 +1372,15 @@ export class Gutter { window.siyuan.menus.menu.append(new MenuItem({ accelerator: window.siyuan.config.keymap.general.enterBack.custom, label: window.siyuan.languages.enterBack, - click() { + click: () => { if (!protyle.block.showAll) { const ids = protyle.path.split("/"); if (ids.length > 2) { /// #if MOBILE - openMobileFileById(ids[ids.length - 2], [Constants.CB_GET_FOCUS, Constants.CB_GET_SCROLL]); + openMobileFileById(this.app, ids[ids.length - 2], [Constants.CB_GET_FOCUS, Constants.CB_GET_SCROLL]); /// #else openFileById({ + app: this.app, id: ids[ids.length - 2], action: [Constants.CB_GET_FOCUS, Constants.CB_GET_SCROLL] }); @@ -1482,7 +1486,7 @@ export class Gutter { label: window.siyuan.languages.addToDeck, icon: "iconRiffCard", click() { - makeCard([nodeElement.getAttribute("data-node-id")]); + makeCard(this.app, [nodeElement.getAttribute("data-node-id")]); } }).element); } @@ -1497,6 +1501,9 @@ export class Gutter { type: "readonly", label: `${updateHTML}${window.siyuan.languages.createdAt} ${dayjs(id.substr(0, 14)).format("YYYY-MM-DD HH:mm:ss")}`, }).element); + this.app.plugins.forEach((plugin) => { + plugin.eventBus.emit("click-blockicon", [nodeElement]); + }); return window.siyuan.menus.menu; } diff --git a/app/src/protyle/header/Background.ts b/app/src/protyle/header/Background.ts index 121a78bcc..e8660fef6 100644 --- a/app/src/protyle/header/Background.ts +++ b/app/src/protyle/header/Background.ts @@ -13,6 +13,7 @@ import {popSearch} from "../../mobile/menu/search"; import {getEventName} from "../util/compatibility"; import {Dialog} from "../../dialog"; import {Constants} from "../../constants"; +import {App} from "../../index"; export class Background { public element: HTMLElement; @@ -22,7 +23,7 @@ export class Background { private tagsElement: HTMLElement; private transparentData = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII="; - constructor(protyle: IProtyle) { + constructor(app: App, protyle: IProtyle) { this.element = document.createElement("div"); this.element.className = "protyle-background"; this.element.innerHTML = `
    @@ -331,10 +332,10 @@ export class Background { break; } else if (type === "open-search") { /// #if !MOBILE - openGlobalSearch(`#${target.textContent}#`, !window.siyuan.ctrlIsPressed); + openGlobalSearch(app, `#${target.textContent}#`, !window.siyuan.ctrlIsPressed); /// #else const searchOption = window.siyuan.storage[Constants.LOCAL_SEARCHDATA]; - popSearch({ + popSearch(app, { removed: searchOption.removed, sort: searchOption.sort, group: searchOption.group, diff --git a/app/src/protyle/header/Title.ts b/app/src/protyle/header/Title.ts index 598dd5f79..ec9ebc00c 100644 --- a/app/src/protyle/header/Title.ts +++ b/app/src/protyle/header/Title.ts @@ -36,13 +36,16 @@ import {makeCard, quickMakeCard} from "../../card/makeCard"; import {viewCards} from "../../card/viewCards"; import {getNotebookName, pathPosix} from "../../util/pathName"; import {commonClick} from "../wysiwyg/commonClick"; +import {App} from "../../index"; export class Title { public element: HTMLElement; public editElement: HTMLElement; private timeout: number; + private app: App; - constructor(protyle: IProtyle) { + constructor(app: App, protyle: IProtyle) { + this.app = app; this.element = document.createElement("div"); this.element.className = "protyle-title"; if (window.siyuan.config.editor.displayBookmarkIcon) { @@ -90,13 +93,14 @@ export class Title { return; } - if (commonHotkey(protyle, event)) { + if (commonHotkey(app, protyle, event)) { return true; } if (matchHotKey(window.siyuan.config.keymap.general.enterBack.custom, event)) { const ids = protyle.path.split("/"); if (ids.length > 2) { openFileById({ + app, id: ids[ids.length - 2], action: [Constants.CB_GET_FOCUS, Constants.CB_GET_SCROLL] }); @@ -264,7 +268,7 @@ export class Title { fetchPost("/api/block/getDocInfo", { id: protyle.block.rootID }, (response) => { - commonClick(event, protyle, response.data.ial); + commonClick(app, event, protyle, response.data.ial); }); }); } @@ -330,7 +334,7 @@ export class Title { label: window.siyuan.languages.outline, accelerator: window.siyuan.config.keymap.editor.general.outline.custom, click: () => { - openOutline(protyle); + openOutline(this.app, protyle); } }).element); window.siyuan.menus.menu.append(new MenuItem({ @@ -338,7 +342,7 @@ export class Title { label: window.siyuan.languages.backlinks, accelerator: window.siyuan.config.keymap.editor.general.backlinks.custom, click: () => { - openBacklink(protyle); + openBacklink(this.app, protyle); } }).element); window.siyuan.menus.menu.append(new MenuItem({ @@ -346,7 +350,7 @@ export class Title { label: window.siyuan.languages.graphView, accelerator: window.siyuan.config.keymap.editor.general.graphView.custom, click: () => { - openGraph(protyle); + openGraph(this.app, protyle); } }).element); window.siyuan.menus.menu.append(new MenuItem({type: "separator"}).element); @@ -363,7 +367,7 @@ export class Title { accelerator: window.siyuan.config.keymap.editor.general.spaceRepetition.custom, click: () => { fetchPost("/api/riff/getTreeRiffDueCards", {rootID: protyle.block.rootID}, (response) => { - openCardByData(response.data, "doc", protyle.block.rootID, this.editElement.textContent); + openCardByData(this.app, response.data, "doc", protyle.block.rootID, this.editElement.textContent); }); } }, { @@ -373,7 +377,7 @@ export class Title { fetchPost("/api/filetree/getHPathByID", { id: protyle.block.rootID }, (response) => { - viewCards(protyle.block.rootID, pathPosix().join(getNotebookName(protyle.notebookId), (response.data)), "Tree"); + viewCards(this.app, protyle.block.rootID, pathPosix().join(getNotebookName(protyle.notebookId), (response.data)), "Tree"); }); } }, { @@ -389,7 +393,7 @@ export class Title { iconHTML: Constants.ZWSP, label: window.siyuan.languages.addToDeck, click: () => { - makeCard([protyle.block.rootID]); + makeCard(this.app, [protyle.block.rootID]); } }); } diff --git a/app/src/protyle/hint/index.ts b/app/src/protyle/hint/index.ts index cfc57560c..19a5bb21f 100644 --- a/app/src/protyle/hint/index.ts +++ b/app/src/protyle/hint/index.ts @@ -32,17 +32,20 @@ import {processRender} from "../util/processCode"; import {AIChat} from "../../ai/chat"; import {isMobile} from "../../util/functions"; import {isCtrl} from "../util/compatibility"; +import {App} from "../../index"; export class Hint { public timeId: number; public element: HTMLDivElement; public enableSlash = true; private enableEmoji = true; + private app: App; public enableExtend = false; public splitChar = ""; public lastIndex = -1; - constructor(protyle: IProtyle) { + constructor(app: App, protyle: IProtyle) { + this.app = app; this.element = document.createElement("div"); this.element.setAttribute("data-close", "false"); // height 402 根据 .emojis max-height+8 得来 @@ -577,9 +580,10 @@ ${unicode2Emoji(emoji.unicode, true)}`; }, () => { insertHTML(`Untitled`, protyle); /// #if MOBILE - openMobileFileById(newSubDocId, [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT]); + openMobileFileById(this.app, newSubDocId, [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT]); /// #else openFileById({ + app: this.app, id: newSubDocId, action: [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT] }); @@ -645,7 +649,7 @@ ${unicode2Emoji(emoji.unicode, true)}`; }); } const rect = imgElement.getBoundingClientRect(); - imgMenu(protyle, range, imgElement, { + imgMenu(this.app, protyle, range, imgElement, { clientX: rect.left, clientY: rect.top }); diff --git a/app/src/protyle/index.ts b/app/src/protyle/index.ts index ac781cabd..7be99ac99 100644 --- a/app/src/protyle/index.ts +++ b/app/src/protyle/index.ts @@ -28,17 +28,20 @@ import {renderBacklink} from "./wysiwyg/renderBacklink"; import {setEmpty} from "../mobile/util/setEmpty"; import {resize} from "./util/resize"; import {getDocByScroll} from "./scroll/saveScroll"; +import {App} from "../index"; export class Protyle { public readonly version: string; public protyle: IProtyle; + private app: App; /** * @param id 要挂载 Protyle 的元素或者元素 ID。 * @param options Protyle 参数 */ - constructor(id: HTMLElement, options?: IOptions) { + constructor(app: App, id: HTMLElement, options?: IOptions) { + this.app = app; this.version = Constants.SIYUAN_VERSION; const getOptions = new Options(options); const mergedOptions = getOptions.merge(); @@ -53,17 +56,17 @@ export class Protyle { block: {}, }; - this.protyle.hint = new Hint(this.protyle); + this.protyle.hint = new Hint(app, this.protyle); if (mergedOptions.render.breadcrumb) { - this.protyle.breadcrumb = new Breadcrumb(this.protyle); + this.protyle.breadcrumb = new Breadcrumb(app, this.protyle); } /// #if !MOBILE if (mergedOptions.render.title) { - this.protyle.title = new Title(this.protyle); + this.protyle.title = new Title(app, this.protyle); } /// #endif if (mergedOptions.render.background) { - this.protyle.background = new Background(this.protyle); + this.protyle.background = new Background(app, this.protyle); } this.protyle.element.innerHTML = ""; @@ -72,11 +75,11 @@ export class Protyle { this.protyle.element.appendChild(this.protyle.breadcrumb.element.parentElement); } this.protyle.undo = new Undo(); - this.protyle.wysiwyg = new WYSIWYG(this.protyle); - this.protyle.toolbar = new Toolbar(this.protyle); + this.protyle.wysiwyg = new WYSIWYG(app, this.protyle); + this.protyle.toolbar = new Toolbar(app, this.protyle); this.protyle.scroll = new Scroll(this.protyle); // 不能使用 render.scroll 来判读是否初始化,除非重构后面用到的相关变量 if (this.protyle.options.render.gutter) { - this.protyle.gutter = new Gutter(this.protyle); + this.protyle.gutter = new Gutter(app, this.protyle); } if (mergedOptions.upload.url || mergedOptions.upload.handler) { this.protyle.upload = new Upload(); @@ -85,6 +88,7 @@ export class Protyle { this.init(); if (!mergedOptions.action.includes(Constants.CB_GET_HISTORY)) { this.protyle.ws = new Model({ + app, id: this.protyle.id, type: "protyle", msgCallback: (data) => { @@ -170,7 +174,7 @@ export class Protyle { case "unmount": if (this.protyle.notebookId === data.data.box) { /// #if MOBILE - setEmpty(); + setEmpty(app); /// #else if (this.protyle.model) { this.protyle.model.parent.parent.removeTab(this.protyle.model.parent.id, false, false); @@ -181,7 +185,7 @@ export class Protyle { case "removeDoc": if (data.data.ids.includes(this.protyle.block.rootID)) { /// #if MOBILE - setEmpty(); + setEmpty(app); /// #else if (this.protyle.model) { this.protyle.model.parent.parent.removeTab(this.protyle.model.parent.id, false, false); @@ -325,7 +329,7 @@ export class Protyle { sanitize: this.protyle.options.preview.markdown.sanitize, }); - this.protyle.preview = new Preview(this.protyle); + this.protyle.preview = new Preview(this.app, this.protyle); initUI(this.protyle); } diff --git a/app/src/protyle/preview/index.ts b/app/src/protyle/preview/index.ts index 076f0e1d5..ef3813978 100644 --- a/app/src/protyle/preview/index.ts +++ b/app/src/protyle/preview/index.ts @@ -17,13 +17,14 @@ import {fetchPost} from "../../util/fetch"; import {processRender} from "../util/processCode"; import {highlightRender} from "../markdown/highlightRender"; import {speechRender} from "../markdown/speechRender"; +import {App} from "../../index"; export class Preview { public element: HTMLElement; public previewElement: HTMLElement; private mdTimeoutId: number; - constructor(protyle: IProtyle) { + constructor(app: App, protyle: IProtyle) { this.element = document.createElement("div"); this.element.className = "protyle-preview fn__none"; @@ -55,7 +56,7 @@ export class Preview { if (isLocalPath(linkAddress)) { /// #if !MOBILE if (Constants.SIYUAN_ASSETS_EXTS.includes(pathPosix().extname((linkAddress.split("?page")[0])))) { - openAsset(linkAddress.split("?page")[0], parseInt(getSearch("page", linkAddress))); + openAsset(app, linkAddress.split("?page")[0], parseInt(getSearch("page", linkAddress))); } else { /// #if !BROWSER openBy(linkAddress, "folder"); diff --git a/app/src/protyle/toolbar/Link.ts b/app/src/protyle/toolbar/Link.ts index 063c4bb69..4de95126a 100644 --- a/app/src/protyle/toolbar/Link.ts +++ b/app/src/protyle/toolbar/Link.ts @@ -4,11 +4,12 @@ import {hasClosestBlock, hasClosestByAttribute} from "../util/hasClosest"; import {focusByRange, focusByWbr} from "../util/selection"; import {readText} from "../util/compatibility"; import {Constants} from "../../constants"; +import {App} from "../../index"; export class Link extends ToolbarItem { public element: HTMLElement; - constructor(protyle: IProtyle, menuItem: IMenuItem) { + constructor(app: App, protyle: IProtyle, menuItem: IMenuItem) { super(protyle, menuItem); // 不能用 getEventName,否则会导致光标位置变动到点击的文档中 this.element.addEventListener("click", async (event: MouseEvent & { changedTouches: MouseEvent[] }) => { @@ -22,7 +23,7 @@ export class Link extends ToolbarItem { } const aElement = hasClosestByAttribute(range.startContainer, "data-type", "a"); if (aElement) { - linkMenu(protyle, aElement); + linkMenu(app, protyle, aElement); return; } diff --git a/app/src/protyle/toolbar/index.ts b/app/src/protyle/toolbar/index.ts index 6fda70775..b7b3c02ab 100644 --- a/app/src/protyle/toolbar/index.ts +++ b/app/src/protyle/toolbar/index.ts @@ -42,6 +42,7 @@ import {mathRender} from "../markdown/mathRender"; import {linkMenu} from "../../menus/protyle"; import {addScript} from "../util/addScript"; import {confirmDialog} from "../../dialog/confirmDialog"; +import {App} from "../../index"; export class Toolbar { public element: HTMLElement; @@ -49,10 +50,11 @@ export class Toolbar { public subElementCloseCB: () => void; public range: Range; private toolbarHeight: number; + private app: App; - constructor(protyle: IProtyle) { + constructor(app: App, protyle: IProtyle) { const options = protyle.options; - + this.app = app; const element = document.createElement("div"); element.className = "protyle-toolbar fn__none"; this.element = element; @@ -224,7 +226,7 @@ export class Toolbar { menuItemObj = new Font(protyle, menuItem); break; case "a": - menuItemObj = new Link(protyle, menuItem); + menuItemObj = new Link(this.app, protyle, menuItem); break; } if (!menuItemObj) { @@ -500,23 +502,23 @@ export class Toolbar { } else if (type === "block-ref" && (types.includes("a") || types.includes("file-annotation-ref"))) { // 虚拟引用和链接/标注不能同时存在 types.find((item, index) => { - if (item === "a"||item === "file-annotation-ref") { + if (item === "a" || item === "file-annotation-ref") { types.splice(index, 1); return true; } }); - } else if (type === "a" && (types.includes("block-ref")|| types.includes("file-annotation-ref"))) { + } else if (type === "a" && (types.includes("block-ref") || types.includes("file-annotation-ref"))) { // 链接和引用/标注不能同时存在 types.find((item, index) => { - if (item === "block-ref"||item === "file-annotation-ref") { + if (item === "block-ref" || item === "file-annotation-ref") { types.splice(index, 1); return true; } }); - } else if (type === "file-annotation-ref" && (types.includes("block-ref")|| types.includes("a"))) { + } else if (type === "file-annotation-ref" && (types.includes("block-ref") || types.includes("a"))) { // 引用和链接/标注不能同时存在 types.find((item, index) => { - if (item === "block-ref"||item === "a") { + if (item === "block-ref" || item === "a") { types.splice(index, 1); return true; } @@ -728,7 +730,7 @@ export class Toolbar { const aElement = newNodes[0] as HTMLElement; if (aElement.textContent.replace(Constants.ZWSP, "") === "" || !aElement.getAttribute("data-href")) { needFocus = false; - linkMenu(protyle, aElement, aElement.getAttribute("data-href") ? true : false); + linkMenu(this.app, protyle, aElement, aElement.getAttribute("data-href") ? true : false); } else { this.range.collapse(false); } diff --git a/app/src/protyle/wysiwyg/commonClick.ts b/app/src/protyle/wysiwyg/commonClick.ts index f54b6289a..b2849111e 100644 --- a/app/src/protyle/wysiwyg/commonClick.ts +++ b/app/src/protyle/wysiwyg/commonClick.ts @@ -4,8 +4,9 @@ import {openAttr, openFileAttr} from "../../menus/commonMenuItem"; import {openGlobalSearch} from "../../search/util"; /// #endif import {isMobile} from "../../util/functions"; +import {App} from "../../index"; -export const commonClick = (event: MouseEvent & { +export const commonClick = (app: App, event: MouseEvent & { target: HTMLElement }, protyle: IProtyle, data?:IObject) => { const isM = isMobile(); @@ -13,7 +14,7 @@ export const commonClick = (event: MouseEvent & { if (attrBookmarkElement) { if (!isM && (event.ctrlKey || event.metaKey)) { /// #if !MOBILE - openGlobalSearch(attrBookmarkElement.textContent.trim(), true); + openGlobalSearch(app, attrBookmarkElement.textContent.trim(), true); /// #endif } else { if (data) { @@ -30,7 +31,7 @@ export const commonClick = (event: MouseEvent & { if (attrNameElement) { if (!isM && (event.ctrlKey || event.metaKey)) { /// #if !MOBILE - openGlobalSearch(attrNameElement.textContent.trim(), true); + openGlobalSearch(app, attrNameElement.textContent.trim(), true); /// #endif } else { if (data ) { @@ -47,7 +48,7 @@ export const commonClick = (event: MouseEvent & { if (attrAliasElement) { if (!isM && (event.ctrlKey || event.metaKey)) { /// #if !MOBILE - openGlobalSearch(attrAliasElement.textContent.trim(), true); + openGlobalSearch(app, attrAliasElement.textContent.trim(), true); /// #endif } else { if (data) { @@ -64,7 +65,7 @@ export const commonClick = (event: MouseEvent & { if (attrMemoElement) { if (!isM && (event.ctrlKey || event.metaKey)) { /// #if !MOBILE - openGlobalSearch(attrMemoElement.getAttribute("aria-label").trim(), true); + openGlobalSearch(app, attrMemoElement.getAttribute("aria-label").trim(), true); /// #endif } else { if (data) { diff --git a/app/src/protyle/wysiwyg/commonHotkey.ts b/app/src/protyle/wysiwyg/commonHotkey.ts index d538fd561..bef602c33 100644 --- a/app/src/protyle/wysiwyg/commonHotkey.ts +++ b/app/src/protyle/wysiwyg/commonHotkey.ts @@ -20,8 +20,9 @@ import {transaction, updateTransaction} from "./transaction"; import {onGet} from "../util/onGet"; import {Constants} from "../../constants"; import * as dayjs from "dayjs"; +import {App} from "../../index"; -export const commonHotkey = (protyle: IProtyle, event: KeyboardEvent) => { +export const commonHotkey = (app: App, protyle: IProtyle, event: KeyboardEvent) => { const target = event.target as HTMLElement; if (matchHotKey(window.siyuan.config.keymap.editor.general.copyHPath.custom, event)) { fetchPost("/api/filetree/getHPathByID", { @@ -51,20 +52,20 @@ export const commonHotkey = (protyle: IProtyle, event: KeyboardEvent) => { if (matchHotKey(window.siyuan.config.keymap.editor.general.backlinks.custom, event)) { event.preventDefault(); event.stopPropagation(); - openBacklink(protyle); + openBacklink(app, protyle); return true; } if (matchHotKey(window.siyuan.config.keymap.editor.general.graphView.custom, event)) { event.preventDefault(); event.stopPropagation(); - openGraph(protyle); + openGraph(app, protyle); return true; } if (matchHotKey(window.siyuan.config.keymap.editor.general.outline.custom, event)) { event.preventDefault(); event.stopPropagation(); const offset = getSelectionOffset(target); - openOutline(protyle); + openOutline(app, protyle); // switchWnd 后,range会被清空,需要重新设置 focusByOffset(target, offset.start, offset.end); return true; diff --git a/app/src/protyle/wysiwyg/index.ts b/app/src/protyle/wysiwyg/index.ts index 1941300d3..84856d774 100644 --- a/app/src/protyle/wysiwyg/index.ts +++ b/app/src/protyle/wysiwyg/index.ts @@ -66,14 +66,17 @@ import {getBacklinkHeadingMore, loadBreadcrumb} from "./renderBacklink"; import {removeSearchMark} from "../toolbar/util"; import {activeBlur, hideKeyboardToolbar} from "../../mobile/util/keyboardToolbar"; import {commonClick} from "./commonClick"; +import {App} from "../../index"; export class WYSIWYG { public lastHTMLs: { [key: string]: string } = {}; public element: HTMLDivElement; public preventKeyup: boolean; + private app: App; - constructor(protyle: IProtyle) { + constructor(app: App, protyle: IProtyle) { + this.app = app; this.element = document.createElement("div"); this.element.className = "protyle-wysiwyg"; this.element.setAttribute("spellcheck", "false"); @@ -91,7 +94,7 @@ export class WYSIWYG { return; } this.bindEvent(protyle); - keydown(protyle, this.element); + keydown(app, protyle, this.element); dropEvent(protyle, this.element); } @@ -1216,7 +1219,7 @@ export class WYSIWYG { removeSearchMark(target); } if (types.includes("block-ref") && !protyle.disabled) { - refMenu(protyle, target); + refMenu(this.app, protyle, target); // 阻止 popover target.setAttribute("prevent-popover", "true"); setTimeout(() => { @@ -1227,13 +1230,13 @@ export class WYSIWYG { protyle.toolbar.showFileAnnotationRef(protyle, target); return false; } else if (types.includes("tag") && !protyle.disabled) { - tagMenu(protyle, target); + tagMenu(this.app, protyle, target); return false; } else if (types.includes("inline-memo")) { protyle.toolbar.showRender(protyle, target); return false; } else if (types.includes("a") && !protyle.disabled) { - linkMenu(protyle, target); + linkMenu(this.app, protyle, target); if (window.siyuan.config.editor.floatWindowMode === 0 && target.getAttribute("data-href")?.startsWith("siyuan://blocks")) { // 阻止 popover @@ -1246,7 +1249,7 @@ export class WYSIWYG { } } if (!protyle.disabled && target.tagName === "IMG" && hasClosestByClassName(target, "img")) { - imgMenu(protyle, protyle.toolbar.range, target.parentElement.parentElement, { + imgMenu(this.app, protyle, protyle.toolbar.range, target.parentElement.parentElement, { clientX: x + 4, clientY: y }); @@ -1509,6 +1512,7 @@ export class WYSIWYG { if (ctrlIsPressed) { fetchPost("/api/block/checkBlockFold", {id: breadcrumbId}, (foldResponse) => { openFileById({ + app: this.app, id: breadcrumbId, action: foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL] : [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT], zoomIn: foldResponse.data @@ -1567,7 +1571,7 @@ export class WYSIWYG { fetchPost("/api/block/checkBlockFold", {id: refBlockId}, (foldResponse) => { /// #if MOBILE - openMobileFileById(refBlockId, foldResponse.data ? [Constants.CB_GET_ALL, Constants.CB_GET_HL] : [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT]); + openMobileFileById(this.app, refBlockId, foldResponse.data ? [Constants.CB_GET_ALL, Constants.CB_GET_HL] : [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT]); activeBlur(); hideKeyboardToolbar(); /// #else @@ -1577,6 +1581,7 @@ export class WYSIWYG { } if (event.shiftKey) { openFileById({ + app: this.app, id: refBlockId, position: "bottom", action: foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL] : [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT], @@ -1584,6 +1589,7 @@ export class WYSIWYG { }); } else if (event.altKey) { openFileById({ + app: this.app, id: refBlockId, position: "right", action: foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL] : [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT], @@ -1591,6 +1597,7 @@ export class WYSIWYG { }); } else if (ctrlIsPressed) { openFileById({ + app: this.app, id: refBlockId, action: foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL] : [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT], keepCursor: true, @@ -1598,6 +1605,7 @@ export class WYSIWYG { }); } else { openFileById({ + app: this.app, id: refBlockId, action: foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL] : [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT], zoomIn: foldResponse.data @@ -1636,7 +1644,7 @@ export class WYSIWYG { } else if (event.shiftKey) { openBy(linkAddress, "app"); } else { - openAsset(linkAddress, fileIds[2], "right"); + openAsset(this.app, linkAddress, fileIds[2], "right"); } /// #endif return; @@ -1660,7 +1668,7 @@ export class WYSIWYG { } else if (event.shiftKey) { openBy(linkAddress, "app"); } else { - openAsset(linkPathname, parseInt(getSearch("page", linkAddress)), "right"); + openAsset(this.app, linkPathname, parseInt(getSearch("page", linkAddress)), "right"); } } else { /// #if !BROWSER @@ -1689,11 +1697,11 @@ export class WYSIWYG { const tagElement = hasClosestByAttribute(event.target, "data-type", "tag"); if (tagElement && !event.altKey) { /// #if !MOBILE - openGlobalSearch(`#${tagElement.textContent}#`, !ctrlIsPressed); + openGlobalSearch(this.app, `#${tagElement.textContent}#`, !ctrlIsPressed); hideElements(["dialog"]); /// #else const searchOption = window.siyuan.storage[Constants.LOCAL_SEARCHDATA]; - popSearch({ + popSearch(this.app, { removed: searchOption.removed, sort: searchOption.sort, group: searchOption.group, @@ -1714,12 +1722,13 @@ export class WYSIWYG { if (embedItemElement) { const embedId = embedItemElement.getAttribute("data-id"); /// #if MOBILE - openMobileFileById(embedId, [Constants.CB_GET_ALL]); + openMobileFileById(this.app, embedId, [Constants.CB_GET_ALL]); activeBlur(); hideKeyboardToolbar(); /// #else if (event.shiftKey) { openFileById({ + app: this.app, id: embedId, position: "bottom", action: [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL], @@ -1727,6 +1736,7 @@ export class WYSIWYG { }); } else if (event.altKey) { openFileById({ + app: this.app, id: embedId, position: "right", action: [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL], @@ -1734,6 +1744,7 @@ export class WYSIWYG { }); } else if (ctrlIsPressed) { openFileById({ + app: this.app, id: embedId, action: [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL], keepCursor: true, @@ -1741,6 +1752,7 @@ export class WYSIWYG { }); } else if (!protyle.disabled) { window.siyuan.blockPanels.push(new BlockPanel({ + app: this.app, targetElement: embedItemElement, nodeIds: [embedId], })); @@ -1750,7 +1762,7 @@ export class WYSIWYG { return; } - if (commonClick(event, protyle)) { + if (commonClick(this.app, event, protyle)) { return; } @@ -1815,7 +1827,7 @@ export class WYSIWYG { if (actionElement) { const type = actionElement.parentElement.parentElement.getAttribute("data-type"); if (type === "img" && !protyle.disabled) { - imgMenu(protyle, range, actionElement.parentElement.parentElement, { + imgMenu(this.app, protyle, range, actionElement.parentElement.parentElement, { clientX: event.clientX + 4, clientY: event.clientY }); diff --git a/app/src/protyle/wysiwyg/keydown.ts b/app/src/protyle/wysiwyg/keydown.ts index 04c7b6d15..d280bfb42 100644 --- a/app/src/protyle/wysiwyg/keydown.ts +++ b/app/src/protyle/wysiwyg/keydown.ts @@ -71,8 +71,9 @@ import {escapeHtml} from "../../util/escape"; import {insertHTML} from "../util/insertHTML"; import {quickMakeCard} from "../../card/makeCard"; import {removeSearchMark} from "../toolbar/util"; +import {App} from "../../index"; -export const keydown = (protyle: IProtyle, editorElement: HTMLElement) => { +export const keydown = (app: App, protyle: IProtyle, editorElement: HTMLElement) => { editorElement.addEventListener("keydown", (event: KeyboardEvent & { target: HTMLElement }) => { if (event.target.localName === "protyle-html") { event.stopPropagation(); @@ -441,6 +442,7 @@ export const keydown = (protyle: IProtyle, editorElement: HTMLElement) => { const ids = protyle.path.split("/"); if (ids.length > 2) { openFileById({ + app, id: ids[ids.length - 2], action: [Constants.CB_GET_FOCUS, Constants.CB_GET_SCROLL] }); @@ -530,7 +532,7 @@ export const keydown = (protyle: IProtyle, editorElement: HTMLElement) => { removeSearchMark(inlineElement); } if (types.includes("block-ref")) { - refMenu(protyle, inlineElement); + refMenu(app, protyle, inlineElement); return; } else if (types.includes("inline-memo")) { protyle.toolbar.showRender(protyle, inlineElement); @@ -539,10 +541,10 @@ export const keydown = (protyle: IProtyle, editorElement: HTMLElement) => { protyle.toolbar.showFileAnnotationRef(protyle, inlineElement); return; } else if (types.includes("a")) { - linkMenu(protyle, inlineElement); + linkMenu(app, protyle, inlineElement); return; } else if (types.includes("tag")) { - tagMenu(protyle, inlineElement); + tagMenu(app, protyle, inlineElement); return; } } @@ -952,7 +954,7 @@ export const keydown = (protyle: IProtyle, editorElement: HTMLElement) => { return true; } /// #if !MOBILE - if (commonHotkey(protyle, event)) { + if (commonHotkey(app, protyle, event)) { return true; } /// #endif @@ -1588,6 +1590,7 @@ export const keydown = (protyle: IProtyle, editorElement: HTMLElement) => { if (matchHotKey(window.siyuan.config.keymap.editor.general.openBy.custom, event)) { fetchPost("/api/block/checkBlockFold", {id}, (foldResponse) => { openFileById({ + app, id, action: foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL] : [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT], zoomIn: foldResponse.data @@ -1600,6 +1603,7 @@ export const keydown = (protyle: IProtyle, editorElement: HTMLElement) => { // 打开块引和编辑器中引用、反链、书签中点击事件需保持一致,都加载上下文 fetchPost("/api/block/checkBlockFold", {id}, (foldResponse) => { openFileById({ + app, id, action: foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL] : [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT], keepCursor: true, @@ -1612,6 +1616,7 @@ export const keydown = (protyle: IProtyle, editorElement: HTMLElement) => { } else if (matchHotKey(window.siyuan.config.keymap.editor.general.insertRight.custom, event)) { fetchPost("/api/block/checkBlockFold", {id}, (foldResponse) => { openFileById({ + app, id, position: "right", action: foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL] : [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT], @@ -1624,6 +1629,7 @@ export const keydown = (protyle: IProtyle, editorElement: HTMLElement) => { } else if (matchHotKey(window.siyuan.config.keymap.editor.general.insertBottom.custom, event)) { fetchPost("/api/block/checkBlockFold", {id}, (foldResponse) => { openFileById({ + app, id, position: "bottom", action: foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL] : [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT], @@ -1636,6 +1642,7 @@ export const keydown = (protyle: IProtyle, editorElement: HTMLElement) => { } else if (matchHotKey(window.siyuan.config.keymap.editor.general.refPopover.custom, event)) { // open popover window.siyuan.blockPanels.push(new BlockPanel({ + app, targetElement: refElement, nodeIds: [id], })); diff --git a/app/src/search/index.ts b/app/src/search/index.ts index dae84db03..f63d682f2 100644 --- a/app/src/search/index.ts +++ b/app/src/search/index.ts @@ -3,19 +3,21 @@ import {Tab} from "../layout/Tab"; import {Protyle} from "../protyle"; import {genSearch} from "./util"; import {setPanelFocus} from "../layout/util"; +import {App} from "../index"; export class Search extends Model { private element: HTMLElement; public config: ISearchOption; public edit: Protyle; - constructor(options: { tab: Tab, config: ISearchOption }) { + constructor(options: { tab: Tab, config: ISearchOption, app: App }) { super({ + app: options.app, id: options.tab.id, }); this.element = options.tab.panelElement as HTMLElement; this.config = options.config; - this.edit = genSearch(this.config, this.element); + this.edit = genSearch(options.app, this.config, this.element); this.element.addEventListener("click", () => { setPanelFocus(this.element.parentElement.parentElement); }); diff --git a/app/src/search/spread.ts b/app/src/search/spread.ts index 67371e848..bb069bbee 100644 --- a/app/src/search/spread.ts +++ b/app/src/search/spread.ts @@ -4,35 +4,42 @@ import {Dialog} from "../dialog"; import {fetchSyncPost} from "../util/fetch"; import {focusByRange} from "../protyle/util/selection"; import {genSearch} from "./util"; +import {App} from "../index"; -export const openSearch = async (hotkey: string, key?: string, notebookId?: string, searchPath?: string) => { +export const openSearch = async (options: { + app: App, + hotkey: string, + key?: string, + notebookId?: string, + searchPath?: string +}) => { const exitDialog = window.siyuan.dialogs.find((item) => { if (item.element.querySelector("#searchList")) { const lastKey = item.element.getAttribute("data-key"); const replaceHeaderElement = item.element.querySelectorAll(".search__header")[1]; - if (lastKey !== hotkey && hotkey === window.siyuan.config.keymap.general.replace.custom && replaceHeaderElement.classList.contains("fn__none")) { + if (lastKey !== options.hotkey && options.hotkey === window.siyuan.config.keymap.general.replace.custom && replaceHeaderElement.classList.contains("fn__none")) { replaceHeaderElement.classList.remove("fn__none"); - item.element.setAttribute("data-key", hotkey); + item.element.setAttribute("data-key", options.hotkey); return true; } const searchPathElement = item.element.querySelector("#searchPathInput"); - if (lastKey !== hotkey && hotkey === window.siyuan.config.keymap.general.globalSearch.custom) { + if (lastKey !== options.hotkey && options.hotkey === window.siyuan.config.keymap.general.globalSearch.custom) { if (searchPathElement.textContent !== "") { item.destroy(); return false; } else if (!replaceHeaderElement.classList.contains("fn__none")) { replaceHeaderElement.classList.add("fn__none"); - item.element.setAttribute("data-key", hotkey); + item.element.setAttribute("data-key", options.hotkey); return true; } } - if (lastKey !== hotkey && hotkey === window.siyuan.config.keymap.general.search.custom) { + if (lastKey !== options.hotkey && options.hotkey === window.siyuan.config.keymap.general.search.custom) { if (searchPathElement.textContent === "") { item.destroy(); return false; } else if (!replaceHeaderElement.classList.contains("fn__none")) { replaceHeaderElement.classList.add("fn__none"); - item.element.setAttribute("data-key", hotkey); + item.element.setAttribute("data-key", options.hotkey); return true; } } @@ -47,18 +54,18 @@ export const openSearch = async (hotkey: string, key?: string, notebookId?: stri const localData = window.siyuan.storage[Constants.LOCAL_SEARCHDATA]; let hPath = ""; let idPath: string[] = []; - if (notebookId) { - hPath = getNotebookName(notebookId); - idPath.push(notebookId); - if (searchPath && searchPath !== "/") { + if (options.notebookId) { + hPath = getNotebookName(options.notebookId); + idPath.push(options.notebookId); + if (options.searchPath && options.searchPath !== "/") { const response = await fetchSyncPost("/api/filetree/getHPathByPath", { - notebook: notebookId, - path: searchPath.endsWith(".sy") ? searchPath : searchPath + ".sy" + notebook: options.notebookId, + path: options.searchPath.endsWith(".sy") ? options.searchPath : options.searchPath + ".sy" }); hPath = pathPosix().join(hPath, response.data); - idPath[0] = pathPosix().join(idPath[0], searchPath); + idPath[0] = pathPosix().join(idPath[0], options.searchPath); } - } else if (window.siyuan.config.keymap.general.globalSearch.custom === hotkey) { + } else if (window.siyuan.config.keymap.general.globalSearch.custom === options.hotkey) { hPath = localData.hPath; idPath = localData.idPath; // 历史原因,2.5.2 之前为 string https://github.com/siyuan-note/siyuan/issues/6902 @@ -84,19 +91,19 @@ export const openSearch = async (hotkey: string, key?: string, notebookId?: stri } } }); - dialog.element.setAttribute("data-key", hotkey); - const edit = genSearch({ + dialog.element.setAttribute("data-key", options.hotkey); + const edit = genSearch( options.app, { removed: localData.removed, - k: key || localData.k, + k: options.key || localData.k, r: localData.r, - hasReplace: hotkey === window.siyuan.config.keymap.general.replace.custom, + hasReplace: options.hotkey === window.siyuan.config.keymap.general.replace.custom, method: localData.method, hPath, idPath, group: localData.group, sort: localData.sort, types: Object.assign({}, localData.types), - page: key ? 1 : localData.page + page: options.key ? 1 : localData.page }, dialog.element.querySelector(".b3-dialog__container").lastElementChild, () => { dialog.destroy({focus: "false"}); }); diff --git a/app/src/search/util.ts b/app/src/search/util.ts index fc2ccb8ae..9a56259b2 100644 --- a/app/src/search/util.ts +++ b/app/src/search/util.ts @@ -17,6 +17,7 @@ import {setStorageVal, updateHotkeyTip} from "../protyle/util/compatibility"; import {newFileByName} from "../util/newFile"; import {matchHotKey} from "../protyle/util/hotKey"; import {filterMenu, getKeyByLiElement, initCriteriaMenu, moreMenu, queryMenu} from "./menu"; +import {App} from "../index"; const saveKeyList = (type: "keys" | "replaceKeys", value: string) => { let list: string[] = window.siyuan.storage[Constants.LOCAL_SEARCHKEYS][type]; @@ -30,7 +31,7 @@ const saveKeyList = (type: "keys" | "replaceKeys", value: string) => { setStorageVal(Constants.LOCAL_SEARCHKEYS, window.siyuan.storage[Constants.LOCAL_SEARCHKEYS]); }; -export const openGlobalSearch = (text: string, replace: boolean) => { +export const openGlobalSearch = (app: App, text: string, replace: boolean) => { text = text.trim(); const searchModel = getAllModels().search.find((item) => { item.parent.parent.switchTab(item.parent.headElement); @@ -42,6 +43,7 @@ export const openGlobalSearch = (text: string, replace: boolean) => { } const localData = window.siyuan.storage[Constants.LOCAL_SEARCHDATA]; openFile({ + app, searchData: { k: text, r: "", @@ -60,7 +62,7 @@ export const openGlobalSearch = (text: string, replace: boolean) => { }; // closeCB 不存在为页签搜索 -export const genSearch = (config: ISearchOption, element: Element, closeCB?: () => void) => { +export const genSearch = (app: App, config: ISearchOption, element: Element, closeCB?: () => void) => { let methodText = window.siyuan.languages.keyword; if (config.method === 1) { methodText = window.siyuan.languages.querySyntax; @@ -181,7 +183,7 @@ export const genSearch = (config: ISearchOption, element: Element, closeCB?: () const historyElement = element.querySelector("#searchHistoryList"); const lineHeight = 30; - const edit = new Protyle(element.querySelector("#searchPreview") as HTMLElement, { + const edit = new Protyle(app, element.querySelector("#searchPreview") as HTMLElement, { blockId: "", render: { gutter: true, @@ -409,7 +411,7 @@ export const genSearch = (config: ISearchOption, element: Element, closeCB?: () } else if (target.id === "searchOpen") { config.k = searchInputElement.value; config.r = replaceInputElement.value; - openFile({searchData: config, position: "right"}); + openFile({app, searchData: config, position: "right"}); if (closeCB) { closeCB(); } @@ -599,7 +601,7 @@ export const genSearch = (config: ISearchOption, element: Element, closeCB?: () replaceInputElement.value = target.textContent; replaceHistoryElement.classList.add("fn__none"); } else if (type === "search-new") { - newFileByName(searchInputElement.value); + newFileByName(app, searchInputElement.value); } else if (type === "search-item") { if (event.detail === 1) { clickTimeout = window.setTimeout(() => { @@ -607,6 +609,7 @@ export const genSearch = (config: ISearchOption, element: Element, closeCB?: () const id = target.getAttribute("data-node-id"); fetchPost("/api/block/checkBlockFold", {id}, (foldResponse) => { openFileById({ + app, id, action: foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL] : [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT], zoomIn: foldResponse.data, @@ -639,6 +642,7 @@ export const genSearch = (config: ISearchOption, element: Element, closeCB?: () const id = target.getAttribute("data-node-id"); fetchPost("/api/block/checkBlockFold", {id}, (foldResponse) => { openFileById({ + app, id, action: foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL] : [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT], zoomIn: foldResponse.data @@ -685,7 +689,7 @@ export const genSearch = (config: ISearchOption, element: Element, closeCB?: () return; } if (searchInputElement.value && matchHotKey(window.siyuan.config.keymap.general.newFile.custom, event)) { - newFileByName(searchInputElement.value); + newFileByName(app, searchInputElement.value); event.preventDefault(); event.stopPropagation(); return; @@ -693,11 +697,12 @@ export const genSearch = (config: ISearchOption, element: Element, closeCB?: () const focusIsNew = currentList.getAttribute("data-type") === "search-new"; if (event.key === "Enter") { if (focusIsNew) { - newFileByName(searchInputElement.value); + newFileByName(app, searchInputElement.value); } else { const id = currentList.getAttribute("data-node-id"); fetchPost("/api/block/checkBlockFold", {id}, (foldResponse) => { openFileById({ + app, id, action: foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL] : [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT], zoomIn: foldResponse.data diff --git a/app/src/types/index.d.ts b/app/src/types/index.d.ts index e4c620b08..034895281 100644 --- a/app/src/types/index.d.ts +++ b/app/src/types/index.d.ts @@ -22,7 +22,7 @@ type TOperation = | "removeFlashcards" type TBazaarType = "templates" | "icons" | "widgets" | "themes" | "plugins" type TCardType = "doc" | "notebook" | "all" -type TEventBus = "ws-main" +type TEventBus = "ws-main" | "click-blockicon" declare module "blueimp-md5" @@ -316,6 +316,7 @@ declare interface IPluginDockTab { } declare interface IOpenFileOptions { + app: import("../index").App, searchData?: ISearchOption, // 搜索必填 // card 和自定义页签 必填 custom?: { diff --git a/app/src/util/backForward.ts b/app/src/util/backForward.ts index 282027ad5..f65d14187 100644 --- a/app/src/util/backForward.ts +++ b/app/src/util/backForward.ts @@ -13,11 +13,12 @@ import {zoomOut} from "../menus/protyle"; import {showMessage} from "../dialog/message"; import {saveScroll} from "../protyle/scroll/saveScroll"; import {getAllModels} from "../layout/getAll"; +import {App} from "../index"; let forwardStack: IBackStack[] = []; let previousIsBack = false; -const focusStack = async (stack: IBackStack) => { +const focusStack = async (app: App, stack: IBackStack) => { hideElements(["gutter", "toolbar", "hint", "util", "dialog"], stack.protyle); let blockElement: HTMLElement; if (!document.contains(stack.protyle.element)) { @@ -52,6 +53,7 @@ const focusStack = async (stack: IBackStack) => { scrollAttr.focusStart = stack.position.start; scrollAttr.focusEnd = stack.position.end; const editor = new Editor({ + app: app, tab, scrollAttr, blockId: stack.zoomId || stack.protyle.block.rootID, @@ -172,10 +174,10 @@ const focusStack = async (stack: IBackStack) => { } }; -export const goBack = async () => { +export const goBack = async (app: App) => { if (window.siyuan.backStack.length === 0) { if (forwardStack.length > 0) { - await focusStack(forwardStack[forwardStack.length - 1]); + await focusStack(app, forwardStack[forwardStack.length - 1]); } return; } @@ -187,7 +189,7 @@ export const goBack = async () => { } let stack = window.siyuan.backStack.pop(); while (stack) { - const isFocus = await focusStack(stack); + const isFocus = await focusStack(app, stack); if (isFocus) { forwardStack.push(stack); break; @@ -201,10 +203,10 @@ export const goBack = async () => { } }; -export const goForward = async () => { +export const goForward = async (app: App) => { if (forwardStack.length === 0) { if (window.siyuan.backStack.length > 0) { - await focusStack(window.siyuan.backStack[window.siyuan.backStack.length - 1]); + await focusStack(app, window.siyuan.backStack[window.siyuan.backStack.length - 1]); } return; } @@ -215,7 +217,7 @@ export const goForward = async () => { let stack = forwardStack.pop(); while (stack) { - const isFocus = await focusStack(stack); + const isFocus = await focusStack(app, stack); if (isFocus) { window.siyuan.backStack.push(stack); break; diff --git a/app/src/util/newFile.ts b/app/src/util/newFile.ts index c5280a757..99fd11969 100644 --- a/app/src/util/newFile.ts +++ b/app/src/util/newFile.ts @@ -12,6 +12,7 @@ import {Constants} from "../constants"; import {replaceFileName, validateName} from "../editor/rename"; import {hideElements} from "../protyle/ui/hideElements"; import {openMobileFileById} from "../mobile/editor"; +import {App} from "../index"; export const getNewFilePath = (useSavePath: boolean) => { let notebookId = ""; @@ -62,7 +63,7 @@ export const getNewFilePath = (useSavePath: boolean) => { return {notebookId, currentPath}; }; -export const newFile = (notebookId?: string, currentPath?: string, paths?: string[], useSavePath = false) => { +export const newFile = (app: App, notebookId?: string, currentPath?: string, paths?: string[], useSavePath = false) => { if (getOpenNotebookCount() === 0) { showMessage(window.siyuan.languages.newFileTip); return; @@ -81,9 +82,9 @@ export const newFile = (notebookId?: string, currentPath?: string, paths?: strin markdown: "" }, response => { /// #if !MOBILE - openFileById({id: response.data, action: [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT]}); + openFileById({app, id: response.data, action: [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT]}); /// #else - openMobileFileById(response.data, [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT]); + openMobileFileById(app, response.data, [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT]); /// #endif }); } else { @@ -97,9 +98,9 @@ export const newFile = (notebookId?: string, currentPath?: string, paths?: strin markdown: "" }, response => { /// #if !MOBILE - openFileById({id: response.data, action: [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT]}); + openFileById({app, id: response.data, action: [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT]}); /// #else - openMobileFileById(response.data, [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT]); + openMobileFileById(app, response.data, [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT]); /// #endif }); }); @@ -123,9 +124,9 @@ export const newFile = (notebookId?: string, currentPath?: string, paths?: strin sorts: paths }, () => { /// #if !MOBILE - openFileById({id, action: [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT]}); + openFileById({app, id, action: [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT]}); /// #else - openMobileFileById(id, [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT]); + openMobileFileById(app, id, [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT]); /// #endif }); } @@ -158,7 +159,7 @@ export const getSavePath = (pathString: string, notebookId: string, cb: (p: stri }); }; -export const newFileByName = (value: string) => { +export const newFileByName = (app: App, value: string) => { const newData = getNewFilePath(true); fetchPost("/api/filetree/getHPathByPath", { notebook: newData.notebookId, @@ -171,9 +172,9 @@ export const newFileByName = (value: string) => { }, response => { hideElements(["dialog"]); /// #if MOBILE - openMobileFileById(response.data, [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT]); + openMobileFileById(app, response.data, [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT]); /// #else - openFileById({id: response.data, action: [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT]}); + openFileById({app, id: response.data, action: [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT]}); /// #endif }); }); diff --git a/app/src/window/index.ts b/app/src/window/index.ts index 76123bcfd..11118a4c0 100644 --- a/app/src/window/index.ts +++ b/app/src/window/index.ts @@ -40,6 +40,7 @@ class App { ctrlIsPressed: false, altIsPressed: false, ws: new Model({ + app: this, id: genUUID(), type: "main", msgCallback: (data) => { @@ -49,7 +50,7 @@ class App { if (data) { switch (data.cmd) { case "syncMergeResult": - reloadSync(data.data); + reloadSync(this, data.data); break; case "progress": progressLoading(data); @@ -116,10 +117,10 @@ class App { } break; case "createdailynote": - openFileById({id: data.data.id, action: [Constants.CB_GET_FOCUS]}); + openFileById({app: this, id: data.data.id, action: [Constants.CB_GET_FOCUS]}); break; case "openFileById": - openFileById({id: data.data.id, action: [Constants.CB_GET_FOCUS]}); + openFileById({app: this, id: data.data.id, action: [Constants.CB_GET_FOCUS]}); break; } } @@ -131,11 +132,11 @@ class App { getLocalStorage(() => { fetchGet(`/appearance/langs/${window.siyuan.config.appearance.lang}.json?v=${Constants.SIYUAN_VERSION}`, (lauguages) => { window.siyuan.languages = lauguages; - window.siyuan.menus = new Menus(siyuanApp); + window.siyuan.menus = new Menus(this); fetchPost("/api/setting/getCloudUser", {}, userResponse => { window.siyuan.user = userResponse.data; - loadPlugins(siyuanApp); - init(siyuanApp); + loadPlugins(this); + init(this); setTitle(window.siyuan.languages.siyuanNote); initMessage(); }); @@ -143,12 +144,12 @@ class App { }); }); setNoteBook(); - initBlockPopover(); + initBlockPopover(this); promiseTransactions(); } } -const siyuanApp = new App(); +new App(); // 再次点击新窗口已打开的 PDF 时,需进行定位 window.newWindow = { diff --git a/app/src/window/init.ts b/app/src/window/init.ts index 611dc4747..af4483d6d 100644 --- a/app/src/window/init.ts +++ b/app/src/window/init.ts @@ -39,7 +39,7 @@ export const init = (app: App) => { window.siyuan.layout.centerLayout = window.siyuan.layout.layout; }); initStatus(true); - initWindow(); + initWindow(app); appearance.onSetappearance(window.siyuan.config.appearance); initAssets(); renderSnippet();