PageSourceSearch

https://www.mairie-chorges.fr/modules/custom/ws_ajax_search/js/ajax-search-block.js?tm9uue

js mairie-chorges.fr collected 2026-10-02 16:29:16 UTC 8,110 bytes, 209 lines download raw bytes

1/* global jQuery */
2/* global Drupal */
3/* global drupalSettings */
4/* global once */
5(function ($, Drupal, drupalSettings, window) {
6
7  Drupal.behaviors.ws_ajax_search__ajax_search_block = {
8    attach: function (context, settings) {
9
10      // Valeurs de la configuration.
11      let { items_per_page, display_results_total, track_with_matomo, no_results_text, show_more_text } = drupalSettings.ws_ajax_search.ajax_search_block;
12      // Éléments HTML de la recherche.
13      let $body = $('body', context);
14      let $inputSearch = $('.ajax-search-input', context);
15      let $wrapperResults = $('.results-wrapper', context);
16      let $divResults = $('.ajax-search-results', context);
17      let $closeResults = $('.ajax-search-close-results', context);
18
19      // Corrige les ids dupliques du champ de recherche et leurs labels.
20      $(once('ajax-search-block-input-id-fix', $('[id="ajax-search-input"]', context))).each(function (index) {
21        const inputId = 'ajax-search-input-' + (index + 1);
22        $(this).attr('id', inputId);
23        $(once('ajax-search-block-label-for-fix', $('label[for="ajax-search-input"]', $(this).parent()))).attr('for', inputId);
24      });
25
26      // Décalage (nombre d'éléments à sauter).
27      let offset = 0;
28      // Gestion des appels simultanés (recherche et suivi Matomo).
29      let rejectLastSearchPromise, rejectLastMatomoPromise = undefined;
30
31      $(once('ajax-search-block-init', $body)).each(function () {
32
33        // Ouverture/fermeture du container des résultats de recherche.
34        $inputSearch.on('input', function () {
35          $body.trigger('ajaxSearch:open');
36        });
37        $closeResults.on('click', function (e) {
38          e.preventDefault();
39          if (display_results_total) {
40            $body.trigger('ajaxSearch:hideResultsTotal');
41          }
42          $body.trigger('ajaxSearch:close');
43        });
44
45        // Perte du focus lors de l'appui sur Entrée.
46        $inputSearch.on('keyup', function (e) {
47          if (e.keyCode === 13) {
48            document.activeElement.blur();
49          }
50        });
51
52        // Saisie dans le champ de recherche.
53        $inputSearch.on('input', function () {
54          let keyword = $(this).val();
55          // Mise à jour de tous les champs de la page (s'il y en a plusieurs).
56          $inputSearch.val(keyword);
57          if (keyword === '') {
58            // Champ vide : vidage et fermeture des résultats.
59            $divResults.empty();
60            $('.ajax-search-show-more', context).remove();
61            if (rejectLastSearchPromise) {
62              rejectLastSearchPromise();
63            }
64            if (rejectLastMatomoPromise) {
65              rejectLastMatomoPromise();
66            }
67            if (display_results_total) {
68              $body.trigger('ajaxSearch:hideResultsTotal');
69            }
70            $body.trigger('ajaxSearch:close');
71          }
72          else {
73            // Nouvelle recherche : RàZ du décalage.
74            offset = 0;
75            let parameters = {
76              q: Drupal.checkPlain(keyword),
77              lang: drupalSettings.path.currentLanguage,
78              offset,
79            };
80            // Récupération et affichage des résultats.
81            doSearch(parameters);
82          }
83        });
84
85        // Clic sur le lien "Voir plus".
86        $body.on('click', '.ajax-search-show-more', function (e) {
87          e.preventDefault();
88          let keyword = $inputSearch.val();
89          let parameters = {
90            q: Drupal.checkPlain(keyword),
91            lang: drupalSettings.path.currentLanguage,
92            offset,
93          };
94          // Récupération et affichage des résultats.
95          doSearch(parameters);
96        });
97
98      });
99
100      function doSearch(parameters) {
101        // Si la précédente recherche n'a pas eu le temps d'aboutir,
102        // alors on rejette la promesse qui avait été lancée en même temps
103        // (ce qui va interrompre le traitement de la précédente recherche).
104        if (rejectLastSearchPromise) {
105          rejectLastSearchPromise();
106        }
107        // Lancement de 2 promesses en même temps :
108        // - La recherche,
109        // - Une promesse vide, dont on stocke la fonction de rejet.
110        // La première des deux à être résolue continue le script.
111        Promise.race([
112          $.get('/' + drupalSettings.path.pathPrefix + 'recherche-ajax', parameters),
113          new Promise((resolve, reject) => {
114            rejectLastSearchPromise = reject;
115          })
116        ])
117          .then((data) => {
118            // Si la recherche a eu le temps d'aboutir (= elle n'a pas été
119            // interrompue par un autre appel), on affiche les résultats.
120            displayResults(data, offset);
121          })
122          .catch(() => {
123            // Dans le cas où la recherche a été interrompue, on ne fait rien
124            // (en attendant que la nouvelle recherche aboutisse).
125          });
126      }
127
128      function displayResults(data, reqOffset) {
129        // Décalage nul = nouvelle recherche.
130        if (reqOffset === 0) {
131          // Suppression des anciens résultats.
132          $divResults.empty();
133          // Aucun résultat.
134          if (!data.total) {
135            $divResults.append('<div class="ajax-search-no-results">' + no_results_text + '</div>');
136          }
137          // Suivi de la recherche via Matomo, si activé.
138          if (track_with_matomo && window._paq !== undefined) {
139            // Search keyword searched for.
140            let keyword = $inputSearch.val();
141            // Search category selected in your search engine. If you do not need this, set to false.
142            let category = false;
143            // Number of results on the Search results page. Zero indicates a 'No Result Search Keyword'. Set to false if you don't know.
144            let searchCount = data.total;
145            // Déclenchement du suivi.
146            doMatomoTrack(keyword, category, searchCount);
147          }
148          // Lancement d'un événement avec le nombre total de résultats.
149          if (display_results_total) {
150            $body.trigger('ajaxSearch:showResultsTotal', data.total);
151          }
152        }
153        // Suppression du lien "Voir plus".
154        $('.ajax-search-show-more', context).remove();
155        // Affichage des nouveaux résultats.
156        if (data.results.length) {
157          data.results.forEach(function (result) {
158            $divResults.append(result.entity);
159          });
160          // Si nécessaire, MàJ du décalage et rajout du lien "Voir plus".
161          if (data.results.length === items_per_page) {
162            offset = reqOffset + items_per_page;
163            $divResults.after('<a href="#" class="ajax-search-show-more">' + show_more_text + '</a>');
164          }
165        }
166      }
167
168      function doMatomoTrack(keyword, category, searchCount) {
169        // @see doSearch()
170        if (rejectLastMatomoPromise) {
171          rejectLastMatomoPromise();
172        }
173        Promise.race([
174          // Délai de 2 secondes avant le suivi Matomo.
175          new Promise((resolve, reject) => {
176            setTimeout(resolve, 2000);
177          }),
178          new Promise((resolve, reject) => {
179            rejectLastMatomoPromise = reject;
180          })
181        ])
182          .then((data) => {
183            // Transformation du mot-clé.
184            // En minuscules.
185            keyword = keyword.toLowerCase();
186            // Sans accents.
187            const replacements = [
188              ['a', /[àâä]/g],
189              ['e', /[éèêë]/g],
190              ['i', /[îï]/g],
191              ['o', /[ôö]/g],
192              ['u', /[ùûü]/g],
193              ['c', /ç/g]
194            ];
195            keyword = replacements.reduce(function (accumulator, [letter, regex]) {
196              return accumulator.replace(regex, letter);
197            }, keyword);
198            // Déclenchement de l'événement de suivi.
199            window._paq.push(['trackSiteSearch', keyword, category, searchCount]);
200          })
201          .catch(() => {
202          });
203
204      }
205
206    }
207  };
208
209})(jQuery, Drupal, drupalSettings, this);

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.