import {getAllModels} from "../layout/getAll"; import {getInstanceById, getWndByLayout, resizeTabs} from "../layout/util"; import {Tab} from "../layout/Tab"; import {Search} from "./index"; import {Wnd} from "../layout/Wnd"; import {Constants} from "../constants"; import {escapeHtml} from "../util/escape"; import {fetchPost, fetchSyncPost} from "../util/fetch"; import {openFileById} from "../editor/util"; import {showMessage} from "../dialog/message"; import {reloadProtyle} from "../protyle/util/reload"; import {MenuItem} from "../menus/Menu"; import {getDisplayName, getNotebookIcon, getNotebookName, movePathTo, pathPosix} from "../util/pathName"; import {Protyle} from "../protyle"; import {onGet} from "../protyle/util/onGet"; import {addLoading, setPadding} from "../protyle/ui/initUI"; import {getIconByType} from "../editor/getIcon"; import {unicode2Emoji} from "../emoji"; import {Dialog} from "../dialog"; 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); 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 = JSON.parse(localStorage.getItem(Constants.LOCAL_SEARCHEDATA) || "{}"); if (!localData.types) { localData.types = { document: window.siyuan.config.search.document, heading: window.siyuan.config.search.heading, list: window.siyuan.config.search.list, listItem: window.siyuan.config.search.listItem, codeBlock: window.siyuan.config.search.codeBlock, htmlBlock: window.siyuan.config.search.htmlBlock, mathBlock: window.siyuan.config.search.mathBlock, table: window.siyuan.config.search.table, blockquote: window.siyuan.config.search.blockquote, superBlock: window.siyuan.config.search.superBlock, paragraph: window.siyuan.config.search.paragraph, }; } const asset = new Search({ tab, config: { k: text, r: "", hasReplace: false, method: localData.method || 0, hPath: "", idPath: [], list: [], replaceList: [], group: localData.group || 0, layout: localData.layout || 0, sort: localData.sort || 0, types: localData.types } }); tab.addModel(asset); resizeTabs(); } }); wnd.split("lr").addTab(tab); }; export const genSearch = (config: ISearchOption, element: Element, closeCB?: () => void) => { let methodText = window.siyuan.languages.keyword; if (config.method === 1) { methodText = window.siyuan.languages.querySyntax; } else if (config.method === 2) { methodText = "SQL"; } else if (config.method === 3) { methodText = window.siyuan.languages.regex; } let includeChild = true; let enableIncludeChild = false; config.idPath.forEach(item => { if (item.endsWith(".sy")) { includeChild = false; } if (item.split("/").length > 1) { enableIncludeChild = true; } }); element.innerHTML = `
${config.hPath}
`; const searchPanelElement = element.querySelector("#searchList"); const searchInputElement = element.querySelector("#searchInput") as HTMLInputElement; const replaceInputElement = element.querySelector("#replaceInput") as HTMLInputElement; const replaceHistoryElement = element.querySelector("#replaceHistoryList"); const historyElement = element.querySelector("#searchHistoryList"); const lineHeight = 30; const edit = new Protyle(element.querySelector("#searchPreview") as HTMLElement, { blockId: "", render: { gutter: true, breadcrumbDocName: true }, }); let clickTimeout: number; let inputTimeout: number; searchInputElement.value = config.k || ""; replaceInputElement.value = config.r || ""; searchInputElement.select(); element.addEventListener("click", (event: MouseEvent) => { let target = event.target as HTMLElement; while (target && !target.isSameNode(element)) { if (target.classList.contains("search__rmpath")) { config.idPath = []; config.hPath = ""; element.querySelector("#searchPathInput").innerHTML = config.hPath; inputTimeout = inputEvent(element, config, inputTimeout, edit, false); const includeElement = element.querySelector("#searchInclude"); includeElement.classList.remove("b3-button--cancel"); includeElement.setAttribute("disabled", "disabled"); event.stopPropagation(); event.preventDefault(); break; } else if (target.id === "searchExpand") { Array.from(searchPanelElement.children).forEach(item => { if (item.classList.contains("b3-list-item")) { item.querySelector(".b3-list-item__arrow").classList.add("b3-list-item__arrow--open"); item.nextElementSibling.classList.remove("fn__none"); } }); event.stopPropagation(); event.preventDefault(); break; } else if (target.id === "searchCollapse") { Array.from(searchPanelElement.children).forEach(item => { if (item.classList.contains("b3-list-item")) { item.querySelector(".b3-list-item__arrow").classList.remove("b3-list-item__arrow--open"); item.nextElementSibling.classList.add("fn__none"); } }); event.stopPropagation(); event.preventDefault(); break; } else if (target.id === "searchPath") { movePathTo((toPath, toNotebook) => { fetchPost("/api/filetree/getHPathsByPaths", {paths: toPath}, (response) => { config.idPath = []; const hPathList: string[] = []; let enableIncludeChild = false; toPath.forEach((item, index) => { if (item === "/") { config.idPath.push(toNotebook[index]); hPathList.push(escapeHtml(getNotebookName(toNotebook[index]))); } else { enableIncludeChild = true; config.idPath.push(pathPosix().join(toNotebook[index], item)); } }); if (response.data) { hPathList.push(...response.data); } config.hPath = escapeHtml(hPathList.join(" ")); element.querySelector("#searchPathInput").innerHTML = `${config.hPath}`; const includeElement = element.querySelector("#searchInclude"); includeElement.classList.remove("b3-button--cancel"); if (enableIncludeChild) { includeElement.removeAttribute("disabled"); } else { includeElement.setAttribute("disabled", "disabled"); } inputTimeout = inputEvent(element, config, inputTimeout, edit, false); }); }, [], undefined, window.siyuan.languages.specifyPath); event.stopPropagation(); event.preventDefault(); break; } else if (target.id === "searchInclude") { target.classList.toggle("b3-button--cancel"); if (target.classList.contains("b3-button--cancel")) { config.idPath.forEach((item, index) => { if (!item.endsWith(".sy") && item.split("/").length > 1) { config.idPath[index] = item + ".sy"; } }); } else { config.idPath.forEach((item, index) => { if (item.endsWith(".sy")) { config.idPath[index] = item.replace(".sy", ""); } }); } inputTimeout = inputEvent(element, config, inputTimeout, edit); event.stopPropagation(); event.preventDefault(); break; } else if (target.id === "searchReplace") { // ctrl+P 不需要保存 config.hasReplace = !config.hasReplace; element.querySelector("#replaceHistoryBtn").parentElement.classList.toggle("fn__none"); event.stopPropagation(); 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) { const asset = new Search({ tab, config }); tab.addModel(asset); resizeTabs(); } }); wnd.split("lr").addTab(tab); if (closeCB) { closeCB(); } event.stopPropagation(); event.preventDefault(); break; } else if (target.id === "searchRefresh") { inputTimeout = inputEvent(element, config, inputTimeout, edit, false); event.stopPropagation(); event.preventDefault(); break; } else if (target.id === "searchMore") { addConfigMoreMenu(config, edit, element, event); event.stopPropagation(); event.preventDefault(); break; } else if (target.id === "searchFilter") { addConfigFilterMenu(config, edit, element); event.stopPropagation(); event.preventDefault(); break; } else if (target.id === "searchSyntaxCheck") { window.siyuan.menus.menu.remove(); addQueryMenu(config, edit, element); window.siyuan.menus.menu.popup({x: event.clientX - 16, y: event.clientY - 16}, true); event.stopPropagation(); event.preventDefault(); break; } else if (target.id === "searchHistoryBtn") { if (!config.list || config.list.length === 0) { return; } let html = ""; (config.list || []).forEach((s: string) => { if (s !== searchInputElement.value) { html += `
${escapeHtml(s)}
`; } }); if (html === "") { return; } historyElement.classList.remove("fn__none"); historyElement.innerHTML = html; replaceHistoryElement.classList.add("fn__none"); event.stopPropagation(); event.preventDefault(); return; } else if (target.id === "replaceHistoryBtn") { if (!config.replaceList || config.replaceList.length === 0) { return; } let html = ""; (config.replaceList || []).forEach((s: string) => { if (s !== replaceInputElement.value) { html += `
${escapeHtml(s)}
`; } }); if (html === "") { return; } replaceHistoryElement.classList.remove("fn__none"); replaceHistoryElement.innerHTML = html; historyElement.classList.add("fn__none"); event.stopPropagation(); event.preventDefault(); return; } else if (target.id === "replaceAllBtn") { replace(element, config, edit, true); event.stopPropagation(); event.preventDefault(); break; } else if (target.id === "replaceBtn") { replace(element, config, edit, false); event.stopPropagation(); event.preventDefault(); break; } else if (target.classList.contains("b3-list-item__toggle")) { target.parentElement.nextElementSibling.classList.toggle("fn__none"); target.firstElementChild.classList.toggle("b3-list-item__arrow--open"); event.stopPropagation(); event.preventDefault(); break; } else if (target.classList.contains("b3-list-item")) { if (target.parentElement.id === "searchHistoryList") { searchInputElement.value = target.textContent; inputTimeout = inputEvent(element, config, inputTimeout, edit, false); } else if (target.parentElement.id === "replaceHistoryList") { replaceInputElement.value = target.textContent; replaceHistoryElement.classList.add("fn__none"); } else if (target.getAttribute("data-type") === "search-item") { if (event.detail === 1) { clickTimeout = window.setTimeout(() => { if (event.altKey) { const id = target.getAttribute("data-node-id"); fetchPost("/api/block/checkBlockFold", {id}, (foldResponse) => { openFileById({ id, action: foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL] : [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT], zoomIn: foldResponse.data, position: "right" }); if (closeCB) { closeCB(); } }); } else if (!target.classList.contains("b3-list-item--focus")) { searchPanelElement.querySelector(".b3-list-item--focus").classList.remove("b3-list-item--focus"); target.classList.add("b3-list-item--focus"); getArticle({ edit, id: target.getAttribute("data-node-id"), k: getKey(target) }); searchInputElement.focus(); } }, Constants.TIMEOUT_DBLCLICK); } else if (event.detail === 2) { clearTimeout(clickTimeout); const id = target.getAttribute("data-node-id"); fetchPost("/api/block/checkBlockFold", {id}, (foldResponse) => { openFileById({ id, action: foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL] : [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT], zoomIn: foldResponse.data }); if (closeCB) { closeCB(); } }); } window.siyuan.menus.menu.remove(); } else if (target.querySelector(".b3-list-item__toggle")) { target.nextElementSibling.classList.toggle("fn__none"); target.firstElementChild.firstElementChild.classList.toggle("b3-list-item__arrow--open"); } event.stopPropagation(); event.preventDefault(); break; } target = target.parentElement; } historyElement.classList.add("fn__none"); replaceHistoryElement.classList.add("fn__none"); }, false); searchInputElement.addEventListener("compositionend", (event: InputEvent) => { inputTimeout = inputEvent(element, config, inputTimeout, edit, false, event); }); searchInputElement.addEventListener("input", (event: InputEvent) => { inputTimeout = inputEvent(element, config, inputTimeout, edit, false, event); }); searchInputElement.addEventListener("blur", () => { let searches: string[] = config.list || []; searches.splice(0, 0, searchInputElement.value); searches = Array.from(new Set(searches)); if (searches.length > window.siyuan.config.search.limit) { searches.splice(window.siyuan.config.search.limit, searches.length - window.siyuan.config.search.limit); } config.list = searches; config.k = searchInputElement.value; if (!element.getAttribute("data-id")) { localStorage.setItem(Constants.LOCAL_SEARCHEDATA, JSON.stringify(config)); } }); searchInputElement.addEventListener("keydown", (event: KeyboardEvent) => { let currentList: HTMLElement = searchPanelElement.querySelector(".b3-list-item--focus"); if (!currentList || event.isComposing) { return; } if (event.key === "ArrowDown") { currentList.classList.remove("b3-list-item--focus"); if (!currentList.nextElementSibling) { if (config.group === 1) { if (currentList.parentElement.nextElementSibling) { currentList.parentElement.nextElementSibling.nextElementSibling.firstElementChild.classList.add("b3-list-item--focus"); } else { searchPanelElement.children[1].firstElementChild.classList.add("b3-list-item--focus"); } } else { 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; } getArticle({ id: currentList.getAttribute("data-node-id"), k: getKey(currentList), edit }); event.preventDefault(); } else if (event.key === "ArrowUp") { currentList.classList.remove("b3-list-item--focus"); if (!currentList.previousElementSibling) { if (config.group === 1) { if (currentList.parentElement.previousElementSibling.previousElementSibling) { currentList.parentElement.previousElementSibling.previousElementSibling.lastElementChild.classList.add("b3-list-item--focus"); } else { searchPanelElement.lastElementChild.lastElementChild.classList.add("b3-list-item--focus"); } } else { 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; } getArticle({ id: currentList.getAttribute("data-node-id"), k: getKey(currentList), edit }); event.preventDefault(); } else if (event.key === "Enter") { const id = currentList.getAttribute("data-node-id"); fetchPost("/api/block/checkBlockFold", {id}, (foldResponse) => { openFileById({ id, action: foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL] : [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT], zoomIn: foldResponse.data }); if (closeCB) { closeCB(); } }); event.preventDefault(); } }); replaceInputElement.addEventListener("keydown", (event: KeyboardEvent) => { if (event.isComposing || event.key !== "Enter") { return; } replace(element, config, edit, false); event.preventDefault(); }); inputTimeout = inputEvent(element, config, inputTimeout, edit, false); return edit; }; const addConfigMoreMenu = async (config: ISearchOption, edit: Protyle, element: Element, event: MouseEvent) => { window.siyuan.menus.menu.remove(); const sortMenu = [{ label: window.siyuan.languages.type, current: config.sort === 0, click() { config.sort = 0; inputEvent(element, config, undefined, edit); } }, { label: window.siyuan.languages.createdASC, current: config.sort === 1, click() { config.sort = 1; inputEvent(element, config, undefined, edit); } }, { label: window.siyuan.languages.createdDESC, current: config.sort === 2, click() { config.sort = 2; inputEvent(element, config, undefined, edit); } }, { label: window.siyuan.languages.modifiedASC, current: config.sort === 3, click() { config.sort = 3; inputEvent(element, config, undefined, edit); } }, { label: window.siyuan.languages.modifiedDESC, current: config.sort === 4, click() { config.sort = 4; inputEvent(element, config, undefined, edit); } }]; if (config.group === 1) { sortMenu.push({ label: window.siyuan.languages.context, current: config.sort === 5, click() { config.sort = 5; inputEvent(element, config, undefined, edit); } }); } window.siyuan.menus.menu.append(new MenuItem({ label: window.siyuan.languages.sort, type: "submenu", submenu: sortMenu, }).element); window.siyuan.menus.menu.append(new MenuItem({ label: window.siyuan.languages.group, type: "submenu", submenu: [{ label: window.siyuan.languages.noGroupBy, current: config.group === 0, click() { element.querySelector("#searchCollapse").parentElement.classList.add("fn__none"); config.group = 0; if (config.sort === 5) { config.sort = 0; } inputEvent(element, config, undefined, edit); } }, { label: window.siyuan.languages.groupByDoc, current: config.group === 1, click() { element.querySelector("#searchCollapse").parentElement.classList.remove("fn__none"); config.group = 1; inputEvent(element, config, undefined, edit); } }] }).element); window.siyuan.menus.menu.append(new MenuItem({ label: window.siyuan.languages.layout, type: "submenu", submenu: [{ label: window.siyuan.languages.topBottomLayout, current: config.layout === 0, click() { element.querySelector(".search__layout").classList.remove("search__layout--row"); setPadding(edit.protyle); config.layout = 0; if (!element.getAttribute("data-id")) { localStorage.setItem(Constants.LOCAL_SEARCHEDATA, JSON.stringify(config)); } } }, { label: window.siyuan.languages.leftRightLayout, current: config.layout === 1, click() { element.querySelector(".search__layout").classList.add("search__layout--row"); setPadding(edit.protyle); config.layout = 1; if (!element.getAttribute("data-id")) { localStorage.setItem(Constants.LOCAL_SEARCHEDATA, JSON.stringify(config)); } } }] }).element); window.siyuan.menus.menu.append(new MenuItem({type: "separator"}).element); window.siyuan.menus.menu.append(new MenuItem({ label: window.siyuan.languages.saveCriterion, click() { const saveDialog = new Dialog({ title: window.siyuan.languages.saveCriterion, content: `
`, width: "520px", }); const btnsElement = saveDialog.element.querySelectorAll(".b3-button"); btnsElement[0].addEventListener("click", () => { saveDialog.destroy(); }); btnsElement[1].addEventListener("click", () => { fetchPost("/api/storage/setCriterion", {criterion: Object.assign({name: saveDialog.element.querySelector("input").value}, config)}, () => { saveDialog.destroy(); }); }); } }).element); const criteria = await fetchSyncPost("/api/storage/getCriteria"); const searchSubMenu: IMenu[] = []; criteria.data.forEach((item: ISearchOption) => { searchSubMenu.push({ label: item.name, click() { if (config.layout !== item.layout) { if (item.layout === 0) { element.querySelector(".search__layout").classList.remove("search__layout--row"); } else { element.querySelector(".search__layout").classList.add("search__layout--row"); } setPadding(edit.protyle); } if (config.hasReplace !== item.hasReplace) { if (item.hasReplace) { element.querySelector("#replaceHistoryBtn").parentElement.classList.remove("fn__none"); } else { element.querySelector("#replaceHistoryBtn").parentElement.classList.add("fn__none"); } } if (item.hPath) { element.querySelector("#searchPathInput").innerHTML = `${item.hPath}`; } else { element.querySelector("#searchPathInput").innerHTML = ""; } if (config.group !== item.group) { if (item.group === 0) { element.querySelector("#searchExpand").parentElement.classList.add("fn__none"); } else { element.querySelector("#searchExpand").parentElement.classList.remove("fn__none"); } } let includeChild = true; let enableIncludeChild = false; item.idPath.forEach(item => { if (item.endsWith(".sy")) { includeChild = false; } if (item.split("/").length > 1) { enableIncludeChild = true; } }); const searchIncludeElement = element.querySelector("#searchInclude"); if (includeChild) { searchIncludeElement.classList.remove("b3-button--cancel"); } else { searchIncludeElement.classList.add("b3-button--cancel"); } if (enableIncludeChild) { searchIncludeElement.removeAttribute("disabled"); } else { searchIncludeElement.setAttribute("disabled", "disabled"); } (element.querySelector("#searchInput") as HTMLInputElement).value = item.k; (element.querySelector("#replaceInput") as HTMLInputElement).value = item.r; inputEvent(element, Object.assign({}, item), undefined, edit); } }); }); if (searchSubMenu.length > 0) { window.siyuan.menus.menu.append(new MenuItem({ label: window.siyuan.languages.useCriterion, type: "submenu", submenu: searchSubMenu }).element); } window.siyuan.menus.menu.popup({x: event.clientX - 16, y: event.clientY - 16}, true); }; const addConfigFilterMenu = (config: ISearchOption, edit: Protyle, element: Element) => { const filterDialog = new Dialog({ title: window.siyuan.languages.type, content: `
`, width: "520px", }); const btnsElement = filterDialog.element.querySelectorAll(".b3-button"); btnsElement[0].addEventListener("click", () => { filterDialog.destroy(); }); btnsElement[1].addEventListener("click", () => { filterDialog.element.querySelectorAll(".b3-switch").forEach((item: HTMLInputElement) => { config.types[item.getAttribute("data-type") as TSearchFilter] = item.checked; }); inputEvent(element, config, undefined, edit); filterDialog.destroy(); }); }; const addQueryMenu = (config: ISearchOption, edit: Protyle, element: Element) => { const searchSyntaxCheckElement = element.querySelector("#searchSyntaxCheck"); window.siyuan.menus.menu.append(new MenuItem({ label: window.siyuan.languages.keyword, current: config.method === 0, click() { config.method = 0; searchSyntaxCheckElement.setAttribute("aria-label", `${window.siyuan.languages.searchMethod} ${window.siyuan.languages.keyword}`); inputEvent(element, config, undefined, edit); } }).element); window.siyuan.menus.menu.append(new MenuItem({ label: window.siyuan.languages.querySyntax, current: config.method === 1, click() { config.method = 1; searchSyntaxCheckElement.setAttribute("aria-label", `${window.siyuan.languages.searchMethod} ${window.siyuan.languages.querySyntax}`); inputEvent(element, config, undefined, edit); } }).element); window.siyuan.menus.menu.append(new MenuItem({ label: "SQL", current: config.method === 2, click() { config.method = 2; searchSyntaxCheckElement.setAttribute("aria-label", `${window.siyuan.languages.searchMethod} SQL`); inputEvent(element, config, undefined, edit); } }).element); window.siyuan.menus.menu.append(new MenuItem({ label: window.siyuan.languages.regex, current: config.method === 3, click() { config.method = 3; searchSyntaxCheckElement.setAttribute("aria-label", `${window.siyuan.languages.searchMethod} ${window.siyuan.languages.regex}`); inputEvent(element, config, undefined, edit); } }).element); }; const getKey = (element: HTMLElement) => { const keys: string[] = []; element.querySelectorAll("mark").forEach(item => { keys.push(item.textContent); }); return [...new Set(keys)].join(" "); }; const getArticle = (options: { id: string, k: string, edit: Protyle }) => { fetchPost("/api/block/checkBlockFold", {id: options.id}, (foldResponse) => { options.edit.protyle.scroll.lastScrollTop = 0; addLoading(options.edit.protyle); fetchPost("/api/filetree/getDoc", { id: options.id, k: options.k, mode: foldResponse.data ? 0 : 3, size: foldResponse.data ? Constants.SIZE_GET_MAX : window.siyuan.config.editor.dynamicLoadBlocks, }, getResponse => { onGet(getResponse, options.edit.protyle, foldResponse.data ? [Constants.CB_GET_ALL, Constants.CB_GET_HTML] : [Constants.CB_GET_HL, Constants.CB_GET_HTML]); const matchElement = options.edit.protyle.wysiwyg.element.querySelector(`div[data-node-id="${options.id}"] span[data-type="search-mark"]`); if (matchElement) { matchElement.scrollIntoView(); } }); }); }; const replace = (element: Element, config: ISearchOption, edit: Protyle, isAll: boolean) => { if (config.method === 1 || config.method === 2) { showMessage(window.siyuan.languages._kernel[132]); return; } const searchPanelElement = element.querySelector("#searchList"); const replaceInputElement = element.querySelector("#replaceInput") as HTMLInputElement; const loadElement = replaceInputElement.nextElementSibling; if (!loadElement.classList.contains("fn__none")) { return; } let searches: string[] = config.replaceList || []; searches.splice(0, 0, replaceInputElement.value); searches = Array.from(new Set(searches)); if (searches.length > window.siyuan.config.search.limit) { searches.splice(window.siyuan.config.search.limit, searches.length - window.siyuan.config.search.limit); } config.replaceList = searches; config.r = replaceInputElement.value; if (!element.getAttribute("data-id")) { localStorage.setItem(Constants.LOCAL_SEARCHEDATA, JSON.stringify(config)); } let currentList: HTMLElement = searchPanelElement.querySelector(".b3-list-item--focus"); if (!currentList) { return; } loadElement.classList.remove("fn__none"); let ids: string[] = []; let rootIds: string[] = []; if (isAll) { searchPanelElement.querySelectorAll('.b3-list-item[data-type="search-item"]').forEach(item => { ids.push(item.getAttribute("data-node-id")); rootIds.push(item.getAttribute("data-root-id")); }); } else { ids = [currentList.getAttribute("data-node-id")]; rootIds = [currentList.getAttribute("data-root-id")]; } fetchPost("/api/search/findReplace", { k: config.method === 0 ? getKey(currentList) : (element.querySelector("#searchInput") as HTMLInputElement).value, r: replaceInputElement.value, ids, types: config.types, method: config.method, }, (response) => { loadElement.classList.add("fn__none"); if (response.code === 1) { showMessage(response.msg); return; } if (ids.length > 1) { return; } getAllModels().editor.forEach(item => { if (rootIds[0] === item.editor.protyle.block.rootID) { reloadProtyle(item.editor.protyle); } }); if (!currentList.nextElementSibling && searchPanelElement.children[0]) { searchPanelElement.children[0].classList.add("b3-list-item--focus"); } else { currentList.nextElementSibling.classList.add("b3-list-item--focus"); } currentList.remove(); if (searchPanelElement.childElementCount === 0) { searchPanelElement.innerHTML = `
${window.siyuan.languages.emptyContent}
`; edit.protyle.element.classList.add("fn__none"); return; } currentList = searchPanelElement.querySelector(".b3-list-item--focus"); if (searchPanelElement.scrollTop < currentList.offsetTop - searchPanelElement.clientHeight + 30 || searchPanelElement.scrollTop > currentList.offsetTop) { searchPanelElement.scrollTop = currentList.offsetTop - searchPanelElement.clientHeight + 30; } getArticle({ edit, id: currentList.getAttribute("data-node-id"), k: getKey(currentList) }); }); }; const inputEvent = (element: Element, config: ISearchOption, inputTimeout: number, edit: Protyle, saveConfig = true, event?: InputEvent) => { if (event && event.isComposing) { return; } clearTimeout(inputTimeout); inputTimeout = window.setTimeout(() => { const searchInputElement = element.querySelector("#searchInput") as HTMLInputElement; const loadingElement = element.querySelector(".fn__loading--top"); loadingElement.classList.remove("fn__none"); const inputValue = searchInputElement.value; element.querySelector("#searchList").scrollTo(0, 0); if (inputValue === "") { fetchPost("/api/block/getRecentUpdatedBlocks", {}, (response) => { onSearch(response.data, edit, element); loadingElement.classList.add("fn__none"); element.querySelector("#searchResult").innerHTML = ""; }); } else { fetchPost("/api/search/fullTextSearchBlock", { query: inputValue, method: config.method, types: config.types, paths: config.idPath || [], groupBy: config.group, orderBy: config.sort, }, (response) => { onSearch(response.data.blocks, edit, element); element.querySelector("#searchResult").innerHTML = window.siyuan.languages.findInDoc.replace("${x}", response.data.matchedRootCount).replace("${y}", response.data.matchedBlockCount); loadingElement.classList.add("fn__none"); }); } if (saveConfig) { config.k = inputValue; if (!element.getAttribute("data-id")) { localStorage.setItem(Constants.LOCAL_SEARCHEDATA, JSON.stringify(config)); } } }, Constants.TIMEOUT_SEARCH); return inputTimeout; }; const onSearch = (data: IBlock[], edit: Protyle, element: Element) => { let resultHTML = ""; data.forEach((item, index) => { if (item.children) { resultHTML += `
${unicode2Emoji(getNotebookIcon(item.box) || Constants.SIYUAN_IMAGE_NOTE, false, "b3-list-item__graphic", true)} ${escapeHtml(getNotebookName(item.box))}${item.hPath}
`; item.children.forEach((childItem, childIndex) => { resultHTML += `
${unicode2Emoji(childItem.ial.icon, false, "b3-list-item__graphic", true)} ${childItem.content}
`; }); resultHTML += "
"; } else { const title = escapeHtml(getNotebookName(item.box)) + getDisplayName(item.hPath, false); resultHTML += `
${unicode2Emoji(item.ial.icon, false, "b3-list-item__graphic", true)} ${item.content} ${title}
`; } }); if (data[0]) { edit.protyle.element.classList.remove("fn__none"); const contentElement = document.createElement("div"); if (data[0].children) { contentElement.innerHTML = data[0].children[0].content; getArticle({ edit, id: data[0].children[0].id, k: getKey(contentElement), }); } else { contentElement.innerHTML = data[0].content; getArticle({ edit, id: data[0].id, k: getKey(contentElement), }); } } else { edit.protyle.element.classList.add("fn__none"); } element.querySelector("#searchList").innerHTML = resultHTML || `
${window.siyuan.languages.emptyContent}
`; };