PageSourceSearch

https://www.ndlalaarena.co.za/assets/nav-mobile.js

js ndlalaarena.co.za collected 2026-10-08 20:00:52 UTC 2,914 bytes, 66 lines download raw bytes

1/* ============================================================
2   Ndlala Arena — mobile menu
3
4   Under 820px the header used to be the desktop nav left to wrap: the brand on
5   its own line, then the links, and the Events dropdown forced open inline as a
6   static row. That row's four nights are wider than a phone, so the centred flex
7   line overflowed on both sides and cut "Events" off at the left edge.
8
9   So below 820px the links become a panel behind a button. There is no second
10   copy of the nav: this toggles the SAME <ul> the desktop uses, so a link added
11   to the header appears in both without being added twice.
12   ============================================================ */
13(function () {
14  'use strict';
15
16  var MQ = '(max-width:820px)';
17
18  function build(nav) {
19    var list = nav.querySelector('ul');
20    var right = nav.querySelector('.nav-right');
21    if (!list || nav.querySelector('.nav-burger')) return;
22
23    list.id = list.id || 'navmenu';
24
25    var btn = document.createElement('button');
26    btn.type = 'button';
27    btn.className = 'nav-burger';
28    btn.setAttribute('aria-label', 'Menu');
29    btn.setAttribute('aria-expanded', 'false');
30    btn.setAttribute('aria-controls', list.id);
31    // Lucide menu / x, from the icon set, not drawn here.
32    btn.innerHTML =
33      '<svg class="i-menu" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"' +
34      ' stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">' +
35      '<path d="M4 5h16"/><path d="M4 12h16"/><path d="M4 19h16"/></svg>
35' +
36      '<svg class="i-close" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"' +
37      ' stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">' +
38      '<path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>';
39
40    if (right) right.appendChild(btn); else nav.appendChild(btn);
41
42    function close() {
43      document.documentElement.classList.remove('nav-open');
44      btn.setAttribute('aria-expanded', 'false');
45    }
46    function toggle() {
47      var open = document.documentElement.classList.toggle('nav-open');
48      btn.setAttribute('aria-expanded', open ? 'true' : 'false');
49    }
50
51    btn.addEventListener('click', toggle);
52    // Following a link closes it. Same-page anchors do not reload, so nothing
53    // else would.
54    list.addEventListener('click', function (e) { if (e.target.closest('a')) close(); });
55    document.addEventListener('keydown', function (e) { if (e.key === 'Escape') close(); });
56    // Crossing back to the desktop layout with the panel open would leave
57    // html.nav-open set and the desktop nav styled by a rule meant for a panel.
58    try {
59      window.matchMedia(MQ).addEventListener('change', function (e) { if (!e.matches) close(); });
60    } catch (x) {}
61  }
62
63  document.addEventListener('DOMContentLoaded', function () {
64    document.querySelectorAll('.nav').forEach(build);
65  });
66})();

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.