1/** 2 * Instant Search Module - CSP Compatible 3 * 4 * This script uses function-based templates instead of Mustache strings 5 * to comply with Content Security Policy (no eval/new Function required). 6 * 7 * Template configuration is passed from PHP via templateConfig object. 8 */ 9 10const as_param = Joomla.getOptions('mod_instant_search.vars'); 11const config = as_param.templateConfig; 12 13const algoliaClient = algoliasearch(as_param.app_id, as_param.apikey); 14const searchClient = { 15 ...algoliaClient, 16 search(requests) { 17 if (requests.every(({params}) => !params.query)) { 18 return Promise.resolve({ 19 results: requests.map(() => ({ 20 hits: [], 21 nbHits: 0, 22 nbPages: 0, 23 page: 0, 24 processingTimeMS: 0, 25 hitsPerPage: 0, 26 exhaustiveNbHits: false, 27 query: '', 28 params: '', 29 })), 30 }); 31 } 32 33 return algoliaClient.search(requests); 34 }, 35}; 36 37const search = instantsearch({ 38 indexName: as_param.index_name, 39 searchClient, 40}); 41 42const widgets = []; 43 44if (as_param.language) { 45 widgets.push(instantsearch.widgets.configure({ 46 filters: 'language:' + as_param.language 47 })); 48} 49 50widgets.push( 51 instantsearch.widgets.searchBox({ 52 container: '#searchbox', 53 }), 54 instantsearch.widgets.hits({ 55 container: '#hits', 56 transformItems(items) { 57 return items.map(item => { 58 item.simpleurl = ''; 59 if (typeof item.image === 'string') { 60 item.image = item.image.replace(as_param.domain, ''); 61 } 62 if (typeof item.pageurl === 'string') { 63 item.simpleurl = item.pageurl.replace(as_param.domain, ''); 64 } 65 return item; 66 }); 67 }, 68 templates: { 69 item(hit, { html, components }) { 70 // Build image element if configured 71 const image = config.showImage && hit.image 72 ? html`<img 73 alt="" 74 src="${hit.image}" 75 style="${config.imageStyle}" 76 class="${config.imageClass}" 77 />` 78 : null; 79 80 // Build title with highlight 81 const title = html`<${config.titleTag} class="${config.titleClass}"> 82 ${components.Highlight({ hit, attribute: 'title' })} 83 </${config.titleTag}>`; 84 85 // Build snippet if configured 86 const snippet = config.showSnippet 87 ? html`<p>${components.Snippet({ hit, attribute: config.snippetAttribute })}</p>` 88 : null; 89 90 // Build link if configured 91 const link = config.showLink 92 ? html`<p><a class="${config.linkClass}" href="${hit.simpleurl}">${hit.pageurl}</a></p>` 93 : null; 94 95 return html` 96 <div class="${config.containerClass}"> 97 ${image} 98 ${title} 99 ${snippet} 100 ${link} 101 </div> 102 `; 103 }, 104 empty(results, { html }) { 105 return html`<div>${config.emptyText}</div>`; 106 } 107 } 108 }) 109); 110 111search.addWidgets(widgets); 112 113search.start();
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.