Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
jQuery selectbox plugin
/*
* jQuery selectbox plugin
*
* Copyright (c) 2007 Sadri Sahraoui (brainfault.com)
* Licensed under the GPL license and MIT:
* http://www.opensource.org/licenses/GPL-license.php
* http://www.opensource.org/licenses/mit-license.php
*
* The code is inspired from Autocomplete plugin (http://www.dyve.net/jquery/?autocomplete)
*
* Revision: $Id$
* Version: 1.2
*
* Changelog :
* Version 1.2 By Guillaume Vergnolle (web-opensource.com)
* - Add optgroup support
* - possibility to choose between span or input as replacement of the select box
* - support for jquery change event
* - add a max height option for drop down list
* Version 1.1
* - Fix IE bug
* Version 1.0
* - Support jQuery noConflict option
* - Add callback for onChange event, thanks to Jason
* - Fix IE8 support
* - Fix auto width support
* - Fix focus on firefox dont show the carret
* Version 0.6
* - Fix IE scrolling problem
* Version 0.5
* - separate css style for current selected element and hover element which solve the highlight issue
* Version 0.4
* - Fix width when the select is in a hidden div @Pawel Maziarz
* - Add a unique id for generated li to avoid conflict with other selects and empty values @Pawel Maziarz
*/
jQuery.fn.extend({
selectbox: function(options) {
return this.each(function() {
new jQuery.SelectBox(this, options);
});
}
});
/* pawel maziarz: work around for ie logging */
if (!window.console) {
var console = {
log: function(msg) {
}
}
}
/* */
jQuery.SelectBox = function(selectobj, options) {
var opt = options || {};
opt.inputType = opt.inputType || "input";
opt.inputClass = opt.inputClass || "selectbox";
opt.containerClass = opt.containerClass || "selectbox-wrapper";
opt.hoverClass = opt.hoverClass || "current";
opt.currentClass = opt.currentClass || "selected";
opt.groupClass = opt.groupClass || "groupname"; //css class for group
opt.maxHeight = opt.maxHeight || 200; // max height of dropdown list
opt.loopnoStep = opt.loopnoStep || false; // to remove the step in list moves loop
opt.onChangeCallback = opt.onChangeCallback || false;
opt.onChangeParams = opt.onChangeParams || false;
opt.debug = opt.debug || false;
var elm_id = selectobj.id;
var active = 0;
var inFocus = false;
var hasfocus = 0;
//jquery object for select element
var $select = jQuery(selectobj);
// jquery container object
var $container = setupContainer(opt);
//jquery input object
var $input = setupInput(opt);
// hide select and append newly created elements
$select.hide().before($input).before($container);
init();
$input
.click(function(){
if (!inFocus) {
$container.toggle();
}
})
.focus(function(){
if ($container.not(':visible')) {
inFocus = true;
$container.show();
}
})
.keydown(function(event) {
switch(event.keyCode) {
case 38: // up
event.preventDefault();
moveSelect(-1);
break;
case 40: // down
event.preventDefault();
moveSelect(1);
break;
//case 9: // tab
case 13: // return
event.preventDefault(); // seems not working in mac !
$('li.'+opt.hoverClass).trigger('click');
break;
case 27: //escape
hideMe();
break;
}
})
.blur(function() {
if ($container.is(':visible') && hasfocus > 0 ) {
if(opt.debug) console.log('container visible and has focus')
} else {
// Workaround for ie scroll - thanks to Bernd Matzner
if((jQuery.browser.msie && jQuery.browser.version.substr(0,1) < 8)
|| (jQuery.browser.safari && !/chrome/.test(navigator.userAgent.toLowerCase()))) {
if(document.activeElement.getAttribute('id').indexOf('_container')==-1){
hideMe();
} else {
$input.focus();
}
} else {
hideMe();
}
}
});
function hideMe() {
hasfocus = 0;
$container.hide();
}
function init() {
$container.append(getSelectOptions($input.attr('id'))).hide();
var width = $input.css('width');
if($container.height() > opt.maxHeight){
$container.width(parseInt(width)+parseInt($input.css('paddingRight'))+parseInt($input.css('paddingLeft')));
$container.height(opt.maxHeight);
} else $container.width(width);
}
function setupContainer(options) {
var container = document.createElement("div");
$container = jQuery(container);
$container.attr('id', elm_id+'_container');
$container.addClass(options.containerClass);
$container.css('display', 'none');
return $container;
}
function setupInput(options) {
if(opt.inputType == "span"){
var input = document.createElement("span");
var $input = jQuery(input);
$input.attr("id", elm_id+"_input");
$input.addClass(options.inputClass);
$input.attr("tabIndex", $select.attr("tabindex"));
} else {
var input = document.createElement("input");
var $input = jQuery(input);
$input.attr("id", elm_id+"_input");
$input.attr("type", "text");
$input.addClass(options.inputClass);
$input.attr("autocomplete", "off");
$input.attr("readonly", "readonly");
$input.attr("tabIndex", $select.attr("tabindex")); // "I" capital is important for ie
$input.css("width", $select.css("width"));
}
return $input;
}
function moveSelect(step) {
var lis = jQuery("li", $container);
if (!lis || lis.length == 0) return false;
// find the first non-group (first option)
firstchoice = 0;
while($(lis[firstchoice]).hasClass(opt.groupClass)) firstchoice++;
active += step;
// if we are on a group step one more time
if($(lis[active]).hasClass(opt.groupClass)) active += step;
//loop through list from the first possible option
if (active < firstchoice) {
(opt.loopnoStep ? active = lis.size()-1 : active = lis.size() );
} else if (opt.loopnoStep && active > lis.size()-1) {
active = firstchoice;
} else if (active > lis.size()) {
active = firstchoice;
}
scroll(lis, active);
lis.removeClass(opt.hoverClass);
jQuery(lis[active]).addClass(opt.hoverClass);
}
function scroll(list, active) {
var el = jQuery(list[active]).get(0);
var list = $container.get(0);
if (el.offsetTop + el.offsetHeight > list.scrollTop + list.clientHeight) {
list.scrollTop = el.offsetTop + el.offsetHeight - list.clientHeight;
} else if(el.offsetTop < list.scrollTop) {
list.scrollTop = el.offsetTop;
}
}
function setCurrent() {
var li = jQuery("li."+opt.currentClass, $container).get(0);
var ar = (''+li.id).split('_');
var el = ar[ar.length-1];
if (opt.onChangeCallback){
$select.get(0).selectedIndex = $('li', $container).index(li);
opt.onChangeParams = { selectedVal : $select.val() };
opt.onChangeCallback(opt.onChangeParams);
} else {
$select.val(el);
$select.change();
}
if(opt.inputType == 'span') $input.html($(li).html());
else $input.val($(li).html());
return true;
}
// select value
function getCurrentSelected() {
return $select.val();
}
// input value
function getCurrentValue() {
return $input.val();
}
function getSelectOptions(parentid) {
var select_options = new Array();
var ul = document.createElement('ul');
select_options = $select.children('option');
if(select_options.length == 0) {
var select_optgroups = new Array();
select_optgroups = $select.children('optgroup');
for(x=0;x<select_optgroups.length;x++){
select_options = $("#"+select_optgroups[x].id).children('option');
var li = document.createElement('li');
li.setAttribute('id', parentid + '_' + $(this).val());
li.innerHTML = $("#"+select_optgroups[x].id).attr('label');
li.className = opt.groupClass;
ul.appendChild(li);
select_options.each(function() {
var li = document.createElement('li');
li.setAttribute('id', parentid + '_' + $(this).val());
li.innerHTML = $(this).html();
if ($(this).is(':selected')) {
$input.html($(this).html());
$(li).addClass(opt.currentClass);
}
ul.appendChild(li);
$(li)
.mouseover(function(event) {
hasfocus = 1;
if (opt.debug) console.log('over on : '+this.id);
jQuery(event.target, $container).addClass(opt.hoverClass);
})
.mouseout(function(event) {
hasfocus = -1;
if (opt.debug) console.log('out on : '+this.id);
jQuery(event.target, $container).removeClass(opt.hoverClass);
})
.click(function(event) {
var fl = $('li.'+opt.hoverClass, $container).get(0);
if (opt.debug) console.log('click on :'+this.id);
$('li.'+opt.currentClass, $container).removeClass(opt.currentClass);
$(this).addClass(opt.currentClass);
setCurrent();
$select.get(0).blur();
hideMe();
});
});
}
} else select_options.each(function() {
var li = document.createElement('li');
li.setAttribute('id', parentid + '_' + $(this).val());
li.innerHTML = $(this).html();
if ($(this).is(':selected')) {
$input.val($(this).html());
$(li).addClass(opt.currentClass);
}
ul.appendChild(li);
$(li)
.mouseover(function(event) {
hasfocus = 1;
if (opt.debug) console.log('over on : '+this.id);
jQuery(event.target, $container).addClass(opt.hoverClass);
})
.mouseout(function(event) {
hasfocus = -1;
if (opt.debug) console.log('out on : '+this.id);
jQuery(event.target, $container).removeClass(opt.hoverClass);
})
.click(function(event) {
var fl = $('li.'+opt.hoverClass, $container).get(0);
if (opt.debug) console.log('click on :'+this.id);
$('li.'+opt.currentClass, $container).removeClass(opt.currentClass);
$(this).addClass(opt.currentClass);
setCurrent();
$select.get(0).blur();
hideMe();
});
});
return ul;
}
};

Hi this is a great plugin, many thanks for you, but i was wondering how do i loose focus even when not selecting an option from a list?

g-mishra commented Dec 1, 2013

Hi i have done some modification in this js related to scroll(ie-8/ie-9),tab,hidden li tags and some other bug.want to know how i can contribute in this code to make it better .

Owner

itsadok commented Dec 26, 2013

@g-misra This is not really my code. I just provided a mirror for a broken link from this stackoverflow answer. I tried contacting the author, but got no response.

If you want to contribute, I suggest you start a proper github repository and link to it from here.

ve3 commented Feb 18, 2014

How to get selected value?

Esty12 commented Jul 8, 2014

Hi,
there is an option to do with this plugin multi-select ?

thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment