|
|
Line 1: |
Line 1: |
− | /*
| |
− | * 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);
| |