1import{Controller}from"@hotwired/stimulus";const MIN_QUERY_LENGTH=2,DEBOUNCE_MS=200;export default class extends Controller{static targets=["input","results","resultsContainer","status"];static values={location:{type:String,default:""},endpoint:{type:String,default:"/autocomplete/school"},usOnly:{type:Boolean,default:!1}};connect(){this.debounceTimer=null,this.activeIndex=-1,this.currentOrganizations=[]}disconnect(){clearTimeout(this.debounceTimer)}updateLocation(t){this.locationValue=t}onInput(){clearTimeout(this.debounceTimer);const t=this.inputTarget.value.trim();t.length<MIN_QUERY_LENGTH?this.clearResults():this.debounceTimer=setTimeout(()=>this.search(t),DEBOUNCE_MS)}onKeydown(t){switch(t.key){case"ArrowDown":this.hasResults()&&(t.preventDefault(),this.moveActive(1));break;case"ArrowUp":this.hasResults()&&(t.preventDefault(),this.moveActive(-1));break;case"Enter":this.activeIndex>=0&&(t.preventDefault(),this.selectActive());break;case"Escape":this.clearResults()}}onBlur(){setTimeout(()=>this.clearResults(),150)}async search(t){const e=new URLSearchParams({q:t,location:this.locationValue});this.usOnlyValue&&e.set("us_only","true");try{const t=await fetch(`${this.endpointValue}?${e}`);if(!t.ok)throw new Error(`Unexpected status ${t.status}`);const s=await t.json();this.renderResults(s.results||[])}catch(t){console.error("OrganizationSearch: search failed",t),this.clearResults()}}renderResults(t){if(this.currentOrganizations=t,this.activeIndex=-1,this.resultsTarget.innerHTML="",0===t.length)return this.hideResults(),void this.announce("No results found");t.forEach((t,e)=>this.resultsTarget.appendChild(this.buildResultItem(t,e))),this.showResults(),this.announce(`${t.length} result${1===t.length?"":"s"} found`)}buildResultItem(t,e){const s=document.createElement("li");if(s.id=`${this.resultsTarget.id}-option-${e}`,s.className="mds-organization-search-organization-search-result",s.setAttribute("role","option"),s.setAttribute("aria-selected","false"),s.textContent=t.name,t.type){const e=document.createElement("span");e.className="mds-organization-search-organization-search-result-badge",e.textContent="district"===t.type?"District":"School",s.appendChild(e)}const i=document.createElement("span");return i.className="mds-organization-search-organization-search-result-meta",i.textContent=[t.city,t.state,t.country].filter(Boolean).join(", "),s.appendChild(i),s.addEventListener("mousedown",e=>{e.preventDefault(),this.select(t)}),s}hasResults(){return this.resultsTarget.children.length>0}moveActive(t){const e=Array.from(this.resultsTarget.children);0!==e.length&&(this.activeIndex=(this.activeIndex+t+e.length)%e.length,this.highlightActive(e))}highlightActive(t=Array.from(this.resultsTarget.children)){t.forEach((t,e)=>{const s=e===this.activeIndex;t.classList.toggle("active",s),t.setAttribute("aria-selected",s?"true":"false")});const e=t[this.activeIndex];e?(this.inputTarget.setAttribute("aria-activedescendant",e.id),e.scrollIntoView({block:"nearest"})):this.inputTarget.removeAttribute("aria-activedescendant")}selectActive(){const t=this.currentOrganizations[this.activeIndex];t&&this.select(t)}select(t){this.inputTarget.value=t.name,this.clearResults(),this.dispatch("selected",{detail:{organization:t}})}clearResults(){this.currentOrganizations=[],this.resultsTarget.innerHTML="",this.hideResults(),this.announce("")}reset(){this.inputTarget.value="",this.clearResults()}showResults(){this.resultsContainerTarget.classList.remove("hidden"),this.inputTarget.setAttribute("aria-expanded","true")}hideResults(){this.resultsContainerTarget.classList.add("hidden"),this.inputTarget.setAttribute("aria-expanded","false"),this.inputTarget.removeAttribute("aria-activedescendant"),this.activeIndex=-1}announce(t){this.hasStatusTarget&&(this.statusTarget.textContent=t)}}
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.