(function(){ function makeCS2(select, {allowAdd=false}={}) { select.classList.add('cs2-hide'); const wrap=document.createElement('div'); wrap.className='cs2-wrap'; select.parentNode.insertBefore(wrap, select); wrap.appendChild(select); // UI const box=document.createElement('div'); box.className='cs2-selected'; const place=document.createElement('span'); place.className='cs2-placeholder'; place.textContent=select.dataset.placeholder||'Select'; const caret=document.createElement('span'); caret.className='cs2-caret'; caret.innerHTML='▾'; box.appendChild(place); box.appendChild(caret); const dd=document.createElement('div'); dd.className='cs2-dropdown'; dd.style.display='none'; const search=document.createElement('div'); search.className='cs2-search'; const input=document.createElement('input'); input.type='text'; input.placeholder='Search...'; search.appendChild(input); const list=document.createElement('div'); list.className='cs2-list'; dd.appendChild(search); dd.appendChild(list); wrap.appendChild(box); wrap.appendChild(dd); const isMultiple=select.multiple; function currentValues(){ return Array.from(select.options).filter(o=>o.selected).map(o=>o.value); } function renderChips(){ box.querySelectorAll('.cs2-chip').forEach(n=>n.remove()); const vals=currentValues(); if(!isMultiple && vals.length===0) place.style.display=''; else place.style.display='none'; if(isMultiple){ vals.forEach(v=>{ const opt=Array.from(select.options).find(o=>o.value===v); if(!opt) return; const chip=document.createElement('span'); chip.className='cs2-chip'; chip.innerHTML = `${opt.text} ×`; chip.querySelector('b').onclick=(e)=>{ e.stopPropagation(); setSelected(v,false); }; box.insertBefore(chip, caret); }); }else{ const v=vals[0]; const text=v ? (Array.from(select.options).find(o=>o.value===v)||{}).text : ''; box.querySelectorAll('.cs2-value').forEach(n=>n.remove()); if(text){ const span=document.createElement('span'); span.className='cs2-value'; span.textContent=text; box.insertBefore(span, caret); }else{ place.style.display=''; } } } function setSelected(value, sel){ const opt=Array.from(select.options).find(o=>o.value===value); if(!opt) return; if(isMultiple){ opt.selected=sel; }else{ Array.from(select.options).forEach(o=>o.selected=false); opt.selected=sel; dd.style.display='none'; } select.dispatchEvent(new Event('change', {bubbles:true})); renderOptions(); renderChips(); } function addOptionIfNeeded(text){ if(!allowAdd || !text) return null; const exists=Array.from(select.options).some(o=>o.text.toLowerCase()===text.toLowerCase()); if(exists) return null; const value='__new__'+Math.random().toString(36).slice(2); const o=new Option(text, value, true, true); select.add(o); return o; } function renderOptions(filter=''){ list.innerHTML=''; const opts=Array.from(select.options).filter(o=>o.value!=='' || select.multiple); const f=filter.trim().toLowerCase(); const matches=opts.filter(o=>o.text.toLowerCase().includes(f)); if(matches.length===0){ const nr=document.createElement('div'); nr.className='cs2-nores'; nr.textContent= allowAdd && f ? `No results. Press Enter to add "${filter}"` : 'No results'; list.appendChild(nr); }else{ matches.forEach(o=>{ const row=document.createElement('div'); row.className='cs2-opt'+(o.selected?' selected':''); row.textContent=o.text; row.onclick=(e)=>{ if(isMultiple) setSelected(o.value, !o.selected); else setSelected(o.value, true); }; list.appendChild(row); }); } let idx=-1; function move(delta){ const items=Array.from(list.querySelectorAll('.cs2-opt')); if(!items.length) return; idx=(idx+delta+items.length)%items.length; items.forEach(i=>i.classList.remove('active')); items[idx].classList.add('active'); items[idx].scrollIntoView({block:'nearest'}); } input.onkeydown=(e)=>{ if(e.key==='ArrowDown'){ e.preventDefault(); move(1); } else if(e.key==='ArrowUp'){ e.preventDefault(); move(-1); } else if(e.key==='Enter'){ e.preventDefault(); const active=list.querySelector('.cs2-opt.active'); if(active){ active.click(); } else if(allowAdd && input.value.trim()){ const o=addOptionIfNeeded(input.value.trim()); if(o){ if(isMultiple) o.selected=true; else { Array.from(select.options).forEach(x=>x.selected=false); o.selected=true; dd.style.display='none';} renderOptions(''); input.value=''; renderChips(); select.dispatchEvent(new Event('change',{bubbles:true})); } } } }; } function openDD(){ dd.style.display='block'; input.focus(); renderOptions(input.value); } function closeDD(){ dd.style.display='none'; } box.addEventListener('click', ()=>{ const open=dd.style.display==='block'; document.querySelectorAll('.cs2-dropdown').forEach(d=>d.style.display='none'); if(!open){ openDD(); } else { closeDD(); } }); input.addEventListener('input', ()=>renderOptions(input.value)); document.addEventListener('click', (e)=>{ if(!wrap.contains(e.target)) closeDD(); }); renderChips(); } // Auto initialize for all selects having class .cs2 document.addEventListener('DOMContentLoaded', function(){ document.querySelectorAll('select.cs2').forEach(sel=>{ makeCS2(sel, { allowAdd: sel.hasAttribute('data-allow-add') }); }); }); })();