← back to Nationalrealestate
public/nav-drawer.js
83 lines
/* nav-drawer.js — turns the page's #topbar into an upper-left hamburger drawer.
* It MOVES the topbar's existing child nodes into the drawer (same DOM nodes), so
* every id and event binding is preserved and page scripts that populate #metrics /
* wire #typeSeg keep working. Include on any page that has a <div id="topbar">. */
(function () {
function init() {
if (document.getElementById('navBurger')) return; // idempotent
var bar = document.getElementById('topbar');
var burger = document.createElement('button');
burger.id = 'navBurger';
burger.type = 'button';
burger.setAttribute('aria-label', 'Menu');
burger.setAttribute('aria-expanded', 'false');
burger.textContent = '☰'; // ☰
var backdrop = document.createElement('div');
backdrop.id = 'navBackdrop';
var drawer = document.createElement('div');
drawer.id = 'navDrawer';
var body = document.createElement('div');
body.id = 'navDrawerBody';
drawer.appendChild(body);
// Relocate the whole topbar into the drawer (preserve nodes/ids/bindings).
if (bar) {
while (bar.firstChild) body.appendChild(bar.firstChild);
bar.parentNode && bar.parentNode.removeChild(bar);
}
// Canonical nav — render one identical link set on every page (marks the
// current page active by URL) so the nav never drifts page-to-page.
var NAV = [
['/', 'Map'], ['/markets.html', 'Markets'], ['/commercial.html', 'Commercial'],
['/compare.html', 'Compare'], ['/brokers.html', 'Brokers'], ['/sources.html', 'Sources'],
['/watchlist.html', 'Watchlist'], ['/admin.html', 'Admin']
];
var here = location.pathname.replace(/\/index\.html$/, '/');
var nav = body.querySelector('nav');
if (!nav) {
nav = document.createElement('nav');
var brand = body.querySelector('.brand');
if (brand && brand.nextSibling) body.insertBefore(nav, brand.nextSibling);
else body.insertBefore(nav, body.firstChild);
}
nav.innerHTML = NAV.map(function (x) {
var active = x[0] === here || (x[0] === '/' && (here === '' || here === '/'));
return '<a href="' + x[0] + '"' + (active ? ' class="active"' : '') + '>' + x[1] + '</a>';
}).join('');
document.body.appendChild(backdrop);
document.body.appendChild(drawer);
document.body.appendChild(burger);
// Clearance so the fixed hamburger never sits on top of page content.
// Grid pages clear it via .cg-rail padding (see nav-drawer.css); normal
// flow-layout pages get body top-padding. The absolute map has no .cg-shell
// and is out of flow, so the padding is harmless there.
if (!document.querySelector('.cg-shell')) document.body.classList.add('navdz-pad');
function open() {
drawer.classList.add('open'); backdrop.classList.add('open'); burger.classList.add('open');
burger.textContent = '✕'; // ✕
burger.setAttribute('aria-expanded', 'true');
}
function close() {
drawer.classList.remove('open'); backdrop.classList.remove('open'); burger.classList.remove('open');
burger.textContent = '☰';
burger.setAttribute('aria-expanded', 'false');
}
burger.addEventListener('click', function () {
drawer.classList.contains('open') ? close() : open();
});
backdrop.addEventListener('click', close);
// clicking a nav link navigates away — close so it isn't left open on the next page
body.addEventListener('click', function (e) { if (e.target.closest('nav a')) close(); });
document.addEventListener('keydown', function (e) { if (e.key === 'Escape') close(); });
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
else init();
})();