From de3ab838c095765eb70309cb0787480fb726dc19 Mon Sep 17 00:00:00 2001 From: matthias Date: Fri, 20 Mar 2015 22:33:30 +0100 Subject: [PATCH 1/4] [FEATURE] Improve initial rendering for big select To prevent browser's freezing, all "
  • " are created as text element without using jQuery and are added to DOM only at end of generation. --- js/jquery.multi-select.js | 80 ++++++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 31 deletions(-) diff --git a/js/jquery.multi-select.js b/js/jquery.multi-select.js index 697d15b..6d636f1 100644 --- a/js/jquery.multi-select.js +++ b/js/jquery.multi-select.js @@ -41,9 +41,22 @@ 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); + var handler = { + selectableUl: [], + selectionUl: [], + selectableOptgroups: {}, + selectionOptgroups: {} + }; + ms.find('option').each(function(index){ + that.generateLisFromOption(this, index, null, handler); }); + that.$selectableUl.html(handler.selectableUl.join('')); + that.$selectionUl.html(handler.selectionUl.join('')); + for(var optgroupId in handler.selectableOptgroups){ + that.$selectableUl.find('#optgroup-selectable-'+optgroupId).html(handler.selectableOptgroups[optgroupId].join('')); + that.$selectionUl.find('#optgroup-selection-'+optgroupId).html(handler.selectionOptgroups[optgroupId].join('')); + } + handler = null; this.$selectionUl.find('.ms-optgroup-label').hide(); @@ -95,7 +108,7 @@ } }, - 'generateLisFromOption' : function(option, index, $container){ + 'generateLisFromOption' : function(option, index, $container, $handler){ var that = this, ms = that.$element, attributes = "", @@ -108,28 +121,17 @@ attributes += attr.name+'="'+attr.value+'" '; } } - var selectableLi = $('
  • '+that.escapeHTML($option.text())+'
  • '), - selectedLi = selectableLi.clone(), - value = $option.val(), - elementId = that.sanitize(value); - - selectableLi - .data('ms-value', value) - .addClass('ms-elem-selectable') - .attr('id', elementId+'-selectable'); - - selectedLi - .data('ms-value', value) - .addClass('ms-elem-selection') - .attr('id', elementId+'-selection') - .hide(); - - if ($option.prop('disabled') || ms.prop('disabled')){ - selectedLi.addClass(that.options.disabledClass); - selectableLi.addClass(that.options.disabledClass); - } + + var value = $option.val(), + elementId = that.sanitize(value), + elementText = that.escapeHTML($option.text()), + elementDisabled = $option.prop('disabled') || ms.prop('disabled'), + selectableLi = '
  • '+elementText+'
  • ', + selectedLi = ''; + var $optgroup = $option.parent('optgroup'); + var hasHandler = typeof $handler === 'object'; if ($optgroup.length > 0){ var optgroupLabel = $optgroup.attr('label'), @@ -159,15 +161,31 @@ } that.$selectableUl.append($selectableOptgroup); that.$selectionUl.append($selectionOptgroup); + + if(hasHandler){ + $handler.selectableOptgroups[optgroupId] = []; + $handler.selectionOptgroups[optgroupId] = []; + } + } + if(hasHandler){ + index = index == undefined ? $handler.selectableOptgroups[optgroupId].length : index; + $handler.selectableOptgroups[optgroupId].splice(index, 0, selectableLi); + $handler.selectionOptgroups[optgroupId].splice(index, 0, selectedLi); + }else{ + index = index == undefined ? $selectableOptgroup.find('ul').children().length : index + 1; + $(selectableLi).insertAt(index, $selectableOptgroup.children()); + $(selectedLi).insertAt(index, $selectionOptgroup.children()); } - index = index == undefined ? $selectableOptgroup.find('ul').children().length : index + 1; - selectableLi.insertAt(index, $selectableOptgroup.children()); - selectedLi.insertAt(index, $selectionOptgroup.children()); } else { - index = index == undefined ? that.$selectableUl.children().length : index; - - selectableLi.insertAt(index, that.$selectableUl); - selectedLi.insertAt(index, that.$selectionUl); + if(hasHandler){ + index = index == undefined ? $handler.selectableUl.length : index; + $handler.selectableUl.splice(index, 0, selectableLi); + $handler.selectionUl.splice(index, 0, selectedLi); + }else{ + index = index == undefined ? that.$selectableUl.children().length : index; + $(selectableLi).insertAt(index, that.$selectableUl); + $(selectedLi).insertAt(index, that.$selectionUl); + } } }, @@ -286,7 +304,7 @@ } if ($nextElem.length > 0){ $nextElem.addClass('ms-hover'); - var scrollTo = $list.scrollTop() + $nextElem.position().top - + var scrollTo = $list.scrollTop() + $nextElem.position().top - containerHeight / 2 + elemHeight / 2; $list.scrollTop(scrollTo); From 90b922fb885d5e1615827ad62acf839312976f8a Mon Sep 17 00:00:00 2001 From: matthias Date: Fri, 20 Mar 2015 22:58:30 +0100 Subject: [PATCH 2/4] [BUGFIX] Option value can't be a integer Option value as integer can't be selected/deselected and
  • id attribute is not W3C.
  • id has been prefixed with "ms-elem-" to be W3C and not start with an integer. --- js/jquery.multi-select.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/js/jquery.multi-select.js b/js/jquery.multi-select.js index 6d636f1..d538c13 100644 --- a/js/jquery.multi-select.js +++ b/js/jquery.multi-select.js @@ -126,8 +126,8 @@ elementId = that.sanitize(value), elementText = that.escapeHTML($option.text()), elementDisabled = $option.prop('disabled') || ms.prop('disabled'), - selectableLi = '
  • '+elementText+'
  • ', - selectedLi = ''; + selectableLi = '
  • '+elementText+'
  • ', + selectedLi = ''; var $optgroup = $option.parent('optgroup'); @@ -360,18 +360,18 @@ }, 'select' : function(value, method){ - if (typeof value === 'string'){ value = [value]; } + if (typeof value === 'string' || typeof value === 'number'){ value = [''+value]; } var that = this, ms = this.$element, 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+')'), + selectables = this.$selectableUl.find('#ms-elem-' + msIds.join('-selectable, #ms-elem-')+'-selectable').filter(':not(.'+that.options.disabledClass+')'), + selections = this.$selectionUl.find('#ms-elem-' + msIds.join('-selection, #ms-elem-') + '-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'); + selectables = this.$selectableUl.find('#ms-elem-' + msIds.join('-selectable, #ms-elem-')+'-selectable'), + selections = this.$selectionUl.find('#ms-elem-' + msIds.join('-selection, #ms-elem-') + '-selection'); } if (selectables.length > 0){ @@ -416,13 +416,13 @@ }, 'deselect' : function(value){ - if (typeof value === 'string'){ value = [value]; } + if (typeof value === 'string' || typeof value === 'number'){ value = [''+value]; } var that = this, ms = this.$element, 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').filter(':not(.'+that.options.disabledClass+')'), + selectables = this.$selectableUl.find('#ms-elem-' + msIds.join('-selectable, #ms-elem-')+'-selectable'), + selections = this.$selectionUl.find('#ms-elem-' + msIds.join('-selection, #ms-elem-')+'-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){ From 23d094b3068c9873a791a465fde2899623c93d68 Mon Sep 17 00:00:00 2001 From: matthias Date: Thu, 14 May 2015 15:07:12 +0200 Subject: [PATCH 3/4] [TASK] Renaming function generateLisFromOption to generateListFromOption --- js/jquery.multi-select.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/jquery.multi-select.js b/js/jquery.multi-select.js index d538c13..be48542 100644 --- a/js/jquery.multi-select.js +++ b/js/jquery.multi-select.js @@ -48,7 +48,7 @@ selectionOptgroups: {} }; ms.find('option').each(function(index){ - that.generateLisFromOption(this, index, null, handler); + that.generateListFromOption(this, index, null, handler); }); that.$selectableUl.html(handler.selectableUl.join('')); that.$selectionUl.html(handler.selectionUl.join('')); @@ -108,7 +108,7 @@ } }, - 'generateLisFromOption' : function(option, index, $container, $handler){ + 'generateListFromOption' : function(option, index, $container, $handler){ var that = this, ms = that.$element, attributes = "", From 04c8226592c5c4fcf65108b60cc9a1e9194246b8 Mon Sep 17 00:00:00 2001 From: matthias Date: Thu, 14 May 2015 15:23:31 +0200 Subject: [PATCH 4/4] [BUGFIX] Option groups are not rendering with improved version --- js/jquery.multi-select.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/js/jquery.multi-select.js b/js/jquery.multi-select.js index be48542..aaeedc2 100644 --- a/js/jquery.multi-select.js +++ b/js/jquery.multi-select.js @@ -50,11 +50,11 @@ ms.find('option').each(function(index){ that.generateListFromOption(this, index, null, handler); }); - that.$selectableUl.html(handler.selectableUl.join('')); - that.$selectionUl.html(handler.selectionUl.join('')); + that.$selectableUl.prepend(handler.selectableUl.join('')); + that.$selectionUl.prepend(handler.selectionUl.join('')); for(var optgroupId in handler.selectableOptgroups){ - that.$selectableUl.find('#optgroup-selectable-'+optgroupId).html(handler.selectableOptgroups[optgroupId].join('')); - that.$selectionUl.find('#optgroup-selection-'+optgroupId).html(handler.selectionOptgroups[optgroupId].join('')); + that.$selectableUl.find('#optgroup-selectable-'+optgroupId+' ul.ms-optgroup').append(handler.selectableOptgroups[optgroupId].join('')); + that.$selectionUl.find('#optgroup-selection-'+optgroupId+' ul.ms-optgroup').append(handler.selectionOptgroups[optgroupId].join('')); } handler = null; @@ -138,7 +138,7 @@ optgroupId = that.sanitize(optgroupLabel), $selectableOptgroup = that.$selectableUl.find('#optgroup-selectable-'+optgroupId), $selectionOptgroup = that.$selectionUl.find('#optgroup-selection-'+optgroupId); - + if ($selectableOptgroup.length === 0){ var optgroupContainerTpl = '
  • ', optgroupTpl = '
    • '+optgroupLabel+'
    '; @@ -200,7 +200,7 @@ $container = option.nested == undefined ? that.$element : $("optgroup[label='"+option.nested+"']") $option.insertAt(index, $container); - that.generateLisFromOption($option.get(0), index, option.nested); + that.generateListFromOption($option.get(0), index, option.nested); } }) },