1(function ($) { 2 var queryParser = function (a) { 3 var i, p, b = {}; 4 if (a === "") { 5 return {}; 6 } 7 for (i = 0; i < a.length; i += 1) { 8 p = a[i].split('='); 9 if (p.length === 2) { 10 b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " ")); 11 } 12 } 13 return b; 14 }; 15 $.queryParams = function () { 16 return queryParser(window.location.search.substr(1).split('&')); 17 }; 18 $.hashParams = function () { 19 return queryParser(window.location.hash.substr(1).split('&')); 20 }; 21 22 23 window.Swiftype = window.Swiftype || {}; 24 Swiftype.root_url = Swiftype.root_url || 'https://api.swiftype.com'; 25 Swiftype.pingUrl = function(endpoint, callback) { 26 var to = setTimeout(callback, 350); 27 var img = new Image(); 28 img.onload = img.onerror = function() { 29 clearTimeout(to); 30 callback(); 31 }; 32 img.src = endpoint; 33 return false; 34 }; 35 Swiftype.pingSearchResultClick = function (engineKey, docId, callback) { 36 var params = { 37 t: new Date().getTime(), 38 engine_key: engineKey, 39 doc_id: docId, 40 q: Swiftype.currentQuery 41 }; 42 var url = Swiftype.root_url + '/api/v1/public/analytics/pc?' + $.param(params); 43 Swiftype.pingUrl(url, callback); 44 }; 45 46 $.fn.swiftypeSearch = function (options) { 47 var options = $.extend({}, $.fn.swiftypeSearch.defaults, options); 48 49 return this.each(function () { 50 var $this = $(this); 51 var config = $.meta ? $.extend({}, options, $this.data()) : options; 52 $this.data('swiftype-config-search', config); 53 54 $this.selectedCallback = function (data) { 55 return function (e) { 56 var $el = $(this); 57 e.preventDefault(); 58 Swiftype.pingSearchResultClick(config.engineKey, data['id'], function() { 59 config.onComplete($el); 60 }); 61 }; 62 }; 63 64 $this.registerResult = function ($element, data) { 65 $element.data('swiftype-item', data); 66 $('a', $element).click($this.selectedCallback(data)); 67 }; 68 69 $this.getContentCache = function () { 70 return $('#' + contentCacheId); 71 }; 72 73 var $resultContainer = $(config.resultContainingElement), 74 initialContentOfResultContainer = $resultContainer.html(), 75 contentCacheId = 'st-content-cache', 76 $contentCache = $this.getContentCache(); 77 78 var setSearchHash = function (query, page) { 79 location.hash = "stq=" + encodeURIComponent(query) + "&stp=" + page; 80 }; 81 82 var submitSearch = function (query, options) { 83 options = $.extend({ 84 page: 1 85 }, options); 86 var params = {}; 87 88 if (!$contentCache.length) { 89 $resultContainer.after("<div id='" + contentCacheId + "' style='display: none;'></div>"); 90 $contentCache.html(initialContentOfResultContainer).hide(); 91 } 92 config.loadingFunction(query, $resultContainer); 93 94 Swiftype.currentQuery = query; 95 params['q'] = query; 96 params['engine_key'] = config.engineKey; 97 params['page'] = options.page; 98 99 function handleFunctionParam(field) { 100 if (field !== undefined) { 101 var evald = field; 102 if (typeof evald === 'function') { 103 evald = evald.call(); 104 } 105 return evald; 106 } 107 return undefined; 108 } 109 110 params['per_page'] = handleFunctionParam(config.perPage); 111 params['search_fields'] = handleFunctionParam(config.searchFields); 112 params['fetch_fields'] = handleFunctionParam(config.fetchFields); 113 params['facets'] = handleFunctionParam(config.facets); 114 params['filters'] = handleFunctionParam(config.filters); 115 params['document_types'] = handleFunctionParam(config.documentTypes); 116 params['functional_boosts'] = handleFunctionParam(config.functionalBoosts); 117 params['sort_field'] = handleFunctionParam(config.sortField); 118 params['sort_direction'] = handleFunctionParam(config.sortDirection); 119 params['spelling'] = handleFunctionParam(config.spelling); 120 params['highlight_fields'] = handleFunctionParam(config.highlightFields); 121 122 $.ajax({ 123 dataType: "json", 124 url: Swiftype.root_url + "/api/v1/public/engines/search.json?callback=?", 125 data: params, 126 xhrFields: { withCredentials: true },
127 success: renderSearchResults 128 }); 129 }; 130 131 function handleHashchange () { 132 var params = $.hashParams(); 133 if (params.stq) { 134 submitSearch(params.stq, { 135 page: params.stp 136 }); 137 } else { 138 var $contentCache = $this.getContentCache(); 139 if ($contentCache.length) { 140 $resultContainer.html($contentCache.html()); 141 $contentCache.remove(); 142 } 143 } 144 } 145 146 // Expose this globally for users to force a refresh of search results. 147 Swiftype.reloadResults = handleHashchange; 148 149 $(window).on("hashchange", handleHashchange); 150 151 var $containingForm = $this.parents('form'); 152 if ($containingForm) { 153 $containingForm.bind('submit', function (e) { 154 e.preventDefault(); 155 var searchQuery = $this.val(); 156 setSearchHash(searchQuery, 1); 157 }); 158 } 159 160 $(document).on('click', '[data-hash][data-page]', function (e) { 161 e.preventDefault(); 162 var $this = $(this); 163 setSearchHash($.hashParams().stq, $this.data('page')); 164 }); 165 166 $(document).on('click', '[data-hash][data-spelling-suggestion]', function (e) { 167 e.preventDefault(); 168 var $this = $(this); 169 setSearchHash($this.data('spelling-suggestion'), 1); 170 }); 171 172 var renderSearchResults = function (data) { 173 if (typeof config.preRenderFunction === 'function') { 174 config.preRenderFunction.call($this, data); 175 } 176 177 config.renderResultsFunction($this.getContext(), data); 178 179 if (typeof config.postRenderFunction === 'function') { 180 config.postRenderFunction.call($this, data); 181 } 182 }; 183 184 $this.getContext = function () { 185 return { 186 config: config, 187 resultContainer: $resultContainer, 188 registerResult: $this.registerResult 189 }; 190 }; 191 192 handleHashchange(); // if the swiftype query hash is present onload (maybe the user is pressing the back button), submit a query onload 193 }); 194 }; 195 196 var renderPagination = function (ctx, resultInfo) { 197 var maxPagesType, maxPages = -1, 198 config = ctx.config; 199 $.each(resultInfo, function(documentType, typeInfo) { 200 if (typeInfo.num_pages > maxPages) { 201 maxPagesType = documentType; 202 maxPages = typeInfo.num_pages; 203 } 204 }); 205 var currentPage = resultInfo[maxPagesType].current_page, 206 totalPages = resultInfo[maxPagesType].num_pages; 207 208 $(config.renderPaginationForType(maxPagesType, currentPage, totalPages)).appendTo(ctx.resultContainer); 209 }; 210 211 212 var normalize = function (str) { 213 return $.trim(str).toLowerCase(); 214 }; 215 216 function htmlEscape(str) { 217 return String(str).replace(/&/g, '&').replace(/"/g, '"').replace(/'/g, ''').replace(/</g, '<').replace(/>/g, '>'); 218 } 219 220 var defaultRenderResultsFunction = function (ctx, data) { 221 var $resultContainer = ctx.resultContainer, 222 config = ctx.config; 223 224 $resultContainer.html(''); 225 226 $.each(data.records, function (documentType, items) { 227 $.each(items, function (idx, item) { 228 ctx.registerResult($(config.renderFunction(documentType, item)).appendTo($resultContainer), item); 229 }); 230 }); 231 232 renderPagination(ctx, data.info); 233 }; 234 235 var defaultRenderFunction = function (document_type, item) { 236 return '<div class="st-result"><h3 class="title"><a href="' + item['url'] + '" class="st-search-result-link">' + htmlEscape(item['title']) + '</a></h3>' + 237 '<p>'+ htmlEscape(item['description']) + '</p></div>'; 238 }; 239 240 var defaultLoadingFunction = function(query, $resultContainer) { 241 $resultContainer.html('<p class="st-loading-message">loading...</p>'); 242 }; 243 244 var defaultOnComplete = function(elem) { 245 window.location = elem.attr('href'); 246 }; 247 248 var defaultPostRenderFunction = function(data) { 249 var totalResultCount = 0; 250 var $resultContainer = this.getContext().resultContainer; 251 var spellingSuggestion = null; 252 253 if (data['info']) { 254 $.each(data['info'], function(index, value) { 255 totalResultCount += value['total_result_count']; 256 if ( value['spelling_suggestion'] ) { 257 spellingSuggestion = value['spelling_suggestion']['text']; 258 } 259 260 }); 261 } 262 263 if (totalResultCount === 0) { 264 $resultContainer.html("<div id='st-no-results' class='st-no-results'>No results found.</div>"); 265 } 266 267 if (spellingSuggestion !== null) { 268 $resultContainer.append('<div class="st-spelling-suggestion">Did you mean <a href="#" data-hash="true" data-spelling-suggestion="' + spellingSuggestion + '">' + spellingSuggestion + '</a>?</div>'); 269 } 270 }; 271 272 273 var defaultRenderPaginationForType = function (type, currentPage, totalPages) { 274 var pages = '<div class="st-page">', 275 previousPage, nextPage; 276 if (currentPage != 1) { 277 previousPage = currentPage - 1; 278 pages = pages + '<a href="#" class="st-prev" data-hash="true" data-page="' + previousPage + '">« previous</a>'; 279 } 280 if (currentPage < totalPages) { 281 nextPage = currentPage + 1; 282 pages = pages + '<a href="#" class="st-next" data-hash="true" data-page="' + nextPage + '">next »</a>'; 283 } 284 pages += '</div>'; 285 return pages; 286 }; 287 288 289 $.fn.swiftypeSearch.defaults = { 290 attachTo: undefined, 291 documentTypes: undefined, 292 facets: undefined, 293 filters: undefined, 294 engineKey: undefined, 295 searchFields: undefined, 296 functionalBoosts: undefined, 297 sortField: undefined, 298 sortDirection: undefined, 299 fetchFields: undefined, 300 highlightFields: undefined, 301 preRenderFunction: undefined, 302 postRenderFunction: defaultPostRenderFunction, 303 loadingFunction: defaultLoadingFunction, 304 renderResultsFunction: defaultRenderResultsFunction, 305 renderFunction: defaultRenderFunction, 306 renderPaginationForType: defaultRenderPaginationForType, 307 onComplete: defaultOnComplete, 308 perPage: 10, 309 spelling: 'strict' 310 }; 311})(jQuery);
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.