app/assets/javascripts/multi-select.js in multi-select-rails-0.9.8.1 vs app/assets/javascripts/multi-select.js in multi-select-rails-0.9.10

- old
+ new

@@ -1,7 +1,7 @@ /* -* MultiSelect v0.9.8 +* MultiSelect v0.9.10 * 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 @@ -18,19 +18,17 @@ * ====================== */ var MultiSelect = function (element, options) { this.options = options; this.$element = $(element); - this.$container = $('<div/>', { 'class': "ms-container" }); this.$selectableContainer = $('<div/>', { 'class': 'ms-selectable' }); this.$selectionContainer = $('<div/>', { 'class': 'ms-selection' }); 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)'; + this.elemsSelector = 'li:visible:not(.ms-optgroup-label,.ms-optgroup-container,.'+options.disabledClass+')'; }; MultiSelect.prototype = { constructor: MultiSelect, @@ -40,11 +38,11 @@ if (ms.next('.ms-container').length === 0){ ms.css({ position: 'absolute', left: '-9999px' }); ms.attr('id', ms.attr('id') ? ms.attr('id') : Math.ceil(Math.random()*1000)+'multiselect'); this.$container.attr('id', 'ms-'+ms.attr('id')); - + this.$container.addClass(that.options.cssClass); ms.find('option').each(function(){ that.generateLisFromOption(this); }); this.$selectionUl.find('.ms-optgroup-label').hide(); @@ -95,27 +93,27 @@ if (typeof that.options.afterInit === 'function') { that.options.afterInit.call(this, this.$container); } }, - 'generateLisFromOption' : function(option){ + 'generateLisFromOption' : function(option, index, $container){ var that = this, ms = that.$element, attributes = "", $option = $(option); for (var cpt = 0; cpt < option.attributes.length; cpt++){ var attr = option.attributes[cpt]; - if(attr.name !== 'value'){ + if(attr.name !== 'value' && attr.name !== 'disabled'){ attributes += attr.name+'="'+attr.value+'" '; } } - var selectableLi = $('<li '+attributes+'><span>'+$option.text()+'</span></li>'), + var selectableLi = $('<li '+attributes+'><span>'+that.escapeHTML($option.text())+'</span></li>'), selectedLi = selectableLi.clone(), value = $option.val(), - elementId = that.sanitize(value, that.sanitizeRegexp); + elementId = that.sanitize(value); selectableLi .data('ms-value', value) .addClass('ms-elem-selectable') .attr('id', elementId+'-selectable'); @@ -133,18 +131,18 @@ var $optgroup = $option.parent('optgroup'); if ($optgroup.length > 0){ var optgroupLabel = $optgroup.attr('label'), - optgroupId = that.sanitize(optgroupLabel, that.sanitizeRegexp), + optgroupId = that.sanitize(optgroupLabel), $selectableOptgroup = that.$selectableUl.find('#optgroup-selectable-'+optgroupId), $selectionOptgroup = that.$selectionUl.find('#optgroup-selection-'+optgroupId); - + if ($selectableOptgroup.length === 0){ var optgroupContainerTpl = '<li class="ms-optgroup-container"></li>', optgroupTpl = '<ul class="ms-optgroup"><li class="ms-optgroup-label"><span>'+optgroupLabel+'</span></li></ul>'; - + $selectableOptgroup = $(optgroupContainerTpl); $selectionOptgroup = $(optgroupContainerTpl); $selectableOptgroup.attr('id', 'optgroup-selectable-'+optgroupId); $selectionOptgroup.attr('id', 'optgroup-selection-'+optgroupId); $selectableOptgroup.append($(optgroupTpl)); @@ -160,18 +158,41 @@ }); } that.$selectableUl.append($selectableOptgroup); that.$selectionUl.append($selectionOptgroup); } - $selectableOptgroup.children().append(selectableLi); - $selectionOptgroup.children().append(selectedLi); + index = index == undefined ? $selectableOptgroup.children().length : index + 1; + selectableLi.insertAt(index, $selectableOptgroup.children()); + selectedLi.insertAt(index, $selectionOptgroup.children()); } else { - that.$selectableUl.append(selectableLi); - that.$selectionUl.append(selectedLi); + index = index == undefined ? that.$selectableUl.children().length : index; + + selectableLi.insertAt(index, that.$selectableUl); + selectedLi.insertAt(index, that.$selectionUl); } }, + 'addOption' : function(options){ + var that = this; + + if (options.value) options = [options]; + $.each(options, function(index, option){ + if (option.value && that.$element.find("option[value='"+option.value+"']").length === 0){ + var $option = $('<option value="'+option.value+'">'+option.text+'</option>'), + index = parseInt((typeof option.index === 'undefined' ? that.$element.children().length : option.index)), + $container = option.nested == undefined ? that.$element : $("optgroup[label='"+option.nested+"']") + + $option.insertAt(index, $container); + that.generateLisFromOption($option.get(0), index, option.nested); + } + }) + }, + + 'escapeHTML' : function(text){ + return $("<div>").text(text).html(); + }, + 'activeKeyboard' : function($list){ var that = this; $list.on('focus', function(){ $(this).addClass('ms-focus'); @@ -185,22 +206,35 @@ 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; + case 9: + if(that.$element.is('[tabindex]')){ + e.preventDefault(); + var tabindex = parseInt(that.$element.attr('tabindex'), 10); + tabindex = (e.shiftKey) ? tabindex-1 : tabindex+1; + $('[tabindex="'+(tabindex)+'"]').focus(); + return; + }else{ + if(e.shiftKey){ + that.$element.trigger('focus'); + } + } } + if($.inArray(e.which, that.options.keySelect) > -1){ + e.preventDefault(); + e.stopPropagation(); + that.selectHighlighted($list); + return; + } }); }, 'moveHighlight': function($list, direction){ var $elems = $list.find(this.elemsSelector), @@ -286,13 +320,15 @@ } }, 'activeMouse' : function($list){ var that = this; - + var lastMovedDom = false; $list.on('mousemove', function(){ - var elems = $list.find(that.elemsSelector); + if (lastMovedDom === this) return; + lastMovedDom = this; + var elems = $list.find(that.elemsSelector); elems.on('mouseenter', function(){ elems.removeClass('ms-hover'); $(this).addClass('ms-hover'); }); @@ -312,15 +348,20 @@ '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)); }), + msIds = $.map(value, function(val){ return(that.sanitize(val)); }), selectables = this.$selectableUl.find('#' + msIds.join('-selectable, #')+'-selectable').filter(':not(.'+that.options.disabledClass+')'), selections = this.$selectionUl.find('#' + msIds.join('-selection, #') + '-selection').filter(':not(.'+that.options.disabledClass+')'), options = ms.find('option:not(:disabled)').filter(function(){ return($.inArray(this.value, value) > -1); }); + if (method === 'init'){ + selectables = this.$selectableUl.find('#' + msIds.join('-selectable, #')+'-selectable'), + selections = this.$selectionUl.find('#' + msIds.join('-selection, #') + '-selection'); + } + if (selectables.length > 0){ selectables.addClass('ms-selected').hide(); selections.addClass('ms-selected').show(); options.prop('selected', true); @@ -340,11 +381,14 @@ $(this).find('.ms-optgroup-label').show(); } }); } else { if (that.options.keepOrder){ - selections.insertAfter(that.$selectionUl.find('.ms-selected').last()); + var selectionLiLast = that.$selectionUl.find('.ms-selected'); + if((selectionLiLast.length > 1) && (selectionLiLast.last().get(0) != selections.get(0))) { + selections.insertAfter(selectionLiLast.last()); + } } } if (method !== 'init'){ ms.trigger('change'); if (typeof that.options.afterSelect === 'function') { @@ -357,13 +401,13 @@ '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)); }), + msIds = $.map(value, function(val){ return(that.sanitize(val)); }), selectables = this.$selectableUl.find('#' + msIds.join('-selectable, #')+'-selectable'), - selections = this.$selectionUl.find('#' + msIds.join('-selection, #')+'-selection').filter('.ms-selected'), + selections = this.$selectionUl.find('#' + msIds.join('-selection, #')+'-selection').filter('.ms-selected').filter(':not(.'+that.options.disabledClass+')'), 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(); @@ -426,12 +470,20 @@ if (typeof this.options.afterDeselect === 'function') { this.options.afterDeselect.call(this, values); } }, - sanitize: function(value, reg){ - return(value.replace(reg, '_')); + sanitize: function(value){ + var hash = 0, i, char; + if (value.length == 0) return hash; + var ls = 0; + for (i = 0, ls = value.length; i < ls; i++) { + char = value.charCodeAt(i); + hash = ((hash<<5)-hash)+char; + hash |= 0; // Convert to 32bit integer + } + return hash; } }; /* MULTISELECT PLUGIN DEFINITION * ======================= */ @@ -454,14 +506,26 @@ } }); }; $.fn.multiSelect.defaults = { + keySelect: [32], selectableOptgroup: false, disabledClass : 'disabled', dblClick : false, - keepOrder: false + keepOrder: false, + cssClass: '' }; $.fn.multiSelect.Constructor = MultiSelect; -}(window.jQuery); \ No newline at end of file + $.fn.insertAt = function(index, $parent) { + return this.each(function() { + if (index === 0) { + $parent.prepend(this); + } else { + $parent.children().eq(index - 1).after(this); + } + }); +} + +}(window.jQuery);