blob: 6edd6d5c724840f85e8b0c286fc562c5dab1e0ae [file] [log] [blame]
/*
* The following code is a jquery extention written to add autocomplete functionality to bootstrap input groups.
*
* Usage:
*
* Then simply call $('.someClass').autoComplete(getSuggestions) on it to enable auto completion.
*
* Also add
* ```
* .autoComplete {
* position: absolute;
* top: 38px;
* width: 229px;
* }
*
* .autoComplete .list-group {
* margin-bottom: 0;
* border: none;
* }
* ```
* to an included css file.
*
* getSuggestions returns by calling its callback parameter with an array of valid strings.
*
*/
(function(){
"use strict";
if (!jQuery){
throw new Error("jQuery is required and must be loaded before this script.")
}
jQuery.fn.extend({
/**
* @param {Array<String>|getSuggestions}
*/
autoComplete: function(suggestions) {
var element = $('<div></div>');
element.addClass('list-group')
.css({
'border-top-left-radius': 0,
'border-top-right-radius': 0,
'width': this.width(),
'position': 'absolute',
'top': this.parent().height(),
'display': 'none',
'max-height': '500px',
'overflow-y': 'auto'
});
this.focus(function(){
element.slideDown();
}).blur(function(){
element.slideUp();
}).before(element);
var getSuggestions = function(current, callback){
callback(suggestions.reduce(function(prev, suggestion){
if (current.toLowerCase().indexOf(suggestion.substr(0, current.length).toLowerCase()) === 0){
prev.push(suggestion);
}
return prev;
}, []));
}
var setAutoComplete = function(list){
element.empty();
element.html(list.reduce(function(prev, current){
return [prev, '<a href="#" class="list-group-item">', current, '</a>'].join("");
}, ""));
}
if (suggestions instanceof Function){
getSuggestions = suggestions;
}
var input = this;
element.bind('click', 'a', function(){
input.val($(this).text());
});
this.keydown(function(e){
switch(e.which){
case 38: //up
var active = element.find('.active');
if (active.length === 0){
element.find(':first-child').addClass('active');
} else {
if (!active.is(':first-child')){
active.removeClass('active').prev().addClass('active');
}
}
e.preventDefault();
break;
case 40: //down
var active = element.find('.active');
if (active.length === 0){
element.find(':first-child').addClass('active');
} else {
if (!active.is(':last-child')){
active.removeClass('active').next().addClass('active');
}
}
e.preventDefault();
break;
case 13: //Enter
var active = element.find('.active');
if (active.length === 1){
$(this).val(active.text());
e.preventDefault();
}
break;
case 9: //Tab
getSuggestions(input.val(), setAutoComplete);
e.preventDefault(); //Don't print tab
break;
}
});
return this;
}
});
})();
/**
* @callback getSuggestions
* @param {string} current - The current value of the input field.
* @param {function}
*/