// 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);