PageSourceSearch

https://online-goal.com/template/stui_tpl/statics/js/jquery.autocomplete.js

js online-goal.com collected 2026-10-08 00:56:06 UTC 25,223 bytes, 665 lines download raw bytes

1/*
2 * jQuery Autocomplete plugin 1.1
3 *
4 * Copyright (c) 2009 Jörn Zaefferer
5 *
6 * Dual licensed under the MIT and GPL licenses:
7 *   http://www.opensource.org/licenses/mit-license.php
8 *   http://www.gnu.org/licenses/gpl.html
9 *
10 * Revision: $Id: jquery.autocomplete.js 15 2009-08-22 10:30:27Z joern.zaefferer $
11 */;
12$.browser = navigator.userAgent;
13(function($) {
14    $.fn.extend({
15        autocomplete: function(urlOrData, options) {
16            var isUrl = typeof urlOrData == "string";
17            options = $.extend({}, $.Autocompleter.defaults, {
18                url: isUrl ? urlOrData : null,
19                data: isUrl ? null : urlOrData,
20                delay: isUrl ? $.Autocompleter.defaults.delay : 10,
21                max: options && !options.scroll ? 10 : 150
22            }, options);
23            options.highlight = options.highlight ||
24                function(value) {
25                    return value;
26                };
27            options.formatMatch = options.formatMatch || options.formatItem;
28            return this.each(function() {
29                new $.Autocompleter(this, options);
30            });
31        },
32        result: function(handler) {
33            return this.bind("result", handler);
34        },
35        search: function(handler) {
36            return this.trigger("search", [handler]);
37        },
38        flushCache: function() {
39            return this.trigger("flushCache");
40        },
41        setOptions: function(options) {
42            return this.trigger("setOptions", [options]);
43        },
44        unautocomplete: function() {
45            return this.trigger("unautocomplete");
46        }
47    });
48    $.Autocompleter = function(input, options) {
49        var KEY = {
50            UP: 38,
51            DOWN: 40,
52            DEL: 46,
53            TAB: 9,
54            RETURN: 13,
55            ESC: 27,
56            COMMA: 188,
57            PAGEUP: 33,
58            PAGEDOWN: 34,
59            BACKSPACE: 8
60        };
61        var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass);
62        var timeout;
63        var previousValue = "";
64        var cache = $.Autocompleter.Cache(options);
65        var hasFocus = 0;
66        var lastKeyPressCode;
67        var config = {
68            mouseDownOnSelect: false
69        };
70        var select = $.Autocompleter.Select(options, input, selectCurrent, config);
71        var blockSubmit;
72        $.browser.opera && $(input.form).bind("submit.autocomplete", function() {
73            if (blockSubmit) {
74                blockSubmit = false;
75                return false;
76            }
77        });
78        $input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(event) {
79            hasFocus = 1;
80            lastKeyPressCode = event.keyCode;
81            switch (event.keyCode) {
82                case KEY.UP:
83                    event.preventDefault();
84                    if (select.visible()) {
85                        select.prev();
86                    } else {
87                        onChange(0, true);
88                    }
89                    break;
90                case KEY.DOWN:
91                    event.preventDefault();
92                    if (select.visible()) {
93                        select.next();
94                    } else {
95                        onChange(0, true);
96                    }
97                    break;
98                case KEY.PAGEUP:
99                    event.preventDefault();
100                    if (select.visible()) {
101                        select.pageUp();
102                    } else {
103                        onChange(0, true);
104                    }
105                    break;
106                case KEY.PAGEDOWN:
107                    event.preventDefault();
108                    if (select.visible()) {
109                        select.pageDown();
110                    } else {
111                        onChange(0, true);
112                    }
113                    break;
114                case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
115                
116				case KEY.TAB:
117				    if( selectCurrent() ) {
118				        // stop default to prevent a form submit, Opera needs special handling
119				        event.preventDefault();
120				        blockSubmit = true;
121				        return false;
122				    }
123				    break;				 
124				case KEY.RETURN:
125				    clearTimeout(timeout);
126				    timeout = setTimeout(onChange, options.delay);
127				    break;				
128                case KEY.ESC:
129                    select.hide();
130                    break;
131                default:
132                    clearTimeout(timeout);
133                    timeout = setTimeout(onChange, options.delay);
134                    break;
135            }
136        }).focus(function() {
137            hasFocus++;
138        }).blur(function() {
139            hasFocus = 0;
140            if (!config.mouseDownOnSelect) {
141                hideResults();
142            }
143        }).click(function() {
144            if (hasFocus++ > 1 && !select.visible()) {
145                onChange(0, true);
146            }
147        }).bind("search", function() {
148            var fn = (arguments.length > 1) ? arguments[1] : null;
149
150            function findValueCallback(q, data) {
151                var result;
152                if (data && data.length) {
153                    for (var i = 0; i < data.length; i++) {
154                        if (data[i].result.toLowerCase() == q.toLowerCase()) {
155                            result = data[i];
156                            break;
157                        }
158                    }
159                }
160                if (typeof fn == "function") fn(result);
161                else $input.trigger("result", result && [result.data, result.value]);
162            }
163            $.each(trimWords($input.val()), function(i, value) {
164                request(value, findValueCallback, findValueCallback);
165            });
166        }).bind("flushCache", function() {
167            cache.flush();
168        }).bind("setOptions", function() {
169            $.extend(options, arguments[1]);
170            if ("data" in arguments[1]) cache.populate();
171        }).bind("unautocomplete", function() {
172            select.unbind();
173            $input.unbind();
174            $(input.form).unbind(".autocomplete");
175        });
176
177        function selectCurrent() {
178            var selected = select.selected();
179            if (!selected) return false;
180            var v = selected.result;
181            previousValue = v;
182            if (options.multiple) {
183                var words = trimWords($input.val());
184                if (words.length > 1) {
185                    var seperator = options.multipleSeparator.length;
186                    var cursorAt = $(input).selection().start;
187                    var wordAt, progress = 0;
188                    $.each(words, function(i, word) {
189                        progress += word.length;
190                        if (cursorAt <= progress) {
191                            wordAt = i;
192                            return false;
193                        }
194                        progress += seperator;
195                    });
196                    words[wordAt] = v;
197                    v = words.join(options.multipleSeparator);
198                }
199                v += options.multipleSeparator;
200            }
201            $input.val(v);
202            hideResultsNow();
203            $input.trigger("result", [selected.data, selected.value]);
204            return true;
205        }
206        function onChange(crap, skipPrevCheck) {
207            if (lastKeyPressCode == KEY.DEL) {
208                select.hide();
209                return;
210            }
211            var currentValue = $input.val();
212            if (!skipPrevCheck && currentValue == previousValue) return;
213            previousValue = currentValue;
214            currentValue = lastWord(currentValue);
215            if (currentValue.length >= options.minChars) {
216                $input.addClass(options.loadingClass);
217                if (!options.matchCase) currentValue = currentValue.toLowerCase();
218                request(currentValue, receiveData, hideResultsNow);
219            } else {
220                stopLoading();
221                select.hide();
222            }
223        };
224
225        function trimWords(value) {
226            if (!value) return [""];
227            if (!options.multiple) return [$.trim(value)];
228            return $.map(value.split(options.multipleSeparator), function(word) {
229                return $.trim(value).length ? $.trim(word) : null;
230            });
231        }
232        function lastWord(value) {
233            if (!options.multiple) return value;
234            var words = trimWords(value);
235            if (words.length == 1) return words[0];
236            var cursorAt = $(input).selection().start;
237            if (cursorAt == value.length) {
238                words = trimWords(value)
239            } else {
240                words = trimWords(value.replace(value.substring(cursorAt), ""));
241            }
242            return words[words.length - 1];
243        }
244        function autoFill(q, sValue) {
245            if (options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE) {
246                $input.val($input.val() + sValue.substring(lastWord(previousValue).length));
247                $(input).selection(previousValue.length, previousValue.length + sValue.length);
248            }
249        };
250
251        function hideResults() {
252            clearTimeout(timeout);
253            timeout = setTimeout(hideResultsNow, 200);
254        };
255
256        function hideResultsNow() {
257            var wasVisible = select.visible();
258            select.hide();
259            clearTimeout(timeout);
260            stopLoading();
261            if (options.mustMatch) {
262                $input.search(function(result) {
263                    if (!result) {
264                        if (options.multiple) {
265                            var words = trimWords($input.val()).slice(0, -1);
266                            $input.val(words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : ""));
267                        } else {
268                            $input.val("");
269                            $input.trigger("result", null);
270                        }
271                    }
272                });
273            }
274        };
275
276        function receiveData(q, data) {
277            if (data && data.length && hasFocus) {
278                stopLoading();
279                select.display(data, q);
280                autoFill(q, data[0].value);
281                select.show();
282            } else {
283                hideResultsNow();
284            }
285        };
286
287        function request(term, success, failure) {
288            if (!options.matchCase) term = term.toLowerCase();
289            var data = cache.load(term);
290            if (data && data.length) {
291                success(term, data);
292            } else if ((typeof options.url == "string") && (options.url.length > 0)) {
293                var extraParams = {
294                    timestamp: +new Date()
295                };
296                $.each(options.extraParams, function(key, param) {
297                    extraParams[key] = typeof param == "function" ? param() : param;
298                });
299                $.ajax({
300                    mode: "abort",
301                    port: "autocomplete" + input.name,
302                    dataType: options.dataType,
303                    url: options.url,
304                    data: $.extend({
305                        wd: lastWord(term),
306                        limit: options.max
307                    }, extraParams),
308                    success: function(data) {
309                        var parsed = options.parse && options.parse(data) || parse(data);
310                        cache.add(term, parsed);
311                        success(term, parsed);
312                    }
313                });
314            } else {
315                select.emptyList();
316                failure(term);
317            }
318        };
319
320        function parse(data) {
321            var parsed = [];
322            var rows = data.split("\n");
323            for (var i = 0; i < rows.length; i++) {
324                var row = $.trim(rows[i]);
325                if (row) {
326                    row = row.split("|");
327                    parsed[parsed.length] = {
328                        data: row,
329                        value: row[0],
330                        result: options.formatResult && options.formatResult(row, row[0]) || row[0]
331                    };
332                }
333            }
334            return parsed;
335        };
336
337        function stopLoading() {
338            $input.removeClass(options.loadingClass);
339        };
340    };
341    $.Autocompleter.defaults = {
342        inputClass: "ac_input",
343        resultsClass: "ac_results",
344        loadingClass: "ac_loading",
345        minChars: 1,
346        delay: 400,
347        matchCase: false,
348        matchSubset: true,
349        matchContains: false,
350        cacheLength: 10,
351        max: 100,
352        mustMatch: false,
353        extraParams: {},
354        selectFirst: true,
355        formatItem: function(row) {
356            return row[0];
357        },
358        formatMatch: null,
359        autoFill: false,
360        width: 0,
361        multiple: false,
362        multipleSeparator: ", ",
363        highlight: function(value, term) {
364            return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
365        },
366        scroll: true,
367        scrollHeight: 180
368    };
369    $.Autocompleter.Cache = function(options) {
370        var data = {};
371        var length = 0;
372
373        function matchSubset(s, sub) {
374            if (!options.matchCase) s = s.toLowerCase();
375            var i = s.indexOf(sub);
376            if (options.matchContains == "word") {
377                i = s.toLowerCase().search("\\b" + sub.toLowerCase());
378            }
379            if (i == -1) return false;
380            return i == 0 || options.matchContains;
381        };
382
383        function add(q, value) {
384            if (length > options.cacheLength) {
385                flush();
386            }
387            if (!data[q]) {
388                length++;
389            }
390            data[q] = value;
391        }
392        function populate() {
393            if (!options.data) return false;
394            var stMatchSets = {},
395                nullData = 0;
396            if (!options.url) options.cacheLength = 1;
397            stMatchSets[""] = [];
398            for (var i = 0, ol = options.data.length; i < ol; i++) {
399                var rawValue = options.data[i];
400                rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;
401                var value = options.formatMatch(rawValue, i + 1, options.data.length);
402                if (value === false) continue;
403                var firstChar = value.charAt(0).toLowerCase();
404                if (!stMatchSets[firstChar]) stMatchSets[firstChar] = [];
405                var row = {
406                    value: value,
407                    data: rawValue,
408                    result: options.formatResult && options.formatResult(rawValue) || value
409                };
410                stMatchSets[firstChar].push(row);
411                if (nullData++ < options.max) {
412                    stMatchSets[""].push(row);
413                }
414            };
415            $.each(stMatchSets, function(i, value) {
416                options.cacheLength++;
417                add(i, value);
418            });
419        }
420        setTimeout(populate, 25);
421
422        function flush() {
423            data = {};
424            length = 0;
425        }
426        return {
427            flush: flush,
428            add: add,
429            populate: populate,
430            load: function(q) {
431                if (!options.cacheLength || !length) return null;
432                if (!options.url && options.matchContains) {
433                    var csub = [];
434                    for (var k in data) {
435                        if (k.length > 0) {
436                            var c = data[k];
437                            $.each(c, function(i, x) {
438                                if (matchSubset(x.value, q)) {
439                                    csub.push(x);
440                                }
441                            });
442                        }
443                    }
444                    return csub;
445                } else if (data[q]) {
446                    return data[q];
447                } else if (options.matchSubset) {
448                    for (var i = q.length - 1; i >= options.minChars; i--) {
449                        var c = data[q.substr(0, i)];
450                        if (c) {
451                            var csub = [];
452                            $.each(c, function(i, x) {
453                                if (matchSubset(x.value, q)) {
454                                    csub[csub.length] = x;
455                                }
456                            });
457                            return csub;
458                        }
459                    }
460                }
461                return null;
462            }
463        };
464    };
465    $.Autocompleter.Select = function(options, input, select, config) {
466        var CLASSES = {
467            ACTIVE: "ac_over"
468        };
469        var listItems, active = -1,
470            data, term = "",
471            needsInit = true,
472            element, list;
473
474        function init() {
475            if (!needsInit) return;
476            element = $("<div/>").hide().addClass(options.resultsClass).css("position", "absolute").appendTo(document.body);
477            list = $("<ul/>").appendTo(element).mouseover(function(event) {
478                if (target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
479                    active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
480                    $(target(event)).addClass(CLASSES.ACTIVE);
481                }
482            }).click(function(event) {
483                $(target(event)).addClass(CLASSES.ACTIVE);
484                select();
485                input.focus();
486                return false;
487            }).mousedown(function() {
488                config.mouseDownOnSelect = true;
489            }).mouseup(function() {
490                config.mouseDownOnSelect = false;
491            });
492            if (options.width > 0) element.css("width", options.width);
493            needsInit = false;
494        }
495        function target(event) {
496            var element = event.target;
497            while (element && element.tagName != "LI") element = element.parentNode;
498            if (!element) return [];
499            return element;
500        }
501        function moveSelect(step) {
502            listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);
503            movePosition(step);
504            var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
505            if (options.scroll) {
506                var offset = 0;
507                listItems.slice(0, active).each(function() {
508                    offset += this.offsetHeight;
509                });
510                if ((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) {
511                    list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight());
512                } else if (offset < list.scrollTop()) {
513                    list.scrollTop(offset);
514                }
515            }
516        };
517
518        function movePosition(step) {
519            active += step;
520            if (active < 0) {
521                active = listItems.size() - 1;
522            } else if (active >= listItems.size()) {
523                active = 0;
524            }
525        }
526        function limitNumberOfItems(available) {
527            return options.max && options.max < available ? options.max : available;
528        }
529        function fillList() {
530            list.empty();
531            var max = limitNumberOfItems(data.length);
532            for (var i = 0; i < max; i++) {
533                if (!data[i]) continue;
534                var formatted = options.formatItem(data[i].data, i + 1, max, data[i].value, term);
535                if (formatted === false) continue;
536                var li = $("<li/>").html(options.highlight(formatted, term)).addClass(i % 2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0];
537                $.data(li, "ac_data", data[i]);
538            }
539            listItems = list.find("li");
540            if (options.selectFirst) {
541                listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
542                active = 0;
543            }
544            if ($.fn.bgiframe) list.bgiframe();
545        }
546        return {
547            display: function(d, q) {
548                init();
549                data = d;
550                term = q;
551                fillList();
552            },
553            next: function() {
554                moveSelect(1);
555            },
556            prev: function() {
557                moveSelect(-1);
558            },
559            pageUp: function() {
560                if (active != 0 && active - 8 < 0) {
561                    moveSelect(-active);
562                } else {
563                    moveSelect(-8);
564                }
565            },
566            pageDown: function() {
567                if (active != listItems.size() - 1 && active + 8 > listItems.size()) {
568                    moveSelect(listItems.size() - 1 - active);
569                } else {
570                    moveSelect(8);
571                }
572            },
573            hide: function() {
574                element && element.hide();
575                listItems && listItems.removeClass(CLASSES.ACTIVE);
576                active = -1;
577            },
578            visible: function() {
579                return element && element.is(":visible");
580            },
581            current: function() {
582                return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);
583            },
584            show: function() {
585                var offset = $(input).offset();
586                element.css({
587                    width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(),
588                    top: offset.top + input.offsetHeight,
589                    left: offset.left
590                }).show();
591                if (options.scroll) {
592                    list.scrollTop(0);
593                    list.css({
594                        maxHeight: options.scrollHeight,
595                        overflow: 'auto'
596                    });
597                    if ($.browser.msie && typeof document.body.style.maxHeight === "undefined") {
598                        var listHeight = 0;
599                        listItems.each(function() {
600                            listHeight += this.offsetHeight;
601                        });
602                        var scrollbarsVisible = listHeight > options.scrollHeight;
603                        list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight);
604                        if (!scrollbarsVisible) {
605                            listItems.width(list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")));
606                        }
607                    }
608                }
609            },
610            selected: function() {
611                var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
612                return selected && selected.length && $.data(selected[0], "ac_data");
613            },
614            emptyList: function() {
615                list && list.empty();
616            },
617            unbind: function() {
618                element && element.remove();
619            }
620        };
621    };
622    $.fn.selection = function(start, end) {
623        if (start !== undefined) {
624            return this.each(function() {
625                if (this.createTextRange) {
626                    var selRange = this.createTextRange();
627                    if (end === undefined || start == end) {
628                        selRange.move("character", start);
629                        selRange.select();
630                    } else {
631                        selRange.collapse(true);
632                        selRange.moveStart("character", start);
633                        selRange.moveEnd("character", end);
634                        selRange.select();
635                    }
636                } else if (this.setSelectionRange) {
637                    this.setSelectionRange(start, end);
638                } else if (this.selectionStart) {
639                    this.selectionStart = start;
640                    this.selectionEnd = end;
641                }
642            });
643        }
644        var field = this[0];
645        if (field.createTextRange) {
646            var range = document.selection.createRange(),
647                orig = field.value,
648                teststring = "<->",
649                textLength = range.text.length;
650            range.text = teststring;
651            var caretAt = field.value.indexOf(teststring);
652            field.value = orig;
653            this.selection(caretAt, caretAt + textLength);
654            return {
655                start: caretAt,
656                end: caretAt + textLength
657            }
658        } else if (field.selectionStart !== undefined) {
659            return {
660                start: field.selectionStart,
661                end: field.selectionEnd
662            }
663        }
664    };
665})(jQuery);

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.