1/* global CONFIG, pjax, LocalSearch */ 2 3document.addEventListener('DOMContentLoaded', () => { 4 if (!CONFIG.path) { 5 // Search DB path 6 console.warn('`hexo-generator-searchdb` plugin is not installed!'); 7 return; 8 } 9 const localSearch = new LocalSearch({ 10 path : CONFIG.path, 11 top_n_per_article: CONFIG.localsearch.top_n_per_article, 12 unescape : CONFIG.localsearch.unescape 13 }); 14 15 const input = document.querySelector('.search-input'); 16 17 const inputEventFunction = () => { 18 if (!localSearch.isfetched) return; 19 const searchText = input.value.trim().toLowerCase(); 20 const keywords = searchText.split(/[-\s]+/); 21 const container = document.querySelector('.search-result-container'); 22 let resultItems = []; 23 if (searchText.length > 0) { 24 // Perform local searching 25 resultItems = localSearch.getResultItems(keywords); 26 } 27 if (keywords.length === 1 && keywords[0] === '') { 28 container.classList.add('no-result'); 29 container.innerHTML = '<div class="search-result-icon"><i class="fa fa-search fa-5x"></i></div>'; 30 } else if (resultItems.length === 0) { 31 container.classList.add('no-result'); 32 container.innerHTML = '<div class="search-result-icon"><i class="far fa-frown fa-5x"></i></div>'; 33 } else { 34 resultItems.sort((left, right) => { 35 if (left.includedCount !== right.includedCount) { 36 return right.includedCount - left.includedCount; 37 } else if (left.hitCount !== right.hitCount) { 38 return right.hitCount - left.hitCount; 39 } 40 return right.id - left.id; 41 }); 42 const stats = CONFIG.i18n.hits.replace('${hits}', resultItems.length); 43 44 container.classList.remove('no-result'); 45 container.innerHTML = `<div class="search-stats">${stats}</div> 46 <hr> 47 <ul class="search-result-list">${resultItems.map(result => result.item).join('')}</ul>`; 48 if (typeof pjax === 'object') pjax.refresh(container); 49 } 50 }; 51 52 localSearch.highlightSearchWords(document.querySelector('.post-body')); 53 if (CONFIG.localsearch.preload) { 54 localSearch.fetchData(); 55 } 56 57 if (CONFIG.localsearch.trigger === 'auto') { 58 input.addEventListener('input', inputEventFunction); 59 } else { 60 document.querySelector('.search-icon').addEventListener('click', inputEventFunction); 61 input.addEventListener('keypress', event => { 62 if (event.key === 'Enter') { 63 inputEventFunction(); 64 } 65 }); 66 } 67 window.addEventListener('search:loaded', inputEventFunction); 68 69 // Handle and trigger popup window 70 document.querySelectorAll('.popup-trigger').forEach(element => { 71 element.addEventListener('click', () => { 72 document.body.classList.add('search-active'); 73 // Wait for search-popup animation to complete 74 setTimeout(() => input.focus(), 500); 75 if (!localSearch.isfetched) localSearch.fetchData(); 76 }); 77 }); 78 79 // Monitor main search box 80 const onPopupClose = () => { 81 document.body.classList.remove('search-active'); 82 }; 83 84 document.querySelector('.search-pop-overlay').addEventListener('click', event => { 85 if (event.target === document.querySelector('.search-pop-overlay')) { 86 onPopupClose(); 87 } 88 }); 89 document.querySelector('.popup-btn-close').addEventListener('click', onPopupClose); 90 document.addEventListener('pjax:success', () => { 91 localSearch.highlightSearchWords(document.querySelector('.post-body')); 92 onPopupClose(); 93 }); 94 window.addEventListener('keyup', event => { 95 if (event.key === 'Escape') { 96 onPopupClose(); 97 } 98 }); 99});
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.