blob: e918390c1249bde0ecaea50b54c2d04887a42a9c [file] [log] [blame]
Tyler Scott93cae872015-07-21 14:58:23 -06001/*
2 * The following code is a jquery extention written to add autocomplete functionality to bootstrap input groups.
3 *
4 * Usage:
5 *
6 * Then simply call $('.someClass').autoComplete(getSuggestions) on it to enable auto completion.
7 *
Tyler Scott93cae872015-07-21 14:58:23 -06008 * getSuggestions returns by calling its callback parameter with an array of valid strings.
9 *
Tyler Scottc55879f2015-07-28 14:56:37 -060010 * Autocomplete can be manually triggered by triggering the autoComplete event.
11 *
Tyler Scott93cae872015-07-21 14:58:23 -060012 */
13(function(){
14 "use strict";
15 if (!jQuery){
16 throw new Error("jQuery is required and must be loaded before this script.")
17 }
18 jQuery.fn.extend({
19 /**
20 * @param {Array<String>|getSuggestions}
21 */
22 autoComplete: function(suggestions) {
23
24 var element = $('<div></div>');
25 element.addClass('list-group')
26 .css({
27 'border-top-left-radius': 0,
28 'border-top-right-radius': 0,
29 'width': this.width(),
30 'position': 'absolute',
31 'top': this.parent().height(),
32 'display': 'none',
33 'max-height': '500px',
34 'overflow-y': 'auto'
35 });
36
37 this.focus(function(){
38 element.slideDown();
39 }).blur(function(){
40 element.slideUp();
41 }).before(element);
42
43 var getSuggestions = function(current, callback){
44 callback(suggestions.reduce(function(prev, suggestion){
45 if (current.toLowerCase().indexOf(suggestion.substr(0, current.length).toLowerCase()) === 0){
46 prev.push(suggestion);
47 }
48 return prev;
49 }, []));
50 }
51
52 var setAutoComplete = function(list){
53 element.empty();
54
55 element.html(list.reduce(function(prev, current){
56 return [prev, '<a href="#" class="list-group-item">', current, '</a>'].join("");
57 }, ""));
58
59 }
60
61 if (suggestions instanceof Function){
62 getSuggestions = suggestions;
63 }
64
65 var input = this;
66
67 element.bind('click', 'a', function(){
68 input.val($(this).text());
69 });
70
71 this.keydown(function(e){
72 switch(e.which){
73 case 38: //up
74 var active = element.find('.active');
75 if (active.length === 0){
76 element.find(':first-child').addClass('active');
77 } else {
78 if (!active.is(':first-child')){
79 active.removeClass('active').prev().addClass('active');
80 }
81 }
82 e.preventDefault();
83 break;
84
85 case 40: //down
86 var active = element.find('.active');
87 if (active.length === 0){
88 element.find(':first-child').addClass('active');
89 } else {
90 if (!active.is(':last-child')){
91 active.removeClass('active').next().addClass('active');
92 }
93 }
94 e.preventDefault();
95 break;
96
97 case 13: //Enter
98 var active = element.find('.active');
99 if (active.length === 1){
100 $(this).val(active.text());
101 e.preventDefault();
102 }
103 break;
104
105 case 9: //Tab
106 getSuggestions(input.val(), setAutoComplete);
107 e.preventDefault(); //Don't print tab
108 break;
109 }
110
111 });
112
Tyler Scottc55879f2015-07-28 14:56:37 -0600113 this.on('autoComplete', function(){
114 getSuggestions(input.val(), setAutoComplete);
115 });
116
Tyler Scott93cae872015-07-21 14:58:23 -0600117 return this;
118
119 }
120 });
121})();
122
123/**
124 * @callback getSuggestions
125 * @param {string} current - The current value of the input field.
126 * @param {function}
127 */