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