PageSourceSearch

https://www.mariecuriealumni.eu/core/misc/autocomplete.js?v=10.6.9

js mariecuriealumni.eu collected 2026-10-01 10:40:58 UTC 7,712 bytes, 282 lines download raw bytes

1/**
2 * @file
3 * Autocomplete based on jQuery UI.
4 */
5
6(function ($, Drupal) {
7  let autocomplete;
8
9  /**
10   * Helper splitting terms from the autocomplete value.
11   *
12   * @function Drupal.autocomplete.splitValues
13   *
14   * @param {string} value
15   *   The value being entered by the user.
16   *
17   * @return {Array}
18   *   Array of values, split by comma.
19   */
20  function autocompleteSplitValues(value) {
21    // We will match the value against comma-separated terms.
22    const result = [];
23    let quote = false;
24    let current = '';
25    const valueLength = value.length;
26    let character;
27
28    for (let i = 0; i < valueLength; i++) {
29      character = value.charAt(i);
30      if (character === '"') {
31        current += character;
32        quote = !quote;
33      } else if (character === ',' && !quote) {
34        result.push(current.trim());
35        current = '';
36      } else {
37        current += character;
38      }
39    }
40    if (value.length > 0) {
41      result.push(current.trim());
42    }
43
44    return result;
45  }
46
47  /**
48   * Returns the last value of a multi-value textfield.
49   *
50   * @function Drupal.autocomplete.extractLastTerm
51   *
52   * @param {string} terms
53   *   The value of the field.
54   *
55   * @return {string}
56   *   The last value of the input field.
57   */
58  function extractLastTerm(terms) {
59    return autocomplete.splitValues(terms).pop();
60  }
61
62  /**
63   * The search handler is called before a search is performed.
64   *
65   * @function Drupal.autocomplete.options.search
66   *
67   * @param {object} event
68   *   The event triggered.
69   *
70   * @return {boolean}
71   *   Whether to perform a search or not.
72   */
73  function searchHandler(event) {
74    const options = autocomplete.options;
75
76    if (options.isComposing) {
77      return false;
78    }
79
80    const term = autocomplete.extractLastTerm(event.target.value);
81    // Abort search if the first character is in firstCharacterBlacklist.
82    if (term.length > 0 && options.firstCharacterBlacklist.includes(term[0])) {
83      return false;
84    }
85    // Only search when the term is at least the minimum length.
86    return term.length >= options.minLength;
87  }
88
89  /**
90   * JQuery UI autocomplete source callback.
91   *
92   * @param {object} request
93   *   The request object.
94   * @param {function} response
95   *   The function to call with the response.
96   */
97  function sourceData(request, response) {
98    const elementId = this.element.attr('id');
99
100    if (!(elementId in autocomplete.cache)) {
101      autocomplete.cache[elementId] = {};
102    }
103
104    /**
105     * Filter through the suggestions removing all terms already tagged and
106     * display the available terms to the user.
107     *
108     * @param {object} suggestions
109     *   Suggestions returned by the server.
110     */
111    function showSuggestions(suggestions) {
112      const tagged = autocomplete.splitValues(request.term);
113      const il = tagged.length;
114      for (let i = 0; i < il; i++) {
115        if (suggestions.includes(tagged[i])) {
116          suggestions.splice(suggestions.indexOf(tagged[i]), 1);
117        }
118      }
119      response(suggestions);
120    }
121
122    // Get the desired term and construct the autocomplete URL for it.
123    const term = autocomplete.extractLastTerm(request.term);
124
125    /**
126     * Transforms the data object into an array and update autocomplete results.
127     *
128     * @param {object} data
129     *   The data sent back from the server.
130     */
131    function sourceCallbackHandler(data) {
132      autocomplete.cache[elementId][term] = data;
133
134      // Send the new string array of terms to the jQuery UI list.
135      showSuggestions(data);
136    }
137
138    // Check if the term is already cached.
139    if (autocomplete.cache[elementId].hasOwnProperty(term)) {
140      showSuggestions(autocomplete.cache[elementId][term]);
141    } else {
142      const options = $.extend(
143        { success: sourceCallbackHandler, data: { q: term } },
144        autocomplete.ajax,
145      );
146      $.ajax(this.element.attr('data-autocomplete-path'), options);
147    }
148  }
149
150  /**
151   * Handles an autocomplete focus event.
152   *
153   * @return {boolean}
154   *   Always returns false.
155   */
156  function focusHandler() {
157    return false;
158  }
159
160  /**
161   * Handles an autocomplete select event.
162   *
163   * @param {jQuery.Event} event
164   *   The event triggered.
165   * @param {object} ui
166   *   The jQuery UI settings object.
167   *
168   * @return {boolean}
169   *   Returns false to indicate the event status.
170   */
171  function selectHandler(event, ui) {
172    const terms = autocomplete.splitValues(event.target.value);
173    // Remove the current input.
174    terms.pop();
175    // Add the selected item.
176    terms.push(ui.item.value);
177
178    event.target.value = terms.join(', ');
179    // Return false to tell jQuery UI that we've filled in the value already.
180    return false;
181  }
182
183  /**
184   * Override jQuery UI _renderItem function to output HTML by default.
185   *
186   * @param {jQuery} ul
187   *   jQuery collection of the ul element.
188   * @param {object} item
189   *   The list item to append.
190   *
191   * @return {jQuery}
192   *   jQuery collection of the ul element.
193   */
194  function renderItem(ul, item) {
195    return $('<li>').append($('<a>').html(item.label)).appendTo(ul);
196  }
197
198  /**
199   * Attaches the autocomplete behavior to all required fields.
200   *
201   * @type {Drupal~behavior}
202   *
203   * @prop {Drupal~behaviorAttach} attach
204   *   Attaches the autocomplete behaviors.
205   * @prop {Drupal~behaviorDetach} detach
206   *   Detaches the autocomplete behaviors.
207   */
208  Drupal.behaviors.autocomplete = {
209    attach(context) {
210      // Act on textfields with the "form-autocomplete" class.
211      once('autocomplete', 'input.form-autocomplete', context).forEach(
212        (element) => {
213          const $autocomplete = $(element);
214          // Allow options to be overridden per instance.
215          const blacklist = $autocomplete.attr(
216            'data-autocomplete-first-character-blacklist',
217          );
218          $.extend(autocomplete.options, {
219            firstCharacterBlacklist: blacklist || '',
220          });
221          // Use jQuery UI Autocomplete on the textfield.
222          $autocomplete.autocomplete(autocomplete.options).each(function () {
223            $(this).data('ui-autocomplete')._renderItem =
224              autocomplete.options.renderItem;
225          });
226
227          // Use CompositionEvent to handle IME inputs. It requests remote server on "compositionend" event only.
228          $autocomplete.on('compositionstart.autocomplete', () => {
229            autocomplete.options.isComposing = true;
230          });
231          $autocomplete.on('compositionend.autocomplete', () => {
232            autocomplete.options.isComposing = false;
233          });
234        },
235      );
236    },
237    detach(context, settings, trigger) {
238      if (trigger === 'unload') {
239        $(
240          once.remove('autocomplete', 'input.form-autocomplete', context),
241        ).autocomplete('destroy');
242      }
243    },
244  };
245
246  /**
247   * Autocomplete object implementation.
248   *
249   * @namespace Drupal.autocomplete
250   */
251  autocomplete = {
252    cache: {},
253    // Exposes options to allow overriding by contrib.
254    splitValues: autocompleteSplitValues,
255    extractLastTerm,
256    // jQuery UI autocomplete options.
257
258    /**
259     * JQuery UI option object.
260     *
261     * @name Drupal.autocomplete.options
262     */
263    options: {
264      source: sourceData,
265      focus: focusHandler,
266      search: searchHandler,
267      select: selectHandler,
268      renderItem,
269      minLength: 1,
270      // Custom options, used by Drupal.autocomplete.
271      firstCharacterBlacklist: '',
272      // Custom options, indicate IME usage status.
273      isComposing: false,
274    },
275    ajax: {
276      dataType: 'json',
277      jsonp: false,
278    },
279  };
280
281  Drupal.autocomplete = autocomplete;
282})(jQuery, Drupal);

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.