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);