PageSourceSearch

https://pravda-nn.ru/wp-content/plugins/wpsolr-free/wpsolr/core/js/devbridge/jquery.autocomplete.js?ver=24.6

js pravda-nn.ru collected 2026-09-24 08:27:51 UTC 34,529 bytes, 1,013 lines download raw bytes

1/**
2 *  Ajax Autocomplete for jQuery, version 1.4.11
3 *  (c) 2017 Tomas Kirda
4 *
5 *  Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license.
6 *  For details, see the web site: https://github.com/devbridge/jQuery-Autocomplete
7 */
8
9/*jslint  browser: true, white: true, single: true, this: true, multivar: true */
10/*global define, window, document, jQuery, exports, require */
11
12// Expose plugin as an AMD module if AMD loader is present:
13(function (factory) {
14    "use strict";
15    if (typeof define === 'function' && define.amd) {
16        // AMD. Register as an anonymous module.
17        define(['jquery'], factory);
18    } else if (typeof exports === 'object' && typeof require === 'function') {
19        // Browserify
20        factory(require('jquery'));
21    } else {
22        // Browser globals
23        factory(jQuery);
24    }
25}(function ($) {
26    'use strict';
27
28    var
29        utils = (function () {
30            return {
31                escapeRegExChars: function (value) {
32                    return value.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&");
33                },
34                createNode: function (containerClass) {
35                    var div = document.createElement('div');
36                    div.className = containerClass;
37                    div.style.position = 'absolute';
38                    div.style.display = 'none';
39                    return div;
40                }
41            };
42        }()),
43
44        keys = {
45            ESC: 27,
46            TAB: 9,
47            RETURN: 13,
48            LEFT: 37,
49            UP: 38,
50            RIGHT: 39,
51            DOWN: 40
52        },
53
54        noop = $.noop;
55
56    function Autocomplete(el, options) {
57        var that = this;
58
59        // Shared variables:
60        that.element = el;
61        that.el = $(el);
62        that.suggestions = [];
63        that.badQueries = [];
64        that.selectedIndex = -1;
65        that.currentValue = that.element.value;
66        that.timeoutId = null;
67        that.cachedResponse = {};
68        that.onChangeTimeout = null;
69        that.onChange = null;
70        that.isLocal = false;
71        that.suggestionsContainer = null;
72        that.noSuggestionsContainer = null;
73        that.options = $.extend(true, {}, Autocomplete.defaults, options);
74        that.classes = {
75            selected: 'autocomplete-selected',
76            suggestion: 'autocomplete-suggestion'
77        };
78        that.hint = null;
79        that.hintValue = '';
80        that.selection = null;
81
82        // Initialize and set options:
83        that.initialize();
84        that.setOptions(options);
85    }
86
87    Autocomplete.utils = utils;
88
89    $.Autocomplete = Autocomplete;
90
91    Autocomplete.defaults = {
92        ajaxSettings: {},
93        autoSelectFirst: false,
94        appendTo: 'body',
95        serviceUrl: null,
96        lookup: null,
97        onSelect: null,
98        onHint: null,
99        width: 'auto',
100        minChars: 1,
101        maxHeight: 300,
102        deferRequestBy: 0,
103        params: {},
104        formatResult: _formatResult,
105        formatGroup: _formatGroup,
106        delimiter: null,
107        zIndex: 9999,
108        type: 'GET',
109        noCache: false,
110        onSearchStart: noop,
111        onSearchComplete: noop,
112        onSearchError: noop,
113        preserveInput: false,
114        containerClass: 'autocomplete-suggestions',
115        tabDisabled: false,
116        dataType: 'text',
117        currentRequest: null,
118        triggerSelectOnValidInput: true,
119        preventBadQueries: true,
120        lookupFilter: _lookupFilter,
121        paramName: 'query',
122        transformResult: _transformResult,
123        showNoSuggestionNotice: false,
124        noSuggestionNotice: 'No results',
125        orientation: 'bottom',
126        forceFixPosition: false
127    };
128
129    function _lookupFilter(suggestion, originalQuery, queryLowerCase) {
130        return suggestion.value.toLowerCase().indexOf(queryLowerCase) !== -1;
131    };
132
133    function _transformResult(response) {
134        return typeof response === 'string' ? $.parseJSON(response) 
134: response;
135    };
136
137    function _formatResult(suggestion, currentValue) {
138        // Do not replace anything if the current value is empty
139        if (!currentValue) {
140            return suggestion.value;
141        }
142
143        var pattern = '(' + utils.escapeRegExChars(currentValue) + ')';
144
145        return suggestion.value
146            .replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>')
147            .replace(/&/g, '&amp;')
148            .replace(/</g, '&lt;')
149            .replace(/>/g, '&gt;')
150            .replace(/"/g, '&quot;')
151            .replace(/&lt;(\/?strong)&gt;/g, '<$1>');
152    };
153
154    function _formatGroup(suggestion, category) {
155        return '<div class="autocomplete-group">' + category + '</div>';
156    };
157
158    Autocomplete.prototype = {
159
160        initialize: function () {
161            var that = this,
162                suggestionSelector = '.' + that.classes.suggestion,
163                selected = that.classes.selected,
164                options = that.options,
165                container;
166
167            that.element.setAttribute('autocomplete', 'off');
168
169            // html() deals with many types: htmlString or Element or Array or jQuery
170            that.noSuggestionsContainer = $('<div class="autocomplete-no-suggestion"></div>')
171                .html(this.options.noSuggestionNotice).get(0);
172
173            that.suggestionsContainer = Autocomplete.utils.createNode(options.containerClass);
174
175            container = $(that.suggestionsContainer);
176
177            container.appendTo(options.appendTo || 'body');
178
179            // Only set width if it was provided:
180            if (options.width !== 'auto') {
181                container.css('width', options.width);
182            }
183
184            // Listen for mouse over event on suggestions list:
185            container.on('mouseover.autocomplete', suggestionSelector, function () {
186                that.activate($(this).data('index'));
187            });
188
189            // Deselect active element when mouse leaves suggestions container:
190            container.on('mouseout.autocomplete', function () {
191                that.selectedIndex = -1;
192                container.children('.' + selected).removeClass(selected);
193            });
194
195            // Listen for click event on suggestions list:
196            container.on('click.autocomplete', suggestionSelector, function () {
197                that.select($(this).data('index'));
198            });
199
200            container.on('click.autocomplete', function () {
201                clearTimeout(that.blurTimeoutId);
202            })
203
204            that.fixPositionCapture = function () {
205                if (that.visible) {
206                    that.fixPosition();
207                }
208            };
209
210            $(window).on('resize.autocomplete', that.fixPositionCapture);
211
212            that.el.on('keydown.autocomplete', function (e) { that.onKeyPress(e); });
213            that.el.on('keyup.autocomplete', function (e) { that.onKeyUp(e); });
214            that.el.on('blur.autocomplete', function () { that.onBlur(); });
215            that.el.on('focus.autocomplete', function () { that.onFocus(); });
216            that.el.on('change.autocomplete', function (e) { that.onKeyUp(e); });
217            that.el.on('input.autocomplete', function (e) { that.onKeyUp(e); });
218        },
219
220        onFocus: function () {
221            var that = this;
222
223            if (that.disabled) {
224                return;
225            }
226
227            that.fixPosition();
228
229            if (that.el.val().length >= that.options.minChars) {
230                that.onValueChange();
231            }
232        },
233
234        onBlur: function () {
235            var that = this,
236                options = that.options,
237                value = that.el.val(),
238                query = that.getQuery(value);
239
240            // If user clicked on a suggestion, hide() will
241            // be canceled, otherwise close suggestions
242            that.blurTimeoutId = setTimeout(function () {
243                that.hide();
244
245                if (that.selection && that.currentValue !== query) {
246                    (options.onInvalidateSelection || $.noop).call(that.element);
247                }
248            }, 200);
249        },
250
251        abortAjax: function () {
252            var that = this;
253            if (that.currentRequest) {
254                that.currentRequest.abort();
255                that.currentRequest = null;
256            }
257        },
258
259        setOptions: function (suppliedOptions) {
260            var that = this,
261                options = $.extend({}, that.options, suppliedOptions);
262
263            that.isLocal = Array.isArray(options.lookup);
264
265            if (that.isLocal) {
266                options.lookup = that.verifySuggestionsFormat(options.lookup);
267            }
268
269            options.orientation = that.validateOrientation(options.orientation, 'bottom');
270
271            // Adjust height, width and z-index:
272            $(that.suggestionsContainer).css({
273                'max-height': options.maxHeight + 'px',
274                'width': options.width + 'px',
275                'z-index': options.zIndex
276            });
277
278            this.options = options;
279        },
280
281
282        clearCache: function () {
283            this.cachedResponse = {};
284            this.badQueries = [];
285        },
286
287        clear: function () {
288            this.clearCache();
289            this.currentValue = '';
290            this.suggestions = [];
291        },
292
293        disable: function () {
294            var that = this;
295            that.disabled = true;
296            clearTimeout(that.onChangeTimeout);
297            that.abortAjax();
298        },
299
300        enable: function () {
301            this.disabled = false;
302        },
303
304        fixPosition: function () {
305            // Use only when container has already its content
306
307            var that = this,
308                $container = $(that.suggestionsContainer),
309                containerParent = $container.parent().get(0);
310            // Fix position automatically when appended to body.
311            // In other cases force parameter must be given.
312            if (containerParent !== document.body && !that.options.forceFixPosition) {
313                return;
314            }
315
316            // Choose orientation
317            var orientation = that.options.orientation,
318                containerHeight = $container.outerHeight(),
319                height = that.el.outerHeight(),
320                offset = that.el.offset(),
321                styles = { 'top': offset.top, 'left': offset.left };
322
323            if (orientation === 'auto') {
324                var viewPortHeight = $(window).height(),
325                    scrollTop = $(window).scrollTop(),
326                    topOverflow = -scrollTop + offset.top - containerHeight,
327                    bottomOverflow = scrollTop + viewPortHeight - (offset.top + height + containerHeight);
328
329                orientation = (Math.max(topOverflow, bottomOverflow) === topOverflow) ? 'top' : 'bottom';
330            }
331
332            if (orientation === 'top') {
333                styles.top += -containerHeight;
334            } else {
335                styles.top += height;
336            }
337
338            // If container is not positioned to body,
339            // correct its position using offset parent offset
340            if(containerParent !== document.body) {
341                var opacity = $container.css('opacity'),
342                    parentOffsetDiff;
343
344                if (!that.visible){
345                    $container.css('opacity', 0).show();
346                }
347
348                parentOffsetDiff = $container.offsetParent().offset();
349                styles.top -= parentOffsetDiff.top;
350                styles.top += containerParent.scrollTop;
351                styles.left -= parentOffsetDiff.left;
352
353                if (!that.visible){
354                    $container.css('opacity', opacity).hide();
355                }
356            }
357
358            if (that.options.width === 'auto') {
359                styles.width = that.el.outerWidth() + 'px';
360            }
361
362            $container.css(styles);
363        },
364
365        isCursorAtEnd: function () {
366            var that = this,
367                valLength = that.el.val().length,
368                selectionStart = that.element.selectionStart,
369                range;
370
371            if (typeof selectionStart === 'number') {
372                return selectionStart === valLength;
373            }
374            if (document.selection) {
375                range = document.selection.createRange();
376                range.moveStart('character', -valLength);
377                return valLength === range.text.length;
378            }
379            return true;
380        },
381
382        onKeyPress: function (e) {
383            var that = this;
384
385            // If suggestions are hidden and user presses arrow down, display suggestions:
386            if (!that.disabled && !that.visible && e.which === keys.DOWN && that.currentValue) {
387                that.suggest();
388                return;
389            }
390
391            if (that.disabled || !that.visible) {
392                return;
393            }
394
395            switch (e.which) {
396                case keys.ESC:
397                    that.el.val(that.currentValue);
398                    that.hide();
399                    break;
400                case keys.RIGHT:
401                    if (that.hint && that.options.onHint && that.isCursorAtEnd()) {
402                        that.selectHint();
403                        break;
404                    }
405                    return;
406                case keys.TAB:
407                    if (that.hint && that.options.onHint) {
408                        that.selectHint();
409                        return;
410                    }
411                    if (that.selectedIndex === -1) {
412                        that.hide();
413                        return;
414                    }
415                    that.select(that.selectedIndex);
416                    if (that.options.tabDisabled === false) {
417                        return;
418                    }
419                    break;
420                case keys.RETURN:
421                    if (that.selectedIndex === -1) {
422                        that.hide();
423                        return;
424                    }
425                    that.select(that.selectedIndex);
426                    break;
427                case keys.UP:
428                    that.moveUp();
429                    break;
430                case keys.DOWN:
431                    that.moveDown();
432                    break;
433                default:
434                    return;
435            }
436
437            // Cancel event if function did not return:
438            e.stopImmediatePropagation();
439            e.preventDefault();
440        },
441
442        onKeyUp: function (e) {
443            var that = this;
444
445            if (that.disabled) {
446                return;
447            }
448
449            switch (e.which) {
450                case keys.UP:
451                case keys.DOWN:
452                    return;
453            }
454
455            clearTimeout(that.onChangeTimeout);
456
457            if (that.currentValue !== that.el.val()) {
458                that.findBestHint();
459                if (that.options.deferRequestBy > 0) {
460                    // Defer lookup in case when value changes very quickly:
461                    that.onChangeTimeout = setTimeout(function () {
462                        that.onValueChange();
463                    }, that.options.deferRequestBy);
464                } else {
465                    that.onValueChange();
466                }
467            }
468        },
469
470        onValueChange: function () {
471            if (this.ignoreValueChange) {
472                this.ignoreValueChange = false;
473                return;
474            }
475
476            var that = this,
477                options = that.options,
478                value = that.el.val(),
479                query = that.getQuery(value);
480
481            if (that.selection && that.currentValue !== query) {
482                that.selection = null;
483                (options.onInvalidateSelection || $.noop).call(that.element);
484            }
485
486            clearTimeout(that.onChangeTimeout);
487            that.currentValue = value;
488            that.selectedIndex = -1;
489
490            // Check existing suggestion for the match before proceeding:
491            if (options.triggerSelectOnValidInput && that.isExactMatch(query)) {
492                that.select(0);
493                return;
494            }
495
496            if (query.length < options.minChars) {
497                that.hide();
498            } else {
499                that.getSuggestions(query);
500            }
501        },
502
503        isExactMatch: function (query) {
504            var suggestions = this.suggestions;
505
506            return (suggestions.length === 1 && suggestions[0].value.toLowerCase() === query.toLowerCase());
507        },
508
509        getQuery: function (value) {
510            var delimiter = this.options.delimiter,
511                parts;
512
513            if (!delimiter) {
514                return value;
515            }
516            parts = value.split(delimiter);
517            return $.trim(parts[parts.length - 1]);
518        },
519
520        getSuggestionsLocal: function (query) {
521            var that = this,
522                options = that.options,
523                queryLowerCase = query.toLowerCase(),
524                filter = options.lookupFilter,
525                limit = parseInt(options.lookupLimit, 10),
526                data;
527
528            data = {
529                suggestions: $.grep(options.lookup, function (suggestion) {
530                    return filter(suggestion, query, queryLowerCase);
531                })
532            };
533
534            if (limit && data.suggestions.length > limit) {
535                data.suggestions = data.suggestions.slice(0, limit);
536            }
537
538            return data;
539        },
540
541        getSuggestions: function (q) {
542            var response,
543                that = this,
544                options = that.options,
545                serviceUrl = options.serviceUrl,
546                params,
547                cacheKey,
548                ajaxSettings;
549
550            options.params[options.paramName] = q;
551
552            if (options.onSearchStart.call(that.element, options.params) === false) {
553                return;
554            }
555
556            params = options.ignoreParams ? null : options.params;
557
558            if ($.isFunction(options.lookup)){
559                options.lookup(q, function (data) {
560                    that.suggestions = data.suggestions;
561                    that.suggest();
562                    options.onSearchComplete.call(that.element, q, data.suggestions);
563                });
564                return;
565            }
566
567            if (that.isLocal) {
568                response = that.getSuggestionsLocal(q);
569            } else {
570                if ($.isFunction(serviceUrl)) {
571                    serviceUrl = serviceUrl.call(that.element, q);
572                }
573                cacheKey = serviceUrl + '?' + $.param(params || {});
574                response = that.cachedResponse[cacheKey];
575            }
576
577            if (response && Array.isArray(response.suggestions)) {
578                that.suggestions = response.suggestions;
579                that.suggest();
580                options.onSearchComplete.call(that.element, q, response.suggestions);
581            } else if (!that.isBadQuery(q)) {
582                that.abortAjax();
583
584                ajaxSettings = {
585                    url: serviceUrl,
586                    data: params,
587                    type: options.type,
588                    dataType: options.dataType
589                };
590
591                $.extend(ajaxSettings, options.ajaxSettings);
592
593                that.currentRequest = $.ajax(ajaxSettings).done(function (data) {
594                    var result;
595                    that.currentRequest = null;
596                    result = options.transformResult(data, q);
597                    that.processResponse(result, q, cacheKey);
598                    options.onSearchComplete.call(that.element, q, result.suggestions);
599                }).fail(function (jqXHR, textStatus, errorThrown) {
600                    options.onSearchError.call(that.element, q, jqXHR, textStatus, errorThrown);
601                });
602            } else {
603                options.onSearchComplete.call(that.element, q, []);
604            }
605        },
606
607        isBadQuery: function (q) {
608            if (!this.options.preventBadQueries){
609                return false;
610            }
611
612            var badQueries = this.badQueries,
613                i = badQueries.length;
614
615            while (i--) {
616                if (q.indexOf(badQueries[i]) === 0) {
617                    return true;
618                }
619            }
620
621            return false;
622        },
623
624        hide: function () {
625            var that = this,
626                container = $(that.suggestionsContainer);
627
628            if ($.isFunction(that.options.onHide) && that.visible) {
629                that.options.onHide.call(that.element, container);
630            }
631
632            that.visible = false;
633            that.selectedIndex = -1;
634            clearTimeout(that.onChangeTimeout);
635            $(that.suggestionsContainer).hide();
636            that.onHint(null);
637        },
638
639        suggest: function () {
640            if (!this.suggestions.length) {
641                if (this.options.showNoSuggestionNotice) {
642                    this.noSuggestions();
643                } else {
644                    this.hide();
645                }
646                return;
647            }
648
649            var that = this,
650                options = that.options,
651                groupBy = options.groupBy,
652                formatResult = options.formatResult,
653                value = that.getQuery(that.currentValue),
654                className = that.classes.suggestion,
655                classSelected = that.classes.selected,
656                container = $(that.suggestionsContainer),
657                noSuggestionsContainer = $(that.noSuggestionsContainer),
658                beforeRender = options.beforeRender,
659                html = '',
660                category,
661                formatGroup = function (suggestion, index) {
662                    var currentCategory = suggestion.data[groupBy];
663
664                    if (category === currentCategory){
665                        return '';
666                    }
667
668                    category = currentCategory;
669
670                    return options.formatGroup(suggestion, category);
671                };
672
673            if (options.triggerSelectOnValidInput && that.isExactMatch(value)) {
674                that.select(0);
675                return;
676            }
677
678            // Build suggestions inner HTML:
679            $.each(that.suggestions, function (i, suggestion) {
680                if (groupBy){
681                    html += formatGroup(suggestion, value, i);
682                }
683
684                html += '<div class="' + className + '" data-index="' + i + '">' + formatResult(suggestion, value, i) + '</div>';
685            });
686
687            this.adjustContainerWidth();
688
689            noSuggestionsContainer.detach();
690            container.html(html);
691
692            if ($.isFunction(beforeRender)) {
693                beforeRender.call(that.element, container, that.suggestions);
694            }
695
696            that.fixPosition();
697            container.show();
698
699            // Select first value by default:
700            if (options.autoSelectFirst) {
701                that.selectedIndex = 0;
702                container.scrollTop(0);
703                container.children('.' + className).first().addClass(classSelected);
704            }
705
706            that.visible = true;
707            that.findBestHint();
708        },
709
710        noSuggestions: function() {
711            var that = this,
712                beforeRender = that.options.beforeRender,
713                container = $(that.suggestionsContainer),
714                noSuggestionsContainer = $(that.noSuggestionsContainer);
715
716            this.adjustContainerWidth();
717
718            // Some explicit steps. Be careful here as it easy to get
719            // noSuggestionsContainer removed from DOM if not detached properly.
720            noSuggestionsContainer.detach();
721
722            // clean suggestions if any
723            container.empty();
724            container.append(noSuggestionsContainer);
725
726            if ($.isFunction(beforeRender)) {
727                beforeRender.call(that.element, container, that.suggestions);
728            }
729
730            that.fixPosition();
731
732            container.show();
733            that.visible = true;
734        },
735
736        adjustContainerWidth: function() {
737            var that = this,
738                options = that.options,
739                width,
740                container = $(that.suggestionsContainer);
741
742            // If width is auto, adjust width before displaying suggestions,
743            // because if instance was created before input had width, it will be zero.
744            // Also it adjusts if input width has changed.
745            if (options.width === 'auto') {
746                width = that.el.outerWidth();
747                container.css('width', width > 0 ? width : 300);
748            } else if(options.width === 'flex') {
749                // Trust the source! Unset the width property so it will be the max length
750                // the containing elements.
751                container.css('width', '');
752            }
753        },
754
755        findBestHint: function () {
756            var that = this,
757                value = that.el.val().toLowerCase(),
758                bestMatch = null;
759
760            if (!value) {
761                return;
762            }
763
764            $.each(that.suggestions, function (i, suggestion) {
765                var foundMatch = suggestion.value.toLowerCase().indexOf(value) === 0;
766                if (foundMatch) {
767                    bestMatch = suggestion;
768                }
769                return !foundMatch;
770            });
771
772            that.onHint(bestMatch);
773        },
774
775        onHint: function (suggestion) {
776            var that = this,
777                onHintCallback = that.options.onHint,
778                hintValue = '';
779
780            if (suggestion) {
781                hintValue = that.currentValue + suggestion.value.substr(that.currentValue.length);
782            }
783            if (that.hintValue !== hintValue) {
784                that.hintValue = hintValue;
785                that.hint = suggestion;
786                if ($.isFunction(onHintCallback)) {
787                    onHintCallback.call(that.element, hintValue);
788                }
789            }
790        },
791
792        verifySuggestionsFormat: function (suggestions) {
793            // If suggestions is string array, convert them to supp
793orted format:
794            if (suggestions.length && typeof suggestions[0] === 'string') {
795                return $.map(suggestions, function (value) {
796                    return { value: value, data: null };
797                });
798            }
799
800            return suggestions;
801        },
802
803        validateOrientation: function(orientation, fallback) {
804            orientation = $.trim(orientation || '').toLowerCase();
805
806            if($.inArray(orientation, ['auto', 'bottom', 'top']) === -1){
807                orientation = fallback;
808            }
809
810            return orientation;
811        },
812
813        processResponse: function (result, originalQuery, cacheKey) {
814            var that = this,
815                options = that.options;
816
817            result.suggestions = that.verifySuggestionsFormat(result.suggestions);
818
819            // Cache results if cache is not disabled:
820            if (!options.noCache) {
821                that.cachedResponse[cacheKey] = result;
822                if (options.preventBadQueries && !result.suggestions.length) {
823                    that.badQueries.push(originalQuery);
824                }
825            }
826
827            // Return if originalQuery is not matching current query:
828            if (originalQuery !== that.getQuery(that.currentValue)) {
829                return;
830            }
831
832            that.suggestions = result.suggestions;
833            that.suggest();
834        },
835
836        activate: function (index) {
837            var that = this,
838                activeItem,
839                selected = that.classes.selected,
840                container = $(that.suggestionsContainer),
841                children = container.find('.' + that.classes.suggestion);
842
843            container.find('.' + selected).removeClass(selected);
844
845            that.selectedIndex = index;
846
847            if (that.selectedIndex !== -1 && children.length > that.selectedIndex) {
848                activeItem = children.get(that.selectedIndex);
849                $(activeItem).addClass(selected);
850                return activeItem;
851            }
852
853            return null;
854        },
855
856        selectHint: function () {
857            var that = this,
858                i = $.inArray(that.hint, that.suggestions);
859
860            that.select(i);
861        },
862
863        select: function (i) {
864            var that = this;
865            that.hide();
866            that.onSelect(i);
867        },
868
869        moveUp: function () {
870            var that = this;
871
872            if (that.selectedIndex === -1) {
873                return;
874            }
875
876            if (that.selectedIndex === 0) {
877                $(that.suggestionsContainer).children('.' + that.classes.suggestion).first().removeClass(that.classes.selected);
878                that.selectedIndex = -1;
879                that.ignoreValueChange = false;
880                that.el.val(that.currentValue);
881                that.findBestHint();
882                return;
883            }
884
885            that.adjustScroll(that.selectedIndex - 1);
886        },
887
888        moveDown: function () {
889            var that = this;
890
891            if (that.selectedIndex === (that.suggestions.length - 1)) {
892                return;
893            }
894
895            that.adjustScroll(that.selectedIndex + 1);
896        },
897
898        adjustScroll: function (index) {
899            var that = this,
900                activeItem = that.activate(index);
901
902            if (!activeItem) {
903                return;
904            }
905
906            var offsetTop,
907                upperBound,
908                lowerBound,
909                heightDelta = $(activeItem).outerHeight();
910
911            offsetTop = activeItem.offsetTop;
912            upperBound = $(that.suggestionsContainer).scrollTop();
913            lowerBound = upperBound + that.options.maxHeight - heightDelta;
914
915            if (offsetTop < upperBound) {
916                $(that.suggestionsContainer).scrollTop(offsetTop);
917            } else if (offsetTop > lowerBound) {
918                $(that.suggestionsContainer).scrollTop(offsetTop - that.options.maxHeight + heightDelta);
919            }
920
921            if (!that.options.preserveInput) {
922                // During onBlur event, browser will trigger "change" event,
923                // because value has changed, to avoid side effect ignore,
924                // that event, so that correct suggestion can be selected
925                // when clicking on suggestion with a mouse
926                that.ignoreValueChange = true;
927                that.el.val(that.getValue(that.suggestions[index].value));
928            }
929
930            that.onHint(null);
931        },
932
933        onSelect: function (index) {
934            var that = this,
935                onSelectCallback = that.options.onSelect,
936                suggestion = that.suggestions[index];
937
938            that.currentValue = that.getValue(suggestion.value);
939
940            if (that.currentValue !== that.el.val() && !that.options.preserveInput) {
941                that.el.val(that.currentValue);
942            }
943
944            that.onHint(null);
945            that.suggestions = [];
946            that.selection = suggestion;
947
948            if ($.isFunction(onSelectCallback)) {
949                onSelectCallback.call(that.element, suggestion);
950            }
951        },
952
953        getValue: function (value) {
954            var that = this,
955                delimiter = that.options.delimiter,
956                currentValue,
957                parts;
958
959            if (!delimiter) {
960                return value;
961            }
962
963            currentValue = that.currentValue;
964            parts = currentValue.split(delimiter);
965
966            if (parts.length === 1) {
967                return value;
968            }
969
970            return currentValue.substr(0, currentValue.length - parts[parts.length - 1].length) + value;
971        },
972
973        dispose: function () {
974            var that = this;
975            that.el.off('.autocomplete').removeData('autocomplete');
976            $(window).off('resize.autocomplete', that.fixPositionCapture);
977            $(that.suggestionsContainer).remove();
978        }
979    };
980
981    // Create jQuery plugin:
982    $.fn.devbridgeAutocomplete = function (options, args) {
983        var dataKey = 'autocomplete';
984        // If function invoked without argument return
985        // instance of the first matched element:
986        if (!arguments.length) {
987            return this.first().data(dataKey);
988        }
989
990        return this.each(function () {
991            var inputElement = $(this),
992                instance = inputElement.data(dataKey);
993
994            if (typeof options === 'string') {
995                if (instance && typeof instance[options] === 'function') {
996                    instance[options](args);
997                }
998            } else {
999                // If instance already exists, destroy it:
1000                if (instance && instance.dispose) {
1001                    instance.dispose();
1002                }
1003                instance = new Autocomplete(this, options);
1004                inputElement.data(dataKey, instance);
1005            }
1006        });
1007    };
1008
1009    // Don't overwrite if it already exists
1010    if (!$.fn.autocomplete) {
1011        $.fn.autocomplete = $.fn.devbridgeAutocomplete;
1012    }
1013}));

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.