PageSourceSearch

https://www.larocheposay.com/wp-content/themes/noyau/assets/js/Search/Search.js?ver=6.8.7

js larocheposay.com collected 2026-09-24 10:12:56 UTC 36,208 bytes, 846 lines download raw bytes

1ready = (callback) => {
2    if (document.readyState !== 'loading') {
3        callback()
4    } else {
5        document.addEventListener('DOMContentLoaded', callback)
6    }
7}
8
9function escapeHtml(text) {
10    var map = {
11        '&': '&',
12        '<': '&lt;',
13        '>': '&gt;',
14        '"': '&quot;',
15        "'": '&#039;'
16    };
17
18    return text.replace(/[&<>"']/g, function (m) {
19        return map[m];
20    });
21}
22
23ready(() => {
24
25    /**
26     * Get data from the wp_localize_script
27     *
28     * ElasticSearch.postType is the CPT list with their name and label
29     * ElasticSearch.indexName is the ElasticSearch index name
30     * */
31    const cpt = ElasticSearch.postType
32    const indexName = ElasticSearch.indexName
33
34    /**
35     * Query the selectors that are use is this script
36     * $searchInput is the input where you write your search
37     * $searchResult is the contaire where the suggestion are inject
38     * */
39    const $searchInput = document.querySelectorAll('.searchInput')
40
41    /**
42     * Get the parameters in the URL
43     * "s" for the search terms
44     * "page" for the number of page that we multiple by 10 to have the correct number of posts per page to display
45     * */
46    const searchQuery = window.location.search
47    let params = new URLSearchParams(searchQuery);
48    let searchedWords = String(params.get("s"))
49    searchedWords = escapeHtml(searchedWords)
50
51    // Create the URL to the right index in the ElasticSearch API
52    let URL = `https://apis.creasrv.net/${indexName}/_search`
53    // URL += '?filter_path=hits.hits._id,'
54    // URL += 'hits.total,'
55    // URL += 'hits.hits._score,'
56    // URL += 'hits.hits._source.post_title,'
57    // URL += 'hits.hits._source.meta.top_post_group_top_post_introduction.value,'
58    // URL += 'hits.hits._source.permalink,'
59    // URL += 'hits.hits._source.post_type,'
60
61    // Create an instance of PostQuery class
62    const Query = new PostsQuery()
63    Query.URLQuery = `?s=${searchedWords}`
64    let fetchArgs = Query.fetchArgs(searchedWords)
65
66    // Init the default post offset, we increment it later
67    let offset = 0;
68
69    let n = 0;
70    /***
71     * This listener is used to get the value from the search input and
72     * load the search results page if the result has content
73     ****/
74    const $searchSVG = document.querySelectorAll('.search-svg')
75    $searchSVG.forEach(function (search) {
76        !!search &&
77        search.addEventListener('click', function () {
78            let $searchInput = this.closest('.search-container').querySelector('.searchInput');
79            if ($searchInput.value.length > 0) {
80                window.location.href = '/?s=' + $searchInput.value
81            }
82        })
83    })
84
85    if (searchedWords !== 'null') {
86
87        // Init the var where we stock the URL parameters
88        let postPerPage = 10
89        let URLcpt
90        let URLdate
91        let pages = Number(params.get("pages")) ?? 0
92
93        // Get the loaded pages' number
94        if (params.get("pages")) {
95            postPerPage = Number(params.get("pages")) * postPerPage;
96        }
97        // Get the selected CPT
98        if (params.get("cpt")) {
99            URLcpt = params.get("cpt");
100            URLcpt = URLcpt.split(',');
101        }
102        // Get the selected range date
103        if (params.get("date")) {
104            URLdate = params.get("date");
105        }
106
107
108        // Search page html selector
109        const $sampleContainer = document.querySelector('.hide[data-sample="searchResult"]')
110        const $resultContainer = document.querySelector('#search_publications') ?? ''
111        const $pageIntroContainer = document.querySelector('.cover__intro') ?? ''
112        const $paginationContainer = document.querySelector('#searchPagination') ?? ''
113        const $paginationButton = document.querySelector('#load-older-posts') ?? ''
114        const $foundPostsContainer = document.querySelector('#foundPosts') ?? ''
115        const $visiblePosts = document.querySelector('#posts_per_page')
116        const $postResultFilters = document.querySelector('#filters-results')
117        const $postTypesFilter = document.querySelector('#postType')
118        const $postTypesInput = document.querySelector('#postTypeInput')
119        const $dateFilter = document.querySelector('#publicationDate')
120        const $dateInput = document.querySelector('#dateInput')
121        const $customFiltersInput = document.querySelectorAll('.filter_custom .filter__input-container input')
122        const $customFilters = document.querySelectorAll('.filter_custom .filter__custom-container ul')
123
124        const $validateFilter = document.querySelector('#validateSystemeFilter')
125        const $resetFilter = document.querySelector('#resetSystemeFilter')
126        const $filters = document.querySelector('.filter__options')
127
128
129        if ($resultContainer) {
130            const selectBoxes = document.querySelectorAll('.select-box')
131
132            !!selectBoxes &&
133            selectBoxes.forEach((selectBox) => {
134                selectBox.addEventListener('click', function () {
135                    if (selectBox.classList.contains('is-closed')) {
136                        selectBox.classList.replace('is-closed', 'is-open')
137                    } else {
138                        selectBox.classList.replace('is-open', 'is-closed')
139                    }
140                })
141            })
142
143            document.addEventListener('click', function (event) {
144                let selectBoxes = document.querySelectorAll('.select-box.is-open')
145                selectBoxes.forEach((selectBox) => {
146                    if (selectBox !== null && selectBox !== event.target.closest('.select-box')) {
147                        selectBox.classList.replace('is-open', 'is-closed')
148                    }
149                })
150            })
151
152            let elementSelected = $filters.querySelectorAll('.selected')
153            // If no element fit the selector, we restore the "reset button" to its original state
154            if (elementSelected.length === 0) {
155                $resetFilter.classList.add('empty-selection')
156                $validateFilter.classList.add('empty-selection')
157            }
158
159        }
160        // Check the checkbox where the value is present in the URLcpt array
161        if ($postTypesFilter && URLcpt !== undefined) {
162            URLcpt.forEach((cpt) => {
163                $postTypesFilter.querySelector(`input[value=${cpt}]`).checked = true
164            })
165        }
166        // Check the checkbox if the URL date is set
167        if ($dateFilter && URLdate !== undefined) {
168            $dateFilter.querySelector(`input[value=${URLdate}]`).checked = true
169        }
170
171        if ($customFilters) {
172            $customFilters.forEach(function ($customFilter) {
173                let URLCustomFilter = ''
174                let param = $customFilter.closest('.filter_custom').querySelector('.filter__input-container input').getAttribute('id')
175                if (params.get(param)) {
176                    URLCustomFilter = params.get(param);
177                }
178
179                if (URLCustomFilter) {
180                    $customFilter.querySelector(`input[value=${URLCustomFilter}]`).checked = true
181                }
182            })
183
184        }
185
186        let filtersKey = ['keyword']
187
188        /***
189         * Function triggered after page load
190         * and on ES fetch query when one of #postType checkbox is checked
191         *
192         * Add or remove the value from :
193         * 1. The Query.URLArgs object where we store the parameters present inside the URL
194         * 2. The Query.FetchArgs object where we store the data require to query the ElasticSearch server
195         *
196         * To understand the structure of the below objects and arrays you need to understand the structure
197         * of the ElasticSearch bool query
198         *
199         * @doc https://www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html
200         ****/
201        function updateCPT() {
202            // Get the $postTypesFilter checkbox NodList
203            let checkboxes = $postTypesFilter.querySelectorAll('input[type="checkbox"]:checked')
204
205            // Init values
206            let value = ''
207
208            // Init the Query.URLArgs object with the cpt entry
209            Query.URLArgs.cpt = {}
210
211            // Init the Query.URLArgs object with the parameterValue array
212            Query.URLArgs.cpt.parameterValue = []
213
214            if (!filtersKey.includes('cpt')) {
215                filtersKey.push('cpt')
216            }
217            // Create the new bool.should entry in the bool.must array from the fetchArgs method
218            // It allows us to make cross filter query on ElasticSearch
219            // According to the ElasticSearch process
220            let newBool = {
221                bool: {
222                    should: []
223                }
224            }
225
226            // Init the var where we store the selected cpt query
227            let newMatch
228            // For each checkbox
229            for (let i = 0; i < checkboxes.length; i++) {
230                // We store the checkbox value
231                let checkbox = checkboxes[i]
232                // if it's checked
233                if (checkbox.checked === true) {
234
235                    // If we are on the last checkbox element of the NodeList
236                    // We don't add a comma
237                    if (i === Number(checkboxes.length - 1)) {
238                        value += `${checkbox.dataset.label}`
239                    } else {
240                        value += `${checkbox.dataset.label}, `
241                    }
242
243                    // We push its value in the Query.URLArgs.cpt.parameterValue
244                    Query.URLArgs.cpt.parameterValue.push(checkbox.value)
245
246                    // Add the checked checkbox value in the newMatch object
247                    newMatch = {
248                        multi_match: {
249                            query: checkbox.value,
250                            fields: [
251                                'post_type'
252                            ],
253                        }
254                    }
255                    // Push this new object inside the newBool.bool.should array
256                    newBool.bool.should.push(newMatch)
257
258                }
259            }
260            // If newMatch isn't undefined it means that one value at least has been selected
261            if (newMatch !== undefined) {
262                // We limit the value to 80 characters based of a Query class method
263                $postTypesInput.value = Query.truncate(value, 80, '...', ',')
264
265
266                // The $subCategoriesInput has class selected
267                $postTypesInput.classList.add('selected')
268
269                // So we can add the "should" query to the fetchArgs object used to fill the ElasticSearch query.
270                let n = filtersKey.indexOf('cpt')
271                fetchArgs.bool.must[n] = newBool
272
273            } else {
274                // Remove the argument from the URL builder
275                delete Query.URLArgs.cpt
276
277                // Restore the original $subCategoriesInput condition
278                $postTypesInput.value = ''
279                $postTypesInput.classList.remove('selected')
280
281                // Get all elements which have .selected as class
282                let elementSelected = $filters.querySelectorAll('.selected')
283                // If no element fit the selector, we restore the "reset button" to its original state
284                if (elementSelected.length === 0) {
285                    $resetFilter.classList.add('empty-selection')
286                    $validateFilter.classList.add('empty-selection')
287                }
288
289                fetchArgs.bool.must.splice(filtersKey.indexOf('cpt'), 1)
290                filtersKey.splice(filtersKey.indexOf('cpt'), 1)
291            }
292        }
293
294        /***
295         * Function triggered after page load
296         * and on ES fetch query when one of #publicationDate checkbox is checked
297         *
298         * Add or remove the value from :
299         * 1. The Query.URLArgs object where we store the parameters present inside the URL
300         * 2. The Query.FetchArgs object where we store the data require to query the ElasticSearch server
301         *
302         * To understand the structure of the below objects and arrays you need to understand the structure
303         * of the ElasticSearch bool query
304         *
305         * @doc https://www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html
306         ****/
307        function updateDate() {
308            // Get the $dateFilter checkbox NodList
309            let checkbox = $dateFilter.querySelectorAll('input[type="radio"]:checked')
310
311            if (checkbox.length > 0) {
312
313
314                // Init values
315                let value = checkbox[0].value
316
317                // Init the Query.URLArgs object with the cpt entry
318                Query.URLArgs.date = {}
319
320                // Init the Query.URLArgs object with the parameterValue array
321                Query.URLArgs.date.parameterValue = []
322
323                // For each checkbox
324                if (value !== 'no_date') {
325
326                    // We limit the value to 80 characters based of a Query class method
327                    $postTypesInput.value = value
328
329                    // The $subCategoriesInput has class selected
330                    $postTypesInput.classList.add('selected')
331
332                    // We push its value in the Query.URLArgs.cpt.parameterValue
333                    Query.URLArgs.date.parameterValue.push(value)
334
335                    // Init the filter object for the ES bool query
336                    fetchArgs.bool.filter = {}
337                    // Add the checked checkbox value in the ES query range filter
338                    fetchArgs.bool.filter.range = {"post_date": {gte: value, lte: "now"}}
339                } else {
340                    // Empty the date object of the Query.URLArgs
341                    Query.URLArgs.date = {}
342
343                    // Remove the filter object for the ES book query
344                    if (fetchArgs.bool) {
345                        delete fetchArgs.bool.filter
346                    }
347
348                    // Restore the original $subCategoriesInput condition
349                    $dateInput.value = ''
350                    $dateInput.classList.remove('selected')
351
352                    // Get all elements which have .selected as class
353                    let elementSelected = $filters.querySelectorAll('.selected')
354                    // If no element fit the selector, we restore the "reset button" to its original state
355                    if (elementSelected.length === 0) {
356                        $resetFilter.classList.add('empty-selection')
357                        $validateFilter.classList.add('empty-selection')
358                    }
359                }
360            }
361        }
362
363        function updateCustomFilters() {
364            // Get the $dateFilter checkbox NodList
365            !!$customFilters &&
366            $customFilters.forEach(function ($customFilter) {
367                let checkboxes = $customFilter.querySelectorAll('input[type="checkbox"]:checked')
368                let param = $customFilter.closest('.filter_custom').querySelector('.filter__input-container input').getAttribute('id')
369                let value = ''
370
371                if (!filtersKey.includes(param)) {
372                    filtersKey.push(param)
373                }
374                // Init the Query.URLArgs object with the cpt entry
375                Query.URLArgs[param] = {}
376
377                // Init the Query.URLArgs object with the parameterValue array
378                Query.URLArgs[param].parameterValue = []
379
380                let newBool = {
381                    bool: {
382                        must: []
383                    }
384                }
385
386                // Init the var where we store the selected cpt query
387                let newMatch
388
389
390                // The $subCategoriesInput has class selected
391                $customFilter.closest('.filter_custom').querySelector('.filter__input-container input').classList.add('selected')
392
393                for (let i = 0; i < checkboxes.length; i++) {
394                    // We store the checkbox value
395                    let checkbox = checkboxes[i]
396
397                    Query.URLArgs[param].parameterValue.push(checkbox.value)
398
399                    // If we are on the last checkbox element of the NodeList
400                    // We don't add a comma
401                    if (i === Number(checkboxes.length - 1)) {
402                        value += `${checkbox.getAttribute('id')}`
403                    } else {
404                        value += `${checkbox.getAttribute('id')}, `
405                    }
406
407                    // Add the checked checkbox value in the newMatch object
408                    newMatch = {
409                        multi_match: {
410                            query: checkbox.value,
411                            fields: [
412                                'meta.' + param + '.value'
413                            ],
414                            operator: 'and'
415                        }
416                    }
417                    // Push this new object inside the newBool.bool.should array
418                    newBool.bool.must.push(newMatch)
419
420                    // We limit the value to 80 characters based of a Query class method
421                    $customFilter.closest('.filter_custom').querySelector('.filter__input-container input').value = Query.truncate(value, 80, '...', ',')
422                }
423
424                if (newMatch !== undefined) {
425                    // We can add the "should" query to the fetchArgs object used to fill the ElasticSearch query.
426                    let n = filtersKey.indexOf(param)
427                    fetchArgs.bool.must[n] = newBool
428                } else {
429                    // Remove the argument from the URL builder
430                    delete Query.URLArgs[param]
431
432                    // Restore the original $subCategoriesInput condition
433                    $customFilter.closest('.filter_custom').querySelector('.filter__input-container input').value.value = ''
434                    $customFilter.closest('.filter_custom').querySelector('.filter__input-container input').classList.remove('selected')
435
436                    // Get all elements which have .selected as class
437                    let elementSelected = $filters.querySelectorAll('.selected')
438                    // If no element fit the selector, we restore the "reset button" to its original state
439                    if (elementSelected.length === 0) {
440                        $resetFilter.classList.add('empty-selection')
441                        $validateFilter.classList.add('empty-selection')
442                    }
443
444                    fetchArgs.bool.must.splice(filtersKey.indexOf(param), 1)
445                    filtersKey.splice(filtersKey.indexOf(param), 1)
446                }
447            })
448        }
449
450        // After page load execute the fuction below if the #publicationDate filter is present
451        if ($dateFilter) {
452            updateDate()
453        }
454
455        // After page load execute the fuction below if the #postType filter is present
456        if ($postTypesFilter) {
457            updateCPT()
458        }
459
460        if ($customFilters) {
461            updateCustomFilters()
462        }
463        /***
464         * Check for the filter validation button's presence and listen his click
465         *
466         * This function is used to build and submit the query to the ES server
467         * Although it builds the url parameter that will be pushed in the page url
468         ****/
469        !!$validateFilter &&
470        $validateFilter.addEventListener('click', function () {
471
472            // As this is a new search, we don't keep the post previously dis
472played
473            Query.nextPage = false
474
475            pages = 0
476            offset = 0
477
478            // Exectute the updateDate() function if #publicationDate is present
479            if ($dateFilter) {
480                updateDate()
481            }
482
483            // Exectute the updateDate() function if #postType is present
484            if ($postTypesFilter) {
485                updateCPT()
486            }
487
488            if ($customFilters) {
489                updateCustomFilters()
490            }
491
492            $resetFilter.classList.remove('empty-selection')
493            // As the functions below have already set the params for the URL, we execute the function
494            // which is in charge of building and displaying the URL params
495            Query.pushSearchArgsInUrl()
496
497            // Call the fetchES method from the Query class
498            execFetch()
499
500        })
501
502        !!$resetFilter &&
503        $resetFilter.addEventListener('click', function () {
504            pages = 0
505            offset = 0
506            postPerPage = 10
507
508            // Remove all the arguments in the URL
509            Object.keys(Query.URLArgs).forEach(function (arg) {
510                delete Query.URLArgs[arg]
511            })
512
513            let $selectedInputs = $filters.querySelectorAll('.selected')
514
515            let $checkedInputs = $filters.querySelectorAll('input:checked')
516
517            $selectedInputs.forEach((input) => {
518                input.classList.remove('selected')
519                input.value = ''
520            })
521
522            $checkedInputs.forEach((input) => {
523                input.checked = false
524            })
525
526            // Exectute the updateDate() function if #publicationDate is present
527            if ($dateFilter) {
528                updateDate()
529            }
530
531            // Exectute the updateDate() function if #postType is present
532            if ($postTypesFilter) {
533                updateCPT()
534            }
535
536            if ($customFilters) {
537                updateCustomFilters()
538            }
539
540            window.history.pushState(
541                '', '', Query.URLQuery
542            )
543
544            execFetch()
545
546            $resetFilter.classList.add('empty-selection')
547        })
548
549        if ($sampleContainer !== null) {
550            // Call the fetchES method from the Query class
551            execFetch()
552        }
553
554
555        !!$paginationButton && (
556            $paginationButton.addEventListener('click', function () {
557                // Call the fetchES method from the Query class
558                Query.nextPage = true
559                Query.fetchES(URL, fetchArgs, offset, postPerPage).then(
560                    data => {
561
562                        // Get the number of post found by the query
563                        let postCount = data.hits.total.value
564
565                        // Get the number of post returned by the query
566                        offset = data.hits.hits.length + offset
567
568                        // Add the number of post found and returned in the pagination information
569                        if ($paginationContainer) {
570                            // Update the displayed post information
571                            $visiblePosts.innerHTML = Number($visiblePosts.innerHTML) + Number(data.hits.hits.length)
572
573                            // Hide the load more posts button only if the number of returned post is equal to the posts found
574                            if ($visiblePosts.innerHTML === $foundPostsContainer.innerHTML) {
575                                Query.fadeOut($paginationButton)
576                            }
577                        }
578
579                        // If the response have posts, we display them
580                        if (postCount > 0) {
581
582                            // List of the posts found
583                            let hits = data.hits.hits
584
585                            // Apped the posts in the container
586                            Query.appendSearchResult($sampleContainer, $resultContainer, hits, cpt)
587
588                            // Return the page number to display it in the URL
589                            pages++
590
591                            Query.URLArgs.pages = {}
592                            Query.URLArgs.pages.parameterValue = []
593
594                            Query.URLArgs.pages.parameterValue.push(pages)
595                            Query.pushSearchArgsInUrl()
596                        } else {
597                            $resultContainer.innerHTML = $sampleC
597ontainer.outerHTML
598                            $resultContainer.innerHTML += 'Aucun résultat pour votre recherche.'
599                        }
600                    }
601                ).catch(err => {
602                    // TODO handle error to send
603                    console.log(err)
604                })
605            })
606        )
607
608        function execFetch() {
609            Query.fetchES(URL, fetchArgs, 0, postPerPage).then(
610                data => {
611                    // Get the number of post found by the query
612                    let postCount = data.hits.total.value
613
614                    // Get the number of post returned by the query
615
616                    offset = data.hits.hits.length + offset
617
618                    // Add the number of post found in the result page intro with the associated searched terms
619                    if ($pageIntroContainer) {
620                        $pageIntroContainer.innerHTML = `${postCount} résultats pour "${searchedWords}"`
621                    }
622
623                    // Add the number of post found and returned in the pagination information
624                    if ($paginationContainer) {
625                        $foundPostsContainer.innerHTML = postCount
626                        $visiblePosts.innerHTML = offset
627                    }
628
629                    // Display the load more posts button only if the number of returned post isn't equal to the posts found
630                    if (offset !== postCount) {
631                        Query.fadeIn($paginationButton)
632                    } else {
633                        Query.fadeOut($paginationButton)
634                    }
635
636                    // If the response have posts, we display them
637                    if (postCount > 0) {
638                        // List of the posts found
639                        let hits = data.hits.hits
640
641                        // Append the result
642                        Query.appendSearchResult($sampleContainer, $resultContainer, hits, cpt)
643                    } else {
644                        $resultContainer.innerHTML = $sampleContainer.outerHTML
645                        $resultContainer.innerHTML += 'Aucun résultat pour votre recherche.'
646                    }
647                }
648            ).catch(err => {
649                // TODO handle error to send
650                console.log(err)
651            })
652        }
653    }
654
655    // Function to debounce another function
656    function debounce(func, delay) {
657        let timeout;
658        return function (...args) {
659            clearTimeout(timeout);
660            timeout = setTimeout(() => func.apply(this, args), delay);
661        };
662    }
663
664    /***
665     * Script use to query the ElasticSearch API and to display his response
666     * */
667    // Once an input is detect inside the search input you trigger this script
668    $searchInput.forEach(function (input) {
669        !!input && (
670            input.addEventListener('input', debounce(async function () {
671                let $searchResult = this.closest('.container').querySelector('.searchResult');
672
673                if ($searchResult) {
674                    if (this.value.length < 3) {
675                        $searchResult.innerHTML = ''
676                        Query.fadeOut($searchResult)
677                        this.closest('div').classList.remove('search-container-open')
678                    }
679
680                    if (this.value.length > 2) {
681                        // Create the URL to redirect
682                        let urlToRedirect = '/?s=' + this.value
683
684                        fetchArgs = Query.fetchArgs(this.value)
685
686                        // Call the fetchES method from the Query class
687                        try {
688                            const data = await Query.fetchES(URL, fetchArgs)
689
690                            // If the response have posts, we display them
691                            if (data.hits.total.value > 0) {
692                                // Display the result container
693                                Query.fadeIn($searchResult)
694                                this.closest('div').classList.add('search-container-open')
695
696                                // List of the posts found
697                                let hits = data.hits.hits
698
699                                // Empty the result container to remove the default message
700                                $searchResult.innerHTML = '';
701
702                                // Build the list of posts found
703                                hits.forEach((hit) => {
704                                    // Get the post info
705                                    let ID = hit._id
706                                    let score = hit._score
707                                    let title = hit._source.post_title
708                                    let post_type = hit._source.post_type
709                                    let link = hit._source.permalink
710
711                                    // Create the li
712                                    let content = '<li class="result" id="' + ID + '" data-score="' + score + '">'
713                                    // Create the a inside the li
714                                    content += '<a class="resultTitle" href="' + link + '">' + title + '</a>'
715
716                                    // Add the CPT name to the li
717                                    // To do it we use the ElasticSearch.postType array
718                                    // to compare the CPT name and get their label
719                                    let entries = Object.entries(cpt);
720                                    entries.forEach(([name, label]) => {
721                                        if (name === post_type) {
722                                            content += '<span class="resultCPT">' + label + '</span>'
723                                        }
724                                    })
725
726                                    // Close the li
727                                    content += '</li>'
728
729                                    // Add the li to the list of result
730                                    $searchResult.innerHTML += content
731                                })
732
733                                // In the last place of the list display a link to the search page
734                                $searchResult.innerHTML += `<li class="show-all"><a href="${urlToRedirect}">Voir tous les résultats</a></li>`
735
736
737                            } else {
738                                // Display default message for no post in the response
739                                $searchResult.innerHTML = '<li class="no-results"><span>Aucun résultat ne correspond à votre recherche</span></li>'
740                            }
741                        } catch (err) {
742                            // TODO handle error to send
743                            console.log(err)
744                        }
745                    }
746                }
747            }, 375))
748        )
749    })
750
751    /*
752    * Script use to check the keydown event
753    * And enable to run through each element of the list helped with the arrow keys
754    *
755    * This script can't work without a success query that returns some results.
756    * */
757
758    // Var use to know if a list's li is already selected
759    let liSelected
760
761    //Once your have press any keycaps inside the search field you trigger this script
762    $searchInput.forEach(function (input) {
763            !!input && (
764                input.addEventListener('keydown', function (event) {
765
766                    // The list of query's ElasticSearch results
767                    const $searchList = this.closest('.container').querySelectorAll('.searchResult li');
768
769                    switch (event.keyCode) {
770
771                        case 40: // if the DOWN key is pressed
772                            // If the var liSelected isn't empty we remove the class from him and his <a>
773                            if (liSelected) {
774                                liSelected.classList.remove('selected');
775                                liSelected.firstChild.classList.remove('selected');
776                                // And we get the next li as liSelected and we add to him and his <a> the .selected
777                                let next = liSelected.nextSibling;
778                                if (next !== null) {
779                                    liSelected = next
780                                    next.classList.add('selected')
781                                    next.firstChild.classList.add('selected');
782                                } else {
783                                    // If no li left we go back to the first element of the list
784                                    liSelected = $searchList.item(0)
785                                    liSelected.classList.add('selected')
786                                    liSelected.firstChild.classList.add('selected');
787                                }
788                            } else {
789                                // If liSelected is empty we take the first element of the list
790                                liSelected = $searchList.item(0);
791                                liSelected.classList.add('selected')
792                                liSelected.firstChild.classList.add('selected');
793                            }
794                            break
795
796                        case 38: // if the UP key is pressed
797                            // If the var liSelected isn't empty we remove the class from him and his <a>
798                            if (liSelected) {
799                                liSelected.classList.remove('selected');
800                                liSelected.firstChild.classList.remove('selected');
801                                // And we get the previous li as liSelected and we add to him and his <a>
801 the .selected
802                                let previous = liSelected.previousSibling;
803                                if (previous !== null) {
804                                    liSelected = previous
805                                    previous.classList.add('selected');
806                                    previous.firstChild.classList.add('selected');
807                                } else {
808                                    // If no li left we go back to the before last element of the list
809                                    // the last element is the link to the search page
810                                    let last = $searchList[$searchList.length - 1];
811                                    liSelected = last
812                                    last.classList.add('selected');
813                                    last.firstChild.classList.add('selected');
814                                }
815                                // If liSelected is empty we take the before last element of the list
816                            } else {
817                                let last = $searchList[$searchList.length - 1];
818                                liSelected = last
819                                last.classList.add('selected');
820                                last.firstChild.classList.add('selected');
821                            }
822                            break
823
824                        case 13 : // if enter key is pressed
825
826                            // If the liSelected isn't empty we redirect to the result page
827                            if (liSelected !== undefined) {
828                                window.location.href = liSelected.firstChild.href;
829                            } else {
830                                // else we go to the search page with the query append
831                                window.location.href = '/?s=' + this.value
832                            }
833                            break
834
835                        case 27 :
836                            // if escap key is pressed we unfocus the search input and hide the result page
837                            Query.fadeOut(input)
838                            input.blur()
839                            break
840                    }
841                })
842            )
843
844        }
845    )
846})

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.