testing moving the functionality into small modules #5

Open
xananax wants to merge 10 commits from split-into-modules into main
8 changed files with 100 additions and 34 deletions
Showing only changes of commit 3d348710e0 - Show all commits

View File

@ -6,10 +6,6 @@
<link href="../../modules/templates/blog.css" rel="stylesheet" /> <link href="../../modules/templates/blog.css" rel="stylesheet" />
</head> </head>
<body> <body>
<section>
<button class="burger">&#8801;</button>
<nav class="menu"></nav>
</section>
<main></main> <main></main>
<pre id="Source"></pre> <pre id="Source"></pre>
<div id="Loading"> <div id="Loading">

View File

@ -9,21 +9,16 @@ import { mode } from "../tickle/mode.mjs";
import { bootstrapRouter } from "../tickle/bootstrapRouter.mjs"; import { bootstrapRouter } from "../tickle/bootstrapRouter.mjs";
export const bootstrap = async () => { export const bootstrap = async () => {
const [Menu, Body, Source, Burger] = [ const [Body, Source] = [
"nav",
"main", "main",
"#Source", "#Source",
".burger",
].map(getElementByCSSSelector); ].map(getElementByCSSSelector);
Burger.addEventListener("click", mode.menuOpen.toggle);
mode.loading.on();
const lines = await fetchText("files.txt"); const lines = await fetchText("files.txt");
const links = parseFileList(lines); const links = parseFileList(lines);
const firstHref = links[0].href; const firstHref = links[0].href;
sortFileListLines(links); sortFileListLines(links);
Menu.appendChild(createMenuEntriesFromFileList(links)); Body.appendChild(createMenuEntriesFromFileList(links));
bootstrapRouter(firstHref, (content, raw) => { bootstrapRouter(firstHref, (content, raw) => {
Body.innerHTML = ""; Body.innerHTML = "";

View File

@ -10,8 +10,8 @@ import { mode } from "./mode.mjs";
/** /**
* Sets up a listener for hashchange events. * Sets up a listener for hashchange events.
* Loads the provided default Href if none is set by the user * Loads the provided default Href if none is set by the user
* @param {string} defaultHref * @param {string} defaultHref
* @param {(content: DocumentFragment, raw: string) => void} onPageLoaded * @param {(content: DocumentFragment, raw: string) => void} onPageLoaded
*/ */
export const bootstrapRouter = async (defaultHref, onPageLoaded) => { export const bootstrapRouter = async (defaultHref, onPageLoaded) => {
/** /**
@ -27,15 +27,19 @@ export const bootstrapRouter = async (defaultHref, onPageLoaded) => {
const { title, raw, content } = await fetchMarkdown(path); const { title, raw, content } = await fetchMarkdown(path);
changeTitle(title); changeTitle(title);
rewriteLocalUrls(content); rewriteLocalUrls(content);
onPageLoaded(content, raw) onPageLoaded(content, raw);
mode.loading.off(); mode.loading.off();
}; };
window.addEventListener("hashchange", onHashChange); window.addEventListener("hashchange", onHashChange);
if (hasNoHashUrl()) { const load = () => {
window.location.hash = `#${defaultHref}`; if (hasNoHashUrl()) {
} else { window.location.hash = `#${defaultHref}`;
onHashChange(); } else {
} onHashChange();
}
};
return load
}; };

View File

@ -2,12 +2,7 @@
import { fetchText } from "./fetchText.mjs"; import { fetchText } from "./fetchText.mjs";
import { waitIfLocalHost } from "./waitIfLocalHost.mjs"; import { waitIfLocalHost } from "./waitIfLocalHost.mjs";
import { generateDomFromString } from "./generateDomFromString.mjs"; import { markupToDom } from "./markupToDom.mjs"
import {getFirstTitleContent} from "./getFirstTitleContent.mjs";
// @ts-ignore
import { micromark } from "https://esm.sh/micromark@3?bundle";
// @ts-ignore
import {frontmatter, frontmatterHtml} from 'https://esm.sh/micromark-extension-frontmatter@1?bundle'
/** /**
* Loads and parses a markdown document. Makes use of micromark. * Loads and parses a markdown document. Makes use of micromark.
@ -16,14 +11,6 @@ import {frontmatter, frontmatterHtml} from 'https://esm.sh/micromark-extension-f
export const fetchMarkdown = (path) => export const fetchMarkdown = (path) =>
fetchText(path) fetchText(path)
.then(waitIfLocalHost()) .then(waitIfLocalHost())
.then((raw) => { .then(raw => markupToDom(raw, path));
const output = micromark(raw, {
extensions: [frontmatter()],
htmlExtensions: [frontmatterHtml()]
})
const content = generateDomFromString(output);
const title = getFirstTitleContent(content) || path.replace(/\.\w{2, 4}$/, "");
return { title, raw, content };
});
export default fetchMarkdown; export default fetchMarkdown;

View File

@ -20,6 +20,9 @@ import { html } from "./html.mjs";
import { isExternalUrl } from "./isExternalUrl.mjs"; import { isExternalUrl } from "./isExternalUrl.mjs";
import { isLocalHost } from "./isLocalHost.mjs"; import { isLocalHost } from "./isLocalHost.mjs";
import { isNotNull } from "./isNotNull.mjs"; import { isNotNull } from "./isNotNull.mjs";
import { markdownToMarkup } from "./markdownToMarkup.mjs";
import { markupToDom } from "./markupToDom.mjs";
import { memoize } from "./memoize.mjs";
import { not } from "./not.mjs"; import { not } from "./not.mjs";
import { import {
onDocumentKeyUp, onDocumentKeyUp,
@ -56,6 +59,9 @@ export {
isExternalUrl, isExternalUrl,
isLocalHost, isLocalHost,
isNotNull, isNotNull,
markdownToMarkup,
markupToDom,
memoize,
not, not,
onDocumentKeyUp, onDocumentKeyUp,
onDocumentKeyDown, onDocumentKeyDown,

View File

@ -0,0 +1,28 @@
//@ts-check
//@ts-ignore
import { micromark } from "https://esm.sh/micromark@3?bundle";
//@ts-ignore
import {frontmatter, frontmatterHtml} from 'https://esm.sh/micromark-extension-frontmatter@1?bundle'
//@ts-ignore
import Yaml from 'https://esm.sh/yaml@2?bundle'
/**
* Transforms a markup string into a valid markup.
* If there's a YAML frontmatter, will parse it too
* @param {string} markdownStr
* @returns
*/
export const markdownToMarkup = (markdownStr) => {
/** @type {string} */
const markup = micromark(markdownStr, {
extensions: [frontmatter()],
htmlExtensions: [frontmatterHtml()]
})
const header = Yaml.parseAllDocuments(markdownStr)[0]
/** @type {Record<string, unknown>} */
const frontMatter = header ? header.toJS() : {}
return { markup, frontMatter }
}
export default markdownToMarkup

View File

@ -0,0 +1,20 @@
//@ts-check
import { generateDomFromString } from "./generateDomFromString.mjs";
import { getFirstTitleContent } from "./getFirstTitleContent.mjs";
import { markdownToMarkup } from './markdownToMarkup.mjs';
/**
* Takes a markdown string and transforms it into dom that can be slotted in a
* document.
* Additionally, it parses the frontmatter, and attempts to extract a title
* by finding either the first title in the doc, or the filename (if provided).
* @param {string} markdownStr
* @param {string} [path] the file path
*/
export const markupToDom = (markdownStr, path = '') => {
const { frontMatter, markup } = markdownToMarkup(markdownStr);
const content = generateDomFromString(markup);
const title = getFirstTitleContent(content) || path.replace(/\.\w{2, 4}$/, "");
return { title, raw: markdownStr, content, frontMatter };
};

30
modules/utils/memoize.mjs Normal file
View File

@ -0,0 +1,30 @@
//@ts-check
/**
* Caches the result of a function.
* The cache is available as `.cache` in case there's a need to clear anything.
* @template {(...args: any[]) => any} T
* @param {T} functionToMemoize
* @returns
*/
export const memoize = (functionToMemoize) => {
/** @type {Map<Parameters<T>[0], ReturnType<T>>} */
const cache = new Map()
/**
*
* @param {Parameters<T>} args
* @returns {ReturnType<T>}
*/
const memoized = (...args) => {
const key = args[0]
if(!cache.has(key)){
cache.set(key, functionToMemoize(...args))
}
//@ts-ignore
return cache.get(key)
}
memoized.map = cache
return memoized
}
export default memoize