PageSourceSearch

https://www.johnbward.com/scripts/site-nav.js

js johnbward.com collected 2026-10-07 22:47:57 UTC 1,977 bytes, 65 lines download raw bytes

1/** Off-canvas menu open/close (no Bricks/jQuery). */
2(function () {
3	function init() {
4		var panel = document.querySelector('[data-nav-panel]');
5		var openBtn = document.querySelector('[data-nav-open]');
6		if (!panel || !openBtn) return;
7
8		var closers = panel.querySelectorAll('[data-nav-close]');
9		var scroller = panel.querySelector('.jbw-menu__panel') || panel;
10		var jumps = panel.querySelectorAll('[data-nav-scroll]');
11
12		function open() {
13			panel.hidden = false;
14			// Force reflow so the transition runs from the hidden state.
15			void panel.offsetWidth;
16			panel.classList.add('is-open');
17			document.body.classList.add('menu-open');
18			openBtn.setAttribute('aria-expanded', 'true');
19			scroller.scrollTop = 0;
20		}
21
22		function close() {
23			panel.classList.remove('is-open');
24			document.body.classList.remove('menu-open');
25			openBtn.setAttribute('aria-expanded', 'false');
26			setTimeout(function () {
27				panel.hidden = true;
28			}, 500);
29		}
30
31		function scrollToSection(id) {
32			var target = document.getElementById(id);
33			if (!target || !scroller.contains(target)) return;
34
35			var scrollerRect = scroller.getBoundingClientRect();
36			var targetRect = target.getBoundingClientRect();
37			var nextTop = scroller.scrollTop + (targetRect.top - scrollerRect.top);
38
39			if (typeof scroller.scrollTo === 'function') {
40				scroller.scrollTo({ top: nextTop, behavior: 'smooth' });
41			} else {
42				scroller.scrollTop = nextTop;
43			}
44		}
45
46		openBtn.addEventListener('click', open);
47		closers.forEach(function (el) {
48			el.addEventListener('click', close);
49		});
50		jumps.forEach(function (btn) {
51			btn.addEventListener('click', function () {
52				scrollToSection(btn.getAttribute('data-nav-scroll'));
53			});
54		});
55		document.addEventListener('keydown', function (e) {
56			if (e.key === 'Escape' && panel.classList.contains('is-open')) close();
57		});
58	}
59
60	if (document.readyState === 'loading') {
61		document.addEventListener('DOMContentLoaded', init);
62	} else {
63		init();
64	}
65})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.