PageSourceSearch

https://carsandcrypto.io/mobile-navigation.js

js carsandcrypto.io collected 2026-10-02 01:57:17 UTC 5,858 bytes, 131 lines download raw bytes

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">&times;</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 &amp; 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.