// menu.js - menu system for small site - 2022 Viljami Ilola
const jsonURL = 'pages.json'
var conf = {}
var pages = {}
var currentPage = null;
loadPages = async() => {
await fetch( jsonURL )
.then( response => response.json() )
.then( json => conf = json )
.catch( error => {
document.body.innerHTML = `Error loading ${jsonURL}
${error}`
} )
pages = conf.pages
installHamburger()
createMenu()
createPlaceholders()
hashToPage()
}
createPlaceholders = () => {
pagesMain = document.createElement('main')
Object.keys(pages).forEach(p => {
if ( pages[p].URL && pages[p].URL !== "" ) {
const pageSection = document.createElement('section')
pageSection.id = `${p}_page`
pageSection.className='page'
pagesMain.appendChild( pageSection )
}
})
document.documentElement.lastChild.append( pagesMain )
}
createMenuIcon = (p) => {
const icon = pages[p].menuIcon ? pages[p].menuIcon : ''
if ( icon === '' ) return null
const iconImg = document.createElement('img')
iconImg.src = icon
const iconAnchor = document.createElement('a')
iconAnchor.href = `#${p}`
iconAnchor.appendChild( iconImg )
const iconDiv = document.createElement('div')
iconDiv.className = 'menuIcon'
iconDiv.appendChild( iconAnchor )
return iconDiv
}
createMenuText = (p) => {
const url = pages[p].URL ? pages[p].URL : ""
const name = pages[p].menuName ? pages[p].menuName : url
if ( name === '' ) return null
const textNode = document.createTextNode( name )
const textAnchor = document.createElement( url === "" ? 'div' : 'a')
textAnchor.href = `#${p}`
textAnchor.appendChild( textNode )
const textDiv = document.createElement('div')
textDiv.className = 'menuText'
textDiv.appendChild( textAnchor )
return textDiv
}
createMenu = () => {
const menuNav = document.createElement('nav')
menuNav.id = 'menu'
menuNav.className = 'menuHidden'
Object.keys(pages).forEach(p => {
const entryDiv = document.createElement('div')
entryDiv.className = 'menuItem'
entryDiv.id = `${p}_menuEntry`
const iconDiv = createMenuIcon(p)
const textDiv = createMenuText(p)
if ( iconDiv ) entryDiv.appendChild( iconDiv )
if ( textDiv ) entryDiv.appendChild( textDiv )
const url = pages[p].URL ? pages[p].URL : ""
const name = pages[p].menuName ? pages[p].menuName : url
if ( url === "" ) entryDiv.className +=
name === "" ? ' menuSpacer' : ' menuTitle'
else entryDiv.onclick = () => window.location.hash = p;
if ( pages[p].hidden ) entryDiv.style.display = 'none';
menuNav.append( entryDiv )
})
document.documentElement.lastChild.append( menuNav )
const spacerDiv = document.createElement('div')
spacerDiv.id = 'spaceBeforePage'
document.documentElement.lastChild.append( spacerDiv )
}
installHamburger = () => {
hamburgerDiv = document.createElement('div')
hamburgerDiv.id = 'hamburgerMenu'
hamburgerDiv.onclick = () => toggleMenu()
document.documentElement.lastChild.append( hamburgerDiv )
}
toggleMenu = () => {
const menuNav = document.getElementById('menu')
menuNav.className = menuNav.className === 'menuHidden' ? '' : 'menuHidden'
if (menuNav.className === '') window.scrollTo(0,0)
}
hashToPage = async () => {
const p = !document.location.hash
? Object.keys(pages)[0] : document.location.hash.substr(1) in pages
? document.location.hash.substr(1) : Object.keys(pages)[0]
if ( p === Object.keys(pages)[0] ) {
window.history.replaceState('', '', window.location.pathname)
}
if ( p === currentPage ) return false
const pageElement = document.getElementById(`${p}_page`)
if ( !currentPage ) currentPage = p;
else document.getElementById(`${currentPage}_page`).className = 'page'
pageElement.className = 'page pageActive'
if ( !pageElement.loaded ) await fetch( pages[p].URL )
.then( response => {
if (!response.ok) return `ERROR loading "${pages[p].URL}"!`
return response.text()
} )
.then( text => {
pageElement.innerHTML = text;
pageElement.loaded = true;
} )
if ( pageElement.innerHTML.startsWith("redirect = ") ) {
pageElement.loaded = false;
window.location.assign( pageElement.innerHTML.slice( 11 ) );
}
// https://plnkr.co/edit/MMegiu by Allen Kim
Array.from(pageElement.querySelectorAll("script")).forEach(oldScript => {
const newScript = document.createElement("script");
Array.from(oldScript.attributes).forEach(attr =>
newScript.setAttribute(attr.name, attr.value));
newScript.appendChild(document.createTextNode(oldScript.innerHTML));
oldScript.parentNode.replaceChild(newScript, oldScript);
});
document.getElementById(`${currentPage}_menuEntry`)
.className = 'menuItem'
document.getElementById(`${p}_menuEntry`)
.className = 'menuItem menuItemActive'
currentPage = p
if (!pages[p].pageTitle) document.title = conf.title
else document.title = `${pages[p].pageTitle} - ${conf.title}`
}
hideMenu = () => document.getElementById('menu').className = 'menuHidden';
window.onload = async() => {
loadPages()
}
window.onhashchange = () => {
hideMenu()
hashToPage()
}