From 4c291a7d87c0ebab791c097f43d62852e50ed295 Mon Sep 17 00:00:00 2001 From: Aiden Bai Date: Sun, 29 May 2022 20:40:44 -0700 Subject: [PATCH] Prerender latex --- assets/js/router.js | 30 ++++--- assets/js/search.js | 171 ++++++++++++++++++------------------- layouts/partials/head.html | 24 +++--- 3 files changed, 114 insertions(+), 111 deletions(-) diff --git a/assets/js/router.js b/assets/js/router.js index 787cd765..3bdc8102 100644 --- a/assets/js/router.js +++ b/assets/js/router.js @@ -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 window.Million = { - router, + apply, navigate, - reload, prefetch, - }; - router(".singlePage") - // We need on initial load, then subsequent redirs - // requestAnimationFrame() delays graph draw until SPA routing is finished - reload(draw) - window.addEventListener("DOMContentLoaded", () => requestAnimationFrame(draw)) + router, + } + + const render = () => requestAnimationFrame(rerender) + + window.addEventListener("DOMContentLoaded", () => { + apply((doc) => init(doc)) + init() + router(".singlePage") + render() + }) + window.addEventListener("million:navigate", render) } diff --git a/assets/js/search.js b/assets/js/search.js index ee006471..5896061b 100644 --- a/assets/js/search.js +++ b/assets/js/search.js @@ -7,47 +7,44 @@ const removeMarkdown = ( gfm: true, useImgAltText: false, preserveLinks: false, - } + }, ) => { - let output = markdown || '' - output = output.replace(/^(-\s*?|\*\s*?|_\s*?){3,}\s*$/gm, '') + let output = markdown || "" + output = output.replace(/^(-\s*?|\*\s*?|_\s*?){3,}\s*$/gm, "") try { if (options.stripListLeaders) { if (options.listUnicodeChar) - output = output.replace( - /^([\s\t]*)([\*\-\+]|\d+\.)\s+/gm, - options.listUnicodeChar + ' $1' - ) - else output = output.replace(/^([\s\t]*)([\*\-\+]|\d+\.)\s+/gm, '$1') + output = output.replace(/^([\s\t]*)([\*\-\+]|\d+\.)\s+/gm, options.listUnicodeChar + " $1") + else output = output.replace(/^([\s\t]*)([\*\-\+]|\d+\.)\s+/gm, "$1") } if (options.gfm) { output = output - .replace(/\n={2,}/g, '\n') - .replace(/~{3}.*\n/g, '') - .replace(/~~/g, '') - .replace(/`{3}.*\n/g, '') + .replace(/\n={2,}/g, "\n") + .replace(/~{3}.*\n/g, "") + .replace(/~~/g, "") + .replace(/`{3}.*\n/g, "") } if (options.preserveLinks) { - output = output.replace(/\[(.*?)\][\[\(](.*?)[\]\)]/g, '$1 ($2)') + output = output.replace(/\[(.*?)\][\[\(](.*?)[\]\)]/g, "$1 ($2)") } output = output - .replace(/<[^>]*>/g, '') - .replace(/^[=\-]{2,}\s*$/g, '') - .replace(/\[\^.+?\](\: .*?$)?/g, '') - .replace(/(#{1,6})\s+(.+)\1?/g, '$2') - .replace(/\s{0,2}\[.*?\]: .*?$/g, '') - .replace(/\!\[(.*?)\][\[\(].*?[\]\)]/g, options.useImgAltText ? '$1' : '') - .replace(/\[(.*?)\][\[\(].*?[\]\)]/g, '$1') - .replace(/!?\[\[\S[^\[\]\|]*(?:\|([^\[\]]*))?\S\]\]/g, '$1') - .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(/(`{3,})(.*?)\1/gm, '$2') - .replace(/`(.+?)`/g, '$1') - .replace(/\n{2,}/g, '\n\n') + .replace(/<[^>]*>/g, "") + .replace(/^[=\-]{2,}\s*$/g, "") + .replace(/\[\^.+?\](\: .*?$)?/g, "") + .replace(/(#{1,6})\s+(.+)\1?/g, "$2") + .replace(/\s{0,2}\[.*?\]: .*?$/g, "") + .replace(/\!\[(.*?)\][\[\(].*?[\]\)]/g, options.useImgAltText ? "$1" : "") + .replace(/\[(.*?)\][\[\(].*?[\]\)]/g, "$1") + .replace(/!?\[\[\S[^\[\]\|]*(?:\|([^\[\]]*))?\S\]\]/g, "$1") + .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(/(`{3,})(.*?)\1/gm, "$2") + .replace(/`(.+?)`/g, "$1") + .replace(/\n{2,}/g, "\n\n") } catch (e) { console.error(e) return markdown @@ -64,27 +61,28 @@ const highlight = (content, term) => { if (directMatchIdx !== -1) { const h = highlightWindow / 2 const before = content.substring(0, directMatchIdx).split(" ").slice(-h) - const after = content.substring(directMatchIdx + term.length, content.length - 1).split(" ").slice(0, h) - return (before.length == h ? `...${before.join(" ")}` : before.join(" ")) + `${term}` + after.join(" ") + const after = content + .substring(directMatchIdx + term.length, content.length - 1) + .split(" ") + .slice(0, h) + return ( + (before.length == h ? `...${before.join(" ")}` : before.join(" ")) + + `${term}` + + after.join(" ") + ) } - const tokenizedTerm = term.split(/\s+/).filter((t) => t !== '') - const splitText = content.split(/\s+/).filter((t) => t !== '') + const tokenizedTerm = term.split(/\s+/).filter((t) => t !== "") + const splitText = content.split(/\s+/).filter((t) => t !== "") const includesCheck = (token) => - tokenizedTerm.some((term) => - token.toLowerCase().startsWith(term.toLowerCase()) - ) + tokenizedTerm.some((term) => token.toLowerCase().startsWith(term.toLowerCase())) const occurrencesIndices = splitText.map(includesCheck) // calculate best index let bestSum = 0 let bestIndex = 0 - for ( - let i = 0; - i < Math.max(occurrencesIndices.length - highlightWindow, 0); - i++ - ) { + for (let i = 0; i < Math.max(occurrencesIndices.length - highlightWindow, 0); i++) { const window = occurrencesIndices.slice(i, i + highlightWindow) const windowSum = window.reduce((total, cur) => total + cur, 0) if (windowSum >= bestSum) { @@ -94,10 +92,7 @@ const highlight = (content, term) => { } const startIndex = Math.max(bestIndex - highlightWindow, 0) - const endIndex = Math.min( - startIndex + 2 * highlightWindow, - splitText.length - ) + const endIndex = Math.min(startIndex + 2 * highlightWindow, splitText.length) const mappedText = splitText .slice(startIndex, endIndex) .map((token) => { @@ -106,27 +101,28 @@ const highlight = (content, term) => { } return token }) - .join(' ') - .replaceAll(' ', ' ') - return `${startIndex === 0 ? '' : '...'}${mappedText}${endIndex === splitText.length ? '' : '...' - }` -}; + .join(" ") + .replaceAll(' ', " ") + return `${startIndex === 0 ? "" : "..."}${mappedText}${ + endIndex === splitText.length ? "" : "..." + }` +} -(async function() { +;(async function () { const encoder = (str) => str.toLowerCase().split(/([^a-z]|[^\x00-\x7F])+/) const contentIndex = new FlexSearch.Document({ cache: true, - charset: 'latin:extra', + charset: "latin:extra", optimize: true, index: [ { - field: 'content', - tokenize: 'reverse', + field: "content", + tokenize: "reverse", encode: encoder, }, { - field: 'title', - tokenize: 'forward', + field: "title", + tokenize: "forward", encode: encoder, }, ], @@ -154,10 +150,8 @@ const highlight = (content, term) => { const redir = (id, term) => { // SPA navigation window.Million.navigate( - new URL( - `${BASE_URL.replace(/\/$/g, "")}${id}#:~:text=${encodeURIComponent(term)}/` - ), - '.singlePage' + new URL(`${BASE_URL.replace(/\/$/g, "")}${id}#:~:text=${encodeURIComponent(term)}/`), + ".singlePage", ) closeSearch() } @@ -169,24 +163,24 @@ const highlight = (content, term) => { content: content[id].content, }) - const source = document.getElementById('search-bar') - const results = document.getElementById('results-container') + const source = document.getElementById("search-bar") + const results = document.getElementById("results-container") let term - source.addEventListener('keyup', (e) => { - if (e.key === 'Enter') { - const anchor = document.getElementsByClassName('result-card')[0] + source.addEventListener("keyup", (e) => { + if (e.key === "Enter") { + const anchor = document.getElementsByClassName("result-card")[0] redir(anchor.id, term) } }) - source.addEventListener('input', (e) => { + source.addEventListener("input", (e) => { term = e.target.value const searchResults = contentIndex.search(term, [ { - field: 'content', + field: "content", limit: 10, }, { - field: 'title', + field: "title", limit: 5, }, ]) @@ -198,7 +192,7 @@ const highlight = (content, term) => { 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) // display @@ -213,58 +207,55 @@ const highlight = (content, term) => { resultToHTML({ ...result, term, - }) + }), ) - .join('\n') - const anchors = [...document.getElementsByClassName('result-card')] + .join("\n") + const anchors = [...document.getElementsByClassName("result-card")] anchors.forEach((anchor) => { anchor.onclick = () => redir(anchor.id, term) }) } }) - const searchContainer = document.getElementById('search-container') + const searchContainer = document.getElementById("search-container") function openSearch() { - if ( - searchContainer.style.display === 'none' || - searchContainer.style.display === '' - ) { - source.value = '' - results.innerHTML = '' - searchContainer.style.display = 'block' + if (searchContainer.style.display === "none" || searchContainer.style.display === "") { + source.value = "" + results.innerHTML = "" + searchContainer.style.display = "block" source.focus() } else { - searchContainer.style.display = 'none' + searchContainer.style.display = "none" } } function closeSearch() { - searchContainer.style.display = 'none' + searchContainer.style.display = "none" } - document.addEventListener('keydown', (event) => { - if (event.key === 'k' && (event.ctrlKey || event.metaKey)) { + document.addEventListener("keydown", (event) => { + if (event.key === "k" && (event.ctrlKey || event.metaKey)) { event.preventDefault() openSearch() } - if (event.key === 'Escape') { + if (event.key === "Escape") { event.preventDefault() closeSearch() } }) - const searchButton = document.getElementById('search-icon') - searchButton.addEventListener('click', (evt) => { + const searchButton = document.getElementById("search-icon") + searchButton.addEventListener("click", (evt) => { openSearch() }) - searchButton.addEventListener('keydown', (evt) => { + searchButton.addEventListener("keydown", (evt) => { openSearch() }) - searchContainer.addEventListener('click', (evt) => { + searchContainer.addEventListener("click", (evt) => { closeSearch() }) - document.getElementById('search-space').addEventListener('click', (evt) => { + document.getElementById("search-space").addEventListener("click", (evt) => { evt.stopPropagation() }) })() diff --git a/layouts/partials/head.html b/layouts/partials/head.html index f10ce145..3b50340e 100644 --- a/layouts/partials/head.html +++ b/layouts/partials/head.html @@ -10,11 +10,7 @@ end }} - + { - // 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. + 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 {{if $.Site.Data.config.enableFooter}} const container = document.getElementById("graph-container") // 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 container.textContent = "" @@ -79,6 +75,7 @@ {{$.Site.Data.graphConfig.enableZoom}} ); {{end}} + {{if $.Site.Data.config.enableLinkPreview}} initPopover( {{strings.TrimRight "/" .Site.BaseURL }}, @@ -86,8 +83,12 @@ {{$.Site.Data.config.enableLatex}} ) {{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}} - renderMathInElement(document.body, { + renderMathInElement(doc.body, { delimiters: [ {left: '$$', right: '$$', display: true}, {left: '$', right: '$', display: false}, @@ -102,7 +103,7 @@ resources.Minify }} {{else}} {{end}}