123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479 |
- /*
- * EASYDROPDOWN - A Drop-down Builder for Styleable Inputs and Menus
- * Version: 2.1.4
- * License: Creative Commons Attribution 3.0 Unported - CC BY 3.0
- * http://creativecommons.org/licenses/by/3.0/
- * This software may be used freely on commercial and non-commercial projects with attribution to the author/copyright holder.
- * Author: Patrick Kunka
- * Copyright 2013 Patrick Kunka, All Rights Reserved
- */
- (function($){
-
- function EasyDropDown(){
- this.isField = true,
- this.down = false,
- this.inFocus = false,
- this.disabled = false,
- this.cutOff = false,
- this.hasLabel = false,
- this.keyboardMode = false,
- this.nativeTouch = true,
- this.wrapperClass = 'dropdown',
- this.onChange = null;
- };
-
- EasyDropDown.prototype = {
- constructor: EasyDropDown,
- instances: {},
- init: function(domNode, settings){
- var self = this;
-
- $.extend(self, settings);
- self.$select = $(domNode);
- self.id = domNode.id;
- self.options = [];
- self.$options = self.$select.find('option');
- self.isTouch = 'ontouchend' in document;
- self.$select.removeClass(self.wrapperClass+' dropdown');
- if(self.$select.is(':disabled')){
- self.disabled = true;
- };
- if(self.$options.length){
- self.$options.each(function(i){
- var $option = $(this);
- if($option.is(':selected')){
- self.selected = {
- index: i,
- title: $option.text()
- }
- self.focusIndex = i;
- };
- if($option.hasClass('label') && i == 0){
- self.hasLabel = true;
- self.label = $option.text();
- $option.attr('value','');
- } else {
- self.options.push({
- domNode: $option[0],
- title: $option.text(),
- value: $option.val(),
- selected: $option.is(':selected')
- });
- };
- });
- if(!self.selected){
- self.selected = {
- index: 0,
- title: self.$options.eq(0).text()
- }
- self.focusIndex = 0;
- };
- self.render();
- };
- },
-
- render: function(){
- var self = this,
- touchClass = self.isTouch && self.nativeTouch ? ' touch' : '',
- disabledClass = self.disabled ? ' disabled' : '';
-
- self.$container = self.$select.wrap('<div class="'+self.wrapperClass+touchClass+disabledClass+'"><span class="old"/></div>').parent().parent();
- self.$active = $('<span class="selected">'+self.selected.title+'</span>').appendTo(self.$container);
- self.$carat = $('<span class="carat"/>').appendTo(self.$container);
- self.$scrollWrapper = $('<div><ul/></div>').appendTo(self.$container);
- self.$dropDown = self.$scrollWrapper.find('ul');
- self.$form = self.$container.closest('form');
- $.each(self.options, function(){
- var option = this,
- active = option.selected ? ' class="active"':'';
- self.$dropDown.append('<li'+active+'>'+option.title+'</li>');
- });
- self.$items = self.$dropDown.find('li');
-
- if(self.cutOff && self.$items.length > self.cutOff)self.$container.addClass('scrollable');
-
- self.getMaxHeight();
-
- if(self.isTouch && self.nativeTouch){
- self.bindTouchHandlers();
- } else {
- self.bindHandlers();
- };
- },
-
- getMaxHeight: function(){
- var self = this;
-
- self.maxHeight = 0;
-
- for(i = 0; i < self.$items.length; i++){
- var $item = self.$items.eq(i);
- self.maxHeight += $item.outerHeight();
- if(self.cutOff == i+1){
- break;
- };
- };
- },
-
- bindTouchHandlers: function(){
- var self = this;
- self.$container.on('click.easyDropDown',function(){
- self.$select.focus();
- });
- self.$select.on({
- change: function(){
- var $selected = $(this).find('option:selected'),
- title = $selected.text(),
- value = $selected.val();
-
- self.$active.text(title);
- if(typeof self.onChange === 'function'){
- self.onChange.call(self.$select[0],{
- title: title,
- value: value
- });
- };
- },
- focus: function(){
- self.$container.addClass('focus');
- },
- blur: function(){
- self.$container.removeClass('focus');
- }
- });
- },
-
- bindHandlers: function(){
- var self = this;
- self.query = '';
- self.$container.on({
- 'click.easyDropDown': function(){
- if(!self.down && !self.disabled){
- self.open();
- } else {
- self.close();
- };
- },
- 'mousemove.easyDropDown': function(){
- if(self.keyboardMode){
- self.keyboardMode = false;
- };
- }
- });
-
- $('body').on('click.easyDropDown.'+self.id,function(e){
- var $target = $(e.target),
- classNames = self.wrapperClass.split(' ').join('.');
- if(!$target.closest('.'+classNames).length && self.down){
- self.close();
- };
- });
- self.$items.on({
- 'click.easyDropDown': function(){
- var index = $(this).index();
- self.select(index);
- self.$select.focus();
- },
- 'mouseover.easyDropDown': function(){
- if(!self.keyboardMode){
- var $t = $(this);
- $t.addClass('focus').siblings().removeClass('focus');
- self.focusIndex = $t.index();
- };
- },
- 'mouseout.easyDropDown': function(){
- if(!self.keyboardMode){
- $(this).removeClass('focus');
- };
- }
- });
- self.$select.on({
- 'focus.easyDropDown': function(){
- self.$container.addClass('focus');
- self.inFocus = true;
- },
- 'blur.easyDropDown': function(){
- self.$container.removeClass('focus');
- self.inFocus = false;
- },
- 'keydown.easyDropDown': function(e){
- if(self.inFocus){
- self.keyboardMode = true;
- var key = e.keyCode;
- if(key == 38 || key == 40 || key == 32){
- e.preventDefault();
- if(key == 38){
- self.focusIndex--
- self.focusIndex = self.focusIndex < 0 ? self.$items.length - 1 : self.focusIndex;
- } else if(key == 40){
- self.focusIndex++
- self.focusIndex = self.focusIndex > self.$items.length - 1 ? 0 : self.focusIndex;
- };
- if(!self.down){
- self.open();
- };
- self.$items.removeClass('focus').eq(self.focusIndex).addClass('focus');
- if(self.cutOff){
- self.scrollToView();
- };
- self.query = '';
- };
- if(self.down){
- if(key == 9 || key == 27){
- self.close();
- } else if(key == 13){
- e.preventDefault();
- self.select(self.focusIndex);
- self.close();
- return false;
- } else if(key == 8){
- e.preventDefault();
- self.query = self.query.slice(0,-1);
- self.search();
- clearTimeout(self.resetQuery);
- return false;
- } else if(key != 38 && key != 40){
- var letter = String.fromCharCode(key);
- self.query += letter;
- self.search();
- clearTimeout(self.resetQuery);
- };
- };
- };
- },
- 'keyup.easyDropDown': function(){
- self.resetQuery = setTimeout(function(){
- self.query = '';
- },1200);
- }
- });
-
- self.$dropDown.on('scroll.easyDropDown',function(e){
- if(self.$dropDown[0].scrollTop >= self.$dropDown[0].scrollHeight - self.maxHeight){
- self.$container.addClass('bottom');
- } else {
- self.$container.removeClass('bottom');
- };
- });
-
- if(self.$form.length){
- self.$form.on('reset.easyDropDown', function(){
- var active = self.hasLabel ? self.label : self.options[0].title;
- self.$active.text(active);
- });
- };
- },
-
- unbindHandlers: function(){
- var self = this;
-
- self.$container
- .add(self.$select)
- .add(self.$items)
- .add(self.$form)
- .add(self.$dropDown)
- .off('.easyDropDown');
- $('body').off('.'+self.id);
- },
-
- open: function(){
- var self = this,
- scrollTop = window.scrollY || document.documentElement.scrollTop,
- scrollLeft = window.scrollX || document.documentElement.scrollLeft,
- scrollOffset = self.notInViewport(scrollTop);
- self.closeAll();
- self.getMaxHeight();
- self.$select.focus();
- window.scrollTo(scrollLeft, scrollTop+scrollOffset);
- self.$container.addClass('open');
- self.$scrollWrapper.css('height',self.maxHeight+'px');
- self.down = true;
- },
-
- close: function(){
- var self = this;
- self.$container.removeClass('open');
- self.$scrollWrapper.css('height','0px');
- self.focusIndex = self.selected.index;
- self.query = '';
- self.down = false;
- },
-
- closeAll: function(){
- var self = this,
- instances = Object.getPrototypeOf(self).instances;
- for(var key in instances){
- var instance = instances[key];
- instance.close();
- };
- },
-
- select: function(index){
- var self = this;
-
- if(typeof index === 'string'){
- index = self.$select.find('option[value='+index+']').index() - 1;
- };
-
- var option = self.options[index],
- selectIndex = self.hasLabel ? index + 1 : index;
- self.$items.removeClass('active').eq(index).addClass('active');
- self.$active.text(option.title);
- self.$select
- .find('option')
- .removeAttr('selected')
- .eq(selectIndex)
- .prop('selected',true)
- .parent()
- .trigger('change');
-
- self.selected = {
- index: index,
- title: option.title
- };
- self.focusIndex = i;
- if(typeof self.onChange === 'function'){
- self.onChange.call(self.$select[0],{
- title: option.title,
- value: option.value
- });
- };
- },
-
- search: function(){
- var self = this,
- lock = function(i){
- self.focusIndex = i;
- self.$items.removeClass('focus').eq(self.focusIndex).addClass('focus');
- self.scrollToView();
- },
- getTitle = function(i){
- return self.options[i].title.toUpperCase();
- };
-
- for(i = 0; i < self.options.length; i++){
- var title = getTitle(i);
- if(title.indexOf(self.query) == 0){
- lock(i);
- return;
- };
- };
-
- for(i = 0; i < self.options.length; i++){
- var title = getTitle(i);
- if(title.indexOf(self.query) > -1){
- lock(i);
- break;
- };
- };
- },
-
- scrollToView: function(){
- var self = this;
- if(self.focusIndex >= self.cutOff){
- var $focusItem = self.$items.eq(self.focusIndex),
- scroll = ($focusItem.outerHeight() * (self.focusIndex + 1)) - self.maxHeight;
-
- self.$dropDown.scrollTop(scroll);
- };
- },
-
- notInViewport: function(scrollTop){
- var self = this,
- range = {
- min: scrollTop,
- max: scrollTop + (window.innerHeight || document.documentElement.clientHeight)
- },
- menuBottom = self.$dropDown.offset().top + self.maxHeight;
-
- if(menuBottom >= range.min && menuBottom <= range.max){
- return 0;
- } else {
- return (menuBottom - range.max) + 5;
- };
- },
-
- destroy: function(){
- var self = this;
- self.unbindHandlers();
- self.$select.unwrap().siblings().remove();
- self.$select.unwrap();
- delete Object.getPrototypeOf(self).instances[self.$select[0].id];
- },
-
- disable: function(){
- var self = this;
- self.disabled = true;
- self.$container.addClass('disabled');
- self.$select.attr('disabled',true);
- if(!self.down)self.close();
- },
-
- enable: function(){
- var self = this;
- self.disabled = false;
- self.$container.removeClass('disabled');
- self.$select.attr('disabled',false);
- }
- };
-
- var instantiate = function(domNode, settings){
- domNode.id = !domNode.id ? 'EasyDropDown'+rand() : domNode.id;
- var instance = new EasyDropDown();
- if(!instance.instances[domNode.id]){
- instance.instances[domNode.id] = instance;
- instance.init(domNode, settings);
- };
- },
- rand = function(){
- return ('00000'+(Math.random()*16777216<<0).toString(16)).substr(-6).toUpperCase();
- };
-
- $.fn.easyDropDown = function(){
- var args = arguments,
- dataReturn = [],
- eachReturn;
-
- eachReturn = this.each(function(){
- if(args && typeof args[0] === 'string'){
- var data = EasyDropDown.prototype.instances[this.id][args[0]](args[1], args[2]);
- if(data)dataReturn.push(data);
- } else {
- instantiate(this, args[0]);
- };
- });
-
- if(dataReturn.length){
- return dataReturn.length > 1 ? dataReturn : dataReturn[0];
- } else {
- return eachReturn;
- };
- };
-
- $(function(){
- if(typeof Object.getPrototypeOf !== 'function'){
- if(typeof 'test'.__proto__ === 'object'){
- Object.getPrototypeOf = function(object){
- return object.__proto__;
- };
- } else {
- Object.getPrototypeOf = function(object){
- return object.constructor.prototype;
- };
- };
- };
-
- $('select.dropdown').each(function(){
- var json = $(this).attr('data-settings');
- settings = json ? $.parseJSON(json) : {};
- instantiate(this, settings);
- });
- });
- })(jQuery);
|