1 2XA.component.sitecoreSearch = (function($) { 3 let api = {}; 4 let config = { 5 widgetId: '', 6 sourceId: '', 7 sources: [], 8 facets: [], 9 filterMap: {}, 10 apiKey: '', 11 apiUrl: '', 12 defaultPageSize: 6, 13 suggestions: '', 14 sortorder: '', 15 permanentFilters: [] 16 }; 17 18 api.configure = function(options) { 19 config = $.extend(true, {}, config, options); 20 }; 21 22 function buildFilterObject(inputArray, permanentFilters) { 23 // Initialize the main AND filter that will contain all filter groups 24 let mainFilter = { 25 type: "and", 26 filters: [] 27 }; 28 29 // Process user input filters if they exist 30 if (Array.isArray(inputArray) && inputArray.length > 0) { 31 // Group filters by name 32 const grouped = inputArray.reduce((acc, item) => { 33 if (!acc[item.name]) acc[item.name] = []; 34 acc[item.name].push(item.value); 35 return acc; 36 }, {}); 37 38 // Create OR filters for each group 39 Object.entries(grouped).forEach(([name, values]) => { 40 if (values.length > 1) { 41 mainFilter.filters.push({ 42 type: "or", 43 filters: values.map(value => ({ 44 name, 45 type: "eq", 46 value 47 })) 48 }); 49 } else { 50 mainFilter.filters.push({ 51 name, 52 type: "eq", 53 value: values[0] 54 }); 55 } 56 }); 57 } 58 59 // Process permanent filters if they exist 60 if (Array.isArray(config.permanentFilters) && config.permanentFilters.length > 0) { 61 // Group permanent filters by name 62 const groupedPermanent = config.permanentFilters.reduce((acc, item) => { 63 const name = item.name; 64 const type = item.type ?? "eq"; 65 const value = item.value; 66 67 if (!acc[name]) acc[name] = []; 68 acc[name].push({ type, value }); 69 return acc; 70 }, {}); 71 72 // Create OR filters for each permanent filter group 73 // Create OR filters for each permanent filter group 74 Object.entries(groupedPermanent).forEach(([name, entries]) => { 75 if (entries.length > 1) { 76 mainFilter.filters.push({ 77 type: "or", 78 filters: entries.map(({ type, value }) => ({ 79 name, 80 type: type ?? "eq", 81 value 82 })) 83 }); 84 } else { 85 mainFilter.filters.push({ 86 name, 87 type: entries[0].type ?? "eq", 88 value: entries[0].value 89 }); 90 } 91 }); 92 } 93 94 // If no filters were added, return null 95 if (mainFilter.filters.length === 0) { 96 return null; 97 } 98 99 return mainFilter; 100 } 101 102 function buildRequest(query, filters, pagesize = config.defaultPageSize, offset = 0) { 103 let requestSources = []; 104 if(config.sources.length > 0) requestSources = config.sources 105 else requestSources = [config.sourceId] 106 let requestItem = { 107 rfk_id: config.widgetId, 108 entity: "content", 109 sources: requestSources, 110 search: { 111 content: {}, 112 limit: pagesize, 113 offset: offset, 114 query: {}, 115 116 } 117 }; 118 if (config.facets.length > 0){ 119 requestItem.search.facet = { 120 all: true, 121 types: config.facets.map(facet => ({ name: facet })) 122 }; 123 } 124 125 if(config.sortorder !== ''){
126 requestItem.search.sort = { 127 value: [ 128 {"name": config.sortorder} 129 ] 130 } 131 }; 132 133 if (query && query.length > 0) { 134 requestItem.search.query.keyphrase = query; 135 } 136 137 if ((filters && filters.length > 0) || (config.permanentFilters && config.permanentFilters.length > 0)) { 138 const filterObject = buildFilterObject(filters, config.permanentFilters); 139 if (filterObject) { 140 requestItem.search.filter = filterObject; 141 } 142 } 143 144 return { 145 widget: { 146 items: [requestItem] 147 } 148 }; 149 } 150 151 function buildSuggestionRequest(query, filters) { 152 let requestSources = []; 153 if(config.sources.length > 0) requestSources = config.sources 154 else requestSources = [config.sourceId] 155 let requestItem = { 156 widget: { 157 items: [{ 158 rfk_id: config.widgetId, 159 entity: "content", 160 sources: requestSources, 161 search: { 162 content: {}, 163 query: { 164 keyphrase: query 165 }, 166 suggestion: [{ 167 name: config.suggestions 168 }] 169 } 170 }] 171 } 172 }; 173 174 if ((filters && filters.length > 0) || (config.permanentFilters && config.permanentFilters.length > 0)) { 175 const filterObject = buildFilterObject(filters, config.permanentFilters); 176 if (filterObject) { 177 requestItem.widget.items[0].search.filter = filterObject; 178 } 179 } 180 181 return requestItem; 182 } 183 184 api.search = function(query = '', filters = [], pagesize = config.defaultPageSize, offset = 0) { 185 const request = buildRequest(query, filters, pagesize, offset); 186 187 //console. log('Search request:', JSON.stringify(request)); 188 189 return $.ajax({ 190 type: "POST", 191 url: config.apiUrl, 192 dataType: 'json', 193 data: JSON.stringify(request), 194 beforeSend: function(xhr) { 195 xhr.setRequestHeader('Authorization', 'Bearer ' + config.apiKey); 196 } 197 }); 198 }; 199 200 api.getSuggestions = function(query) { 201 if(config.suggestions === '') return; 202 203 if (!query || query.length < 2) { 204 return Promise.resolve({ widgets: [] }); 205 } 206 207 const request = buildSuggestionRequest(query); 208 209 return $.ajax({ 210 type: "POST", 211 url: config.apiUrl, 212 dataType: 'json', 213 data: JSON.stringify(request), 214 beforeSend: function(xhr) { 215 xhr.setRequestHeader('Authorization', 'Bearer ' + config.apiKey); 216 } 217 }); 218 }; 219 220 api.buildPagination = function(totalItems, limit, currentPage) { 221 const totalPages = Math.ceil(totalItems / limit); 222 const pages = new Set(); 223 const result = []; 224 225 if (totalPages <= 7) { 226 for (let i = 1; i <= totalPages; i++) pages.add(i); 227 } else if (currentPage <= 5) { 228 for (let i = 1; i <= 5; i++) pages.add(i); 229 pages.add(totalPages); 230 } else if (currentPage >= totalPages - 4) { 231 pages.add(1); 232 for (let i = totalPages - 4; i <= totalPages; i++) pages.add(i); 233 } else { 234 pages.add(1); 235 for (let i = currentPage - 2; i <= currentPage + 2; i++) pages.add(i); 236 pages.add(totalPages); 237 } 238 239 const sortedPages = Array.from(pages).sort((a, b) => a - b); 240 241 if (currentPage > 1) { 242 result.push({ type: "previous", page: currentPage - 1, offset: (currentPage - 2) * limit }); 243 } 244 245 for (let i = 0; i < sortedPages.length; i++) { 246 const page = sortedPages[i]; 247 result.push({ 248 type: "page", 249 page, 250 offset: (page - 1) * limit, 251 isCurrent: page === currentPage 252 }); 253 254 const next = sortedPages[i + 1];
255 if (next && next - page > 1) { 256 result.push({ type: "ellipsis" }); 257 } 258 } 259 260 if (currentPage < totalPages) { 261 result.push({ type: "next", page: currentPage + 1, offset: currentPage * limit }); 262 } 263 264 return result; 265 }; 266 267 return api; 268})(jQuery); 269 270XA.register("sitecoreSearch", XA.component.sitecoreSearch);
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.