diff options
author | lou <louiscuny@gmail.com> | 2013-06-24 00:46:07 +0200 |
---|---|---|
committer | lou <louiscuny@gmail.com> | 2013-06-24 00:46:07 +0200 |
commit | ae7917ec4488ee43d8949553e067f3d650f05ac1 (patch) | |
tree | 373571367735611d01bd785813e074a0a2ed3735 /js/jquery.multi-select.js | |
parent | 336010e015aedf83d8206b21731a6592f095a274 (diff) | |
download | multi-select-ae7917ec4488ee43d8949553e067f3d650f05ac1.zip multi-select-ae7917ec4488ee43d8949553e067f3d650f05ac1.tar.gz multi-select-ae7917ec4488ee43d8949553e067f3d650f05ac1.tar.bz2 |
nevisit the way to handle the focus on lists0.9.6
Diffstat (limited to 'js/jquery.multi-select.js')
-rw-r--r-- | js/jquery.multi-select.js | 252 |
1 files changed, 138 insertions, 114 deletions
diff --git a/js/jquery.multi-select.js b/js/jquery.multi-select.js index ff37d66..d6a0c18 100644 --- a/js/jquery.multi-select.js +++ b/js/jquery.multi-select.js @@ -1,5 +1,5 @@ /* -* MultiSelect v0.9.5 +* MultiSelect v0.9.6 * Copyright (c) 2012 Louis Cuny * * This program is free software. It comes without any warranty, to @@ -26,10 +26,11 @@ this.$container = $('<div/>', { 'id': "ms-"+id, 'class': "ms-container" }); this.$selectableContainer = $('<div/>', { 'class': 'ms-selectable' }); this.$selectionContainer = $('<div/>', { 'class': 'ms-selection' }); - this.$selectableUl = $('<ul/>', { 'class': "ms-list" }); - this.$selectionUl = $('<ul/>', { 'class': "ms-list" }); + this.$selectableUl = $('<ul/>', { 'class': "ms-list", 'tabindex' : '-1' }); + this.$selectionUl = $('<ul/>', { 'class': "ms-list", 'tabindex' : '-1' }); this.scrollTo = 0; this.sanitizeRegexp = new RegExp("\\W+", 'gi'); + this.elemsSelector = 'li:visible:not(.ms-optgroup-label,.ms-optgroup-container)'; }; MultiSelect.prototype = { @@ -160,12 +161,9 @@ that.$container.append(that.$selectableContainer); that.$container.append(that.$selectionContainer); ms.after(that.$container); - that.$selectableUl.on('mouseenter', '.ms-elem-selectable', function(){ - $('li', that.$container).removeClass('ms-hover'); - $(this).addClass('ms-hover'); - }).on('mouseleave', function(){ - $('li', that.$container).removeClass('ms-hover'); - }); + + that.activeMouse(that.$selectableUl); + that.activeKeyboard(that.$selectableUl); var action = that.options.dblClick ? 'dblclick' : 'click'; @@ -176,119 +174,151 @@ that.deselect($(this).data('ms-value')); }); + that.activeMouse(that.$selectionUl); + that.activeKeyboard(that.$selectionUl); - that.$selectionUl.on('mouseenter', '.ms-elem-selection', function(){ - $('li', that.$selectionUl).removeClass('ms-hover'); - $(this).addClass('ms-hover'); - }).on('mouseleave', function(){ - $('li', that.$selectionUl).removeClass('ms-hover'); - }); + ms.on('focus', function(){ + that.$selectableUl.focus(); + }) + } - that.$selectableUl.on('focusin', function(){ - $(this).addClass('ms-focus'); - that.$selectionUl.focusout(); - }).on('focusout', function(){ - $(this).removeClass('ms-focus'); - $('li', that.$container).removeClass('ms-hover'); - }); + var selectedValues = ms.find('option:selected').map(function(){ return $(this).val(); }).get(); + that.select(selectedValues, 'init'); - that.$selectionUl.on('focusin', function(){ - $(this).addClass('ms-focus'); - }).on('focusout', function(){ - $(this).removeClass('ms-focus'); - $('li', that.$container).removeClass('ms-hover'); - }); + if (typeof that.options.afterInit === 'function') { + that.options.afterInit.call(this, this.$container); + } + }, - ms.on('focusin', function(){ - ms.focusout(); - that.$selectableUl.focusin(); - }).on('focusout', function(){ - that.$selectableUl.removeClass('ms-focus'); - that.$selectionUl.removeClass('ms-focus'); - }); + 'activeKeyboard' : function($list){ + var that = this; + + $list.on('focus', function(){ + $(this).addClass('ms-focus'); + }) + .on('blur', function(){ + $(this).removeClass('ms-focus'); + }) + .on('keydown', function(e){ + switch (e.which) { + case 40: + case 38: + e.preventDefault(); + e.stopPropagation(); + that.moveHighlight($(this), (e.which === 38) ? -1 : 1); + return; + case 32: + e.preventDefault(); + e.stopPropagation(); + that.selectHighlighted($list); + return; + case 37: + case 39: + e.preventDefault(); + e.stopPropagation(); + that.switchList($list); + return; + } + }); + }, - ms.onKeyDown = function(e, keyContainer){ - var ul = that.$container.find('.'+keyContainer).find('.ms-list'), - lis = ul.find('li:visible:not(.ms-optgroup-label, .ms-optgroup-container)'), - lisNumber = lis.length, - liFocused = ul.find('li.ms-hover'), - liFocusedIndex = liFocused.length > 0 ? lis.index(liFocused) : -1, - ulHeight = ul.innerHeight(), - liHeight = lis.first().outerHeight(true), - numberOfLisDisplayed = Math.floor(ulHeight / liHeight), - ulPosition = null; - - if (e.keyCode === 32){ // space - if (liFocused.length >0){ - if (keyContainer === 'ms-selectable'){ - that.select(liFocused.data('ms-value')); - } else { - that.deselect(liFocused.data('ms-value')); - } - lis.removeClass('ms-hover'); - that.scrollTo = 0; - ul.scrollTop(that.scrollTo); - } - } else if (e.keyCode === 40){ // Down - if (lis.length > 0){ - var nextLiIndex = liFocusedIndex+1, - nextLi = (lisNumber !== nextLiIndex) ? lis.eq(nextLiIndex) : lis.first(), - nextLiPosition = nextLi.position().top; - - ulPosition = ul.position().top; - lis.removeClass('ms-hover'); - nextLi.addClass('ms-hover'); - - if (lisNumber === nextLiIndex){ - that.scrollTo = 0; - } else if (nextLiPosition >= (ulPosition + (numberOfLisDisplayed * liHeight))){ - that.scrollTo += liHeight; - } - ul.scrollTop(that.scrollTo); - } - } else if (e.keyCode === 38){ // Up - if (lis.length > 0){ - var prevLiIndex = Math.max(liFocusedIndex-1, -1), - prevLi = lis.eq(prevLiIndex), - prevLiPosition = prevLi.position().top; - - ulPosition = ul.position().top; - lis.removeClass('ms-hover'); - prevLi.addClass('ms-hover'); - if (prevLiPosition <= ulPosition){ - that.scrollTo -= liHeight; - } else if (prevLiIndex < 0){ - that.scrollTo = (lisNumber - numberOfLisDisplayed) * liHeight; - } - ul.scrollTop(that.scrollTo); - } - } else if (e.keyCode === 37 || e.keyCode === 39){ - if (that.$selectableUl.hasClass('ms-focus')){ - that.$selectableUl.focusout(); - that.$selectionUl.focusin(); + 'moveHighlight': function($list, direction){ + var $elems = $list.find(this.elemsSelector), + $currElem = $elems.filter('.ms-hover'), + $nextElem = null, + elemHeight = $elems.first().outerHeight(), + containerHeight = $list.height(), + containerSelector = '#'+this.$container.prop('id'); + + // Deactive mouseenter event when move is active + // It fixes a bug when mouse is over the list + $elems.off('mouseenter'); + + $elems.removeClass('ms-hover'); + if (direction === 1){ // DOWN + + $nextElem = $currElem.nextAll(this.elemsSelector).first(); + if ($nextElem.length === 0){ + var $optgroupUl = $currElem.parent(); + + if ($optgroupUl.hasClass('ms-optgroup')){ + var $optgroupLi = $optgroupUl.parent(), + $nextOptgroupLi = $optgroupLi.next(':visible'); + + if ($nextOptgroupLi.length > 0){ + $nextElem = $nextOptgroupLi.find(this.elemsSelector).first(); } else { - that.$selectableUl.focusin(); - that.$selectionUl.focusout(); + $nextElem = $elems.first(); } + } else { + $nextElem = $elems.first(); } - }; + } + } else if (direction === -1){ // UP + + $nextElem = $currElem.prevAll(this.elemsSelector).first(); + if ($nextElem.length === 0){ + var $optgroupUl = $currElem.parent(); + + if ($optgroupUl.hasClass('ms-optgroup')){ + var $optgroupLi = $optgroupUl.parent(), + $prevOptgroupLi = $optgroupLi.prev(':visible'); - ms.on('keydown', function(e){ - if (ms.is(':focus')){ - var keyContainer = that.$selectableUl.hasClass('ms-focus') ? 'ms-selectable' : 'ms-selection'; - ms.onKeyDown(e, keyContainer); + if ($prevOptgroupLi.length > 0){ + $nextElem = $prevOptgroupLi.find(this.elemsSelector).last(); + } else { + $nextElem = $elems.last(); + } + } else { + $nextElem = $elems.last(); } - }); + } } + if ($nextElem.length > 0){ + $nextElem.addClass('ms-hover'); + var scrollTo = $list.scrollTop() + $nextElem.position().top - + containerHeight / 2 + elemHeight / 2; - var selectedValues = ms.find('option:selected').map(function(){ return $(this).val(); }).get(); - that.select(selectedValues, 'init'); + $list.scrollTop(scrollTo); + } + }, - if (typeof that.options.afterInit === 'function') { - that.options.afterInit.call(this, this.$container); + 'selectHighlighted' : function($list){ + var $elems = $list.find(this.elemsSelector), + $highlightedElem = $elems.filter('.ms-hover').first(); + + if ($highlightedElem.length > 0){ + if ($list.parent().hasClass('ms-selectable')){ + this.select($highlightedElem.data('ms-value')); + } else { + this.deselect($highlightedElem.data('ms-value')); + } + $elems.removeClass('ms-hover'); + } + }, + + 'switchList' : function($list){ + $list.blur(); + if ($list.parent().hasClass('ms-selectable')){ + this.$selectionUl.focus(); + } else { + this.$selectableUl.focus(); } }, + 'activeMouse' : function($list){ + var that = this; + + $list.on('mousemove', function(){ + var elems = $list.find(that.elemsSelector); + + elems.on('mouseenter', function(){ + elems.removeClass('ms-hover'); + $(this).addClass('ms-hover'); + }); + }); + }, + 'refresh' : function() { this.destroy(); this.$element.multiSelect(this.options); @@ -332,8 +362,6 @@ }); } if (method !== 'init'){ - that.$selectionUl.focusout(); - that.$selectableUl.focusin(); ms.trigger('change'); if (typeof that.options.afterSelect === 'function') { that.options.afterSelect.call(this, value); @@ -374,8 +402,6 @@ } }); } - this.$selectableUl.focusout(); - this.$selectionUl.focusin(); ms.trigger('change'); if (typeof that.options.afterDeselect === 'function') { that.options.afterDeselect.call(this, value); @@ -392,8 +418,7 @@ this.$selectionUl.find('.ms-optgroup-label').show(); this.$selectableUl.find('.ms-optgroup-label').hide(); this.$selectionUl.find('.ms-elem-selection').addClass('ms-selected').show(); - this.$selectionUl.focusin(); - this.$selectableUl.focusout(); + this.$selectionUl.focus(); ms.trigger('change'); if (typeof this.options.afterSelect === 'function') { var selectedValues = $.grep(ms.val(), function(item){ @@ -412,8 +437,7 @@ this.$selectionUl.find('.ms-optgroup-label').hide(); this.$selectableUl.find('.ms-optgroup-label').show(); this.$selectionUl.find('.ms-elem-selection').removeClass('ms-selected').hide(); - this.$selectableUl.focusin(); - this.$selectionUl.focusout(); + this.$selectableUl.focus(); ms.trigger('change'); if (typeof this.options.afterDeselect === 'function') { this.options.afterDeselect.call(this, values); |