1/** global javascript instantsearch algoliasearch */ 2const indexname = drupalSettings.algolia.config.indexname; 3const appId = drupalSettings.algolia.config.appId; 4const apiKey = drupalSettings.algolia.config.apiKey; 5const template = drupalSettings.algolia.config.template; 6const pagination = drupalSettings.algolia.config.pagination; 7const { liteClient: algoliasearch } = window["algoliasearch/lite"]; 8 9if(indexname && appId && apiKey && template) { 10 const algoliaClient = algoliasearch( 11 appId, 12 apiKey 13 ); 14 15 const searchClient = { 16 ...algoliaClient, 17 search(requests) { 18 if (requests.every(({ params }) => !params.query)) { 19 return Promise.resolve({ 20 results: requests.map(() => ({ 21 hits: [], 22 nbHits: 0, 23 nbPages: 0, 24 page: 0, 25 processingTimeMS: 0, 26 hitsPerPage: 0, 27 exhaustiveNbHits: false, 28 query: '', 29 params: '', 30 })), 31 }); 32 } 33 34 return algoliaClient.search(requests); 35 }, 36 }; 37 38 39 const search = instantsearch({ 40 indexName: indexname, 41 searchClient, 42 }); 43 /** 44 * Facet values we want to re-map 45 */ 46 const facetMapping = { 47 blog: 'Blogs', 48 faq: 'FAQs', 49 page: 'Civic Info', 50 product: 'Products', 51 sections_page: 'Services' 52 }; 53 54 55 search.addWidgets([ 56 instantsearch.widgets.searchBox({ 57 container: '#ais-search', 58 placeholder: 'Search', 59 wrapInput: false, 60 showSubmit: false, 61 showReset: false, 62 }), 63 64 instantsearch.widgets.refinementList({ 65 container: '#facet-content-types', 66 attribute: 'left_filters', 67 transformItems(items) { 68 return items.map(item => ({ 69 ...item, 70 // The label to use 71 label: facetMapping[item.value], 72 highlighted: facetMapping[item.value] 73 ? facetMapping[item.value] 74 : item.value, 75 })); 76 }, 77 }) 78 79 ]); 80 81 /** 82 * check to enable pagination 83 * pagination limit configurable on algolia account 84 */ 85 if(pagination && pagination != 0) { 86 search.addWidgets([ 87 instantsearch.widgets.pagination({ 88 container: '#algolia-pagination', 89 showFirst: false, 90 showLast: false, 91 padding: 2 92 }) 93 ]); 94 } 95 96 /* Hits widget */ 97 search.addWidget( 98 instantsearch.widgets.hits({ 99 container: '#algolia-hits', 100 templates: { 101 empty: ` 102 <div class="no-results"> 103 <p>We could not find a match for "{{query}}". Please try another search.</p> 104 <ul> 105 <li>Try different or more general keywords</li> 106 <li>Try fewer keywords</li> 107 </ul> 108 </div> 109 `, 110 item(hit, { html, components }) { 111 return html` 112 <h2 class="ais-Hits-title"> 113 <a href=${hit.url}>${components.Highlight({ attribute: 'title', hit })}</a> 114 </h2> 115 <p>${components.Snippet({ attribute: 'rendered_item', hit })}</p> 116 `; 117 }, 118 }, 119 }) 120 ); 121 122 /** 123 * Business/Personal menu items with a reset as "All" 124 */ 125 search.addWidget( 126 instantsearch.widgets.menu({ 127 container: '#menu', 128 attribute: 'member_type_filter', 129 sortBy: ['count:desc', 'name:asc'], 130 templates: { 131 item: ` 132 <a class="{{cssClasses.link}}" href="{{url}}"> 133 <span class="{{cssClasses.label}}">{{label}}</span> 134 </a> 135 `, 136 }, 137 // Probably not needed any longer, but leaving here for reference if we ever need to do it again. 138 // transformItems(items) { 139 // var orderedList = ['Business Products','Personal']; 140 // var returnedItems =[];
141 // for(ol in orderedList) { 142 // for (il in items) { 143 // if (orderedList[ol] == items[il].value) { 144 // if (items[il].value == 'Business Products'){ 145 // items[il].label = 'Business' 146 // } 147 // returnedItems.push(items[il]); 148 // } 149 // } 150 // } 151 // return returnedItems; 152 // }, 153 }) 154 ); 155 156 search.addWidget( 157 instantsearch.widgets.clearRefinements({ 158 container: '#clearRefinements', 159 cssClasses: { 160 link: 'ais-clear-all--link__active' 161 }, 162 templates: { 163 resetLabel: 'All', 164 }, 165 autoHideContainer: false 166 }) 167 ); 168 169 /* Stats widget */ 170 search.addWidget( 171 instantsearch.widgets.stats({ 172 container: '#stats', 173 templates: { 174 text: ` 175 {{#areHitsSorted}} 176 {{#hasNoSortedResults}}No Relevant Results{{/hasNoSortedResults}} 177 {{#hasOneSortedResults}}1 Relevant Result{{/hasOneSortedResults}} 178 {{#hasManySortedResults}}{{#helpers.formatNumber}}{{nbSortedHits}}{{/helpers.formatNumber}} Relevant Results{{/hasManySortedResults}} 179 Sorted Out Of {{#helpers.formatNumber}}{{nbHits}}{{/helpers.formatNumber}} 180 {{/areHitsSorted}} 181 {{^areHitsSorted}} 182 {{#hasNoResults}}No Results{{/hasNoResults}} 183 {{#hasOneResult}}1 Result{{/hasOneResult}} 184 {{#hasManyResults}}{{#helpers.formatNumber}}{{nbHits}}{{/helpers.formatNumber}} Results{{/hasManyResults}} 185 {{/areHitsSorted}} 186 Below 187 `, 188 }, 189 }) 190 ); 191 192 // Create the render function 193 const renderSortBy = (renderOptions, isFirstRender) => { 194 const { 195 options, 196 currentRefinement, 197 hasNoResults, 198 refine, 199 widgetParams, 200 } = renderOptions; 201 202 if (isFirstRender) { 203 const sortby = document.createElement('ul'); 204 205 sortby.addEventListener('click', event => { 206 refine(event.target.getAttribute('data-value')); 207 }); 208 209 widgetParams.container.appendChild(sortby); 210 } 211 212 const sortby = widgetParams.container.querySelector('ul'); 213 214 sortby.disabled = hasNoResults; 215 216 sortby.innerHTML = ` 217 ${options 218 .map( 219 option => ` 220 <li 221 data-value="${option.value}" 222 ${option.value === currentRefinement ? ' class="selected"' : ''} 223 > 224 ${option.label} 225 </li> 226 ` 227 ) 228 .join('')} 229 `; 230 }; 231 232// Create the custom widget 233 const customSortBy = instantsearch.connectors.connectSortBy(renderSortBy); 234 235 search.addWidgets([ 236 customSortBy({ 237 container: document.querySelector('#sort-by'), 238 items: [ 239 { label: 'MOST RELEVANT', value: indexname }, 240 { label: 'LATEST', value: indexname +'_latest'}, 241 ], 242 }) 243 ]); 244 245 search.start(); 246 247} else 248{ 249 throw "Algolia settings missing"; 250}
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.