(function() { var input = document.getElementById('wiz-category'); var dropdown = document.getElementById('category-dropdown'); if (!input || !dropdown) return; // The wait between keystrokes and the search is `Intent::Debounce`, spent // through the shared helper on the core module. It used to be a 200ms // timeout hand-rolled here, which was this typeahead disagreeing with the // docs search for no reason anyone recorded. var SEARCH = 'category-search'; function showDropdown(items, query) { dropdown.innerHTML = ''; items.forEach(function(c) { var div = document.createElement('div'); div.className = 'suggestion-item'; div.textContent = c.name; div.addEventListener('mousedown', function(e) { e.preventDefault(); input.value = c.name; dropdown.classList.remove('open'); }); dropdown.appendChild(div); }); var q = query.trim(); if (q.length > 0 && !items.some(function(c) { return c.name.toLowerCase() === q.toLowerCase(); })) { var create = document.createElement('div'); create.className = 'suggestion-item suggestion-create'; create.textContent = 'Create: ' + q; create.addEventListener('mousedown', function(e) { e.preventDefault(); input.value = q; dropdown.classList.remove('open'); }); dropdown.appendChild(create); } if (dropdown.children.length > 0) { dropdown.classList.add('open'); } else { dropdown.classList.remove('open'); } } input.addEventListener('input', function() { var q = input.value.trim(); if (q.length < 1) { window.timing.cancelDebounce(SEARCH); dropdown.classList.remove('open'); return; } window.timing.debounce(SEARCH, function() { fetch('/api/categories/search?q=' + encodeURIComponent(q)) .then(function(r) { return r.json(); }) .then(function(cats) { showDropdown(cats, q); }) .catch(function() {}); }); }); input.addEventListener('focus', function() { if (dropdown.children.length > 0) dropdown.classList.add('open'); }); input.addEventListener('blur', function() { // Not a timing intent: the dropdown has to outlive the blur long enough // for a mousedown on one of its rows to land. A race, so it keeps its // own number. setTimeout(function() { dropdown.classList.remove('open'); }, 150); }); // AI tier toggle document.querySelectorAll('input[name="ai_tier"]').forEach(function(r) { r.addEventListener('change', function() { var group = document.getElementById('ai-disclosure-group'); group.classList.toggle('hidden', this.value !== 'assisted'); }); }); })();