1document.addEventListener('DOMContentLoaded', () => { 2 const root = document.querySelector('[data-product-collection]'); 3 const tools = root?.querySelector('[data-catalog-tools]'); 4 if (!tools) return; 5 const cards = Array.from(root.querySelectorAll('[data-catalog-card]')); 6 const filters = Array.from(root.querySelectorAll('[data-catalog-filter]')); 7 const search = root.querySelector('[data-catalog-search]'); 8 const count = root.querySelector('[data-catalog-count]'); 9 const empty = root.querySelector('[data-catalog-empty]'); 10 let category = 'all'; 11 const update = () => { 12 const query = search.value.trim().toLocaleLowerCase(); 13 let visible = 0; 14 cards.forEach(card => { 15 const matches = (category === 'all' || card.dataset.category === category) 16 && card.dataset.search.toLocaleLowerCase().includes(query); 17 card.hidden = !matches; 18 if (matches) visible++; 19 }); 20 filters.forEach(button => button.setAttribute('aria-pressed', String(button.dataset.catalogFilter === category))); 21 count.textContent = `${visible} ${visible === 1 ? 'product' : 'products'}`; 22 empty.hidden = visible !== 0; 23 }; 24 filters.forEach(button => button.addEventListener('click', () => { category = button.dataset.catalogFilter; update(); })); 25 search.addEventListener('input', update); 26 root.querySelector('[data-catalog-reset]').addEventListener('click', () => { 27 category = 'all'; search.value = ''; update(); search.focus(); 28 }); 29 tools.hidden = false; 30 update(); 31});
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.