diff --git a/app/src/protyle/util/compatibility.ts b/app/src/protyle/util/compatibility.ts index 021658c42..2114532a5 100644 --- a/app/src/protyle/util/compatibility.ts +++ b/app/src/protyle/util/compatibility.ts @@ -154,7 +154,13 @@ export const getLocalStorage = (cb: () => void) => { row: "", layout: 0, method: 0, - types: [".txt", ".md", ".docx", ".xlsx", ".pptx"], + types: { + ".txt": true, + ".md": true, + ".docx": true, + ".xlsx": true, + ".pptx": true, + }, sort: 0, k: "", }; diff --git a/app/src/search/assets.ts b/app/src/search/assets.ts index efd7bd36f..6144ae351 100644 --- a/app/src/search/assets.ts +++ b/app/src/search/assets.ts @@ -1,8 +1,10 @@ import {Constants} from "../constants"; import {fetchPost} from "../util/fetch"; +import {upDownHint} from "../util/upDownHint"; +import {escapeHtml} from "../util/escape"; export const openSearchAsset = (element: HTMLElement, isStick: boolean) => { - const localSearch = window.siyuan.storage[Constants.LOCAL_SEARCHASSET] + const localSearch = window.siyuan.storage[Constants.LOCAL_SEARCHASSET] as ISearchAssetOption let methodText = window.siyuan.languages.keyword; if (localSearch.method === 1) { methodText = window.siyuan.languages.querySyntax; @@ -18,10 +20,10 @@ export const openSearchAsset = (element: HTMLElement, isStick: boolean) => { - -
+ +
- + @@ -56,7 +58,7 @@ export const openSearchAsset = (element: HTMLElement, isStick: boolean) => {
-
+
@@ -67,18 +69,133 @@ export const openSearchAsset = (element: HTMLElement, isStick: boolean) => { ` element.previousElementSibling.classList.add("fn__none"); element.classList.remove("fn__none") - if (element.querySelector("#searchList").innerHTML !== "") { + const searchPanelElement = element.querySelector("#searchAssetList"); + if (element.querySelector("#searchAssetList").innerHTML !== "") { return } + const searchInputElement = element.querySelector("#searchAssetInput") as HTMLInputElement + searchInputElement.addEventListener("compositionend", (event: InputEvent) => { + if (event.isComposing) { + return; + } + inputEvent(localSearch, element, 1); + }); + searchInputElement.addEventListener("input", (event: InputEvent) => { + if (event.isComposing) { + return; + } + inputEvent(localSearch, element, 1); + }); + searchInputElement.addEventListener("blur", () => { + // saveKeyList("keys", searchInputElement.value); + }); + const historyElement = element.querySelector("#searchAssetHistoryList") + const lineHeight = 30; + searchInputElement.addEventListener("keydown", (event: KeyboardEvent) => { + let currentList: HTMLElement = searchPanelElement.querySelector(".b3-list-item--focus"); + if (!currentList || event.isComposing) { + return; + } + const isHistory = !historyElement.classList.contains("fn__none"); + if (event.key === "Enter") { + if (!isHistory) { + // TODO open folder + } else { + searchInputElement.value = historyElement.querySelector(".b3-list-item--focus").textContent.trim(); + inputEvent(localSearch, element, 1); + toggleSearchHistory(historyElement, searchInputElement); + } + event.preventDefault(); + } + if (event.key === "ArrowDown" && event.altKey) { + toggleSearchHistory(historyElement, searchInputElement); + return; + } + if (isHistory) { + if (event.key === "Escape") { + toggleSearchHistory(historyElement, searchInputElement); + } else { + upDownHint(historyElement, event); + } + event.stopPropagation(); + event.preventDefault(); + return; + } + if (!isHistory) { + return; + } + if (event.key === "ArrowDown") { + currentList.classList.remove("b3-list-item--focus"); + if (!currentList.nextElementSibling) { + searchPanelElement.firstElementChild.classList.add("b3-list-item--focus"); + } else { + currentList.nextElementSibling.classList.add("b3-list-item--focus"); + } + currentList = searchPanelElement.querySelector(".b3-list-item--focus"); + if (searchPanelElement.scrollTop < currentList.offsetTop - searchPanelElement.clientHeight + lineHeight || + searchPanelElement.scrollTop > currentList.offsetTop) { + searchPanelElement.scrollTop = currentList.offsetTop - searchPanelElement.clientHeight + lineHeight; + } + event.preventDefault(); + } else if (event.key === "ArrowUp") { + currentList.classList.remove("b3-list-item--focus"); + if (!currentList.previousElementSibling) { + searchPanelElement.lastElementChild.classList.add("b3-list-item--focus"); + } else { + currentList.previousElementSibling.classList.add("b3-list-item--focus"); + } + currentList = searchPanelElement.querySelector(".b3-list-item--focus"); + if (searchPanelElement.scrollTop < currentList.offsetTop - searchPanelElement.clientHeight + lineHeight || + searchPanelElement.scrollTop > currentList.offsetTop - lineHeight * 2) { + searchPanelElement.scrollTop = currentList.offsetTop - lineHeight * 2; + } + event.preventDefault(); + } + }); + inputEvent(localSearch, element); +} + +const inputEvent = (localSearch: ISearchAssetOption, element: Element, page = 1) => { + const searchInputElement = element.querySelector("#searchAssetInput") as HTMLInputElement fetchPost("/api/search/fullTextSearchAssetContent", { - page: 1, - query: localSearch.k, + page, + query: searchInputElement.value, types: localSearch.types, method: localSearch.method, orderBy: localSearch.sort }, (response) => { - loadingElement.classList.remove("fn__none") + element.nextElementSibling.classList.add("fn__none") console.log(response) }) } + + +export const reIndexAssets = (loadingElement: HTMLElement) => { + loadingElement.classList.remove("fn__none") + fetchPost("/api/asset/fullReindexAssetContent", {}, (response) => { + loadingElement.classList.add("fn__none") + }) +} + +const toggleSearchHistory = (historyElement: Element, searchInputElement: HTMLInputElement) => { + if (historyElement.classList.contains("fn__none")) { + const keys = window.siyuan.storage[Constants.LOCAL_SEARCHASSET].keys; + if (!keys || keys.length === 0) { + return; + } + let html = ""; + keys.forEach((s: string) => { + if (s !== searchInputElement.value && s) { + html += `
${escapeHtml(s)}
`; + } + }); + if (html === "") { + return; + } + historyElement.classList.remove("fn__none"); + historyElement.innerHTML = html; + } else { + historyElement.classList.add("fn__none"); + } +}; diff --git a/app/src/search/util.ts b/app/src/search/util.ts index 12f1ca36e..04952db40 100644 --- a/app/src/search/util.ts +++ b/app/src/search/util.ts @@ -19,7 +19,7 @@ import {matchHotKey} from "../protyle/util/hotKey"; import {filterMenu, getKeyByLiElement, initCriteriaMenu, moreMenu, queryMenu, saveCriterion} from "./menu"; import {App} from "../index"; import {upDownHint} from "../util/upDownHint"; -import {openSearchAsset} from "./assets"; +import {openSearchAsset, reIndexAssets} from "./assets"; const toggleReplaceHistory = (replaceHistoryElement: Element, historyElement: Element, replaceInputElement: HTMLInputElement) => { if (replaceHistoryElement.classList.contains("fn__none")) { @@ -642,6 +642,11 @@ export const genSearch = (app: App, config: ISearchOption, element: Element, clo event.stopPropagation(); event.preventDefault(); break; + } else if (type === "reindexAssets") { + reIndexAssets(element.querySelector(".fn__loading--top")); + event.stopPropagation(); + event.preventDefault(); + break; } else if (target.id === "replaceBtn") { replace(element, config, edit, false); event.stopPropagation(); diff --git a/app/src/types/index.d.ts b/app/src/types/index.d.ts index c143d1de9..8969a37c3 100644 --- a/app/src/types/index.d.ts +++ b/app/src/types/index.d.ts @@ -142,6 +142,23 @@ interface IPluginSettingOption { createActionElement?(): HTMLElement } +interface ISearchAssetOption { + keys: string[], + col: string, + row: string, + layout: number, + method: number, + types: { + ".txt": boolean, + ".md": boolean, + ".docx": boolean, + ".xlsx": boolean, + ".pptx": boolean, + }, + sort: number, + k: string, +} + interface ISearchOption { page: number removed?: boolean // 移除后需记录搜索内容 https://github.com/siyuan-note/siyuan/issues/7745