1/** 2 * The 'Sip Archive: the finding aid. 3 * 4 * Every story is already in the HTML. This just hides the ones that do not 5 * match. If the script never loads, the reader still sees the full list. 6 */ 7( function () { 8 'use strict'; 9 10 function initBrowser( root ) { 11 12 var list = root.querySelector( '[data-sip-list]' ); 13 var items = Array.prototype.slice.call( root.querySelectorAll( '.sip-browser__item' ) ); 14 var count = root.querySelector( '[data-sip-count]' ); 15 var empty = root.querySelector( '[data-sip-empty]' ); 16 var reset = root.querySelector( '[data-sip-reset]' ); 17 var inputs = Array.prototype.slice.call( root.querySelectorAll( '[data-sip-filter]' ) ); 18 19 if ( ! list || ! items.length ) { 20 return; 21 } 22 23 var singular = ( count && count.dataset.singular ) || 'story'; 24 var plural = ( count && count.dataset.plural ) || 'stories'; 25 26 function currentFilters() { 27 var filters = { q: '', issue: '', section: '', author: '' }; 28 29 inputs.forEach( function ( input ) { 30 var key = input.getAttribute( 'data-sip-filter' ); 31 if ( key in filters ) { 32 filters[ key ] = ( input.value || '' ).trim(); 33 } 34 } ); 35 36 return filters; 37 } 38 39 function matches( item, filters ) { 40 41 if ( filters.issue && item.getAttribute( 'data-issue' ) !== filters.issue ) { 42 return false; 43 } 44 45 if ( filters.section && item.getAttribute( 'data-section' ) !== filters.section ) { 46 return false; 47 } 48 49 if ( filters.author && item.getAttribute( 'data-author' ) !== filters.author ) { 50 return false; 51 } 52 53 if ( filters.q ) { 54 var haystack = item.getAttribute( 'data-search' ) || ''; 55 var needles = filters.q.toLowerCase().split( /\s+/ ); 56 57 for ( var i = 0; i < needles.length; i++ ) { 58 if ( haystack.indexOf( needles[ i ] ) === -1 ) { 59 return false; 60 } 61 } 62 } 63 64 return true; 65 } 66 67 function apply() { 68 69 var filters = currentFilters(); 70 var shown = 0; 71 var active = !! ( filters.q || filters.issue || filters.section || filters.author ); 72 73 items.forEach( function ( item ) { 74 if ( matches( item, filters ) ) { 75 item.hidden = false; 76 shown++; 77 } else { 78 item.hidden = true; 79 } 80 } ); 81 82 if ( count ) { 83 count.textContent = shown.toLocaleString() + ' ' + ( 1 === shown ? singular : plural ); 84 } 85 86 if ( empty ) { 87 empty.hidden = shown !== 0; 88 } 89 90 if ( reset ) { 91 reset.hidden = ! active; 92 } 93 } 94 95 inputs.forEach( function ( input ) { 96 var event = 'search' === input.type || 'text' === input.type ? 'input' : 'change'; 97 input.addEventListener( event, apply ); 98 } ); 99 100 if ( reset ) { 101 reset.addEventListener( 'click', function () { 102 inputs.forEach( function ( input ) { 103 input.value = ''; 104 } ); 105 apply(); 106 var search = root.querySelector( '[data-sip-filter="q"]' ); 107 if ( search ) { 108 search.focus(); 109 } 110 } ); 111 } 112 113 apply(); 114 } 115 116 function init() { 117 var roots = document.querySelectorAll( '[data-sip-browser]' ); 118 Array.prototype.forEach.call( roots, initBrowser ); 119 } 120 121 if ( 'loading' === document.readyState ) { 122 document.addEventListener( 'DOMContentLoaded', init ); 123 } else { 124 init(); 125 } 126}() );
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.