| | |
| | | import FlexSearch from "flexsearch" |
| | | import FlexSearch, { DefaultDocumentSearchResults } from "flexsearch" |
| | | import { ContentDetails } from "../../plugins/emitters/contentIndex" |
| | | import { registerEscapeHandler, removeAllChildren } from "./util" |
| | | import { FullSlug, normalizeRelativeURLs, resolveRelative } from "../../util/path" |
| | |
| | | title: string |
| | | content: string |
| | | tags: string[] |
| | | [key: string]: any |
| | | } |
| | | |
| | | // Can be expanded with things like "term" in the future |
| | | type SearchType = "basic" | "tags" |
| | | let searchType: SearchType = "basic" |
| | | let currentSearchTerm: string = "" |
| | | const encoder = (str: string) => str.toLowerCase().split(/([^a-z]|[^\x00-\x7F])/) |
| | | const encoder = (str: string): string[] => { |
| | | const tokens: string[] = [] |
| | | let bufferStart = -1 |
| | | let bufferEnd = -1 |
| | | const lower = str.toLowerCase() |
| | | |
| | | let i = 0 |
| | | for (const char of lower) { |
| | | const code = char.codePointAt(0)! |
| | | |
| | | const isCJK = |
| | | (code >= 0x3040 && code <= 0x309f) || |
| | | (code >= 0x30a0 && code <= 0x30ff) || |
| | | (code >= 0x4e00 && code <= 0x9fff) || |
| | | (code >= 0xac00 && code <= 0xd7af) || |
| | | (code >= 0x20000 && code <= 0x2a6df) |
| | | |
| | | const isWhitespace = code === 32 || code === 9 || code === 10 || code === 13 |
| | | |
| | | if (isCJK) { |
| | | if (bufferStart !== -1) { |
| | | tokens.push(lower.slice(bufferStart, bufferEnd)) |
| | | bufferStart = -1 |
| | | } |
| | | tokens.push(char) |
| | | } else if (isWhitespace) { |
| | | if (bufferStart !== -1) { |
| | | tokens.push(lower.slice(bufferStart, bufferEnd)) |
| | | bufferStart = -1 |
| | | } |
| | | } else { |
| | | if (bufferStart === -1) bufferStart = i |
| | | bufferEnd = i + char.length |
| | | } |
| | | |
| | | i += char.length |
| | | } |
| | | |
| | | if (bufferStart !== -1) { |
| | | tokens.push(lower.slice(bufferStart)) |
| | | } |
| | | |
| | | return tokens |
| | | } |
| | | |
| | | let index = new FlexSearch.Document<Item>({ |
| | | charset: "latin:extra", |
| | | encode: encoder, |
| | | document: { |
| | | id: "id", |
| | |
| | | |
| | | // If search is active, then we will render the first result and display accordingly |
| | | if (!container.classList.contains("active")) return |
| | | if (e.key === "Enter") { |
| | | if (e.key === "Enter" && !e.isComposing) { |
| | | // If result has focus, navigate to that one, otherwise pick first result |
| | | if (results.contains(document.activeElement)) { |
| | | const active = document.activeElement as HTMLInputElement |
| | |
| | | itemTile.classList.add("result-card") |
| | | itemTile.id = slug |
| | | itemTile.href = resolveUrl(slug).toString() |
| | | itemTile.innerHTML = `<h3>${title}</h3>${htmlTags}${ |
| | | enablePreview && window.innerWidth > 600 ? "" : `<p>${content}</p>` |
| | | }` |
| | | itemTile.innerHTML = ` |
| | | <h3 class="card-title">${title}</h3> |
| | | ${htmlTags} |
| | | <p class="card-description">${content}</p> |
| | | ` |
| | | itemTile.addEventListener("click", (event) => { |
| | | if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) return |
| | | hideSearch() |
| | |
| | | searchLayout.classList.toggle("display-results", currentSearchTerm !== "") |
| | | searchType = currentSearchTerm.startsWith("#") ? "tags" : "basic" |
| | | |
| | | let searchResults: FlexSearch.SimpleDocumentSearchResultSetUnit[] |
| | | let searchResults: DefaultDocumentSearchResults<Item> |
| | | if (searchType === "tags") { |
| | | currentSearchTerm = currentSearchTerm.substring(1).trim() |
| | | const separatorIndex = currentSearchTerm.indexOf(" ") |
| | |
| | | // return at least 10000 documents, so it is enough to filter them by tag (implemented in flexsearch) |
| | | limit: Math.max(numSearchResults, 10000), |
| | | index: ["title", "content"], |
| | | tag: tag, |
| | | tag: { tags: tag }, |
| | | }) |
| | | for (let searchResult of searchResults) { |
| | | searchResult.result = searchResult.result.slice(0, numSearchResults) |