1const useAutoComplete = (select) => { 2 const parent = select.parentNode 3 4 destroyExistingElements(parent) 5 6 const search = generateInputSearch(select, parent) 7 const list = generateSearchList(select, search) 8 9 select.style.display = 'none' 10 11 generateEvents(select, search, list) 12} 13 14const destroyExistingElements = (parent) => { 15 const existingInput = parent.querySelector('.autocomplete-search-input') 16 const existingList = parent.querySelector('.autocomplete-search-list') 17 18 if (existingInput) { 19 existingInput.remove() 20 } 21 22 if (existingList) { 23 existingList.remove() 24 } 25 26} 27 28const generateInputSearch = (el, parent) => { 29 let placeholder; 30 if (el.tagName == 'INPUT'){ 31 placeholder = el.getAttribute('placeholder'); 32 } else { 33 placeholder = el.options[0].text; 34 } 35 const searchInput = document.createElement('input') 36 searchInput.classList.add('autocomplete-search-input') 37 searchInput.placeholder = placeholder; 38 searchInput.setAttribute('autocomplete','new-password'); 39 searchInput.readOnly = true 40 searchInput.value = el.value; 41 parent.insertBefore(searchInput, el); 42 43 return searchInput; 44} 45 46const generateSearchList = (el, input) => { 47 let options; 48 if (el.tagName == 'INPUT') { 49 options = JSON.parse(el.dataset.options); 50 } else { 51 options = el.options; 52 } 53 const list = document.createElement('ul'); 54 list.classList.add('autocomplete-search-list'); 55 list.style.display = 'none'; // Inicialmente oculta 56 57 for (let i = 0; i < options.length; i++) { 58 const option = options[i]; 59 const li = document.createElement('li'); 60 li.dataset.value = option.value; 61 if (el.tagName == 'INPUT') { 62 li.innerText = option.label; 63 }else{ 64 li.innerText = option.text; 65 } 66 67 list.appendChild(li); 68 } 69 70 input.insertAdjacentElement('afterend', list) 71 72 return list 73} 74 75const normalizeString = (string) => { 76 return string.normalize('NFD').replace(/[\u0300-\u036f]/g, ''); 77} 78 79const filterList = (event, list, originalOptions) => { 80 const value = event.target.value.toLowerCase() 81 82 list.innerHTML = '' 83 84 let filteredOptions = originalOptions.filter(option => 85 normalizeString(option.text.toLowerCase()) 86 .includes(normalizeString(value.toLowerCase())) 87 ) 88 89 filteredOptions.forEach(option => { 90 const li = document.createElement('li') 91 li.dataset.value = option.value 92 li.innerText = option.text 93 list.appendChild(li) 94 }) 95} 96 97const refreshList = (list, originalOptions) => { 98 // Limpa a lista 99 list.innerHTML = '' 100 101 // Adiciona todas as opções originais 102 originalOptions.forEach(option => { 103 const li = document.createElement('li') 104 li.dataset.value = option.value 105 li.innerText = option.text 106 list.appendChild(li) 107 }) 108} 109 110const generateEvents = (el, input, list) => { 111 112 let originalOptions; 113 if (el.tagName == 'INPUT') { 114 originalOptions = Array.from(JSON.parse(el.dataset.options)).map(option => ({ 115 value: option.value, 116 text: option.label 117 })) 118 } else { 119 originalOptions = Array.from(el.options).map(option => ({ 120 value: option.value, 121 text: option.text 122 })) 123 } 124 // Armazena as opções originais 125 126 // Evento de clique no input 127 input.addEventListener('click', (e) => { 128 129 input.readOnly = false 130 input.value = '' 131 132 list.style.display = 'block' 133 refreshList(list, originalOptions) 134 135 input.focus() 136 }) 137 138 // Evento de input para filtrar 139 input.addEventListener('input', (e) => { 140 filterList(e, list, originalOptions) 141 }) 142 143 // Evento de clique nos itens da lista 144 list.addEventListener('click', (e) => { 145 if (e.target.tagName === 'LI') { 146 const selectedValue = e.target.dataset.value 147 const selectedText = e.target.innerText 148 149 el.value = selectedValue 150 input.value = selectedText 151 list.style.display = 'none' 152 153 el.dispatchEvent(new Event('change')) 154 } 155 }) 156 157 // Evento para fechar ao clicar fora 158 document.addEventListener('click', (e) => { 159 if (!input.contains(e.target) && !list.contains(e.target)) { 160 list.style.display = 'none' 161 } 162 }) 163}
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.