diff --git a/app/src/boot/globalEvent/keydown.ts b/app/src/boot/globalEvent/keydown.ts index 371f3823a..36639f4ee 100644 --- a/app/src/boot/globalEvent/keydown.ts +++ b/app/src/boot/globalEvent/keydown.ts @@ -187,11 +187,18 @@ const editKeydown = (app: App, event: KeyboardEvent) => { } if (range) { window.siyuan.dialogs.find(item => { - if (item.editor && item.editor.protyle.element.contains(range.startContainer)) { - protyle = item.editor.protyle; - // https://github.com/siyuan-note/siyuan/issues/9384 - isFileFocus = false; - return true; + if (item.editors) { + Object.keys(item.editors).find(key => { + if (item.editors[key].protyle.element.contains(range.startContainer)) { + protyle = item.editors[key].protyle; + // https://github.com/siyuan-note/siyuan/issues/9384 + isFileFocus = false; + return true; + } + }); + if (protyle) { + return true; + } } }); } @@ -200,7 +207,11 @@ const editKeydown = (app: App, event: KeyboardEvent) => { if (activeTab.model instanceof Editor) { protyle = activeTab.model.editor.protyle; } else if (activeTab.model instanceof Search) { - protyle = activeTab.model.edit.protyle; + if (activeTab.model.element.querySelector("#searchUnRefPanel").classList.contains("fn__none")) { + protyle = activeTab.model.editors.edit.protyle; + } else { + protyle = activeTab.model.editors.unRefEdit.protyle; + } } else if (activeTab.model instanceof Custom && activeTab.model.data?.editor instanceof Protyle) { protyle = activeTab.model.data.editor.protyle; } else { diff --git a/app/src/boot/globalEvent/searchKeydown.ts b/app/src/boot/globalEvent/searchKeydown.ts index e9706cb06..cb2595360 100644 --- a/app/src/boot/globalEvent/searchKeydown.ts +++ b/app/src/boot/globalEvent/searchKeydown.ts @@ -16,6 +16,7 @@ import {assetInputEvent, renderPreview, toggleAssetHistory} from "../../search/a import {initSearchMenu} from "../../menus/search"; import {writeText} from "../../protyle/util/compatibility"; import {checkFold} from "../../util/noRelyPCFunction"; +import {getUnRefList} from "../../search/unRef"; export const searchKeydown = (app: App, event: KeyboardEvent) => { if (getSelection().rangeCount === 0) { @@ -28,13 +29,15 @@ export const searchKeydown = (app: App, event: KeyboardEvent) => { let element: HTMLElement; let dialog: Dialog; let edit; + let unRefEdit; let config: ISearchOption; window.siyuan.dialogs.find((item) => { if (item.element.contains(range.startContainer) && item.element.querySelector("#searchList")) { element = item.element.querySelector(".b3-dialog__body"); dialog = item; config = dialog.data; - edit = dialog.editor; + edit = dialog.editors.edit; + unRefEdit = dialog.editors.unRefEdit; return true; } }); @@ -42,8 +45,9 @@ export const searchKeydown = (app: App, event: KeyboardEvent) => { getAllModels().search.find((item) => { if (item.element.contains(range.startContainer)) { element = item.element; - edit = item.edit; + edit = item.editors.edit; config = item.config; + unRefEdit = item.editors.unRefEdit; return true; } }); @@ -52,10 +56,11 @@ export const searchKeydown = (app: App, event: KeyboardEvent) => { return false; } const assetsElement = element.querySelector("#searchAssets"); - const isAsset = !assetsElement.classList.contains("fn__none"); - const listElement = isAsset ? assetsElement.querySelector("#searchAssetList") : element.querySelector("#searchList"); + const unRefElement = element.querySelector("#searchUnRefPanel"); + const searchType = assetsElement.classList.contains("fn__none") ? (unRefElement.classList.contains("fn__none") ? "doc" : "unRef") : "asset"; + const listElement = searchType === "asset" ? assetsElement.querySelector("#searchAssetList") : (searchType === "doc" ? element.querySelector("#searchList") : unRefElement.querySelector("#searchUnRefList")); const searchInputElement = element.querySelector("#searchInput") as HTMLInputElement; - if (!isAsset && matchHotKey(window.siyuan.config.keymap.general.newFile.custom, event)) { + if (searchType === "doc" && matchHotKey(window.siyuan.config.keymap.general.newFile.custom, event)) { if (config.method === 0) { newFileByName(app, searchInputElement.value); } @@ -63,9 +68,9 @@ export const searchKeydown = (app: App, event: KeyboardEvent) => { } const targetId = (event.target as HTMLElement).id; if (event.key === "ArrowDown" && event.altKey) { - if (isAsset) { + if (searchType === "asset") { toggleAssetHistory(assetsElement); - } else { + } else if (searchType === "doc") { if (targetId === "replaceInput") { toggleReplaceHistory(element); } else { @@ -90,7 +95,7 @@ export const searchKeydown = (app: App, event: KeyboardEvent) => { } return false; } - if (!isAsset) { + if (searchType !== "asset") { if (matchHotKey(window.siyuan.config.keymap.editor.general.insertRight.custom, event)) { const id = currentList.getAttribute("data-node-id"); checkFold(id, (zoomIn, action) => { @@ -151,7 +156,7 @@ export const searchKeydown = (app: App, event: KeyboardEvent) => { } if (Constants.KEYCODELIST[event.keyCode] === "PageUp") { - if (isAsset) { + if (searchType === "asset") { if (!assetsElement.querySelector('[data-type="assetPrevious"]').getAttribute("disabled")) { let currentPage = parseInt(assetsElement.querySelector("#searchAssetResult .fn__flex-center").textContent.split("/")[0]); if (currentPage > 1) { @@ -159,18 +164,26 @@ export const searchKeydown = (app: App, event: KeyboardEvent) => { assetInputEvent(assetsElement, assetLocal, currentPage); } } - } else { + } else if (searchType === "doc") { if (!element.querySelector('[data-type="previous"]').getAttribute("disabled")) { if (config.page > 1) { config.page--; inputEvent(element, config, edit); } } + } else if (searchType === "unRef") { + if (!element.querySelector('[data-type="unRefPrevious"]').getAttribute("disabled")) { + let currentPage = parseInt(unRefElement.querySelector("#searchUnRefResult").textContent); + if (currentPage > 1) { + currentPage--; + getUnRefList(unRefElement, unRefEdit, currentPage); + } + } } return true; } if (Constants.KEYCODELIST[event.keyCode] === "PageDown") { - if (isAsset) { + if (searchType === "asset") { if (!assetsElement.querySelector('[data-type="assetNext"]').getAttribute("disabled")) { const assetPages = assetsElement.querySelector("#searchAssetResult .fn__flex-center").textContent.split("/"); let currentPage = parseInt(assetPages[0]); @@ -179,7 +192,7 @@ export const searchKeydown = (app: App, event: KeyboardEvent) => { assetInputEvent(assetsElement, assetLocal, currentPage); } } - } else { + } else if (searchType === "doc") { const nextElement = element.querySelector('[data-type="next"]'); if (!nextElement.getAttribute("disabled")) { if (config.page < parseInt(nextElement.parentElement.querySelector("#searchResult").getAttribute("data-pagecount"))) { @@ -187,6 +200,14 @@ export const searchKeydown = (app: App, event: KeyboardEvent) => { inputEvent(element, config, edit); } } + } else if (searchType === "unRef") { + if (!element.querySelector('[data-type="unRefNext"]').getAttribute("disabled")) { + let currentPage = parseInt(unRefElement.querySelector("#searchUnRefResult").textContent); + if (currentPage < parseInt(unRefElement.querySelector("#searchUnRefResult").textContent.split("/")[1])) { + currentPage++; + getUnRefList(unRefElement, unRefEdit, currentPage); + } + } } return true; } @@ -194,7 +215,7 @@ export const searchKeydown = (app: App, event: KeyboardEvent) => { return false; } if (event.key === "Enter") { - if (!isAsset) { + if (searchType !== "asset") { if (targetId === "replaceInput") { replace(element, config, edit, false); } else { @@ -223,7 +244,7 @@ export const searchKeydown = (app: App, event: KeyboardEvent) => { if (event.key === "ArrowDown") { currentList.classList.remove("b3-list-item--focus"); if (!currentList.nextElementSibling) { - if (config.group === 1 && !isAsset) { + if (config.group === 1 && searchType === "doc") { if (currentList.parentElement.nextElementSibling) { currentList.parentElement.nextElementSibling.nextElementSibling.firstElementChild.classList.add("b3-list-item--focus"); } else { @@ -240,22 +261,27 @@ export const searchKeydown = (app: App, event: KeyboardEvent) => { listElement.scrollTop > currentList.offsetTop) { listElement.scrollTop = currentList.offsetTop - listElement.clientHeight + lineHeight; } - if (isAsset) { + if (searchType === "asset") { renderPreview(assetPreviewElement, currentList.dataset.id, searchInputElement.value, assetLocal.method); - } else { + } else if (searchType === "doc") { getArticle({ id: currentList.getAttribute("data-node-id"), config, value: searchInputElement.value, edit, }); + } else { + getArticle({ + id: currentList.getAttribute("data-node-id"), + edit: unRefEdit, + }); } return true; } if (event.key === "ArrowUp") { currentList.classList.remove("b3-list-item--focus"); if (!currentList.previousElementSibling) { - if (config.group === 1 && !isAsset) { + if (config.group === 1 && searchType === "doc") { if (currentList.parentElement.previousElementSibling.previousElementSibling) { currentList.parentElement.previousElementSibling.previousElementSibling.lastElementChild.classList.add("b3-list-item--focus"); } else { @@ -272,15 +298,20 @@ export const searchKeydown = (app: App, event: KeyboardEvent) => { listElement.scrollTop > currentList.offsetTop - lineHeight * 2) { listElement.scrollTop = currentList.offsetTop - lineHeight * 2; } - if (isAsset) { + if (searchType === "asset") { renderPreview(assetPreviewElement, currentList.dataset.id, searchInputElement.value, assetLocal.method); - } else { + } else if (searchType === "doc") { getArticle({ id: currentList.getAttribute("data-node-id"), config, value: searchInputElement.value, edit, }); + } else if (searchType === "unRef") { + getArticle({ + id: currentList.getAttribute("data-node-id"), + edit: unRefEdit, + }); } return true; } diff --git a/app/src/card/openCard.ts b/app/src/card/openCard.ts index 2c24e3337..bda8f8026 100644 --- a/app/src/card/openCard.ts +++ b/app/src/card/openCard.ts @@ -509,7 +509,9 @@ export const openCardByData = async (app: App, cardsData: ICardData, cardType: T cardType, dialog }); - dialog.editor = editor; + dialog.editors = { + card: editor + }; /// #if !MOBILE const focusElement = dialog.element.querySelector(".block__icons button.block__icon") as HTMLElement; focusElement.focus(); diff --git a/app/src/card/viewCards.ts b/app/src/card/viewCards.ts index 712758f79..b72717cb6 100644 --- a/app/src/card/viewCards.ts +++ b/app/src/card/viewCards.ts @@ -70,7 +70,9 @@ export const viewCards = (app: App, deckID: string, title: string, deckType: "Tr if (window.siyuan.mobile) { window.siyuan.mobile.popEditor = edit; } - dialog.editor = edit; + dialog.editors = { + card: edit + }; getArticle(edit, dialog.element.querySelector(".b3-list-item--focus")?.getAttribute("data-id")); } const previousElement = dialog.element.querySelector('[data-type="previous"]'); diff --git a/app/src/dialog/index.ts b/app/src/dialog/index.ts index 421b71091..1366e5eca 100644 --- a/app/src/dialog/index.ts +++ b/app/src/dialog/index.ts @@ -12,7 +12,7 @@ export class Dialog { public element: HTMLElement; private id: string; private disableClose: boolean; - public editor: Protyle; + public editors: { [key: string]: Protyle }; public data: any; constructor(options: { diff --git a/app/src/layout/Wnd.ts b/app/src/layout/Wnd.ts index bcd74ad31..e03d5d9e7 100644 --- a/app/src/layout/Wnd.ts +++ b/app/src/layout/Wnd.ts @@ -681,9 +681,8 @@ export class Wnd { return; } if (model instanceof Search) { - if (model.edit) { - model.edit.destroy(); - } + model.editors.edit.destroy(); + model.editors.unRefEdit.destroy(); return; } if (model instanceof Asset) { diff --git a/app/src/layout/getAll.ts b/app/src/layout/getAll.ts index b110bacbe..21e3576f3 100644 --- a/app/src/layout/getAll.ts +++ b/app/src/layout/getAll.ts @@ -20,7 +20,8 @@ export const getAllEditor = () => { editors.push(item.editor); }); models.search.forEach(item => { - editors.push(item.edit); + editors.push(item.editors.edit); + editors.push(item.editors.unRefEdit); }); models.custom.forEach(item => { if (item.data?.editor instanceof Protyle) { @@ -33,8 +34,10 @@ export const getAllEditor = () => { }); }); window.siyuan.dialogs.forEach(item => { - if (item.editor) { - editors.push(item.editor); + if (item.editors) { + Object.keys(item.editors).forEach(key => { + editors.push(item.editors[key]); + }); } }); window.siyuan.blockPanels.forEach(item => { diff --git a/app/src/layout/tabUtil.ts b/app/src/layout/tabUtil.ts index 48a4872b5..97b5e64e7 100644 --- a/app/src/layout/tabUtil.ts +++ b/app/src/layout/tabUtil.ts @@ -108,7 +108,11 @@ export const resizeTabs = (isSaveLayout = true) => { }); }); models.search.forEach(item => { - item.edit.resize(); + if (item.element.querySelector("#searchUnRefPanel").classList.contains("fn__none")) { + item.editors.edit.resize(); + } else { + item.editors.unRefEdit.resize(); + } }); models.custom.forEach(item => { if (item.resize) { diff --git a/app/src/search/index.ts b/app/src/search/index.ts index d75ef50b6..60dd59ffe 100644 --- a/app/src/search/index.ts +++ b/app/src/search/index.ts @@ -8,7 +8,7 @@ import {App} from "../index"; export class Search extends Model { public element: HTMLElement; public config: ISearchOption; - public edit: Protyle; + public editors: { edit: Protyle, unRefEdit: Protyle }; constructor(options: { tab: Tab, config: ISearchOption, app: App }) { super({ @@ -20,7 +20,7 @@ export class Search extends Model { } this.element = options.tab.panelElement as HTMLElement; this.config = options.config; - this.edit = genSearch(options.app, this.config, this.element); + this.editors = 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 3cf19c158..6979ea9b2 100644 --- a/app/src/search/spread.ts +++ b/app/src/search/spread.ts @@ -88,13 +88,16 @@ export const openSearch = async (options: { if (range && !options) { focusByRange(range); } - if (edit) { - edit.destroy(); - } + dialog.editors.edit.destroy(); + dialog.editors.unRefEdit.destroy(); }, resizeCallback(type: string) { - if (type !== "d" && type !== "t" && edit) { - edit.resize(); + if (type !== "d" && type !== "t") { + if (dialog.element.querySelector("#searchUnRefPanel").classList.contains("fn__none")) { + dialog.editors.edit.resize(); + } else { + dialog.editors.unRefEdit.resize(); + } } } }); @@ -113,9 +116,8 @@ export const openSearch = async (options: { replaceTypes: Object.assign({}, localData.replaceTypes), page: options.key ? 1 : localData.page }; - const edit = genSearch(options.app, config, dialog.element.querySelector(".b3-dialog__body"), () => { + dialog.editors = genSearch(options.app, config, dialog.element.querySelector(".b3-dialog__body"), () => { dialog.destroy({focus: "false"}); }); - dialog.editor = edit; dialog.data = config; }; diff --git a/app/src/search/unRef.ts b/app/src/search/unRef.ts index 616a278c9..dc29ba8e3 100644 --- a/app/src/search/unRef.ts +++ b/app/src/search/unRef.ts @@ -10,65 +10,30 @@ import {getIconByType} from "../editor/getIcon"; import {unicode2Emoji} from "../emoji"; import {getDisplayName, getNotebookName} from "../util/pathName"; import {Protyle} from "../protyle"; -import {App} from "../index"; import {resize} from "../protyle/util/resize"; import {Menu} from "../plugin/Menu"; -export const openSearchUnRef = (app: App, element: Element, isStick: boolean) => { +export const openSearchUnRef = (element: Element, editor: Protyle) => { window.siyuan.menus.menu.remove(); element.previousElementSibling.previousElementSibling.classList.add("fn__none"); element.classList.remove("fn__none"); - if (element.innerHTML) { + if (element.querySelector("#searchUnRefResult").innerHTML) { return; } - const localSearch = window.siyuan.storage[Constants.LOCAL_SEARCHUNREF] as ISearchAssetOption; element.parentElement.querySelector(".fn__loading--top").classList.remove("fn__none"); - element.innerHTML = `
- - - - - - - - - - - - - - -
-
-
-
-
-
-
- ↑/↓/PageUp/PageDown ${window.siyuan.languages.searchTip1} - Enter/Double Click ${window.siyuan.languages.searchTip2} - ${updateHotkeyTip(window.siyuan.config.keymap.editor.general.insertRight.custom)}/${updateHotkeyTip("⌥Click")} ${window.siyuan.languages.searchTip4} - Esc ${window.siyuan.languages.searchTip5} -
`; if (element.querySelector("#searchUnRefList").innerHTML !== "") { return; } - const edit = new Protyle(app, element.querySelector("#searchUnRefPreview") as HTMLElement, { - blockId: "", - render: { - gutter: true, - breadcrumbDocName: true - }, - }); + const localSearch = window.siyuan.storage[Constants.LOCAL_SEARCHUNREF] as ISearchAssetOption; if (localSearch.layout === 1) { if (localSearch.col) { - edit.protyle.element.style.width = localSearch.col; - edit.protyle.element.classList.remove("fn__flex-1"); + editor.protyle.element.style.width = localSearch.col; + editor.protyle.element.classList.remove("fn__flex-1"); } } else { if (localSearch.row) { - edit.protyle.element.classList.remove("fn__flex-1"); - edit.protyle.element.style.height = localSearch.row; + editor.protyle.element.classList.remove("fn__flex-1"); + editor.protyle.element.style.height = localSearch.row; } } @@ -105,12 +70,11 @@ export const openSearchUnRef = (app: App, element: Element, isStick: boolean) => window.siyuan.storage[Constants.LOCAL_SEARCHUNREF][direction === "lr" ? "col" : "row"] = nextElement[direction === "lr" ? "clientWidth" : "clientHeight"] + "px"; setStorageVal(Constants.LOCAL_SEARCHUNREF, window.siyuan.storage[Constants.LOCAL_SEARCHUNREF]); if (direction === "lr") { - resize(edit.protyle); + resize(editor.protyle); } }; }); - getUnRefList(element, edit); - return edit; + getUnRefList(element, editor); }; export const getUnRefList = (element: Element, edit: Protyle, page = 1) => { diff --git a/app/src/search/util.ts b/app/src/search/util.ts index f359d7192..a5430654c 100644 --- a/app/src/search/util.ts +++ b/app/src/search/util.ts @@ -253,6 +253,7 @@ export const genSearch = (app: App, config: ISearchOption, element: Element, clo } }); const data = window.siyuan.storage[Constants.LOCAL_SEARCHKEYS]; + const unRefLocal = window.siyuan.storage[Constants.LOCAL_SEARCHUNREF]; element.innerHTML = `
@@ -362,7 +363,35 @@ export const genSearch = (app: App, config: ISearchOption, element: Element, clo
-
+
+
+ + + + + + + + + + + + + + +
+
+
+
+
+
+
+ ↑/↓/PageUp/PageDown ${window.siyuan.languages.searchTip1} + Enter/Double Click ${window.siyuan.languages.searchTip2} + ${updateHotkeyTip(window.siyuan.config.keymap.editor.general.insertRight.custom)}/${updateHotkeyTip("⌥Click")} ${window.siyuan.languages.searchTip4} + Esc ${window.siyuan.languages.searchTip5} +
+
`; const criteriaData: ISearchOption[] = []; @@ -378,6 +407,13 @@ export const genSearch = (app: App, config: ISearchOption, element: Element, clo breadcrumbDocName: true }, }); + const unRefEdit = new Protyle(app, element.querySelector("#searchUnRefPreview") as HTMLElement, { + blockId: "", + render: { + gutter: true, + breadcrumbDocName: true + }, + }); if (closeCB) { if (data.layout === 1) { if (data.col) { @@ -451,7 +487,6 @@ export const genSearch = (app: App, config: ISearchOption, element: Element, clo const localSearch = window.siyuan.storage[Constants.LOCAL_SEARCHASSET] as ISearchAssetOption; const assetsElement = element.querySelector("#searchAssets"); const unRefPanelElement = element.querySelector("#searchUnRefPanel"); - let unRefEdit: Protyle; element.addEventListener("click", (event: MouseEvent) => { let target = event.target as HTMLElement; const searchPathInputElement = element.querySelector("#searchPathInput"); @@ -545,7 +580,7 @@ export const genSearch = (app: App, config: ISearchOption, element: Element, clo config.idPath = []; config.hPath = ""; config.page = 1; - searchPathInputElement.innerHTML = config.hPath; + searchPathInputElement.textContent = ""; searchPathInputElement.setAttribute("aria-label", ""); inputEvent(element, config, edit, true); const includeElement = element.querySelector("#searchInclude"); @@ -594,7 +629,7 @@ export const genSearch = (app: App, config: ISearchOption, element: Element, clo } config.hPath = hPathList.join(" "); config.page = 1; - searchPathInputElement.innerHTML = `${escapeHtml(config.hPath)}`; + searchPathInputElement.innerHTML = `${escapeGreat(config.hPath)}`; searchPathInputElement.setAttribute("aria-label", escapeHtml(config.hPath)); const includeElement = element.querySelector("#searchInclude"); includeElement.firstElementChild.classList.add("ft__primary"); @@ -638,7 +673,7 @@ export const genSearch = (app: App, config: ISearchOption, element: Element, clo event.preventDefault(); break; } else if (target.id === "searchUnRef") { - unRefEdit = openSearchUnRef(app, unRefPanelElement, !closeCB); + openSearchUnRef(unRefPanelElement, unRefEdit); event.stopPropagation(); event.preventDefault(); break; @@ -657,10 +692,10 @@ export const genSearch = (app: App, config: ISearchOption, element: Element, clo break; } else if (type === "unRefPrevious") { if (!target.getAttribute("disabled")) { - let currentPage = parseInt(assetsElement.querySelector("#searchUnRefResult").textContent); + let currentPage = parseInt(unRefPanelElement.querySelector("#searchUnRefResult").textContent); if (currentPage > 1) { currentPage--; - getUnRefList(assetsElement, unRefEdit, currentPage); + getUnRefList(unRefPanelElement, unRefEdit, currentPage); } } event.stopPropagation(); @@ -668,10 +703,10 @@ export const genSearch = (app: App, config: ISearchOption, element: Element, clo break; } else if (type === "unRefNext") { if (!target.getAttribute("disabled")) { - let currentPage = parseInt(assetsElement.querySelector("#searchUnRefResult").textContent); - if (currentPage < parseInt(assetsElement.querySelector("#searchAssetResult .fn__flex-center").textContent.split("/")[1])) { + let currentPage = parseInt(unRefPanelElement.querySelector("#searchUnRefResult").textContent); + if (currentPage < parseInt(unRefPanelElement.querySelector("#searchUnRefResult").textContent.split("/")[1])) { currentPage++; - getUnRefList(assetsElement, unRefEdit, currentPage); + getUnRefList(unRefPanelElement, unRefEdit, currentPage); } } event.stopPropagation(); @@ -1040,7 +1075,7 @@ export const genSearch = (app: App, config: ISearchOption, element: Element, clo height: searchInputElement.clientHeight, }); inputEvent(element, config, edit); - return edit; + return {edit, unRefEdit}; }; export const getQueryTip = (method: number) => { @@ -1079,7 +1114,7 @@ const updateConfig = (element: Element, item: ISearchOption, config: ISearchOpti } const searchPathInputElement = element.querySelector("#searchPathInput"); if (item.hPath) { - searchPathInputElement.innerHTML = `${escapeHtml(item.hPath)}`; + searchPathInputElement.innerHTML = `${escapeGreat(item.hPath)}`; searchPathInputElement.setAttribute("aria-label", escapeHtml(item.hPath)); } else { searchPathInputElement.innerHTML = "";