Merge branch 'hugo' into hugo

This commit is contained in:
DhammaCharts 2022-06-06 12:56:47 +01:00 committed by GitHub
commit 84c75d0546
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 114 additions and 111 deletions

View File

@ -1,16 +1,26 @@
import { router, navigate, reload, prefetch } from "https://unpkg.com/million@1.9.6/dist/router.mjs" import {
apply,
navigate,
prefetch,
router,
} from "https://unpkg.com/million@1.9.8-0/dist/router.mjs"
export const attachSPARouting = (draw) => { export const attachSPARouting = (init, rerender) => {
// Attach SPA functions to the global Million namespace // Attach SPA functions to the global Million namespace
window.Million = { window.Million = {
router, apply,
navigate, navigate,
reload,
prefetch, prefetch,
}; router,
router(".singlePage") }
// We need on initial load, then subsequent redirs
// requestAnimationFrame() delays graph draw until SPA routing is finished const render = () => requestAnimationFrame(rerender)
reload(draw)
window.addEventListener("DOMContentLoaded", () => requestAnimationFrame(draw)) window.addEventListener("DOMContentLoaded", () => {
apply((doc) => init(doc))
init()
router(".singlePage")
render()
})
window.addEventListener("million:navigate", render)
} }

View File

@ -7,47 +7,44 @@ const removeMarkdown = (
gfm: true, gfm: true,
useImgAltText: false, useImgAltText: false,
preserveLinks: false, preserveLinks: false,
} },
) => { ) => {
let output = markdown || '' let output = markdown || ""
output = output.replace(/^(-\s*?|\*\s*?|_\s*?){3,}\s*$/gm, '') output = output.replace(/^(-\s*?|\*\s*?|_\s*?){3,}\s*$/gm, "")
try { try {
if (options.stripListLeaders) { if (options.stripListLeaders) {
if (options.listUnicodeChar) if (options.listUnicodeChar)
output = output.replace( output = output.replace(/^([\s\t]*)([\*\-\+]|\d+\.)\s+/gm, options.listUnicodeChar + " $1")
/^([\s\t]*)([\*\-\+]|\d+\.)\s+/gm, else output = output.replace(/^([\s\t]*)([\*\-\+]|\d+\.)\s+/gm, "$1")
options.listUnicodeChar + ' $1'
)
else output = output.replace(/^([\s\t]*)([\*\-\+]|\d+\.)\s+/gm, '$1')
} }
if (options.gfm) { if (options.gfm) {
output = output output = output
.replace(/\n={2,}/g, '\n') .replace(/\n={2,}/g, "\n")
.replace(/~{3}.*\n/g, '') .replace(/~{3}.*\n/g, "")
.replace(/~~/g, '') .replace(/~~/g, "")
.replace(/`{3}.*\n/g, '') .replace(/`{3}.*\n/g, "")
} }
if (options.preserveLinks) { if (options.preserveLinks) {
output = output.replace(/\[(.*?)\][\[\(](.*?)[\]\)]/g, '$1 ($2)') output = output.replace(/\[(.*?)\][\[\(](.*?)[\]\)]/g, "$1 ($2)")
} }
output = output output = output
.replace(/<[^>]*>/g, '') .replace(/<[^>]*>/g, "")
.replace(/^[=\-]{2,}\s*$/g, '') .replace(/^[=\-]{2,}\s*$/g, "")
.replace(/\[\^.+?\](\: .*?$)?/g, '') .replace(/\[\^.+?\](\: .*?$)?/g, "")
.replace(/(#{1,6})\s+(.+)\1?/g, '<b>$2</b>') .replace(/(#{1,6})\s+(.+)\1?/g, "<b>$2</b>")
.replace(/\s{0,2}\[.*?\]: .*?$/g, '') .replace(/\s{0,2}\[.*?\]: .*?$/g, "")
.replace(/\!\[(.*?)\][\[\(].*?[\]\)]/g, options.useImgAltText ? '$1' : '') .replace(/\!\[(.*?)\][\[\(].*?[\]\)]/g, options.useImgAltText ? "$1" : "")
.replace(/\[(.*?)\][\[\(].*?[\]\)]/g, '<a>$1</a>') .replace(/\[(.*?)\][\[\(].*?[\]\)]/g, "<a>$1</a>")
.replace(/!?\[\[\S[^\[\]\|]*(?:\|([^\[\]]*))?\S\]\]/g, '<a>$1</a>') .replace(/!?\[\[\S[^\[\]\|]*(?:\|([^\[\]]*))?\S\]\]/g, "<a>$1</a>")
.replace(/^\s{0,3}>\s?/g, '') .replace(/^\s{0,3}>\s?/g, "")
.replace(/(^|\n)\s{0,3}>\s?/g, '\n\n') .replace(/(^|\n)\s{0,3}>\s?/g, "\n\n")
.replace(/^\s{1,2}\[(.*?)\]: (\S+)( ".*?")?\s*$/g, '') .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{0,1})\1/g, '$2') .replace(/([\*_]{1,3})(\S.*?\S{0,1})\1/g, "$2")
.replace(/(`{3,})(.*?)\1/gm, '$2') .replace(/(`{3,})(.*?)\1/gm, "$2")
.replace(/`(.+?)`/g, '$1') .replace(/`(.+?)`/g, "$1")
.replace(/\n{2,}/g, '\n\n') .replace(/\n{2,}/g, "\n\n")
} catch (e) { } catch (e) {
console.error(e) console.error(e)
return markdown return markdown
@ -64,27 +61,28 @@ const highlight = (content, term) => {
if (directMatchIdx !== -1) { if (directMatchIdx !== -1) {
const h = highlightWindow / 2 const h = highlightWindow / 2
const before = content.substring(0, directMatchIdx).split(" ").slice(-h) const before = content.substring(0, directMatchIdx).split(" ").slice(-h)
const after = content.substring(directMatchIdx + term.length, content.length - 1).split(" ").slice(0, h) const after = content
return (before.length == h ? `...${before.join(" ")}` : before.join(" ")) + `<span class="search-highlight">${term}</span>` + after.join(" ") .substring(directMatchIdx + term.length, content.length - 1)
.split(" ")
.slice(0, h)
return (
(before.length == h ? `...${before.join(" ")}` : before.join(" ")) +
`<span class="search-highlight">${term}</span>` +
after.join(" ")
)
} }
const tokenizedTerm = term.split(/\s+/).filter((t) => t !== '') const tokenizedTerm = term.split(/\s+/).filter((t) => t !== "")
const splitText = content.split(/\s+/).filter((t) => t !== '') const splitText = content.split(/\s+/).filter((t) => t !== "")
const includesCheck = (token) => const includesCheck = (token) =>
tokenizedTerm.some((term) => tokenizedTerm.some((term) => token.toLowerCase().startsWith(term.toLowerCase()))
token.toLowerCase().startsWith(term.toLowerCase())
)
const occurrencesIndices = splitText.map(includesCheck) const occurrencesIndices = splitText.map(includesCheck)
// calculate best index // calculate best index
let bestSum = 0 let bestSum = 0
let bestIndex = 0 let bestIndex = 0
for ( for (let i = 0; i < Math.max(occurrencesIndices.length - highlightWindow, 0); i++) {
let i = 0;
i < Math.max(occurrencesIndices.length - highlightWindow, 0);
i++
) {
const window = occurrencesIndices.slice(i, i + highlightWindow) const window = occurrencesIndices.slice(i, i + highlightWindow)
const windowSum = window.reduce((total, cur) => total + cur, 0) const windowSum = window.reduce((total, cur) => total + cur, 0)
if (windowSum >= bestSum) { if (windowSum >= bestSum) {
@ -94,10 +92,7 @@ const highlight = (content, term) => {
} }
const startIndex = Math.max(bestIndex - highlightWindow, 0) const startIndex = Math.max(bestIndex - highlightWindow, 0)
const endIndex = Math.min( const endIndex = Math.min(startIndex + 2 * highlightWindow, splitText.length)
startIndex + 2 * highlightWindow,
splitText.length
)
const mappedText = splitText const mappedText = splitText
.slice(startIndex, endIndex) .slice(startIndex, endIndex)
.map((token) => { .map((token) => {
@ -106,27 +101,28 @@ const highlight = (content, term) => {
} }
return token return token
}) })
.join(' ') .join(" ")
.replaceAll('</span> <span class="search-highlight">', ' ') .replaceAll('</span> <span class="search-highlight">', " ")
return `${startIndex === 0 ? '' : '...'}${mappedText}${endIndex === splitText.length ? '' : '...' return `${startIndex === 0 ? "" : "..."}${mappedText}${
}` endIndex === splitText.length ? "" : "..."
}; }`
}
(async function() { ;(async function () {
const encoder = (str) => str.toLowerCase().split(/([^a-z]|[^\x00-\x7F])+/) const encoder = (str) => str.toLowerCase().split(/([^a-z]|[^\x00-\x7F])+/)
const contentIndex = new FlexSearch.Document({ const contentIndex = new FlexSearch.Document({
cache: true, cache: true,
charset: 'latin:extra', charset: "latin:extra",
optimize: true, optimize: true,
index: [ index: [
{ {
field: 'content', field: "content",
tokenize: 'reverse', tokenize: "reverse",
encode: encoder, encode: encoder,
}, },
{ {
field: 'title', field: "title",
tokenize: 'forward', tokenize: "forward",
encode: encoder, encode: encoder,
}, },
], ],
@ -154,10 +150,8 @@ const highlight = (content, term) => {
const redir = (id, term) => { const redir = (id, term) => {
// SPA navigation // SPA navigation
window.Million.navigate( window.Million.navigate(
new URL( new URL(`${BASE_URL.replace(/\/$/g, "")}${id}#:~:text=${encodeURIComponent(term)}/`),
`${BASE_URL.replace(/\/$/g, "")}${id}#:~:text=${encodeURIComponent(term)}/` ".singlePage",
),
'.singlePage'
) )
closeSearch() closeSearch()
} }
@ -169,24 +163,24 @@ const highlight = (content, term) => {
content: content[id].content, content: content[id].content,
}) })
const source = document.getElementById('search-bar') const source = document.getElementById("search-bar")
const results = document.getElementById('results-container') const results = document.getElementById("results-container")
let term let term
source.addEventListener('keyup', (e) => { source.addEventListener("keyup", (e) => {
if (e.key === 'Enter') { if (e.key === "Enter") {
const anchor = document.getElementsByClassName('result-card')[0] const anchor = document.getElementsByClassName("result-card")[0]
redir(anchor.id, term) redir(anchor.id, term)
} }
}) })
source.addEventListener('input', (e) => { source.addEventListener("input", (e) => {
term = e.target.value term = e.target.value
const searchResults = contentIndex.search(term, [ const searchResults = contentIndex.search(term, [
{ {
field: 'content', field: "content",
limit: 10, limit: 10,
}, },
{ {
field: 'title', field: "title",
limit: 5, limit: 5,
}, },
]) ])
@ -198,7 +192,7 @@ const highlight = (content, term) => {
return [...results[0].result] return [...results[0].result]
} }
} }
const allIds = new Set([...getByField('title'), ...getByField('content')]) const allIds = new Set([...getByField("title"), ...getByField("content")])
const finalResults = [...allIds].map(formatForDisplay) const finalResults = [...allIds].map(formatForDisplay)
// display // display
@ -213,58 +207,55 @@ const highlight = (content, term) => {
resultToHTML({ resultToHTML({
...result, ...result,
term, term,
}) }),
) )
.join('\n') .join("\n")
const anchors = [...document.getElementsByClassName('result-card')] const anchors = [...document.getElementsByClassName("result-card")]
anchors.forEach((anchor) => { anchors.forEach((anchor) => {
anchor.onclick = () => redir(anchor.id, term) anchor.onclick = () => redir(anchor.id, term)
}) })
} }
}) })
const searchContainer = document.getElementById('search-container') const searchContainer = document.getElementById("search-container")
function openSearch() { function openSearch() {
if ( if (searchContainer.style.display === "none" || searchContainer.style.display === "") {
searchContainer.style.display === 'none' || source.value = ""
searchContainer.style.display === '' results.innerHTML = ""
) { searchContainer.style.display = "block"
source.value = ''
results.innerHTML = ''
searchContainer.style.display = 'block'
source.focus() source.focus()
} else { } else {
searchContainer.style.display = 'none' searchContainer.style.display = "none"
} }
} }
function closeSearch() { function closeSearch() {
searchContainer.style.display = 'none' searchContainer.style.display = "none"
} }
document.addEventListener('keydown', (event) => { document.addEventListener("keydown", (event) => {
if (event.key === 'k' && (event.ctrlKey || event.metaKey)) { if (event.key === "k" && (event.ctrlKey || event.metaKey)) {
event.preventDefault() event.preventDefault()
openSearch() openSearch()
} }
if (event.key === 'Escape') { if (event.key === "Escape") {
event.preventDefault() event.preventDefault()
closeSearch() closeSearch()
} }
}) })
const searchButton = document.getElementById('search-icon') const searchButton = document.getElementById("search-icon")
searchButton.addEventListener('click', (evt) => { searchButton.addEventListener("click", (evt) => {
openSearch() openSearch()
}) })
searchButton.addEventListener('keydown', (evt) => { searchButton.addEventListener("keydown", (evt) => {
openSearch() openSearch()
}) })
searchContainer.addEventListener('click', (evt) => { searchContainer.addEventListener("click", (evt) => {
closeSearch() closeSearch()
}) })
document.getElementById('search-space').addEventListener('click', (evt) => { document.getElementById("search-space").addEventListener("click", (evt) => {
evt.stopPropagation() evt.stopPropagation()
}) })
})() })()

View File

@ -10,11 +10,7 @@
end }} end }}
</title> </title>
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<link <link rel="shortcut icon" type="image/png" href="{{$.Site.BaseURL}}/icon.png" />
rel="shortcut icon"
type="image/png"
href="{{$.Site.BaseURL}}/icon.png"
/>
<!-- CSS Stylesheets and Fonts --> <!-- CSS Stylesheets and Fonts -->
<link <link
@ -61,18 +57,18 @@
content, content,
})) }))
const draw = () => { const render = () => {
// NOTE: everything within this callback will be executed for every page navigation. This is a good place to put JavaScript that loads or modifies data on the page, adds event listeners, etc. If you are only dealing with basic DOM replacement, use the init function
const siteBaseURL = new URL({{$.Site.BaseURL}}); const siteBaseURL = new URL({{$.Site.BaseURL}});
const pathBase = siteBaseURL.pathname; const pathBase = siteBaseURL.pathname;
const pathWindow = window.location.pathname; const pathWindow = window.location.pathname;
const isHome = pathBase == pathWindow; const isHome = pathBase == pathWindow;
// NOTE: everything within this callback will be executed for every page navigation. This is a good place to put JavaScript that loads or modifies data on the page.
{{if $.Site.Data.config.enableFooter}} {{if $.Site.Data.config.enableFooter}}
const container = document.getElementById("graph-container") const container = document.getElementById("graph-container")
// retry if the graph is not ready // retry if the graph is not ready
if (!container) return requestAnimationFrame(draw) if (!container) return requestAnimationFrame(render)
// clear the graph in case there is anything within it // clear the graph in case there is anything within it
container.textContent = "" container.textContent = ""
@ -93,6 +89,7 @@
} }
{{end}} {{end}}
{{if $.Site.Data.config.enableLinkPreview}} {{if $.Site.Data.config.enableLinkPreview}}
initPopover( initPopover(
{{strings.TrimRight "/" .Site.BaseURL }}, {{strings.TrimRight "/" .Site.BaseURL }},
@ -100,8 +97,12 @@
{{$.Site.Data.config.enableLatex}} {{$.Site.Data.config.enableLatex}}
) )
{{end}} {{end}}
}
const init = (doc = document) => {
// NOTE: everything within this callback will be executed for initial page navigation. This is a good place to put JavaScript that only replaces DOM nodes.
{{if $.Site.Data.config.enableLatex}} {{if $.Site.Data.config.enableLatex}}
renderMathInElement(document.body, { renderMathInElement(doc.body, {
delimiters: [ delimiters: [
{left: '$$', right: '$$', display: true}, {left: '$$', right: '$$', display: true},
{left: '$', right: '$', display: false}, {left: '$', right: '$', display: false},
@ -116,7 +117,7 @@
resources.Minify }} resources.Minify }}
<script type="module"> <script type="module">
import { attachSPARouting } from "{{$router.Permalink}}" import { attachSPARouting } from "{{$router.Permalink}}"
attachSPARouting(draw) attachSPARouting(init, render)
</script> </script>
{{else}} {{else}}
<script> <script>
@ -124,7 +125,8 @@
navigate: (url) => (window.location.href = url), navigate: (url) => (window.location.href = url),
prefetch: () => {}, prefetch: () => {},
} }
draw() init()
render()
</script> </script>
{{end}} {{end}}
</head> </head>