diff --git a/app/src/asset/index.ts b/app/src/asset/index.ts index 491e1e9d5..ebc9b5580 100644 --- a/app/src/asset/index.ts +++ b/app/src/asset/index.ts @@ -3,6 +3,7 @@ import {Tab} from "../layout/Tab"; import {Constants} from "../constants"; import {setPanelFocus} from "../layout/util"; /// #if !MOBILE +import {setModelsHash} from "../window/setHeader"; // @ts-ignore import {webViewerLoad} from "./pdf/viewer"; // @ts-ignore @@ -497,6 +498,7 @@ export class Asset extends Model { this.element, this.pdfPage, this.pdfId); this.element.setAttribute("data-loading", "true"); } + setModelsHash(); }, Constants.TIMEOUT_BLOCKLOAD); /// #endif } diff --git a/app/src/asset/pdf/app.js b/app/src/asset/pdf/app.js index 4acb38971..87259caaf 100644 --- a/app/src/asset/pdf/app.js +++ b/app/src/asset/pdf/app.js @@ -2467,20 +2467,7 @@ function webViewerResize() { } function webViewerHashchange(evt) { - const hash = evt.hash; - if (!hash) { - return; - } // NOTE - const pdfInstance = getPdfInstance(evt.source) - if (!pdfInstance) { - return - } - if (!pdfInstance.isInitialViewSet) { - pdfInstance.initialBookmark = hash; - } else if (!pdfInstance.pdfHistory?.popStateInProgress) { - pdfInstance.pdfLinkService.setHash(hash); - } } if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) { diff --git a/app/src/editor/index.ts b/app/src/editor/index.ts index cf7e263b3..dc5156f08 100644 --- a/app/src/editor/index.ts +++ b/app/src/editor/index.ts @@ -4,6 +4,9 @@ import {Model} from "../layout/Model"; import {disabledProtyle} from "../protyle/util/onGet"; import {setPadding} from "../protyle/ui/initUI"; import {getAllModels} from "../layout/getAll"; +/// #if !BROWSER +import {setModelsHash} from "../window/setHeader"; +/// #endif import {countBlockWord} from "../layout/status"; export class Editor extends Model { @@ -62,6 +65,9 @@ export class Editor extends Model { }); } countBlockWord([], editor.protyle.block.rootID); + /// #if !BROWSER + setModelsHash(); + /// #endif }, }); // 需在 after 回调之前,否则不会聚焦 https://github.com/siyuan-note/siyuan/issues/5303 diff --git a/app/src/editor/util.ts b/app/src/editor/util.ts index 9e8840fa9..9d337094e 100644 --- a/app/src/editor/util.ts +++ b/app/src/editor/util.ts @@ -14,7 +14,7 @@ import {focusBlock, focusByRange} from "../protyle/util/selection"; import {onGet} from "../protyle/util/onGet"; /// #if !BROWSER import {shell} from "electron"; -import {BrowserWindow} from "@electron/remote"; +import {BrowserWindow, getCurrentWindow} from "@electron/remote"; /// #endif import {pushBack} from "../util/backForward"; import {Asset} from "../asset"; @@ -158,31 +158,31 @@ export const openFile = (options: IOpenFileOptions) => { } } - let hasOpen = false; /// #if !BROWSER // https://github.com/siyuan-note/siyuan/issues/7491 - BrowserWindow.getAllWindows().find((item) => { - const json = getSearch("json", new URL(item.webContents.getURL()).search); - if (json) { - const jsonObj = JSON.parse(json); - if ((jsonObj.children.rootId && jsonObj.children.rootId === options.rootID) || - (jsonObj.children.path && jsonObj.children.path === options.assetPath)) { - item.focus(); - if (options.assetPath) { - item.webContents.executeJavaScript(`window.newWindow.positionPDF("${options.assetPath}", ${typeof options.page === "number" ? options.page : `"${options.page}"`})`); - } - hasOpen = true; - return true; + const currentWindowId = getCurrentWindow().id + const hasMatch = BrowserWindow.getAllWindows().find(item => { + if (item.id === currentWindowId) { + return; + } + const ids = decodeURIComponent(new URL(item.webContents.getURL()).hash.substring(1)).split(Constants.ZWSP); + if (ids.includes(options.rootID) || ids.includes(options.assetPath)) { + let execJS = `window.newWindow.switchTabById("${options.rootID || options.assetPath}");` + if (options.assetPath) { + execJS += `window.newWindow.positionPDF("${options.assetPath}", ${typeof options.page === "number" ? options.page : `"${options.page}"`})` } + item.focus(); + item.webContents.executeJavaScript(execJS); + if (options.afterOpen) { + options.afterOpen(); + } + return true; } - }); - /// #endif - if (hasOpen) { - if (options.afterOpen) { - options.afterOpen(); - } + }) + if (hasMatch) { return; } + /// #endif let wnd: Wnd = undefined; // 获取光标所在 tab diff --git a/app/src/layout/Wnd.ts b/app/src/layout/Wnd.ts index 63cafca06..18af80a13 100644 --- a/app/src/layout/Wnd.ts +++ b/app/src/layout/Wnd.ts @@ -17,7 +17,7 @@ import {Constants} from "../constants"; /// #if !BROWSER import {webFrame, ipcRenderer} from "electron"; import {getCurrentWindow} from "@electron/remote"; -import {setTabPosition} from "../window/setHeader"; +import {setModelsHash, setTabPosition} from "../window/setHeader"; /// #endif import {Search} from "../search"; import {showMessage} from "../dialog/message"; @@ -228,6 +228,7 @@ export class Wnd { ipcRenderer.send(Constants.SIYUAN_SEND_WINDOWS, {cmd: "closetab", data: tabData.id}); it.querySelector("li[data-clone='true']").remove(); wnd.switchTab(oldTab.headElement); + getCurrentWindow().focus(); } } /// #endif @@ -334,6 +335,7 @@ export class Wnd { JSONToCenter(tabData, this); oldTab = this.children[this.children.length - 1]; ipcRenderer.send(Constants.SIYUAN_SEND_WINDOWS, {cmd: "closetab", data: tabData.id}); + getCurrentWindow().focus(); } /// #endif if (!oldTab) { @@ -552,6 +554,7 @@ export class Wnd { } /// #if !BROWSER setTabPosition(); + setModelsHash(); /// #endif } @@ -689,9 +692,6 @@ export class Wnd { } }); } - /// #if !BROWSER - setTabPosition(); - /// #endif return; } if (item.headElement) { @@ -746,6 +746,7 @@ export class Wnd { /// #if !BROWSER webFrame.clearCache(); getCurrentWindow().webContents.session.clearCache(); + setTabPosition(); /// #endif }; diff --git a/app/src/layout/getAll.ts b/app/src/layout/getAll.ts index 6824443d1..191ac1c6e 100644 --- a/app/src/layout/getAll.ts +++ b/app/src/layout/getAll.ts @@ -64,12 +64,12 @@ export const getAllModels = () => { }; export const getAllTabs = () => { - const models: Tab[] = []; + const tabs: Tab[] = []; const getTabs = (layout: Layout) => { for (let i = 0; i < layout.children.length; i++) { const item = layout.children[i]; if (item instanceof Tab) { - models.push(item); + tabs.push(item); } else { getTabs(item as Layout); } @@ -79,7 +79,7 @@ export const getAllTabs = () => { if (window.siyuan.layout.centerLayout) { getTabs(window.siyuan.layout.centerLayout); } - return models; + return tabs; }; export const getAllDocks = () => { diff --git a/app/src/layout/util.ts b/app/src/layout/util.ts index 954ef20bc..46de19de6 100644 --- a/app/src/layout/util.ts +++ b/app/src/layout/util.ts @@ -237,7 +237,7 @@ const JSONToDock = (json: any) => { window.siyuan.layout.bottomDock = new Dock({position: "Bottom", data: json.bottom}); }; -export const JSONToCenter = (json: any, layout?: Layout | Wnd | Tab | Model, isStart = false) => { +export const JSONToCenter = (json: ILayoutJSON, layout?: Layout | Wnd | Tab | Model, isStart = false) => { let child: Layout | Wnd | Tab | Model; if (json.instance === "Layout") { if (!layout) { @@ -309,7 +309,7 @@ export const JSONToCenter = (json: any, layout?: Layout | Wnd | Tab | Model, isS tab: (layout as Tab), blockId: json.blockId, rootId: json.rootId, - type: json.type, + type: json.type as "pin" | "local", })); } else if (json.instance === "Bookmark") { (layout as Tab).addModel(new Bookmark((layout as Tab))); @@ -322,13 +322,13 @@ export const JSONToCenter = (json: any, layout?: Layout | Wnd | Tab | Model, isS tab: (layout as Tab), blockId: json.blockId, rootId: json.rootId, - type: json.type + type: json.type as "pin" | "local" | "global", })); } else if (json.instance === "Outline") { (layout as Tab).addModel(new Outline({ tab: (layout as Tab), blockId: json.blockId, - type: json.type + type: json.type as "pin" | "local", })); } else if (json.instance === "Tag") { (layout as Tab).addModel(new Tag((layout as Tab))); @@ -347,7 +347,7 @@ export const JSONToCenter = (json: any, layout?: Layout | Wnd | Tab | Model, isS if (Array.isArray(json.children)) { json.children.forEach((item: any, index: number) => { JSONToCenter(item, layout ? child : window.siyuan.layout.layout, isStart); - if (item.instance === "Tab" && index === json.children.length - 1) { + if (item.instance === "Tab" && index === (json.children as ILayoutJSON[]).length - 1) { const activeTabElement = (child as Wnd).headersElement.querySelector('[data-init-active="true"]') as HTMLElement; if (activeTabElement) { if (window.siyuan.config.fileTree.closeTabsOnStart && isStart && @@ -832,7 +832,7 @@ export const newCenterEmptyTab = () => { callback(tab: Tab) { tab.panelElement.addEventListener("click", (event) => { let target = event.target as HTMLElement; - while (target && !target.isEqualNode( tab.panelElement)) { + while (target && !target.isEqualNode(tab.panelElement)) { if (target.id === "editorEmptySearch") { openSearch(window.siyuan.config.keymap.general.globalSearch.custom); event.stopPropagation(); @@ -852,22 +852,22 @@ export const newCenterEmptyTab = () => { event.stopPropagation(); event.preventDefault(); break; - }else if (target.id === "editorEmptyHistory") { + } else if (target.id === "editorEmptyHistory") { openHistory(); event.stopPropagation(); event.preventDefault(); break; - }else if (target.id === "editorEmptyFile") { + } else if (target.id === "editorEmptyFile") { newFile(undefined, undefined, undefined, true); event.stopPropagation(); event.preventDefault(); break; - }else if (target.id === "editorEmptyNewNotebook") { + } else if (target.id === "editorEmptyNewNotebook") { newNotebook(); event.stopPropagation(); event.preventDefault(); break; - }else if (target.id === "editorEmptyHelp") { + } else if (target.id === "editorEmptyHelp") { mountHelp(); event.stopPropagation(); event.preventDefault(); diff --git a/app/src/types/index.d.ts b/app/src/types/index.d.ts index ff687c14b..0427cf0eb 100644 --- a/app/src/types/index.d.ts +++ b/app/src/types/index.d.ts @@ -50,6 +50,7 @@ interface Window { newWindow: { positionPDF(pathStr: string, page: string | number): void + switchTabById(id: string): void } Protyle: import("../protyle/method").default @@ -271,6 +272,29 @@ interface IObject { [key: string]: string; } +declare interface ILayoutJSON extends ILayoutOptions { + instance?: string, + width?: string, + height?: string, + title?: string, + lang?: string + docIcon?: string + page?: string + path?: string + blockId?: string + icon?: string + rootId?: string + active?: boolean + pin?: boolean + data?: { + cardType: TCardType, + id: string, + title?: string + } + config?: ISearchOption + children?: ILayoutJSON[] | ILayoutJSON +} + declare interface IDockTab { type: TDockType; size: { width: number, height: number } diff --git a/app/src/window/global/function.ts b/app/src/window/global/function.ts new file mode 100644 index 000000000..79feec9f9 --- /dev/null +++ b/app/src/window/global/function.ts @@ -0,0 +1,37 @@ +import {getAllTabs} from "../../layout/getAll"; +import {Asset} from "../../asset"; +import {Editor} from "../../editor"; + +export const positionPDF = (pathStr: string, page: string | number) => { + getAllTabs().forEach((tab) => { + if (tab.model instanceof Asset && tab.model.pdfObject && tab.model.path === pathStr) { + tab.parent.switchTab(tab.headElement); + tab.model.goToPage(page); + } + }); +}; + +export const switchTabById = (id: string) => { + getAllTabs().find((tab) => { + if (!tab.model) { + const initTab = tab.headElement.getAttribute("data-initdata"); + if (initTab) { + const initTabData = JSON.parse(initTab); + if (initTabData.rootId === id) { + tab.parent.switchTab(tab.headElement); + return true; + } + } + } else if (tab.model instanceof Editor) { + if (tab.model.editor.protyle.block.rootID === id) { + tab.parent.switchTab(tab.headElement); + return true + } + } else if (tab.model instanceof Asset) { + if (tab.model.path === id) { + tab.parent.switchTab(tab.headElement); + return true + } + } + }); +} diff --git a/app/src/window/global/positionPDF.ts b/app/src/window/global/positionPDF.ts deleted file mode 100644 index f8c0595ac..000000000 --- a/app/src/window/global/positionPDF.ts +++ /dev/null @@ -1,11 +0,0 @@ -import {getAllTabs} from "../../layout/getAll"; -import {Asset} from "../../asset"; - -export const positionPDF = (pathStr: string, page: string | number) => { - getAllTabs().forEach((tab) => { - if (tab.model instanceof Asset && tab.model.pdfObject && tab.model.path === pathStr) { - tab.parent.switchTab(tab.headElement); - tab.model.goToPage(page); - } - }); -}; diff --git a/app/src/window/index.ts b/app/src/window/index.ts index ee0e22c94..a289d4a6e 100644 --- a/app/src/window/index.ts +++ b/app/src/window/index.ts @@ -20,7 +20,7 @@ import {initMessage} from "../dialog/message"; import {getAllTabs} from "../layout/getAll"; import {getLocalStorage} from "../protyle/util/compatibility"; import {init} from "../window/init"; -import {positionPDF} from "./global/positionPDF"; +import {positionPDF, switchTabById} from "./global/function"; class App { constructor() { @@ -145,5 +145,6 @@ new App(); // 再次点击新窗口已打开的 PDF 时,需进行定位 window.newWindow = { - positionPDF: positionPDF + positionPDF: positionPDF, + switchTabById: switchTabById }; diff --git a/app/src/window/init.ts b/app/src/window/init.ts index 1506a6f38..e11b81da8 100644 --- a/app/src/window/init.ts +++ b/app/src/window/init.ts @@ -36,7 +36,6 @@ export const init = () => { }] }); window.siyuan.layout.centerLayout = window.siyuan.layout.layout; - }); initStatus(true); initWindow(); diff --git a/app/src/window/setHeader.ts b/app/src/window/setHeader.ts index 3ed50e502..e29a5652b 100644 --- a/app/src/window/setHeader.ts +++ b/app/src/window/setHeader.ts @@ -2,6 +2,10 @@ import {isWindow} from "../util/functions"; import {Wnd} from "../layout/Wnd"; import {getCurrentWindow} from "@electron/remote"; import {Layout} from "../layout"; +import {getAllTabs} from "../layout/getAll"; +import {Editor} from "../editor"; +import {Asset} from "../asset"; +import {Constants} from "../constants"; const getAllWnds = (layout: Layout, wnds: Wnd[]) => { for (let i = 0; i < layout.children.length; i++) { @@ -50,3 +54,25 @@ export const setTabPosition = () => { } }); }; + + +export const setModelsHash = () => { + if (!isWindow()) { + return + } + let hash = "" + getAllTabs().forEach(tab => { + if (!tab.model) { + const initTab = tab.headElement.getAttribute("data-initdata"); + if (initTab) { + const initTabData = JSON.parse(initTab); + hash += initTabData.rootId + Constants.ZWSP + } + } else if (tab.model instanceof Editor) { + hash += tab.model.editor.protyle.block.rootID + Constants.ZWSP + } else if (tab.model instanceof Asset) { + hash += tab.model.path + Constants.ZWSP + } + }) + window.location.hash = hash +}