| | |
| | | .replace(/^\s{0,3}>\s?/g, "") |
| | | .replace(/(^|\n)\s{0,3}>\s?/g, "\n\n") |
| | | .replace(/^\s{1,2}\[(.*?)\]: (\S+)( ".*?")?\s*$/g, "") |
| | | .replace(/([\*_]{1,3})(\S.*?\S{0,1})\1/g, "$2") |
| | | .replace(/([\*_]{1,3})(\S.*?\S{0,1})\1/g, "$2") |
| | | .replace(/([\*_]{1,3})(\S.*?\S?)\1/g, "$2") |
| | | .replace(/([\*_]{1,3})(\S.*?\S?)\1/g, "$2") |
| | | .replace(/(`{3,})(.*?)\1/gm, "$2") |
| | | .replace(/`(.+?)`/g, "$1") |
| | | .replace(/\n{2,}/g, "\n\n") |
| | |
| | | |
| | | const highlight = (content, term) => { |
| | | const highlightWindow = 20 |
| | | |
| | | // try to find direct match first |
| | | const directMatchIdx = content.indexOf(term) |
| | | if (directMatchIdx !== -1) { |
| | | const h = highlightWindow / 2 |
| | | const h = highlightWindow |
| | | const before = content.substring(0, directMatchIdx).split(" ").slice(-h) |
| | | const after = content |
| | | .substring(directMatchIdx + term.length, content.length - 1) |
| | | .substring(directMatchIdx + term.length, content.length - 2) |
| | | .split(" ") |
| | | .slice(0, h) |
| | | return ( |
| | | (before.length == h ? `...${before.join(" ")}` : before.join(" ")) + |
| | | (before.length === h ? `...${before.join(" ")}` : before.join(" ")) + |
| | | `<span class="search-highlight">${term}</span>` + |
| | | after.join(" ") |
| | | ) |
| | |
| | | } |
| | | |
| | | // Common utilities for search |
| | | const resultToHTML = ({ url, title, content, term }) => { |
| | | const text = removeMarkdown(content) |
| | | const resultTitle = highlight(title, term) |
| | | const resultText = highlight(text, term) |
| | | const resultToHTML = ({ url, title, content }) => { |
| | | return `<button class="result-card" id="${url}"> |
| | | <h3>${resultTitle}</h3> |
| | | <p>${resultText}</p> |
| | | <h3>${title}</h3> |
| | | <p>${content}</p> |
| | | </button>` |
| | | } |
| | | |
| | | const redir = (id, term) => { |
| | | // SPA navigation |
| | | const shouldTrim = PRODUCTION && SEARCH_ENABLED |
| | | const baseURLPrefix = shouldTrim ? "" : BASE_URL.replace(/\/$/g, "") |
| | | const urlString = `${baseURLPrefix}${id}#:~:text=${encodeURIComponent(term)}/` |
| | | window.Million.navigate( |
| | | new URL(`${BASE_URL.replace(/\/$/g, "")}${id}#:~:text=${encodeURIComponent(term)}/`), |
| | | new URL(urlString), |
| | | ".singlePage", |
| | | ) |
| | | closeSearch() |
| | |
| | | }) |
| | | } |
| | | |
| | | const displayResults = (finalResults) => { |
| | | const displayResults = (term, finalResults, extractHighlight = false) => { |
| | | const results = document.getElementById("results-container") |
| | | if (finalResults.length === 0) { |
| | | results.innerHTML = `<button class="result-card"> |
| | |
| | | </button>` |
| | | } else { |
| | | results.innerHTML = finalResults |
| | | .map((result) => |
| | | resultToHTML({ |
| | | ...result, |
| | | term, |
| | | }), |
| | | .map((result) => { |
| | | if (extractHighlight) { |
| | | return resultToHTML({ |
| | | url: result.url, |
| | | title: highlight(result.title, term), |
| | | content: highlight(removeMarkdown(result.content), term) |
| | | }) |
| | | } else { |
| | | return resultToHTML(result) |
| | | } |
| | | } |
| | | ) |
| | | .join("\n") |
| | | if (LATEX_ENABLED) { |
| | | renderMathInElement(results, { |
| | | delimiters: [ |
| | | { left: '$$', right: '$$', display: false }, |
| | | { left: '$', right: '$', display: false }, |
| | | ], |
| | | throwOnError: false |
| | | }) |
| | | } |
| | | |
| | | const anchors = [...document.getElementsByClassName("result-card")] |
| | | anchors.forEach((anchor) => { |
| | | anchor.onclick = () => redir(anchor.id, term) |