// author: david qin
// date: 2014-11-05
(function($){
// a case insensitive jquery :contains selector
$.expr[":"].searchableselectcontains = $.expr.createpseudo(function(arg) {
return function( elem ) {
if(arg){
arg=arg.touppercase();
}
return $(elem).text().touppercase().indexof(arg) >= 0;
};
});
$.searchableselect = function(element, options) {
this.element = element;
this.options = options || {};
this.init();
var _this = this;
this.searchableelement.click(function(event){
// event.stoppropagation();
_this.show();
}).on('keydown', function(event){
if (event.which === 13 || event.which === 40 || event.which == 38){
event.preventdefault();
_this.show();
}
});
$(document).on('click', null, function(event){
if(_this.searchableelement.has($(event.target)).length === 0)
_this.hide();
});
this.input.on('keydown', function(event){
event.stoppropagation();
if(event.which === 13){ //enter
event.preventdefault();
_this.selectcurrenthoveritem();
_this.hide();
} else if (event.which == 27) { //ese
_this.hide();
} else if (event.which == 40) { //down
_this.hovernextitem();
} else if (event.which == 38) { //up
_this.hoverpreviousitem();
}
}).on('keyup', function(event){
if(event.which != 13 && event.which != 27 && event.which != 38 && event.which != 40)
_this.filter();
})
}
var $ss = $.searchableselect;
$ss.fn = $ss.prototype = {
version: '0.0.1'
};
$ss.fn.extend = $ss.extend = $.extend;
$ss.fn.extend({
init: function(){
var _this = this;
this.element.hide();
this.searchableelement = $('
');
this.holder = $('');
this.dropdown = $('');
this.input = $('');
this.items = $('');
this.caret = $('');
this.scrollpart = $('');
this.hasprivious = $('...
');
this.hasnext = $('...
');
this.hasnext.on('mouseenter', function(){
_this.hasnexttimer = null;
var f = function(){
var scrolltop = _this.items.scrolltop();
_this.items.scrolltop(scrolltop + 20);
_this.hasnexttimer = settimeout(f, 50);
}
f();
}).on('mouseleave', function(event) {
cleartimeout(_this.hasnexttimer);
});
this.hasprivious.on('mouseenter', function(){
_this.hasprivioustimer = null;
var f = function(){
var scrolltop = _this.items.scrolltop();
_this.items.scrolltop(scrolltop - 20);
_this.hasprivioustimer = settimeout(f, 50);
}
f();
}).on('mouseleave', function(event) {
cleartimeout(_this.hasprivioustimer);
});
this.dropdown.append(this.input);
this.dropdown.append(this.scrollpart);
this.scrollpart.append(this.hasprivious);
this.scrollpart.append(this.items);
this.scrollpart.append(this.hasnext);
this.searchableelement.append(this.caret);
this.searchableelement.append(this.holder);
this.searchableelement.append(this.dropdown);
this.element.after(this.searchableelement);
this.builditems();
this.setpriviousandnextvisibility();
},
filter: function(){
var text = this.input.val();
this.items.find('.searchable-select-item').addclass('searchable-select-hide');
this.items.find('.searchable-select-item:searchableselectcontains('+text+')').removeclass('searchable-select-hide');
if(this.currentselecteditem.hasclass('searchable-select-hide') && this.items.find('.searchable-select-item:not(.searchable-select-hide)').length > 0){
this.hoverfirstnothideitem();
}
this.setpriviousandnextvisibility();
},
hoverfirstnothideitem: function(){
this.hoveritem(this.items.find('.searchable-select-item:not(.searchable-select-hide)').first());
},
selectcurrenthoveritem: function(){
if(!this.currenthoveritem.hasclass('searchable-select-hide'))
this.selectitem(this.currenthoveritem);
},
hoverpreviousitem: function(){
if(!this.hascurrenthoveritem())
this.hoverfirstnothideitem();
else{
var previtem = this.currenthoveritem.prevall('.searchable-select-item:not(.searchable-select-hide):first')
if(previtem.length > 0)
this.hoveritem(previtem);
}
},
hovernextitem: function(){
if(!this.hascurrenthoveritem())
this.hoverfirstnothideitem();
else{
var nextitem = this.currenthoveritem.nextall('.searchable-select-item:not(.searchable-select-hide):first')
if(nextitem.length > 0)
this.hoveritem(nextitem);
}
},
builditems: function(){
var _this = this;
this.element.find('option').each(function(){
var item = $(''+$(this).text()+'
');
if(_this.element[0].id=='jumpmenu2'&&$(this).attr('value').length==2){
item = $(''+$(this).text()+'
');
}
if(this.selected){
_this.selectitem(item);
_this.hoveritem(item);
}
item.on('mouseenter', function(){
$(this).addclass('hover');
}).on('mouseleave', function(){
$(this).removeclass('hover');
}).click(function(event){
event.stoppropagation();
_this.selectitem($(this));
_this.hide();
});
_this.items.append(item);
});
this.items.on('scroll', function(){
_this.setpriviousandnextvisibility();
})
},
show: function(){
this.dropdown.removeclass('searchable-select-hide');
this.input.focus();
this.status = 'show';
this.setpriviousandnextvisibility();
},
hide: function(){
if(!(this.status === 'show'))
return;
if(this.items.find(':not(.searchable-select-hide)').length === 0)
this.input.val('');
this.dropdown.addclass('searchable-select-hide');
this.searchableelement.trigger('focus');
this.status = 'hide';
},
hascurrentselecteditem: function(){
return this.currentselecteditem && this.currentselecteditem.length > 0;
},
selectitem: function(item){
if(this.hascurrentselecteditem())
this.currentselecteditem.removeclass('selected');
this.currentselecteditem = item;
item.addclass('selected');
this.hoveritem(item);
this.holder.text(item.text());
var value = item.data('value');
this.holder.data('value', value);
this.element.val(value);
loaddata();
if(this.options.afterselectitem){
this.options.afterselectitem.apply(this);
}
},
hascurrenthoveritem: function(){
return this.currenthoveritem && this.currenthoveritem.length > 0;
},
hoveritem: function(item){
if(this.hascurrenthoveritem())
this.currenthoveritem.removeclass('hover');
if(item.outerheight() + item.position().top > this.items.height())
this.items.scrolltop(this.items.scrolltop() + item.outerheight() + item.position().top - this.items.height());
else if(item.position().top < 0)
this.items.scrolltop(this.items.scrolltop() + item.position().top);
this.currenthoveritem = item;
item.addclass('hover');
},
setpriviousandnextvisibility: function(){
if(this.items.scrolltop() === 0){
this.hasprivious.addclass('searchable-select-hide');
this.scrollpart.removeclass('has-privious');
} else {
this.hasprivious.removeclass('searchable-select-hide');
this.scrollpart.addclass('has-privious');
}
if(this.items.scrolltop() + this.items.innerheight() >= this.items[0].scrollheight){
this.hasnext.addclass('searchable-select-hide');
this.scrollpart.removeclass('has-next');
} else {
this.hasnext.removeclass('searchable-select-hide');
this.scrollpart.addclass('has-next');
}
}
});
$.fn.searchableselect = function(options){
this.each(function(){
var ss = new $ss($(this), options);
});
return this;
};
})(jquery);