router/router.js

152 lines
4.2 KiB
JavaScript

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()
}
})
}