PageSourceSearch

https://blombo.com/js/soulmkt/utils/autocomplete.js?v=056ee659272090bf4fb293e147c44caa

js blombo.com collected 2026-10-05 22:45:00 UTC 4,411 bytes, 163 lines download raw bytes

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.