search.html 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. {% extends "layout.html" %}
  2. {% set title = _('Search') %}
  3. {% block body %}
  4. <noscript>
  5. <div id="fallback" class="admonition warning">
  6. <p class="last">
  7. {% trans trimmed %}Please activate JavaScript to enable the search
  8. functionality.{% endtrans %}
  9. </p>
  10. </div>
  11. </noscript>
  12. <div id="search-results">
  13. </div>
  14. <nav id="pagination" class="pagination" aria-label="pagination" hidden="true" >
  15. <button class="pagination-previous" id="pagination-previous">
  16. ← Previous
  17. </button>
  18. <ul class="pagination-list"></ul>
  19. <button class="pagination-next" id="pagination-next">
  20. Next →
  21. </button>
  22. </nav>
  23. {% endblock %}
  24. {% block footer %}
  25. {{ super() }}
  26. <script>
  27. function runSearchPageSearch(page) {
  28. const urlParams = new URLSearchParams(window.location.search)
  29. const query = urlParams.get('q')
  30. const searchResultsContainer = document.getElementById('search-results')
  31. // Erase previous results
  32. searchResultsContainer.innerHTML = ""
  33. document.querySelector('.pagination-list').innerHTML = ""
  34. addHeadingForQuery(query, searchResultsContainer)
  35. const docSearch = docSearchReady()
  36. const index = docSearch.client.initIndex('wagtail')
  37. index.search(
  38. query,
  39. {
  40. hitsPerPage: 100,
  41. page: page,
  42. facetFilters: [getVersionFacetFilter()]
  43. }
  44. )
  45. .then(result => {
  46. // Display pagination if more than 1 page returned
  47. let nbPages = result["nbPages"]
  48. if (nbPages > 1) {
  49. document.querySelector("#pagination").hidden = false;
  50. displayPagination(page, nbPages)
  51. }
  52. // Display hits
  53. let hits = result["hits"]
  54. addResultsList(hits, query, searchResultsContainer)
  55. })
  56. .catch((error) => console.log(error))
  57. }
  58. function displayPagination(page, totalPages) {
  59. const pagination = document.querySelector("#pagination")
  60. const paginationList = pagination.querySelector(".pagination-list")
  61. // Hide previous/next button if showing first/last page
  62. pagination.querySelector(".pagination-previous").hidden = false;
  63. pagination.querySelector(".pagination-previous").hidden = page === 0;
  64. pagination.querySelector(".pagination-next").hidden = page === totalPages -1;
  65. // Display at most "toBeDisplayed" page links in the paginator
  66. const toBeDisplayed = 7
  67. let [start, end] = setStartEndForPaginator(page, totalPages, toBeDisplayed)
  68. for (let i = start; i < end; i++) {
  69. let newPaginationItem = document.createElement("li")
  70. let newPaginationbutton = document.createElement("button")
  71. newPaginationbutton.classList.add("pagination-button")
  72. newPaginationbutton.innerHTML = i + 1
  73. if (i == page) {
  74. newPaginationbutton.setAttribute("aria-label", `page ${i+1}`)
  75. newPaginationbutton.setAttribute("aria-current", "page")
  76. } else {
  77. newPaginationbutton.setAttribute("aria-label", `Go to page ${i+1}`)
  78. }
  79. // Register event handlers
  80. newPaginationbutton.onclick = function() {
  81. runSearchPageSearch(i)
  82. };
  83. pagination.querySelector(".pagination-previous").onclick = function() {
  84. runSearchPageSearch(page - 1)
  85. };
  86. pagination.querySelector(".pagination-next").onclick = function() {
  87. runSearchPageSearch(page + 1)
  88. };
  89. newPaginationItem.append(newPaginationbutton)
  90. paginationList.append(newPaginationItem)
  91. }
  92. }
  93. function setStartEndForPaginator(currentPage, totalPages, nbPagesLinkToDisplay) {
  94. let start = 0
  95. let end = totalPages
  96. if (totalPages > nbPagesLinkToDisplay) {
  97. start = currentPage
  98. if (totalPages - currentPage < nbPagesLinkToDisplay) {
  99. start = totalPages - nbPagesLinkToDisplay
  100. }
  101. if (totalPages - start > nbPagesLinkToDisplay) {
  102. end = currentPage + nbPagesLinkToDisplay
  103. }
  104. }
  105. return [start, end]
  106. }
  107. function addHeadingForQuery(query, parentElement) {
  108. const searchHeading = document.createElement('h1')
  109. searchHeading.textContent = `Search results for “${query}”`
  110. parentElement.appendChild(searchHeading)
  111. }
  112. function addResultsList(hits, query, parentElement) {
  113. const searchResultsList = document.createElement('ul')
  114. searchResultsList.className = "search"
  115. for (hit of hits) {
  116. const hitElement = createHitElement(hit, query)
  117. searchResultsList.appendChild(hitElement)
  118. }
  119. parentElement.appendChild(searchResultsList)
  120. }
  121. function createHitElement(hitData, query) {
  122. const pageURL = new URL(hitData.url)
  123. pageURL.hash = '';
  124. pageURL.searchParams.set('highlight', query);
  125. const anchorURL = new URL(hitData.url);
  126. anchorURL.searchParams.set('highlight', query);
  127. const result = hitData._highlightResult
  128. const hitListElement = document.createElement('li')
  129. const hierarchies = Object.values(result.hierarchy);
  130. const firstHierarchyLevel = hierarchies[0];
  131. const lastHierarchyLevel = hierarchies[hierarchies.length - 1];
  132. const pageLink = document.createElement('a')
  133. hitListElement.appendChild(pageLink)
  134. pageLink.innerHTML = firstHierarchyLevel.value
  135. pageLink.href = pageURL
  136. const contextElement = document.createElement('div')
  137. hitListElement.appendChild(contextElement)
  138. contextElement.className = 'context'
  139. if (lastHierarchyLevel && lastHierarchyLevel !== firstHierarchyLevel ) {
  140. const contextLinkContainer = document.createElement('div')
  141. contextElement.appendChild(contextLinkContainer)
  142. const contextLink = document.createElement('a')
  143. contextLinkContainer.appendChild(contextLink)
  144. contextLink.innerHTML = lastHierarchyLevel.value
  145. contextLink.href = anchorURL
  146. }
  147. if (result.content) {
  148. const contentElement = document.createElement('div')
  149. contentElement.innerHTML = result.content.value
  150. contextElement.appendChild(contentElement)
  151. }
  152. return hitListElement
  153. }
  154. window.addEventListener('DOMContentLoaded', () => runSearchPageSearch(0));
  155. </script>
  156. {% endblock %}