1(function() { 2 'use strict'; 3 4 function normalizeText(value) { 5 return String(value || '').trim().toLowerCase(); 6 } 7 8 function setDisplay(element, visible) { 9 if (!element) { 10 return; 11 } 12 13 element.style.display = visible ? '' : 'none'; 14 } 15 16 function getOrCreateNoResults(root) { 17 const existing = root.querySelector('.libd-no-results'); 18 19 if (existing) { 20 return existing; 21 } 22 23 const element = document.createElement('p'); 24 element.className = 'libd-no-results'; 25 element.textContent = root.dataset.notFound || ''; 26 element.style.display = 'none'; 27 28 root.appendChild(element); 29 30 return element; 31 } 32 33 function setActiveNav(navLinks, activeFilter) { 34 navLinks.forEach((link) => { 35 link.classList.toggle('libd-active', link.dataset.filter === activeFilter); 36 }); 37 } 38 39 function getCountText(totalShown, isMulti, multiLabel, resultSingular, resultPlural) { 40 if (totalShown < 1) { 41 return ''; 42 } 43 44 if (isMulti && multiLabel) { 45 return totalShown === 1 46 ? `1 item in ${multiLabel}` 47 : `${totalShown} ${multiLabel}`; 48 } 49 50 return `${totalShown} ${totalShown === 1 ? resultSingular : resultPlural}`; 51 } 52 53 function initDirectory(root) { 54 if (!root || root.dataset.libdInit === '1') { 55 return; 56 } 57 58 root.dataset.libdInit = '1'; 59 60 const searchInput = root.querySelector('.libd-search'); 61 const clearBtn = root.querySelector('.libd-clear'); 62 const countEl = root.querySelector('.libd-result-count'); 63 const navLinks = Array.from(root.querySelectorAll('.libd-nav-link')); 64 const sections = Array.from(root.querySelectorAll('.libd-section')); 65 const noResults = getOrCreateNoResults(root); 66 67 if (!searchInput || !clearBtn || !countEl || !navLinks.length || !sections.length) { 68 return; 69 } 70 71 let activeFilter = 'all'; 72 let query = ''; 73 74 const resultSingular = root.dataset.resultSingular || 'item'; 75 const resultPlural = root.dataset.resultPlural || 'items'; 76 const multiLabel = root.dataset.multiLabel || ''; 77 const isMulti = root.dataset.isMulti === '1'; 78 79 function render() { 80 let totalShown = 0; 81 const normalizedQuery = normalizeText(query); 82 83 sections.forEach((section) => { 84 const sectionFilters = (section.dataset.filter || '').split(/\s+/).filter(Boolean); 85 const entries = Array.from(section.querySelectorAll('.libd-entry')); 86 let shownInSection = 0; 87 88 if (activeFilter !== 'all' && !sectionFilters.includes(activeFilter)) { 89 entries.forEach((entry) => setDisplay(entry, false)); 90 setDisplay(section, false); 91 return; 92 } 93 94 entries.forEach((entry) => { 95 const titleEl = entry.querySelector('.libd-entry-title'); 96 const title = normalizeText(titleEl ? titleEl.textContent : '');
97 const entryFilters = (entry.dataset.filter || '').split(/\s+/).filter(Boolean); 98 const matchesQuery = !normalizedQuery || title.includes(normalizedQuery); 99 const matchesFilter = 100 activeFilter === 'all' || entryFilters.includes(activeFilter); 101 const isVisible = matchesQuery && matchesFilter; 102 103 setDisplay(entry, isVisible); 104 105 if (isVisible) { 106 shownInSection++; 107 } 108 }); 109 110 setDisplay(section, shownInSection > 0); 111 totalShown += shownInSection; 112 }); 113 114 setDisplay(noResults, totalShown === 0); 115 countEl.textContent = getCountText( 116 totalShown, 117 isMulti, 118 multiLabel, 119 resultSingular, 120 resultPlural 121 ); 122 } 123 124 navLinks.forEach((link) => { 125 link.addEventListener('click', (event) => { 126 event.preventDefault(); 127 128 if (link.classList.contains('libd-empty')) { 129 return; 130 } 131 132 const clickedFilter = link.dataset.filter || 'all'; 133 134 searchInput.value = ''; 135 query = ''; 136 137 if (activeFilter === clickedFilter && clickedFilter !== 'all') { 138 activeFilter = 'all'; 139 } else { 140 activeFilter = clickedFilter; 141 } 142 143 setActiveNav(navLinks, activeFilter); 144 render(); 145 }); 146 }); 147 148 searchInput.addEventListener('input', () => { 149 query = searchInput.value || ''; 150 activeFilter = 'all'; 151 setActiveNav(navLinks, activeFilter); 152 render(); 153 }); 154 155 clearBtn.addEventListener('click', () => { 156 searchInput.value = ''; 157 query = ''; 158 activeFilter = 'all'; 159 setActiveNav(navLinks, activeFilter); 160 searchInput.focus(); 161 render(); 162 }); 163 164 setActiveNav(navLinks, activeFilter); 165 render(); 166 } 167 168 function init() { 169 document.querySelectorAll('.library-display').forEach(initDirectory); 170 } 171 172 if (document.readyState === 'loading') { 173 document.addEventListener('DOMContentLoaded', init); 174 } else { 175 init(); 176 } 177})();
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.