1/** 2 * RallyTrain theme: mobile navigation drawer. 3 * 4 * Turns the primary nav into an off-canvas drawer (slides in from the right) 5 * with a full-screen backdrop. Closes on the â button, an overlay/outside 6 * click, Escape, or a nav-link click. Progressive enhancement: if this script 7 * doesn't load the toggle simply does nothing. 8 */ 9(function () { 10 'use strict'; 11 12 document.addEventListener('DOMContentLoaded', function () { 13 var toggle = document.querySelector('.rt-menu-toggle'); 14 var nav = document.getElementById('rt-primary-nav'); 15 var overlay = document.querySelector('.rt-nav-overlay'); 16 var closeBtn = nav ? nav.querySelector('.rt-nav-close') : null; 17 18 if (!toggle || !nav) { 19 return; 20 } 21 22 function isOpen() { 23 return nav.classList.contains('is-open'); 24 } 25 26 function open() { 27 nav.classList.add('is-open'); 28 if (overlay) { 29 overlay.classList.add('is-open'); 30 } 31 document.body.classList.add('rt-nav-open'); 32 toggle.setAttribute('aria-expanded', 'true'); 33 if (closeBtn) { 34 closeBtn.focus({ preventScroll: true }); 35 } 36 } 37 38 function close() { 39 nav.classList.remove('is-open'); 40 if (overlay) { 41 overlay.classList.remove('is-open'); 42 } 43 document.body.classList.remove('rt-nav-open'); 44 toggle.setAttribute('aria-expanded', 'false'); 45 toggle.focus({ preventScroll: true }); 46 // Collapsed-submenu mode: a reopened drawer starts tidy. 47 nav.querySelectorAll('.rt-submenu-open').forEach(function (li) { 48 li.classList.remove('rt-submenu-open'); 49 var btn = li.querySelector(':scope > .rt-submenu-toggle'); 50 if (btn) { 51 btn.setAttribute('aria-expanded', 'false'); 52 } 53 }); 54 } 55 56 toggle.addEventListener('click', function () { 57 if (isOpen()) { 58 close(); 59 } else { 60 open(); 61 } 62 }); 63 64 if (overlay) { 65 overlay.addEventListener('click', close); 66 } 67 if (closeBtn) { 68 closeBtn.addEventListener('click', close); 69 } 70 71 document.addEventListener('keydown', function (e) { 72 if (e.key === 'Escape' && isOpen()) { 73 close(); 74 } 75 }); 76 77 // Clicks inside the drawer. A parent that owns a submenu is a TOGGLE 78 // there, never a link: every parent has a child that goes where the 79 // parent used to, and a mis-tap navigating away mid-browse was the 80 // complaint. Ordinary links still navigate and close the drawer. 81 nav.addEventListener('click', function (e) { 82 var a = e.target && e.target.closest ? e.target.closest('a') : null; 83 if (!a) { 84 return; 85 } 86 var li = a.parentElement; 87 if (isOpen() && li && li.classList.contains('menu-item-has-children')) { 88 e.preventDefault(); 89 if (document.body.classList.contains('rt-mobile-submenus-closed')) { 90 var open = li.classList.toggle('rt-submenu-open'); 91 var btn = li.querySelector(':scope > .rt-submenu-toggle'); 92 if (btn) { 93 btn.setAttribute('aria-expanded', open ? 'true' : 'false'); 94 } 95 } 96 return; 97 } 98 close(); 99 }); 100 101 // Collapsed-submenu mode (body class printed by the plugin when the 102 // site's Mobile menu setting is "closed"): give every parent item a 103 // real toggle button. The parent link keeps navigating; only the 104 // button expands. Buttons are display:none outside the drawer. 105 if (document.body.classList.contains('rt-mobile-submenus-closed')) { 106 nav.querySelectorAll('.menu-item-has-children').forEach(function (li) { 107 var btn = document.createElement('button'); 108 btn.type = 'button'; 109 btn.className = 'rt-submenu-toggle'; 110 btn.setAttribute('aria-expanded', 'false'); 111 btn.setAttribute('aria-label', 'Toggle submenu'); 112 btn.addEventListener('click', function (e) { 113 e.stopPropagation(); 114 var open = li.classList.toggle('rt-submenu-open'); 115 btn.setAttribute('aria-expanded', open ? 'true' : 'false'); 116 }); 117 li.insertBefore(btn, li.querySelector(':scope > ul')); 118 }); 119 } 120 121 // Suppress drawer transitions while the window is resizing, so the drawer 122 // doesn't animate into view when crossing the mobile breakpoint. 123 var resizeTimer; 124 window.addEventListener('resize', function () { 125 document.documentElement.classList.add('rt-resizing'); 126 clearTimeout(resizeTimer); 127 resizeTimer = setTimeout(function () { 128 document.documentElement.classList.remove('rt-resizing'); 129 }, 200); 130 }); 131 }); 132})(); 133 134/* External links open in a new tab, site-wide. Content authors never have to 135 remember target="_blank"; internal links are untouched. */ 136document.addEventListener('DOMContentLoaded', function () { 137 document.querySelectorAll('a[href^="http"]').forEach(function (a) { 138 if (a.host && a.host !== window.location.host) { 139 a.target = '_blank';
140 if (!/\bnoopener\b/.test(a.rel)) { 141 a.rel = (a.rel ? a.rel + ' ' : '') + 'noopener'; 142 } 143 } 144 }); 145});
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.