PageSourceSearch

https://www.aucklandleisure.co.nz/scripts/AddressSearch.js

js aucklandleisure.co.nz collected 2026-10-08 01:33:06 UTC 34,658 bytes, 1,007 lines download raw bytes

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

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.