A keyboard- or mouse-navigated dropdown menu for a text field or other input method. Runs on jQuery.
Usage
Initially, the dropdown has to be set up, as such:
$("input.dropdown").dropdown({
objects: [], // this is a textual list of each of the items in the list to begin with
maxitems: 10, // maximum number of items to display
listclass: 'textDropdown', // the class of the list
objclass: 'textDropdownElement', // the class of each list element
containerclass: 'textDropdownContainer', // the class of the container wrapping around the list
selectedclass: 'textDropdownSelected', // the class of the selected item
onrender: function(item, listclass) {
// item is a passed list object; listclass is the class that the renderer is using for it
// should return a string, using an <li> tag as a wrapper
},
onclick: function($item) {
// $item is the item clicked, as a jQuery object
}
});
When the list is to be updated, it can be called using $("input.dropdown").dropdown('update',data);
, where data
is a variable array containing the list elements. You can also call to show or hide the list as-is, using $("input.dropdown").dropdown('show');
or $("input.dropdown").dropdown('hide');
.
A CSS file also has to be set up with a code to manage the classes for the lists. Here is the example a previous website of mine used for its AJAX search:
div.textDropdownContainer {
background:#a39c8f;
padding:1px;
}
ul.textDropdown {
background:transparent;
margin:0;
padding:0;
}
li.textDropdownSelected {
background:#99ee99 !important;
color:#116611 !important;
}
li.textDropdownElementBest {
background:#dce4dc;
}
li.textDropdownElementGood {
background:#e4e3dc;
}
li.textDropdownElementPoor {
background:#e4dcdc;
}
li.textDropdownElement {
color:#6b614f;
cursor:pointer;
cursor:hand;
font-size:80%;
list-style-type:none;
margin-top:1px;
padding:2px 4px;
text-align:left;
}
li.textDropdownElement:hover {
background:#f0efed;
}
Code
(function($){
var t = undefined;
var $element = undefined;
var $node = undefined;
var settings = {
objects: [],
maxitems: 10,
listclass: 'textDropdown',
objclass: 'textDropdownElement',
containerclass: 'textDropdownContainer',
selectedclass: 'textDropdownSelected',
onrender: undefined,
onclick: undefined
};
var selected = 0;
var lastupdate = "";
var methods = {
init: function() {
methods.move.apply(t);
$(window).resize(function() {
methods.move.apply(t);
});
$element.blur(function() {
setTimeout(function() { methods.hide.apply(t); },250);
});
$element.keyup(function(event) {
if (event.which == 38) {
selected--;
if (selected < 0) selected = 0;
} else if (event.which == 40) {
selected++;
if (selected > settings.maxitems+1) selected = settings.maxitems+1;
} else if (event.which == 13) {
if (selected > 0 && selected <= settings.maxitems)
methods.click.apply(t,[$node.find("li:nth-child("+selected+")")]);
} else {
return;
}
$node.find("li").not(":nth-child("+selected+")").each(function() {
$(this).removeClass(settings.selectedclass);
});
$node.find("li:nth-child("+selected+")").each(function() {
$(this).addClass(settings.selectedclass);
});
});
methods.hide.apply(t);
return t.each(function() {});
},
show: function() {
$node.show();
methods.move.apply(t);
return t.each(function() {});
},
hide: function() {
selected = 0;
$node.hide();
return t.each(function() {});
},
click: function($item) {
if (settings.onclick && typeof settings.onclick == "function")
return settings.onclick.apply(t,[$item]);
$element.val($item.html());
methods.hide.apply(t);
return t.each(function() {});
},
render: function(item) {
if (settings.onrender && typeof settings.onrender == "function")
return settings.onrender.apply(t,[item,settings.objclass]);
return "<li class='"+settings.objclass+"'>"+item+"</li>";
},
update: function(newobjs) {
if (newobjs.length <= 0 || newobjs[0].length <= 0) {
methods.hide.apply(t);
return t.each(function() {});
}
var text = "";
text += "<ul class='"+settings.listclass+"'>";
for (i = 0; i < newobjs.length && i < settings.maxitems; i++) {
text += methods.render.apply(t,[newobjs[i]]);
}
text += "</ul>";
if (text != lastupdate) {
selected = 0;
$node.empty();
lastupdate = text;
$node.html(text);
$node.find("ul > li").each(function() {
$(this).click(function() {
methods.click.apply(t,[$(this)]);
});
});
}
methods.show.apply(t);
return t.each(function() {});
},
move: function() {
var offset = $element.offset();
offset.top += $element.height()
+ parseInt ($element.css("padding-top"))
+ parseInt ($element.css("border-top-width"))
+ parseInt ($element.css("border-bottom-width"));
$node.offset(offset);
return t.each(function() {});
}
}
$.fn.dropdown = function(options) {
t = this;
if (options && typeof options == "string" && methods[options]) {
return methods[options].apply(t,Array.prototype.slice.call(arguments,1));
} else {
if (options)
$.extend(settings,options);
$element = $(this);
$node = $("<div></div>",{
id: 'dropdownObj',
style: 'position:absolute;top:-999px;left:-999px;width:'+$element.width()+'px'
}).addClass(settings.containerclass);
$node.appendTo($("body"));
methods.init.apply(t);
}
return t.each(function() {});
};
})(jQuery);