|
8 | 8 | var SOLIDUS_KEY_CODE = 191
|
9 | 9 | var SEARCH_FILTER_ACTIVE_KEY = 'docs:search-filter-active'
|
10 | 10 | var SAVED_SEARCH_STATE_KEY = 'docs:saved-search-state'
|
| 11 | + var SAVED_SEARCH_STATE_VERSION = '1' |
11 | 12 |
|
12 | 13 | activateSearch(require('docsearch.js/dist/cdn/docsearch.js'), document.getElementById('search-script').dataset)
|
13 | 14 |
|
14 | 15 | function activateSearch (docsearch, config) {
|
15 | 16 | appendStylesheet(config.stylesheet)
|
16 | 17 | var baseAlgoliaOptions = {
|
17 |
| - hitsPerPage: parseInt(config.maxResults) || 15, |
| 18 | + hitsPerPage: parseInt(config.pageSize) || 20, // cannot exceed the hitsPerPage value defined on the index |
18 | 19 | }
|
19 | 20 | var searchField = document.getElementById(config.searchFieldId || 'search')
|
20 | 21 | searchField.appendChild(Object.assign(document.createElement('div'), { className: 'algolia-autocomplete-results' }))
|
|
32 | 33 | autoWidth: false,
|
33 | 34 | templates: {
|
34 | 35 | footer:
|
35 |
| - '<div class="ds-footer"><div class="algolia-docsearch-footer">' + |
| 36 | + '<div class="ds-footer"><div class="ds-pagination">' + |
| 37 | + '<span class="ds-pagination--curr">Page 1</span>' + |
| 38 | + '<a href="#" class="ds-pagination--prev">Prev</a>' + |
| 39 | + '<a href="#" class="ds-pagination--next">Next</a></div>' + |
| 40 | + '<div class="algolia-docsearch-footer">' + |
36 | 41 | 'Search by <a class="algolia-docsearch-footer--logo" href="https://www.algolia.com/docsearch" ' +
|
37 | 42 | 'target="_blank" rel="noopener">Algolia</a>' +
|
38 | 43 | '</div></div>',
|
39 | 44 | },
|
40 | 45 | },
|
41 |
| - algoliaOptions: baseAlgoliaOptions, |
42 |
| - transformData: protectHitOrder, |
43 |
| - queryHook: |
44 |
| - searchField.classList.contains('has-filter') && |
45 |
| - function (query) { |
46 |
| - controller.algoliaOptions = typeahead.$facetFilterInput.prop('checked') |
47 |
| - ? Object.assign({}, baseAlgoliaOptions, { facetFilters: [typeahead.$facetFilterInput.data('facetFilter')] }) |
48 |
| - : baseAlgoliaOptions |
49 |
| - }, |
| 46 | + baseAlgoliaOptions: baseAlgoliaOptions, |
50 | 47 | })
|
51 | 48 | var input = controller.input
|
52 | 49 | var typeahead = input.data('aaAutocomplete')
|
53 | 50 | var dropdown = typeahead.dropdown
|
54 | 51 | var menu = dropdown.$menu
|
55 | 52 | var dataset = dropdown.datasets[0]
|
56 | 53 | dataset.cache = false
|
| 54 | + dataset.source = controller.getAutocompleteSource(undefined, processQuery.bind(typeahead, controller)) |
57 | 55 | delete dataset.templates.footer
|
| 56 | + controller.queryDataCallback = processQueryData.bind(typeahead) |
58 | 57 | typeahead.setVal() // clear value on page reload
|
59 | 58 | input.on('autocomplete:closed', clearSearch.bind(typeahead))
|
60 | 59 | input.on('autocomplete:cursorchanged autocomplete:cursorremoved', saveSearchState.bind(typeahead))
|
|
71 | 70 | .find('.filter input')
|
72 | 71 | .on('change', toggleFilter.bind(typeahead))
|
73 | 72 | .prop('checked', window.localStorage.getItem(SEARCH_FILTER_ACTIVE_KEY) === 'true')
|
| 73 | + menu.find('.ds-pagination--prev').on('click', paginate.bind(typeahead, -1)).css('visibility', 'hidden') |
| 74 | + menu.find('.ds-pagination--next').on('click', paginate.bind(typeahead, 1)).css('visibility', 'hidden') |
74 | 75 | monitorCtrlKey.call(typeahead)
|
75 | 76 | searchField.addEventListener('click', confineEvent)
|
76 | 77 | document.documentElement.addEventListener('click', clearSearch.bind(typeahead))
|
|
87 | 88 | } else if (e.persisted && !isClosed(this)) {
|
88 | 89 | this.$input.focus()
|
89 | 90 | this.$input.val(this.getVal())
|
| 91 | + this.dropdown.datasets[0].page = this.dropdown.$menu.find('.ds-pagination--curr').data('page') |
90 | 92 | } else if (window.sessionStorage.getItem('docs:restore-search-on-back') === 'true') {
|
91 | 93 | if (!window.matchMedia('(min-width: 1024px)').matches) document.querySelector('.navbar-burger').click()
|
92 | 94 | restoreSearch.call(this)
|
|
104 | 106 | var restoring = dropdown.restoring
|
105 | 107 | delete dropdown.restoring
|
106 | 108 | if (isClosed(this)) return
|
107 |
| - getScrollableResultsContainer(dropdown).scrollTop(0) |
| 109 | + updatePagination.call(dropdown) |
108 | 110 | if (restoring && restoring.query === this.getVal() && restoring.filter === this.$facetFilterInput.prop('checked')) {
|
109 | 111 | var cursor = restoring.cursor
|
110 | 112 | if (cursor) dropdown._moveCursor(cursor)
|
|
164 | 166 | function onCtrlKeyDown (e) {
|
165 | 167 | if (e.keyCode !== CTRL_KEY_CODE) return
|
166 | 168 | this.ctrlKeyDown = true
|
167 |
| - var dropdown = this.dropdown |
168 |
| - var container = getScrollableResultsContainer(dropdown) |
| 169 | + var container = getScrollableResultsContainer(this.dropdown) |
169 | 170 | var prevScrollTop = container.scrollTop()
|
170 |
| - dropdown.getCurrentCursor().find('a').focus() |
| 171 | + this.dropdown.getCurrentCursor().find('a').focus() |
171 | 172 | container.scrollTop(prevScrollTop) // calling focus can cause the container to scroll, so restore it
|
172 | 173 | }
|
173 | 174 |
|
|
195 | 196 | }
|
196 | 197 | }
|
197 | 198 |
|
198 |
| - function clearSearch () { |
199 |
| - this.isActivated = true // we can't rely on this state being correct |
200 |
| - this.setVal() |
201 |
| - delete this.ctrlKeyDown |
| 199 | + function paginate (delta, e) { |
| 200 | + e.preventDefault() |
| 201 | + var dataset = this.dropdown.datasets[0] |
| 202 | + dataset.page = (dataset.page || 0) + delta |
| 203 | + requery.call(this) |
| 204 | + } |
| 205 | + |
| 206 | + function updatePagination () { |
| 207 | + var result = this.datasets[0].result |
| 208 | + var page = result.page |
| 209 | + var menu = this.$menu |
| 210 | + menu |
| 211 | + .find('.ds-pagination--curr') |
| 212 | + .html(result.pages ? 'Page ' + (page + 1) + ' of ' + result.pages : 'No results') |
| 213 | + .data('page', page) |
| 214 | + menu.find('.ds-pagination--prev').css('visibility', page > 0 ? '' : 'hidden') |
| 215 | + menu.find('.ds-pagination--next').css('visibility', result.pages > page + 1 ? '' : 'hidden') |
| 216 | + getScrollableResultsContainer(this).scrollTop(0) |
202 | 217 | }
|
203 | 218 |
|
204 | 219 | function requery (query) {
|
|
209 | 224 | this.dropdown.open()
|
210 | 225 | }
|
211 | 226 |
|
| 227 | + function clearSearch () { |
| 228 | + this.isActivated = true // we can't rely on this state being correct |
| 229 | + this.setVal() |
| 230 | + delete this.ctrlKeyDown |
| 231 | + delete this.dropdown.datasets[0].result |
| 232 | + } |
| 233 | + |
| 234 | + function processQuery (controller, query) { |
| 235 | + var algoliaOptions = {} |
| 236 | + if (this.$facetFilterInput.prop('checked')) { |
| 237 | + algoliaOptions.facetFilters = [this.$facetFilterInput.data('facetFilter')] |
| 238 | + } |
| 239 | + var dataset = this.dropdown.datasets[0] |
| 240 | + var activeResult = dataset.result |
| 241 | + algoliaOptions.page = !activeResult || query === activeResult.query ? dataset.page || 0 : (dataset.page = 0) |
| 242 | + controller.algoliaOptions = Object.keys(algoliaOptions).length |
| 243 | + ? Object.assign({}, controller.baseAlgoliaOptions, algoliaOptions) |
| 244 | + : controller.baseAlgoliaOptions |
| 245 | + } |
| 246 | + |
| 247 | + function processQueryData (data) { |
| 248 | + var result = data.results[0] |
| 249 | + this.dropdown.datasets[0].result = { page: result.page, pages: result.nbPages, query: result.query } |
| 250 | + result.hits = preserveHitOrder(result.hits) |
| 251 | + } |
| 252 | + |
212 | 253 | // preserves the original order of results by qualifying unique occurrences of the same lvl0 and lvl1 values
|
213 |
| - function protectHitOrder (hits) { |
| 254 | + function preserveHitOrder (hits) { |
214 | 255 | var prevLvl0
|
215 | 256 | var lvl0Qualifiers = {}
|
216 | 257 | var lvl1Qualifiers = {}
|
|
236 | 277 | function readSavedSearchState () {
|
237 | 278 | try {
|
238 | 279 | var state = window.localStorage.getItem(SAVED_SEARCH_STATE_KEY)
|
239 |
| - if (state) return JSON.parse(state) |
| 280 | + if (state && (state = JSON.parse(state))._version.toString() === SAVED_SEARCH_STATE_VERSION) return state |
240 | 281 | } catch (e) {
|
241 | 282 | window.localStorage.removeItem(SAVED_SEARCH_STATE_KEY)
|
242 | 283 | }
|
|
247 | 288 | if (!searchState) return
|
248 | 289 | this.dropdown.restoring = searchState
|
249 | 290 | this.$facetFilterInput.prop('checked', searchState.filter) // change event will be ignored
|
| 291 | + var dataset = this.dropdown.datasets[0] |
| 292 | + dataset.page = searchState.page |
| 293 | + delete dataset.result |
250 | 294 | requery.call(this, searchState.query) // cursor is restored by onResultsUpdated =>
|
251 | 295 | }
|
252 | 296 |
|
|
255 | 299 | window.localStorage.setItem(
|
256 | 300 | SAVED_SEARCH_STATE_KEY,
|
257 | 301 | JSON.stringify({
|
258 |
| - query: this.getVal(), |
259 |
| - filter: this.$facetFilterInput.prop('checked'), |
| 302 | + _version: SAVED_SEARCH_STATE_VERSION, |
260 | 303 | cursor: this.dropdown.getCurrentCursor().index() + 1,
|
| 304 | + filter: this.$facetFilterInput.prop('checked'), |
| 305 | + page: this.dropdown.datasets[0].page, |
| 306 | + query: this.getVal(), |
261 | 307 | })
|
262 | 308 | )
|
263 | 309 | }
|
|
0 commit comments