1(function () { 2 'use strict'; 3 4 var APP_STORE_URL = 'https://apps.apple.com/app/id6757994357'; 5 var instanceCount = 0; 6 7 function init(root) { 8 if (!root || root.dataset.mobileNavigationReady === 'true') return; 9 root.dataset.mobileNavigationReady = 'true'; 10 instanceCount += 1; 11 12 var menuId = 'cc-mobile-menu-' + instanceCount; 13 root.innerHTML = 14 '<button class="cc-menu-trigger" type="button" aria-label="Open navigation menu" aria-expanded="false" aria-controls="' + menuId + '">' + 15 '<span class="cc-menu-icon" aria-hidden="true"><span></span><span></span><span></span></span>' + 16 '</button>' + 17 '<div class="cc-menu-layer" id="' + menuId + '" aria-hidden="true">' + 18 '<button class="cc-menu-backdrop" type="button" tabindex="-1" aria-label="Close navigation menu"></button>' + 19 '<div class="cc-menu-panel" role="dialog" aria-modal="true" aria-label="Navigation menu" tabindex="-1">' + 20 '<div class="cc-menu-heading"><span class="cc-menu-label">Navigate</span>' + 21 '<button class="cc-menu-close" type="button" aria-label="Close navigation menu"><span aria-hidden="true">×</span></button>' + 22 '</div>' + 23 '<nav class="cc-menu-links" aria-label="Mobile navigation">' + 24 '<a class="cc-menu-link" href="/">Home</a>' + 25 '<a class="cc-menu-link" href="/services">Services</a>' + 26 '<a class="cc-menu-link" href="/misc">Misc</a>' + 27 '<a class="cc-menu-link" href="/rentals">Rentals</a>' + 28 '<a class="cc-menu-link" href="/inventory">Browse Inventory</a>' + 29 '<a class="cc-menu-link" href="' + APP_STORE_URL + '" target="_blank" rel="noopener noreferrer">Download App</a>' + 30 '<a class="cc-menu-link" href="/contact">Contact</a>' + 31 '</nav>' + 32 '<p class="cc-menu-footnote">Cars & Crypto</p>' + 33 '</div>' + 34 '</div>'; 35 36 var trigger = root.querySelector('.cc-menu-trigger'); 37 var layer = root.querySelector('.cc-menu-layer'); 38 var panel = root.querySelector('.cc-menu-panel'); 39 var closeButton = root.querySelector('.cc-menu-close'); 40 var backdrop = root.querySelector('.cc-menu-backdrop'); 41 var links = Array.prototype.slice.call(root.querySelectorAll('.cc-menu-link')); 42 var previouslyFocused = null; 43 44 function focusableItems() { 45 return Array.prototype.slice.call(panel.querySelectorAll('a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"])')); 46 } 47 48 function openMenu() { 49 previouslyFocused = document.activeElement; 50 layer.classList.add('is-open'); 51 layer.setAttribute('aria-hidden', 'false'); 52 trigger.setAttribute('aria-expanded', 'true'); 53 document.body.classList.add('cc-menu-open'); 54 closeButton.focus(); 55 } 56 57 function closeMenu(restoreFocus) { 58 if (!layer.classList.contains('is-open')) return; 59 layer.classList.remove('is-open'); 60 layer.setAttribute('aria-hidden', 'true'); 61 trigger.setAttribute('aria-expanded', 'false'); 62 document.body.classList.remove('cc-menu-open'); 63 if (restoreFocus !== false && previouslyFocused && previouslyFocused.focus) previouslyFocused.focus(); 64 } 65 66 function onKeydown(event) { 67 if (!layer.classList.contains('is-open')) return; 68 if (event.key === 'Escape') { 69 event.preventDefault(); 70 closeMenu(true); 71 return; 72 } 73 if (event.key !== 'Tab') return; 74 var items = focusableItems(); 75 var first = items[0]; 76 var last = items[items.length - 1]; 77 if (event.shiftKey && document.activeElement === first) { 78 event.preventDefault(); 79 last.focus(); 80 } else if (!event.shiftKey && document.activeElement === last) { 81 event.preventDefault(); 82 first.focus(); 83 } 84 } 85 86 trigger.addEventListener('click', openMenu); 87 closeButton.addEventListener('click', function () { closeMenu(true); }); 88 backdrop.addEventListener('click', function () { closeMenu(true); }); 89 links.forEach(function (link) { 90 link.addEventListener('click', function (event) { 91 closeMenu(false); 92 93 // A page-level navigation handler may already own this click (the 94 // marketing homepage uses one to paint its loading cover first). 95 if (event.defaultPrevented) return; 96 97 // Always send internal menu links to their real Next.js route. Using 98 // an explicit hard navigation keeps this legacy shared menu outside 99 // React/Next's client-side link interception and avoids a transition 100 // getting stuck behind the loading overlay. 101 var href = link.getAttribute('href'); 102 if (!href || href.charAt(0) !== '/') return; 103 if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || event.button === 1) return; 104 event.preventDefault(); 105 106 // Let React commit the global loading cover and give the browser a 107 // full paint before beginning the hard navigation. 108 window.requestAnimationFrame(function () { 109 window.requestAnimationFrame(function () { 110 window.location.assign(href); 111 }); 112 }); 113 }); 114 }); 115 document.addEventListener('keydown', onKeydown); 116 window.addEventListener('resize', function () { 117 if (window.innerWidth > 1024) closeMenu(false); 118 }); 119 } 120 121 function initAll() { 122 // Auto-initialize only legacy/non-React markup. The Next.js SiteNav calls 123 // init itself from a React effect after hydration. 124 document.querySelectorAll('[data-mobile-navigation-auto]').forEach(init); 125 } 126 127 window.CarsCryptoMobileNavigation = { init: init, initAll: initAll }; 128 window.dispatchEvent(new Event('carscrypto:navigation-ready')); 129 if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', initAll); 130 else initAll(); 131})();
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.