1document.addEventListener('DOMContentLoaded', function() { 2 const app = document.getElementById('buscador-form-app'); 3 if (!app) return; 4 5 const searchInput = app.querySelector('#calendario-q'); 6 const autocompleteContainer = app.querySelector('#autocomplete-results'); 7 const keywords = calendario_ajax.keywords || []; 8 let currentArgs = calendario_ajax.initial_args || {}; 9 10 function escapeRegExp(str) { 11 return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); 12 } 13 14 function shouldShowAutocomplete(rawValue) { 15 const value = (rawValue || '').toLowerCase(); 16 // Requisito: no autocompletar hasta tener 3 caracteres, y que exista un espacio 17 // (evita casos extremos tipo "IA" â coincidencias por contains). 18 if (value.length < 3) return false; 19 if (!value.includes(' ')) return false; 20 return true; 21 } 22 23 function keywordMatchesQuery(keyword, query) { 24 const q = (query || '').toLowerCase().trim(); 25 if (!q) return false; 26 const terms = q.split(/\s+/).filter(Boolean); 27 const kw = (keyword || '').toLowerCase(); 28 29 return terms.every(term => { 30 // Para términos muy cortos (p.ej. "IA") forzamos coincidencia por palabra completa. 31 if (term.length <= 2) { 32 const re = new RegExp(`(^|\\W)${escapeRegExp(term)}(\\W|$)`, 'i'); 33 return re.test(keyword); 34 } 35 return kw.includes(term); 36 }); 37 } 38 39 searchInput.addEventListener('input', function() { 40 const value = this.value.toLowerCase(); 41 autocompleteContainer.innerHTML = ''; 42 if (!value || !shouldShowAutocomplete(value)) { 43 autocompleteContainer.classList.remove('active'); 44 return; 45 } 46 47 const suggestions = keywords.filter(kw => keywordMatchesQuery(kw, value)).slice(0, 7); 48 49 if (suggestions.length > 0) { 50 suggestions.forEach(suggestion => { 51 const item = document.createElement('div'); 52 item.className = 'autocomplete-item'; 53 // Resaltar la coincidencia 54 const safe = escapeRegExp(value.trim()); 55 const regex = safe ? new RegExp(`(${safe})`, 'gi') : null; 56 item.innerHTML = regex ? suggestion.replace(regex, '<strong>$1</strong>') : suggestion; 57 58 item.addEventListener('click', function() { 59 searchInput.value = suggestion; 60 autocompleteContainer.classList.remove('active'); 61 currentArgs.paged = 1; 62 const form = searchInput.closest('form'); 63 if (form) { 64 form.submit(); 65 } 66 }); 67 autocompleteContainer.appendChild(item); 68 }); 69 autocompleteContainer.classList.add('active'); 70 } else { 71 autocompleteContainer.classList.remove('active'); 72 } 73 }); 74 75 // Cerrar el autocompletado si se hace clic fuera 76 document.addEventListener('click', function(e) { 77 if (e.target !== searchInput) { 78 autocompleteContainer.classList.remove('active'); 79 } 80 }); 81 82});
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.