/*
* tinySelect
*
* Licensed under MIT license.
*
* @version 1.0.4
* @author Pekka Harjamäki
*/
;(function($) {
"use strict";
var TinySelect = {
/* ******************************************************************* *
* Class initializers
* ******************************************************************* */
init: function($el, options) {
$el.data("tinySelectObj",this);
this.config = $.extend({
showSearch: true,
txtLoading: "Loading...",
txtAjaxFailure: "Error...",
dataUrl: null,
dataParser: null
},options);
this.state = {
container: null,
selectBox: null,
itemContainer: null,
searchContainer: null,
searchBox: null,
$el: null,
open: false,
ajaxPending: false,
selectedValue: -1,
originalItemData: [],
filteredItemData: []
};
this.readSelect($el);
this.createSelect($el);
},
createSelect: function($el) {
// Create container for select, search and options
this.state.container = $("
").
addClass("tinyselect").
css({ width: $el.css("width") });
// Create the select element
this.state.selectBox = $("
").
addClass("selectbox").
on("click", { self:this }, this.onSelectBoxClicked );
this.state.container.append(this.state.selectBox);
// Create container to hold search and results
this.state.dropdown = $("
").
addClass("dropdown").
hide();
this.state.container.append(this.state.dropdown);
// Add search as first element
if(this.config.showSearch)
this.createSearch(this.state.dropdown);
// Create ul to hold items
this.state.itemContainer = $("").
addClass("itemcontainer");
this.state.dropdown.append(this.state.itemContainer);
//
this.createItems();
// Hide original select element and add new component to below
$el.hide().after(this.state.container);
this.state.$el = $el;
// Hide select content when clicked elsewhere in the document
$(document).on("click", {self: this}, this.onDocumentClicked );
},
createItems: function(selected) {
var l1, opt;
// Remove all
this.state.itemContainer.empty();
//
for(l1=0; l1").
text( opt.text ).
addClass( "item" ).
attr( "data-value", opt.val );
if( opt.val == this.state.selectedValue )
{
this.state.selectBox.html( opt.text );
newLi.addClass("selected");
}
newLi.on("click", { self:this }, this.onSelectLiClicked );
this.state.itemContainer.append(newLi);
}
},
createSearch: function($el) {
this.state.searchContainer = $("
").
addClass("searchcontainer");
this.state.searchBox = $(" ").
addClass("searchbox").
on("click",function(e) { e.stopPropagation(); }).
on("keyup",{ self: this }, this.onSearchKeyPress);
this.state.searchContainer.append($(" "));
this.state.searchContainer.append(this.state.searchBox);
this.state.dropdown.append(this.state.searchContainer);
},
readSelect: function($el) {
var self = this;
$el.find("option").each(function(index){
var opt = $(this);
self.state.originalItemData.push({ val: opt.val() , text: opt.text() });
});
this.state.filteredItemData = this.state.originalItemData;
this.state.selectedValue = $el.val();
},
setAjaxIndicator: function(failure) {
this.state.ajaxPending = true;
this.state.itemContainer.empty();
if(this.state.searchContainer !== null)
this.state.searchContainer.hide();
var newLi = $(" ");
if(!failure)
{
newLi.text( this.config.txtLoading ).
addClass( "loadindicator" );
} else {
newLi.text( this.config.txtAjaxFailure ).
addClass( "loaderrorindicator" );
}
this.state.itemContainer.append(newLi);
},
/* ******************************************************************* *
* Event handlers
* ******************************************************************* */
onDocumentClicked: function(e) {
var self = e.data.self;
if( self.state.open )
self.onSelectBoxClicked(e);
},
onSearchKeyPress: function(e) {
var self = e.data.self,
sval = $(e.currentTarget).val();
if(sval.length === 0)
{
self.state.filteredItemData = self.state.originalItemData;
} else {
self.state.filteredItemData = self.state.originalItemData.filter(function(item){
return item.text.toLowerCase().indexOf(sval) >= 0 ? true: false;
});
}
self.createItems();
},
onSelectBoxClicked: function(e) {
var self = e.data.self;
// Do nothing, if currently animating
if(self.state.dropdown.is(":animated"))
return;
// Close selectBox
if( self.state.open )
{
self.state.open = false;
self.state.selectBox.removeClass("open");
self.state.dropdown.slideUp(100);
return;
}
// Open selectbox
if(self.config.dataUrl !== null)
{
self.setAjaxIndicator(false);
$.ajax({
url: self.config.dataUrl,
dataType: "json",
type: "GET"
}). done( function(data) { self.onAjaxLoadSuccess(self, data); } ).
fail( function(data) { self.onAjaxLoadError(self, data); } );
}
self.state.open = true;
self.state.selectBox.addClass("open");
self.state.dropdown.slideDown(100);
},
onAjaxLoadSuccess: function(self,data) {
self.state.ajaxPending = false;
if(self.config.dataParser !== null )
{
data = self.config.dataParser(data, self.state.selectedValue);
}
self.state.$el.empty();
data.forEach(function(v){
if(v.selected)
self.state.selectedValue = v.val;
self.state.$el.append(
$(" ").
text( v.text ).
val( v.val )
);
});
self.state.$el.val( self.state.selectedValue );
self.state.originalItemData = data;
self.state.filteredItemData = data;
if(this.state.searchContainer !== null)
this.state.searchContainer.show();
self.createItems();
},
onAjaxLoadError: function(self,data) {
self.setAjaxIndicator(true);
},
onSelectLiClicked: function(e) {
var self = e.data.self,
item = $(e.currentTarget);
self.state.dropdown.find("li").each(function() {
$(this).removeClass("selected");
});
item.addClass("selected");
self.state.selectBox.html( item.text() );
self.state.selectedValue = item.attr("data-value");
self.state.$el.val(self.state.selectedValue);
self.state.$el.trigger("change");
},
/* ******************************************************************* *
* External callbacks
* ******************************************************************* */
};
/* ******************************************************************* *
* Plugin main
* ******************************************************************* */
$.fn.tinyselect = function(options) {
if( typeof(options) != "undefined" )
{
}
return this.each(function(){
var sel = Object.create(TinySelect);
sel.init( $(this) , options);
});
};
}(jQuery));