123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462 |
- /*
- * MultiSelect v0.9.5
- * Copyright (c) 2012 Louis Cuny
- *
- * This program is free software. It comes without any warranty, to
- * the extent permitted by applicable law. You can redistribute it
- * and/or modify it under the terms of the Do What The Fuck You Want
- * To Public License, Version 2, as published by Sam Hocevar. See
- * http://sam.zoy.org/wtfpl/COPYING for more details.
- */
- !function ($) {
- "use strict";
- /* MULTISELECT CLASS DEFINITION
- * ====================== */
- var MultiSelect = function (element, options) {
- this.options = options;
- this.$element = $(element);
- var id = this.$element.attr('id');
- 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.scrollTo = 0;
- this.sanitizeRegexp = new RegExp("\\W+", 'gi');
- };
- MultiSelect.prototype = {
- constructor: MultiSelect,
- init: function(){
- var that = this,
- ms = this.$element;
- if (ms.next('.ms-container').length === 0){
- ms.css({ position: 'absolute', left: '-9999px' });
- ms.attr('id', ms.attr('id') ? ms.attr('id') : 'ms-'+Math.ceil(Math.random()*1000));
- var optgroupLabel = null,
- optgroupId = null,
- optgroupCpt = 0,
- optgroupContainerTemplate = '<li class="ms-optgroup-container"></li>',
- optgroupUlTemplate = '<ul class="ms-optgroup"></ul>',
- optgroupLiTemplate = '<li class="ms-optgroup-label"><span></span></li>';
- ms.find('optgroup, option').each(function(){
- if ($(this).is('optgroup')){
- optgroupLabel = '<span>'+$(this).attr('label')+'</span>';
- optgroupId = 'ms-'+ms.attr('id')+'-optgroup-'+optgroupCpt;
- var optgroup = $(this),
- optgroupSelectable = $(optgroupContainerTemplate),
- optgroupSelection = $(optgroupContainerTemplate),
- optgroupSelectionLi = $(optgroupLiTemplate),
- optgroupSelectableLi = $(optgroupLiTemplate);
- if (that.options.selectableOptgroup){
- optgroupSelectableLi.on('click', function(){
- var values = optgroup.children(':not(:selected)').map(function(){ return $(this).val(); }).get();
- that.select(values);
- });
- optgroupSelectionLi.on('click', function(){
- var values = optgroup.children(':selected').map(function(){ return $(this).val(); }).get();
- that.deselect(values);
- });
- }
- optgroupSelectableLi.html(optgroupLabel);
- optgroupSelectable.attr('id', optgroupId+'-selectable')
- .append($(optgroupUlTemplate)
- .append(optgroupSelectableLi));
- that.$selectableUl.append(optgroupSelectable);
- optgroupSelectionLi.html(optgroupLabel);
- optgroupSelection.attr('id', optgroupId+'-selection')
- .append($(optgroupUlTemplate)
- .append(optgroupSelectionLi));
- that.$selectionUl.append(optgroupSelection);
- optgroupCpt++;
- } else {
- var attributes = "";
- for (var cpt = 0; cpt < this.attributes.length; cpt++){
- var attr = this.attributes[cpt];
- if(that.isDomNode(attr.name)){
- attributes += attr.name+'="'+attr.value+'" ';
- }
- }
- var selectableLi = $('<li '+attributes+'><span>'+$(this).text()+'</span></li>'),
- selectedLi = selectableLi.clone();
- var value = $(this).val(),
- msId = that.sanitize(value, that.sanitizeRegexp);
- selectableLi
- .data('ms-value', value)
- .addClass('ms-elem-selectable')
- .attr('id', msId+'-selectable');
- selectedLi
- .data('ms-value', value)
- .addClass('ms-elem-selection')
- .attr('id', msId+'-selection')
- .hide();
- that.$selectionUl.find('.ms-optgroup-label').hide();
- if ($(this).prop('disabled') || ms.prop('disabled')){
- if (this.selected) {
- selectedLi.prop('disabled', true);
- selectedLi.addClass(that.options.disabledClass);
- } else {
- selectableLi.prop('disabled', true);
- selectableLi.addClass(that.options.disabledClass);
- }
- }
- if (optgroupId){
- that.$selectableUl.children('#'+optgroupId+'-selectable').find('ul').first().append(selectableLi);
- that.$selectionUl.children('#'+optgroupId+'-selection').find('ul').first().append(selectedLi);
- } else {
- that.$selectableUl.append(selectableLi);
- that.$selectionUl.append(selectedLi);
- }
- }
- });
- if (that.options.selectableHeader){
- that.$selectableContainer.append(that.options.selectableHeader);
- }
- that.$selectableContainer.append(that.$selectableUl);
- if (that.options.selectableFooter){
- that.$selectableContainer.append(that.options.selectableFooter);
- }
- if (that.options.selectionHeader){
- that.$selectionContainer.append(that.options.selectionHeader);
- }
- that.$selectionContainer.append(that.$selectionUl);
- if (that.options.selectionFooter){
- that.$selectionContainer.append(that.options.selectionFooter);
- }
- 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');
- });
- var action = that.options.dblClick ? 'dblclick' : 'click';
- that.$selectableUl.on(action, '.ms-elem-selectable', function(){
- that.select($(this).data('ms-value'));
- });
- that.$selectionUl.on(action, '.ms-elem-selection', function(){
- that.deselect($(this).data('ms-value'));
- });
- 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');
- });
- 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');
- });
- that.$selectionUl.on('focusin', function(){
- $(this).addClass('ms-focus');
- }).on('focusout', function(){
- $(this).removeClass('ms-focus');
- $('li', that.$container).removeClass('ms-hover');
- });
- ms.on('focusin', function(){
- ms.focusout();
- that.$selectableUl.focusin();
- }).on('focusout', function(){
- that.$selectableUl.removeClass('ms-focus');
- that.$selectionUl.removeClass('ms-focus');
- });
- 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();
- } else {
- that.$selectableUl.focusin();
- that.$selectionUl.focusout();
- }
- }
- };
- ms.on('keydown', function(e){
- if (ms.is(':focus')){
- var keyContainer = that.$selectableUl.hasClass('ms-focus') ? 'ms-selectable' : 'ms-selection';
- ms.onKeyDown(e, keyContainer);
- }
- });
- }
- var selectedValues = ms.find('option:selected').map(function(){ return $(this).val(); }).get();
- that.select(selectedValues, 'init');
- if (typeof that.options.afterInit === 'function') {
- that.options.afterInit.call(this, this.$container);
- }
- },
- 'refresh' : function() {
- $("#ms-"+this.$element.attr("id")).remove();
- this.init(this.options);
- },
- 'select' : function(value, method){
- if (typeof value === 'string'){ value = [value]; }
- var that = this,
- ms = this.$element,
- msIds = $.map(value, function(val){ return(that.sanitize(val, that.sanitizeRegexp)); }),
- selectables = this.$selectableUl.find('#' + msIds.join('-selectable, #')+'-selectable').filter(':not(.'+that.options.disabledClass+')'),
- selections = this.$selectionUl.find('#' + msIds.join('-selection, #') + '-selection'),
- options = ms.find('option').filter(function(){ return($.inArray(this.value, value) > -1); });
- if (selectables.length > 0){
- selectables.addClass('ms-selected').hide();
- selections.addClass('ms-selected').show();
- options.prop('selected', true);
- var selectableOptgroups = that.$selectableUl.children('.ms-optgroup-container');
- if (selectableOptgroups.length > 0){
- selectableOptgroups.each(function(){
- var selectablesLi = $(this).find('.ms-elem-selectable');
- if (selectablesLi.length === selectablesLi.filter('.ms-selected').length){
- $(this).find('.ms-optgroup-label').hide();
- }
- });
- var selectionOptgroups = that.$selectionUl.children('.ms-optgroup-container');
- selectionOptgroups.each(function(){
- var selectionsLi = $(this).find('.ms-elem-selection');
- if (selectionsLi.filter('.ms-selected').length > 0){
- $(this).find('.ms-optgroup-label').show();
- }
- });
- }
- if (method !== 'init'){
- that.$selectionUl.focusout();
- that.$selectableUl.focusin();
- ms.trigger('change');
- if (typeof that.options.afterSelect === 'function') {
- that.options.afterSelect.call(this, value);
- }
- }
- }
- },
- 'deselect' : function(value){
- if (typeof value === 'string'){ value = [value]; }
- var that = this,
- ms = this.$element,
- msIds = $.map(value, function(val){ return(that.sanitize(val, that.sanitizeRegexp)); }),
- selectables = this.$selectableUl.find('#' + msIds.join('-selectable, #')+'-selectable'),
- selections = this.$selectionUl.find('#' + msIds.join('-selection, #')+'-selection').filter('.ms-selected'),
- options = ms.find('option').filter(function(){ return($.inArray(this.value, value) > -1); });
- if (selections.length > 0){
- selectables.removeClass('ms-selected').show();
- selections.removeClass('ms-selected').hide();
- options.prop('selected', false);
- var selectableOptgroups = that.$selectableUl.children('.ms-optgroup-container');
- if (selectableOptgroups.length > 0){
- selectableOptgroups.each(function(){
- var selectablesLi = $(this).find('.ms-elem-selectable');
- if (selectablesLi.filter(':not(.ms-selected)').length > 0){
- $(this).find('.ms-optgroup-label').show();
- }
- });
- var selectionOptgroups = that.$selectionUl.children('.ms-optgroup-container');
- selectionOptgroups.each(function(){
- var selectionsLi = $(this).find('.ms-elem-selection');
- if (selectionsLi.filter('.ms-selected').length === 0){
- $(this).find('.ms-optgroup-label').hide();
- }
- });
- }
- this.$selectableUl.focusout();
- this.$selectionUl.focusin();
- ms.trigger('change');
- if (typeof that.options.afterDeselect === 'function') {
- that.options.afterDeselect.call(this, value);
- }
- }
- },
- 'select_all' : function(){
- var ms = this.$element,
- values = ms.val();
- ms.find('option').prop('selected', true);
- this.$selectableUl.find('.ms-elem-selectable').addClass('ms-selected').hide();
- 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();
- ms.trigger('change');
- if (typeof this.options.afterSelect === 'function') {
- var selectedValues = $.grep(ms.val(), function(item){
- return $.inArray(item, values) < 0;
- });
- this.options.afterSelect.call(this, selectedValues);
- }
- },
- 'deselect_all' : function(){
- var ms = this.$element,
- values = ms.val();
- ms.find('option').prop('selected', false);
- this.$selectableUl.find('.ms-elem-selectable').removeClass('ms-selected').show();
- 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();
- ms.trigger('change');
- if (typeof this.options.afterDeselect === 'function') {
- this.options.afterDeselect.call(this, values);
- }
- },
- isDomNode: function (attr){
- return (
- attr &&
- typeof attr === "object" &&
- typeof attr.nodeType === "number" &&
- typeof attr.nodeName === "string"
- );
- },
- sanitize: function(value, reg){
- return(value.replace(reg, '_'));
- }
- };
- /* MULTISELECT PLUGIN DEFINITION
- * ======================= */
- $.fn.multiSelect = function () {
- var option = arguments[0],
- args = arguments;
- return this.each(function () {
- var $this = $(this),
- data = $this.data('multiselect'),
- options = $.extend({}, $.fn.multiSelect.defaults, $this.data(), typeof option === 'object' && option);
- if (!data){ $this.data('multiselect', (data = new MultiSelect(this, options))); }
- if (typeof option === 'string'){
- data[option](args[1]);
- } else {
- data.init();
- }
- });
- };
- $.fn.multiSelect.defaults = {
- selectableOptgroup: false,
- disabledClass : 'disabled',
- dblClick : false
- };
- $.fn.multiSelect.Constructor = MultiSelect;
- }(window.jQuery);
|