diff --git a/app/src/card/newCardTab.ts b/app/src/card/newCardTab.ts index e1fb95bac..246ee7505 100644 --- a/app/src/card/newCardTab.ts +++ b/app/src/card/newCardTab.ts @@ -1,42 +1,9 @@ -import {Wnd} from "../layout/Wnd"; -import {getInstanceById, getWndByLayout} from "../layout/util"; import {Tab} from "../layout/Tab"; import {Custom} from "../layout/dock/Custom"; import {bindCardEvent, genCardHTML} from "./openCard"; import {fetchPost} from "../util/fetch"; import {Protyle} from "../protyle"; -export const newCardTab = (options: { - cardType: TCardType, - id: string, - title?: string -}) => { - let wnd: Wnd; - const element = document.querySelector(".layout__wnd--active"); - if (element) { - wnd = getInstanceById(element.getAttribute("data-id")) as Wnd; - } - if (!wnd) { - wnd = getWndByLayout(window.siyuan.layout.centerLayout); - } - - const tab = new Tab({ - icon: "iconRiffCard", - title: window.siyuan.languages.spaceRepetition, - callback(tab) { - tab.addModel(newCardModel({ - tab, - data: { - cardType: options.cardType, - id: options.id, - title: options.title - } - })); - } - }); - wnd.split("lr").addTab(tab); -} - export const newCardModel = (options: { tab: Tab, data: { diff --git a/app/src/card/openCard.ts b/app/src/card/openCard.ts index c8d978cf6..1270708e9 100644 --- a/app/src/card/openCard.ts +++ b/app/src/card/openCard.ts @@ -11,7 +11,7 @@ import {fullscreen} from "../protyle/breadcrumb/action"; import {MenuItem} from "../menus/Menu"; import {escapeHtml} from "../util/escape"; /// #if !MOBILE -import {newCardTab} from "./newCardTab"; +import {openFile} from "../editor/util"; /// #endif import {getDisplayName, movePathTo} from "../util/pathName"; @@ -203,10 +203,13 @@ export const bindCardEvent = (options: { /// #if !MOBILE const sticktabElement = hasClosestByAttribute(target, "data-type", "sticktab"); if (sticktabElement) { - newCardTab({ - cardType: filterElement.getAttribute("data-cardtype") as TCardType, - id: filterElement.getAttribute("data-id"), - title: options.title + openFile({ + position: "right", + customData:{ + cardType: filterElement.getAttribute("data-cardtype") as TCardType, + id: filterElement.getAttribute("data-id"), + title: options.title + } }); if (options.dialog) { options.dialog.destroy(); diff --git a/app/src/dialog/index.ts b/app/src/dialog/index.ts index b740ca75e..6f1d1fcdb 100644 --- a/app/src/dialog/index.ts +++ b/app/src/dialog/index.ts @@ -2,7 +2,7 @@ import {genUUID} from "../util/genID"; import {isMobile} from "../util/functions"; export class Dialog { - private destroyCallback: () => void; + private destroyCallback: (options?:IObject) => void; public element: HTMLElement; private id: string; private disableClose: boolean; @@ -13,7 +13,7 @@ export class Dialog { content: string, width?: string height?: string, - destroyCallback?: () => void + destroyCallback?: (options?:IObject) => void disableClose?: boolean disableAnimation?: boolean }) { @@ -59,12 +59,12 @@ export class Dialog { window.siyuan.menus.menu.remove(); } - public destroy() { + public destroy(options?:IObject) { this.element.remove(); // https://github.com/siyuan-note/siyuan/issues/6783 window.siyuan.menus.menu.remove(); if (this.destroyCallback) { - this.destroyCallback(); + this.destroyCallback(options); } window.siyuan.dialogs.find((item, index) => { if (item.id === this.id) { diff --git a/app/src/editor/util.ts b/app/src/editor/util.ts index 0b85f2187..f981970f1 100644 --- a/app/src/editor/util.ts +++ b/app/src/editor/util.ts @@ -1,7 +1,7 @@ import {Tab} from "../layout/Tab"; import {Editor} from "./index"; import {Wnd} from "../layout/Wnd"; -import {getDockByType, getInstanceById, getWndByLayout, pdfIsLoading} from "../layout/util"; +import {getDockByType, getInstanceById, getWndByLayout, pdfIsLoading, resizeTabs, setPanelFocus} from "../layout/util"; import {getAllModels, getAllTabs} from "../layout/getAll"; import {highlightById, scrollCenter} from "../util/highlightById"; import {getDisplayName, pathPosix} from "../util/pathName"; @@ -24,8 +24,10 @@ import {setTitle} from "../dialog/processSystem"; import {zoomOut} from "../menus/protyle"; import {countBlockWord, countSelectWord} from "../layout/status"; import {showMessage} from "../dialog/message"; -import {getSearch} from "../util/functions"; +import {getSearch, objEquals} from "../util/functions"; import {resize} from "../protyle/util/resize"; +import {newCardModel} from "../card/newCardTab"; +import {Search} from "../search"; export const openFileById = async (options: { id: string, @@ -74,7 +76,7 @@ export const openAsset = (assetPath: string, page: number | string, position?: s }); }; -const openFile = (options: IOpenFileOptions) => { +export const openFile = (options: IOpenFileOptions) => { const allModels = getAllModels(); // 文档已打开 if (options.assetPath) { @@ -94,6 +96,32 @@ const openFile = (options: IOpenFileOptions) => { } return; } + } else if (options.customData) { + const custom = allModels.custom.find((item) => { + if (objEquals(item.data, options.customData)) { + if (!pdfIsLoading(item.parent.parent.element)) { + item.parent.parent.switchTab(item.parent.headElement); + item.parent.parent.showHeading(); + } + return true; + } + }); + if (custom) { + return; + } + } else if (options.searchData) { + const search = allModels.search.find((item) => { + if (objEquals(item.config, options.searchData)) { + if (!pdfIsLoading(item.parent.parent.element)) { + item.parent.parent.switchTab(item.parent.headElement); + item.parent.parent.showHeading(); + } + return true; + } + }); + if (search) { + return; + } } else if (!options.position) { let editor: Editor; let activeEditor: Editor; @@ -347,15 +375,39 @@ const newTab = (options: IOpenFileOptions) => { icon, title: getDisplayName(options.assetPath), callback(tab) { - const asset = new Asset({ + tab.addModel(new Asset({ tab, path: options.assetPath, page: options.page, - }); - tab.addModel(asset); + })); + setPanelFocus(tab.panelElement.parentElement.parentElement); } }); } + } else if (options.customData) { + tab = new Tab({ + icon: "iconRiffCard", + title: window.siyuan.languages.spaceRepetition, + callback(tab) { + tab.addModel(newCardModel({ + tab, + data: options.customData + })); + setPanelFocus(tab.panelElement.parentElement.parentElement); + } + }); + } else if (options.searchData) { + tab = new Tab({ + icon: "iconSearch", + title: window.siyuan.languages.search, + callback(tab) { + tab.addModel(new Search({ + tab, + config: options.searchData + })); + setPanelFocus(tab.panelElement.parentElement.parentElement); + } + }); } else { tab = new Tab({ title: getDisplayName(options.fileName, true, true), diff --git a/app/src/search/index.ts b/app/src/search/index.ts index 236c21071..dae84db03 100644 --- a/app/src/search/index.ts +++ b/app/src/search/index.ts @@ -2,6 +2,7 @@ import {Model} from "../layout/Model"; import {Tab} from "../layout/Tab"; import {Protyle} from "../protyle"; import {genSearch} from "./util"; +import {setPanelFocus} from "../layout/util"; export class Search extends Model { private element: HTMLElement; @@ -15,6 +16,9 @@ export class Search extends Model { this.element = options.tab.panelElement as HTMLElement; this.config = options.config; this.edit = genSearch(this.config, this.element); + this.element.addEventListener("click", () => { + setPanelFocus(this.element.parentElement.parentElement); + }); } public updateSearch(text: string, replace: boolean) { diff --git a/app/src/search/spread.ts b/app/src/search/spread.ts index d90521a13..67371e848 100644 --- a/app/src/search/spread.ts +++ b/app/src/search/spread.ts @@ -75,8 +75,8 @@ export const openSearch = async (hotkey: string, key?: string, notebookId?: stri content: "", width: "80vw", height: "90vh", - destroyCallback: () => { - if (range) { + destroyCallback(options: IObject) { + if (range && !options) { focusByRange(range); } if (edit) { @@ -98,7 +98,7 @@ export const openSearch = async (hotkey: string, key?: string, notebookId?: stri types: Object.assign({}, localData.types), page: key ? 1 : localData.page }, dialog.element.querySelector(".b3-dialog__container").lastElementChild, () => { - dialog.destroy(); + dialog.destroy({focus: "false"}); }); // 搜索面板层级需高于 201(.protyle-hint) 且小于205(.block__popover) dialog.element.firstElementChild.setAttribute("style", "z-index:202"); // https://github.com/siyuan-note/siyuan/issues/3515 diff --git a/app/src/search/util.ts b/app/src/search/util.ts index 033107b00..44993925d 100644 --- a/app/src/search/util.ts +++ b/app/src/search/util.ts @@ -1,12 +1,8 @@ import {getAllModels} from "../layout/getAll"; -import {getInstanceById, getWndByLayout, resizeTabs, setPanelFocus} from "../layout/util"; -import {Tab} from "../layout/Tab"; -import {Search} from "./index"; -import {Wnd} from "../layout/Wnd"; import {Constants} from "../constants"; import {escapeAttr, escapeGreat, escapeHtml} from "../util/escape"; import {fetchPost} from "../util/fetch"; -import {openFileById} from "../editor/util"; +import {openFile, openFileById} from "../editor/util"; import {showMessage} from "../dialog/message"; import {reloadProtyle} from "../protyle/util/reload"; import {MenuItem} from "../menus/Menu"; @@ -36,48 +32,31 @@ const saveKeyList = (type: "keys" | "replaceKeys", value: string) => { export const openGlobalSearch = (text: string, replace: boolean) => { text = text.trim(); - let wnd: Wnd; - const searchModel = getAllModels().search.find((item, index) => { - if (index === 0) { - wnd = item.parent.parent; - } - wnd.switchTab(item.parent.headElement); + const searchModel = getAllModels().search.find((item) => { + item.parent.parent.switchTab(item.parent.headElement); item.updateSearch(text, replace); return true; }); if (searchModel) { return; } - if (!wnd) { - wnd = getWndByLayout(window.siyuan.layout.centerLayout); - } - const tab = new Tab({ - icon: "iconSearch", - title: window.siyuan.languages.search, - callback(tab) { - const localData = window.siyuan.storage[Constants.LOCAL_SEARCHDATA]; - const asset = new Search({ - tab, - config: { - k: text, - r: "", - hasReplace: false, - method: localData.method, - hPath: "", - idPath: [], - group: localData.group, - sort: localData.sort, - types: Object.assign({}, localData.types), - removed: localData.removed, - page: 1 - } - }); - tab.addModel(asset); - resizeTabs(); - } + const localData = window.siyuan.storage[Constants.LOCAL_SEARCHDATA]; + openFile({ + searchData: { + k: text, + r: "", + hasReplace: false, + method: localData.method, + hPath: "", + idPath: [], + group: localData.group, + sort: localData.sort, + types: Object.assign({}, localData.types), + removed: localData.removed, + page: 1 + }, + position: "right" }); - wnd.split("lr").addTab(tab); - setPanelFocus(tab.panelElement); }; // closeCB 不存在为页签搜索 @@ -428,29 +407,9 @@ export const genSearch = (config: ISearchOption, element: Element, closeCB?: () event.preventDefault(); break; } else if (target.id === "searchOpen") { - let wnd: Wnd; - const element = document.querySelector(".layout__wnd--active"); - if (element) { - wnd = getInstanceById(element.getAttribute("data-id")) as Wnd; - } - if (!wnd) { - wnd = getWndByLayout(window.siyuan.layout.centerLayout); - } - const tab = new Tab({ - icon: "iconSearch", - title: window.siyuan.languages.search, - callback(tab) { - config.k = searchInputElement.value; - config.r = replaceInputElement.value; - const asset = new Search({ - tab, - config - }); - tab.addModel(asset); - resizeTabs(); - } - }); - wnd.split("lr").addTab(tab); + config.k = searchInputElement.value; + config.r = replaceInputElement.value; + openFile({searchData: config, position: "right"}); if (closeCB) { closeCB(); } diff --git a/app/src/types/index.d.ts b/app/src/types/index.d.ts index 65041a1aa..b5ec54165 100644 --- a/app/src/types/index.d.ts +++ b/app/src/types/index.d.ts @@ -280,6 +280,8 @@ declare interface IDockTab { } declare interface IOpenFileOptions { + searchData?: ISearchOption, // 搜索必填 + customData?: any, // card 必填 assetPath?: string, // asset 必填 fileName?: string, // file 必填 rootIcon?: string, // 文档图标 diff --git a/app/src/util/functions.ts b/app/src/util/functions.ts index e566541c4..158a83886 100644 --- a/app/src/util/functions.ts +++ b/app/src/util/functions.ts @@ -46,3 +46,13 @@ export const isFileAnnotation = (text: string) => { export const looseJsonParse = (text: string) => { return Function(`"use strict";return (${text})`)(); }; + +export const objEquals = (a: any, b: any): boolean => { + if (a === b) return true; + if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime(); + if (!a || !b || (typeof a !== 'object' && typeof b !== 'object')) return a === b; + if (a.prototype !== b.prototype) return false; + const keys = Object.keys(a); + if (keys.length !== Object.keys(b).length) return false; + return keys.every(k => objEquals(a[k], b[k])); +};