(function($){
var rEscape=/[\-\[\]{}()*+?.,\\\^$|#\s]/g;
$.widget('ech.multiselectfilter', {
options: {
label: 'Filter:',
width: null, 
placeholder: 'Enter keywords',
autoReset: false
},
_create: function(){
var opts=this.options;
var elem=$(this.element);
var instance=(this.instance=(elem.data('echMultiselect')||elem.data("multiselect")));
var header=(this.header=instance.menu.find('.ui-multiselect-header').addClass('ui-multiselect-hasfilter'));
var wrapper=(this.wrapper=$('<div class="ui-multiselect-filter">' + (opts.label.length ? opts.label:'') + '<input placeholder="'+opts.placeholder+'" type="search"' + (/\d/.test(opts.width) ? 'style="width:'+opts.width+'px"':'') + ' /></div>').prependTo(this.header));
this.inputs=instance.menu.find('input[type="checkbox"], input[type="radio"]');
this.input=wrapper.find('input').bind({
keydown: function(e){
if(e.which===13){
e.preventDefault();
}},
keyup: $.proxy(this._handler, this),
click: $.proxy(this._handler, this)
});
this.updateCache();
instance._toggleChecked=function(flag, group){
var $inputs=(group&&group.length) ?  group:this.labels.find('input');
var _self=this;
var selector=instance._isOpen ?  ':disabled, :hidden':':disabled';
$inputs=$inputs
.not(selector)
.each(this._toggleState('checked', flag));
this.update();
var values=$inputs.map(function(){
return this.value;
}).get();
this.element.find('option').filter(function(){
if(!this.disabled&&$.inArray(this.value, values) > -1){
_self._toggleState('selected', flag).call(this);
}});
if($inputs.length){
this.element.trigger('change');
}};
var doc=$(document).bind('multiselectrefresh', $.proxy(function(){
this.updateCache();
this._handler();
}, this));
if(this.options.autoReset){
doc.bind('multiselectclose', $.proxy(this._reset, this));
}},
_handler: function(e){
var term=$.trim(this.input[0].value.toLowerCase()),
rows=this.rows, inputs=this.inputs, cache=this.cache;
if(!term){
rows.show();
}else{
rows.hide();
var regex=new RegExp(term.replace(rEscape, "\\$&"), 'gi');
this._trigger("filter", e, $.map(cache, function(v, i){
if(v.search(regex)!==-1){
rows.eq(i).show();
return inputs.get(i);
}
return null;
}));
}
this.instance.menu.find(".ui-multiselect-optgroup-label").each(function(){
var $this=$(this);
var isVisible=$this.nextUntil('.ui-multiselect-optgroup-label').filter(function(){
return $.css(this, "display")!=='none';
}).length;
$this[isVisible ? 'show':'hide']();
});
},
_reset: function(){
this.input.val('').trigger('keyup');
},
updateCache: function(){
this.rows=this.instance.menu.find(".ui-multiselect-checkboxes li:not(.ui-multiselect-optgroup-label)");
this.cache=this.element.children().map(function(){
var elem=$(this);
if(this.tagName.toLowerCase()==="optgroup"){
elem=elem.children();
}
return elem.map(function(){
return this.innerHTML.toLowerCase();
}).get();
}).get();
},
widget: function(){
return this.wrapper;
},
destroy: function(){
$.Widget.prototype.destroy.call(this);
this.input.val('').trigger("keyup");
this.wrapper.remove();
}});
})(jQuery);