1(function () { 2 var btn = document.getElementById('nav-toggle'); 3 var nav = document.getElementById('site-nav'); 4 var backdrop = document.getElementById('nav-backdrop'); 5 if (!btn || !nav) return; 6 var labelOpen = btn.getAttribute('data-aria-label-open') || 'Open menu'; 7 var labelClose = btn.getAttribute('data-aria-label-close') || 'Close menu'; 8 function setMenuAria(open) { 9 btn.setAttribute('aria-expanded', open ? 'true' : 'false'); 10 btn.setAttribute('aria-label', open ? labelClose : labelOpen); 11 } 12 function setMenuOpen(open) { 13 nav.classList.toggle('open', open); 14 btn.classList.toggle('open', open); 15 setMenuAria(open); 16 if (backdrop) { 17 backdrop.hidden = !open; 18 backdrop.setAttribute('aria-hidden', open ? 'false' : 'true'); 19 document.body.classList.toggle('nav-menu-open', open); 20 } 21 if (open) { 22 nav.querySelectorAll('.nav-dropdown').forEach(function (drop) { 23 drop.classList.add('is-open'); 24 var toggle = drop.querySelector('.nav-dropdown__toggle'); 25 if (toggle) toggle.setAttribute('aria-expanded', 'true'); 26 }); 27 } 28 } 29 btn.addEventListener('click', function () { 30 setMenuOpen(!nav.classList.contains('open')); 31 }); 32 if (backdrop) { 33 backdrop.addEventListener('click', function () { 34 setMenuOpen(false); 35 }); 36 } 37 document.addEventListener('click', function (e) { 38 if (!nav.classList.contains('open')) return; 39 if (btn.contains(e.target) || nav.contains(e.target)) return; 40 if (backdrop && backdrop.contains(e.target)) return; 41 setMenuOpen(false); 42 }); 43})(); 44(function () { 45 var wrap = document.getElementById('nav-search-wrap'); 46 var input = document.getElementById('nav-game-search'); 47 var list = document.getElementById('nav-search-listbox'); 48 if (!wrap || !input || !list) return; 49 var noResults = wrap.getAttribute('data-no-results') || 'No matching games'; 50 var allGames = []; 51 var loaded = false; 52 var loadTimer = null; 53 function loadData(cb) { 54 if (loaded) { 55 cb(); 56 return; 57 } 58 fetch('/data/games.json', { credentials: 'same-origin' }) 59 .then(function (r) { 60 return r.ok ? r.json() : Promise.reject(); 61 }) 62 .then(function (data) { 63 allGames = data && Array.isArray(data.games) ? data.games : []; 64 loaded = true; 65 cb(); 66 }) 67 .catch(function () { 68 allGames = []; 69 loaded = true; 70 cb(); 71 }); 72 } 73 function norm(s) { 74 return String(s || '').toLowerCase(); 75 } 76 function showDropdown(show) { 77 list.hidden = !show; 78 input.setAttribute('aria-expanded', show ? 'true' : 'false'); 79 } 80 window.SpaceWavesSearchClose = function () { 81 list.innerHTML = ''; 82 showDropdown(false); 83 }; 84 function fillList(hits) { 85 list.innerHTML = ''; 86 hits.forEach(function (g) { 87 var a = document.createElement('a'); 88 a.className = 'nav-search__opt'; 89 a.href = g.url || '#'; 90 a.setAttribute('role', 'option'); 91 var img = document.createElement('img'); 92 img.src = g.image || ''; 93 img.alt = ''; 94 img.width = 28; 95 img.height = 28; 96 img.loading = 'lazy'; 97 var span = document.createElement('span'); 98 span.textContent = g.name || g.slug || ''; 99 a.appendChild(img); 100 a.appendChild(span); 101 list.appendChild(a); 102 }); 103 } 104 function updatePanel() { 105 var q = norm(input.value).trim(); 106 loadData(function () { 107 var hits; 108 if (q.length < 1) { 109 hits = allGames; 110 } else { 111 hits = allGames 112 .filter(function (g) { 113 return norm(g.name).indexOf(q) >= 0 || norm(g.slug).indexOf(q.replace(/\s+/g, '-')) >= 0; 114 }) 115 .slice(0, 14); 116 } 117 if (q.length >= 1 && !hits.length) { 118 list.innerHTML = ''; 119 var empty = document.createElement('div'); 120 empty.className = 'nav-search__empty'; 121 empty.textContent = noResults; 122 list.appendChild(empty); 123 showDropdown(true); 124 return; 125 } 126 if (!hits.length) { 127 list.innerHTML = ''; 128 showDropdown(false); 129 return; 130 } 131 fillList(hits); 132 showDropdown(true); 133 }); 134 } 135 function debounceUpdate() { 136 clearTimeout(loadTimer); 137 loadTimer = setTimeout(updatePanel, 100); 138 } 139 input.addEventListener('input', debounceUpdate); 140 input.addEventListener('focus', function () { 141 updatePanel(); 142 }); 143 input.addEventListener('click', function () { 144 updatePanel(); 145 }); 146 document.addEventListener('click', function (e) { 147 if (!wrap.contains(e.target)) { 148 list.innerHTML = ''; 149 showDropdown(false); 150 } 151 }); 152 input.addEventListener('keydown', function (e) { 153 if (e.key === 'Escape') { 154 list.innerHTML = ''; 155 showDropdown(false); 156 input.blur(); 157 } 158 }); 159})(); 160(function () { 161 var nav = document.getElementById('site-nav'); 162 if (!nav) return; 163 var path = (location.pathname || '/').replace(/\/index\.html$/i, '/').toLowerCase(); 164 if (path.length >
164 1 && path.charAt(path.length - 1) === '/') { 165 path = path.slice(0, -1); 166 } 167 var langRoots = ['pt-br', 'nl', 'sv', 'es', 'fr', 'de']; 168 var i; 169 for (i = 0; i < langRoots.length; i++) { 170 var root = '/' + langRoots[i]; 171 if (path === root) { 172 path = '/'; 173 break; 174 } 175 if (path.indexOf(root + '/') === 0) { 176 path = path.slice(root.length) || '/'; 177 break; 178 } 179 } 180 var links = nav.querySelectorAll('.nav-link'); 181 var best = null; 182 var bestLen = -1; 183 links.forEach(function (a) { 184 var href = (a.getAttribute('href') || '').split('?')[0].split('#')[0].toLowerCase(); 185 if (!href) return; 186 if (href.length > 1 && href.charAt(href.length - 1) === '/') { 187 href = href.slice(0, -1); 188 } 189 var extra = (a.getAttribute('data-nav-match') || '').split(','); 190 var matched = false; 191 if (href === '/') { 192 matched = path === '/'; 193 } else { 194 matched = path === href || path.indexOf(href + '/') === 0; 195 } 196 extra.forEach(function (raw) { 197 var m = String(raw || '').trim().toLowerCase(); 198 if (!m) return; 199 if (m.length > 1 && m.charAt(m.length - 1) === '/') m = m.slice(0, -1); 200 if (path === m || path.indexOf(m + '/') === 0) matched = true; 201 }); 202 if (matched && href.length > bestLen) { 203 best = a; 204 bestLen = href.length; 205 } 206 }); 207 if (best) { 208 links.forEach(function (a) { 209 a.classList.remove('active'); 210 a.removeAttribute('aria-current'); 211 }); 212 best.classList.add('active'); 213 best.setAttribute('aria-current', 'page'); 214 } 215 nav.querySelectorAll('.nav-dropdown__item[href]').forEach(function (item) { 216 var href = (item.getAttribute('href') || '').replace(/\/+$/, '') || '/'; 217 var onItem = path === href || path.indexOf(href + '/') === 0; 218 item.classList.toggle('is-active', onItem); 219 if (onItem) item.setAttribute('aria-current', 'page'); 220 else item.removeAttribute('aria-current'); 221 }); 222})(); 223(function () { 224 function isHoverDevice() { 225 try { 226 return window.matchMedia('(hover: hover) and (pointer: fine)').matches; 227 } catch (e) { 228 return true; 229 } 230 } 231 document.querySelectorAll('.nav-dropdown').forEach(function (drop) { 232 var toggle = drop.querySelector('.nav-dropdown__toggle'); 233 var trigger = drop.querySelector('.nav-dropdown__trigger'); 234 function setOpen(open) { 235 drop.classList.toggle('is-open', !!open); 236 if (toggle) toggle.setAttribute('aria-expanded', open ? 'true' : 'false'); 237 } 238 function flip(e) { 239 e.preventDefault(); 240 e.stopPropagation(); 241 setOpen(!drop.classList.contains('is-open')); 242 if (toggle) toggle.blur(); 243 } 244 if (toggle) toggle.addEventListener('click', flip); 245 // More Games has no link: clicking the label also toggles the menu 246 if (trigger && trigger.tagName !== 'A') { 247 trigger.addEventListener('click', flip); 248 trigger.style.cursor = 'pointer'; 249 } 250 drop.addEventListener('mouseenter', function () { 251 if (!isHoverDevice()) return; 252 setOpen(true); 253 }); 254 drop.addEventListener('mouseleave', function () { 255 if (!isHoverDevice()) return; 256 setOpen(false); 257 }); 258 }); 259})();
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.