PageSourceSearch

https://www.nsws.gov.in/core/misc/autocomplete.js?v=10.1.6

js nsws.gov.in collected 2026-10-02 05:00:25 UTC 7,742 bytes, 286 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 (
83      term.length > 0 &&
84      options.firstCharacterBlacklist.indexOf(term[0]) !== -1
85    ) {
86      return false;
87    }
88    // Only search when the term is at least the minimum length.
89    return term.length >= options.minLength;
90  }
91
92  /**
93   * JQuery UI autocomplete source callback.
94   *
95   * @param {object} request
96   *   The request object.
97   * @param {function} response
98   *   The function to call with the response.
99   */
100  function sourceData(request, response) {
101    const elementId = this.element.attr('id');
102
103    if (!(elementId in autocomplete.cache)) {
104      autocomplete.cache[elementId] = {};
105    }
106
107    /**
108     * Filter through the suggestions removing all terms already tagged and
109     * display the available terms to the user.
110     *
111     * @param {object} suggestions
112     *   Suggestions returned by the server.
113     */
114    function showSuggestions(suggestions) {
115      const tagged = autocomplete.splitValues(request.term);
116      const il = tagged.length;
117      for (let i = 0; i < il; i++) {
118        const index = suggestions.indexOf(tagged[i]);
119        if (index >= 0) {
120          suggestions.splice(index, 1);
121        }
122      }
123      response(suggestions);
124    }
125
126    // Get the desired term and construct the autocomplete URL for it.
127    const term = autocomplete.extractLastTerm(request.term);
128
129    /**
130     * Transforms the data object into an array and update autocomplete results.
131     *
132     * @param {object} data
133     *   The data sent back from the server.
134     */
135    function sourceCallbackHandler(data) {
136      autocomplete.cache[elementId][term] = data;
137
138      // Send the new string array of terms to the jQuery UI list.
139      showSuggestions(data);
140    }
141
142    // Check if the term is already cached.
143    if (autocomplete.cache[elementId].hasOwnProperty(term)) {
144      showSuggestions(autocomplete.cache[elementId][term]);
145    } else {
146      const options = $.extend(
147        { success: sourceCallbackHandler, data: { q: term } },
148        autocomplete.ajax,
149      );
150      $.ajax(this.element.attr('data-autocomplete-path'), options);
151    }
152  }
153
154  /**
155   * Handles an autocompletefocus event.
156   *
157   * @return {boolean}
158   *   Always returns false.
159   */
160  function focusHandler() {
161    return false;
162  }
163
164  /**
165   * Handles an autocompleteselect event.
166   *
167   * @param {jQuery.Event} event
168   *   The event triggered.
169   * @param {object} ui
170   *   The jQuery UI settings object.
171   *
172   * @return {boolean}
173   *   Returns false to indicate the event status.
174   */
175  function selectHandler(event, ui) {
176    const terms = autocomplete.splitValues(event.target.value);
177    // Remove the current input.
178    terms.pop();
179    // Add the selected item.
180    terms.push(ui.item.value);
181
182    event.target.value = terms.join(', ');
183    // Return false to tell jQuery UI that we've filled in the value already.
184    return false;
185  }
186
187  /**
188   * Override jQuery UI _renderItem function to output HTML by default.
189   *
190   * @param {jQuery} ul
191   *   jQuery collection of the ul element.
192   * @param {object} item
193   *   The list item to append.
194   *
195   * @return {jQuery}
196   *   jQuery collection of the ul element.
197   */
198  function renderItem(ul, item) {
199    return $('<li>').append($('<a>').html(item.label)).appendTo(ul);
200  }
201
202  /**
203   * Attaches the autocomplete behavior to all required fields.
204   *
205   * @type {Drupal~behavior}
206   *
207   * @prop {Drupal~behaviorAttach} attach
208   *   Attaches the autocomplete behaviors.
209   * @prop {Drupal~behaviorDetach} detach
210   *   Detaches the autocomplete behaviors.
211   */
212  Drupal.behaviors.autocomplete = {
213    attach(context) {
214      // Act on textfields with the "form-autocomplete" class.
215      once('autocomplete', 'input.form-autocomplete', context).forEach(
216        (element) => {
217          const $autocomplete = $(element);
218          // Allow options to be overridden per instance.
219          const blacklist = $autocomplete.attr(
220            'data-autocomplete-first-character-blacklist',
221          );
222          $.extend(autocomplete.options, {
223            firstCharacterBlacklist: blacklist || '',
224          });
225          // Use jQuery UI Autocomplete on the textfield.
226          $autocomplete.autocomplete(autocomplete.options).each(function () {
227            $(this).data('ui-autocomplete')._renderItem =
228              autocomplete.options.renderItem;
229          });
230
231          // Use CompositionEvent to handle IME inputs. It requests remote server on "compositionend" event only.
232          $autocomplete.on('compositionstart.autocomplete', () => {
233            autocomplete.options.isComposing = true;
234          });
235          $autocomplete.on('compositionend.autocomplete', () => {
236            autocomplete.options.isComposing = false;
237          });
238        },
239      );
240    },
241    detach(context, settings, trigger) {
242      if (trigger === 'unload') {
243        $(
244          once.remove('autocomplete', 'input.form-autocomplete', context),
245        ).autocomplete('destroy');
246      }
247    },
248  };
249
250  /**
251   * Autocomplete object implementation.
252   *
253   * @namespace Drupal.autocomplete
254   */
255  autocomplete = {
256    cache: {},
257    // Exposes options to allow overriding by contrib.
258    splitValues: autocompleteSplitValues,
259    extractLastTerm,
260    // jQuery UI autocomplete options.
261
262    /**
263     * JQuery UI option object.
264     *
265     * @name Drupal.autocomplete.options
266     */
267    options: {
268      source: sourceData,
269      focus: focusHandler,
270      search: searchHandler,
271      select: selectHandler,
272      renderItem,
273      minLength: 1,
274      // Custom options, used by Drupal.autocomplete.
275      firstCharacterBlacklist: '',
276      // Custom options, indicate IME usage status.
277      isComposing: false,
278    },
279    ajax: {
280      dataType: 'json',
281      jsonp: false,
282    },
283  };
284
285  Drupal.autocomplete = autocomplete;
286})(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.