// Typeahead for the search box. Rather than ship 3,500 item names to every visitor, the input asks // for the handful matching what has been typed and drops them into its . // // Not importing /common.module.js: that module binds to a #log element on load, which this page // does not have. const input = document.getElementById("q"); const names = document.getElementById("drop-names"); /** The request whose answer is still wanted; any earlier one is stale. */ let inFlight = null; if (input && names) { input.addEventListener("input", debounce(suggest, 150)); // Someone arriving on ?q=… already has a query typed; offer the list for it straight away. if (input.value.trim()) suggest(); } async function suggest() { const query = input.value.trim(); if (query.length < 2) { names.replaceChildren(); return; } // A slow response for "ni" must not overwrite the suggestions for "nikana p". inFlight?.abort(); const request = inFlight = new AbortController(); try { const response = await fetch(`/api/warframe/names?q=${encodeURIComponent(query)}`, {signal: request.signal}); if (!response.ok) return; const suggestions = await response.json(); names.replaceChildren(...suggestions.map(name => { const option = document.createElement("option"); option.value = name; return option; })); } catch (error) { // An abort is this function doing its job; any other failure just means no suggestions, // and the form still submits. if (error.name !== "AbortError") console.debug("suggest failed", error); } } function debounce(callback, wait) { let timeoutId = null; return (...args) => { window.clearTimeout(timeoutId); timeoutId = window.setTimeout(() => callback(...args), wait); }; }