algolia-search.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. /*************************************************
  2. * Wowchemy
  3. * https://github.com/wowchemy/wowchemy-hugo-themes
  4. *
  5. * Algolia based search algorithm.
  6. **************************************************/
  7. import {algoliaConfig, i18n, content_type} from '@params';
  8. import algoliasearch from 'https://cdn.jsdelivr.net/npm/algoliasearch@4/dist/algoliasearch.esm.browser.js';
  9. // import instantsearch from 'https://cdn.jsdelivr.net/npm/instantsearch.js@4/es/index.js'
  10. // import {searchBox, infiniteHits} from 'https://cdn.jsdelivr.net/npm/instantsearch.js@4/es/widgets/index.js';
  11. if (algoliaConfig.analytics) {
  12. let ALGOLIA_INSIGHTS_SRC = 'https://cdn.jsdelivr.net/npm/search-insights@2.0.2/dist/search-insights.iife.min.js';
  13. !(function (e, a, t, n, s, i, c) {
  14. (e.AlgoliaAnalyticsObject = s),
  15. (e[s] =
  16. e[s] ||
  17. function () {
  18. (e[s].queue = e[s].queue || []).push(arguments);
  19. }),
  20. (i = a.createElement(t)),
  21. (c = a.getElementsByTagName(t)[0]),
  22. (i.async = 1),
  23. (i.src = n),
  24. c.parentNode.insertBefore(i, c);
  25. })(window, document, 'script', ALGOLIA_INSIGHTS_SRC, 'aa');
  26. }
  27. function getTemplate(templateName) {
  28. return document.querySelector(`#${templateName}-template`).innerHTML;
  29. }
  30. // Get query from URI.
  31. function getSearchQuery(name) {
  32. return decodeURIComponent((location.search.split(name + '=')[1] || '').split('&')[0]).replace(/\+/g, ' ');
  33. }
  34. // On page load, check for search query in URL.
  35. document.addEventListener('DOMContentLoaded', () => {
  36. let queryURL = getSearchQuery('q');
  37. if (queryURL) {
  38. $('body').addClass('searching');
  39. $('.search-results').css({opacity: 0, visibility: 'visible'}).animate({opacity: 1}, 200);
  40. let commonQueries = document.querySelector('#search-common-queries');
  41. commonQueries.style.display = 'none';
  42. }
  43. if (typeof instantsearch === 'function' && $('#search-box').length) {
  44. const search = instantsearch({
  45. indexName: algoliaConfig.indexName,
  46. searchClient: algoliasearch(algoliaConfig.appId, algoliaConfig.apiKey),
  47. searchParameters: {
  48. clickAnalytics: algoliaConfig.analytics,
  49. enablePersonalization: algoliaConfig.personalization,
  50. },
  51. searchFunction(helper) {
  52. if (helper.state.query) {
  53. helper.search();
  54. }
  55. },
  56. routing: {
  57. router: instantsearch.routers.history({
  58. parseURL() {
  59. return {
  60. q: getSearchQuery('q'),
  61. };
  62. },
  63. }),
  64. stateMapping: {
  65. stateToRoute(uiState) {
  66. const indexUiState = uiState[algoliaConfig.indexName];
  67. return {
  68. q: indexUiState.query,
  69. };
  70. },
  71. routeToState(routeState) {
  72. return {
  73. [algoliaConfig.indexName]: {
  74. query: routeState.q,
  75. },
  76. };
  77. },
  78. },
  79. },
  80. });
  81. let timerId = undefined;
  82. let searchResults = document.querySelector('#search-hits');
  83. let commonQueries = document.querySelector('#search-common-queries');
  84. // Initialize search box.
  85. search.addWidget(
  86. instantsearch.widgets.searchBox({
  87. container: '#search-box',
  88. autofocus: true,
  89. showReset: true,
  90. placeholder: i18n.placeholder,
  91. queryHook(query, refine) {
  92. if (query === '') {
  93. searchResults.style.display = 'none';
  94. commonQueries.style.display = 'block';
  95. } else {
  96. commonQueries.style.display = 'none';
  97. searchResults.style.display = 'block';
  98. }
  99. if (timerId) {
  100. clearTimeout(timerId);
  101. }
  102. timerId = setTimeout(() => refine(query), 300);
  103. },
  104. }),
  105. );
  106. // Initialize search results.
  107. search.addWidget(
  108. instantsearch.widgets.infiniteHits({
  109. container: '#search-hits',
  110. escapeHTML: true,
  111. templates: {
  112. empty: '<div class="search-no-results">' + i18n.no_results + '</div>',
  113. item: getTemplate('search-hit-algolia'),
  114. },
  115. cssClasses: {
  116. loadMore: 'btn btn-outline-primary',
  117. },
  118. }),
  119. );
  120. // On render search results, localize the content type metadata.
  121. search.on('render', function () {
  122. $('.search-hit-type').each(function () {
  123. let content_key = $(this).text();
  124. if (content_key in content_type) {
  125. $(this).text(content_type[content_key]);
  126. }
  127. });
  128. });
  129. if (algoliaConfig.analytics) {
  130. const insightsMiddleware = instantsearch.middlewares.createInsightsMiddleware({
  131. insightsClient: window.aa,
  132. insightsInitParams: {
  133. useCookie: true,
  134. },
  135. });
  136. search.use(insightsMiddleware);
  137. }
  138. // Start search.
  139. search.start();
  140. }
  141. });