Basic router functionality

This commit is contained in:
Patrick Elmer 2022-02-01 18:34:44 +09:00
commit 243217334a
3 changed files with 164 additions and 0 deletions

11
index.html Normal file
View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Router</title>
</head>
<body id="router">
</body>
</html>

1
pages/index.html Normal file
View File

@ -0,0 +1 @@
<h1>Index</h1>

152
router.js Normal file
View File

@ -0,0 +1,152 @@
const router = document.querySelector("#router")
const path = typeof router.getAttribute('dir') === 'string' ? router.getAttribute('dir') : 'pages'
const page_404 = `
<h1>404</h1>
<p>Page not found</p>
`
window.addEventListener("DOMContentLoaded", onRouteChange)
window.addEventListener("hashchange", onRouteChange)
async function checkPath(link) {
let response = await fetch(link)
return !(response.status === 404)
}
function getPathname() {
let pathname = window.location.pathname
if (pathname.endsWith("index.html")) {
pathname = pathname.substring(0, pathname.length - 10)
}
return pathname
}
function onRouteChange() {
let hashLocation
if (window.location.hash.substring(1, 2) == "/") {
hashLocation = window.location.hash.substring(2)
} else {
hashLocation = window.location.hash.substring(1)
}
if (!hashLocation) {
hashLocation = "index"
}
loadContent(hashLocation)
}
async function loadContent(uri) {
if (!(await fetchData(`${path}/${uri}.html`))) {
updatePage(page_404)
}
}
async function fetchData(link) {
let response = await fetch(link)
if (!response.ok) { return false }
let content = await response.text()
// Get <style> tag from content
const styleStart = content.indexOf("<style>\n")
let styleText
if (styleStart !== -1) {
const styleEnd = content.indexOf("</style>", styleStart + 8)
styleText = content.substring(styleStart + 8, styleEnd)
content = content.replace("<style>\n" + styleText + "</style>", "")
}
// Get <script> tag from content
const scriptStart = content.indexOf("<script>\n")
let scriptText
if (scriptStart !== -1) {
const scriptEnd = content.indexOf("</script>", scriptStart + 9)
scriptText = content.substring(scriptStart + 9, scriptEnd)
content = content.replace("<script>\n" + scriptText + "</script>", "")
}
// Get all linked stylesheets
const links = content.match(/<link[^>]+>/g) || ""
if (links) {
links.forEach((link) => {
let href = link.match(/href=".*"/g)
if (href.length === 0) {
return
}
href = href[0]
if (href.length === 7) {
return
}
const newLink = document.createElement("link")
newLink.href = href.substring(6, href.length - 1)
newLink.rel = "stylesheet"
router.appendChild(newLink)
content.replace(link, "")
})
}
// Get all script tags with src attribute
const scripts = content.match(/<script[^>]+>[^>]*>/g) || ""
if (scripts) {
scripts.forEach((script) => {
const src = script.match(/src=".*"/g)[0]
if (src.length === 6) {
return
}
const newScript = document.createElement("script")
newScript.src = src.substring(5, src.length - 1)
router.appendChild(newScript)
content.replace(script, "")
})
}
updatePage(content, styleText, scriptText)
return true
}
function updatePage(content, styleText='', scriptText='') {
removeStyle()
removeScript()
router.innerHTML = ""
router.insertAdjacentHTML("afterbegin", content)
if (styleText.length != 0) { injectStyle(styleText) }
if (scriptText.length != 0) { injectScript(scriptText) }
}
// Dynamically inject <script>
function injectScript(scriptText) {
var script = document.createElement("script")
script.text = scriptText
document.body.appendChild(script)
}
function removeScript() {
const scripts = [...document.querySelectorAll("script")].filter(
(script) => !script.src
)
let counter = 0
scripts.forEach((script) => {
counter++
if (counter !== scripts.length) {
script.remove()
}
})
}
// Dynamically inject <style>
function injectStyle(styleText) {
var style = document.createElement("style")
style.innerHTML = styleText
document.head.appendChild(style)
}
function removeStyle() {
let counter = 0
const styles = document.querySelectorAll("style")
styles.forEach((style) => {
counter++
if (counter !== styles.length) {
style.remove()
}
})
}