From 304aa486773081cd102eed9581d18440790c7710 Mon Sep 17 00:00:00 2001 From: Alexander Deeb Date: Sat, 9 Jun 2018 10:30:09 -0700 Subject: [PATCH 01/10] Use disabledText only when multiselect is disabled Remove unnecessary condition causing the bug. --- dist/js/bootstrap-multiselect.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dist/js/bootstrap-multiselect.js b/dist/js/bootstrap-multiselect.js index 2a028b77..e23bff12 100644 --- a/dist/js/bootstrap-multiselect.js +++ b/dist/js/bootstrap-multiselect.js @@ -249,9 +249,7 @@ * @returns {String} */ buttonText: function(options, select) { - if (this.disabledText.length > 0 - && (select.prop('disabled') || (options.length == 0 && this.disableIfEmpty))) { - + if (this.disabledText.length > 0 && select.prop('disabled')) { return this.disabledText; } else if (options.length === 0) { From a53fec52e83f2cbd174609bc88fb99e3bcda7bb3 Mon Sep 17 00:00:00 2001 From: Alexander Deeb Date: Sat, 9 Jun 2018 10:58:45 -0700 Subject: [PATCH 02/10] Use select.children().length Retrieve the number of options rather than the number of selected options. --- dist/js/bootstrap-multiselect.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dist/js/bootstrap-multiselect.js b/dist/js/bootstrap-multiselect.js index e23bff12..18ac8a35 100644 --- a/dist/js/bootstrap-multiselect.js +++ b/dist/js/bootstrap-multiselect.js @@ -249,7 +249,8 @@ * @returns {String} */ buttonText: function(options, select) { - if (this.disabledText.length > 0 && select.prop('disabled')) { + if (this.disabledText.length > 0 + && (select.prop('disabled') || (select.children().length === 0 && this.disableIfEmpty))) { return this.disabledText; } else if (options.length === 0) { From e08c5601e9999846243bfca9a030a39c4593cc5d Mon Sep 17 00:00:00 2001 From: adeeb1 Date: Wed, 3 Jul 2019 16:03:02 -0700 Subject: [PATCH 03/10] Fix the styling for Bootstrap 4. Fix a selector typo in selectAll. Prevent the dropdown from closing after each click. --- dist/js/bootstrap-multiselect.js | 57 +++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/dist/js/bootstrap-multiselect.js b/dist/js/bootstrap-multiselect.js index 18ac8a35..f1d79c59 100644 --- a/dist/js/bootstrap-multiselect.js +++ b/dist/js/bootstrap-multiselect.js @@ -399,10 +399,10 @@ }, enableHTML: false, - buttonClass: 'btn btn-default', + buttonClass: 'btn btn-secondary', inheritClass: false, buttonWidth: 'auto', - buttonContainer: '
', + buttonContainer: '
', dropRight: false, dropUp: false, selectedClass: 'active', @@ -438,14 +438,14 @@ includeResetDivider: false, resetText: 'Reset', templates: { - button: '', - ul: '', - filter: '
  • ', - filterClearBtn: '', - li: '
  • ', - divider: '
  • ', - liGroup: '
  • ', - resetButton: '
  • ' + button: '', + ul: '', + filter: '
  • ', + filterClearBtn: '', + li: '', + divider: '', + liGroup: '', + resetButton: '
  • ' } }, @@ -508,7 +508,7 @@ this.$ul = $(this.options.templates.ul); if (this.options.dropRight) { - this.$ul.addClass('pull-right'); + this.$ul.addClass('float-right'); } // Set max height of dropdown menu to activate auto scrollbar. @@ -534,6 +534,13 @@ }); } + if (this.options.multiple) { + // Prevent the dropdown from closing after each click + this.$ul.on("click", function(e) { + e.stopPropagation(); + }); + } + this.$container.append(this.$ul); }, @@ -624,9 +631,6 @@ $($checkboxesNotThis).prop('checked', false); $optionsNotThis.prop('selected', false); - - // It's a single selection, so close. - this.$button.click(); } if (this.options.selectedClass === "active") { @@ -738,7 +742,7 @@ } var index = $items.index($items.filter(':focus')); - + // Navigation up. if (event.keyCode === 38 && index > 0) { index--; @@ -868,10 +872,20 @@ var value = $element.val(); var inputType = this.options.multiple ? "checkbox" : "radio"; + // Generate a random number between 0 and MAX_SAFE_INTEGER to use as a highly unique ID + var randomNum = Math.floor(Math.random() * Math.floor(Number.MAX_SAFE_INTEGER)); + + // This element ID is required for the label and checkbox so that Bootstrap 4 will select the option when the label is clicked + // Ex: "bootstrap-multiselect-option-7-2193414947069541" + var optionComponentId = "bootstrap-multiselect-option-" + value + "-" + randomNum; + var $li = $(this.options.templates.li); var $label = $('label', $li); + var $div = $('div', $li); $label.addClass(inputType); + $label.addClass("form-check-label"); $label.attr("title", label); + $label.attr("for", optionComponentId); $li.addClass(classes); // Hide all children items when collapseOptGroupsByDefault is true @@ -889,19 +903,22 @@ var $checkbox = $('').attr('type', inputType); + $checkbox.attr('id', optionComponentId); + $checkbox.addClass('form-check-input'); + var name = this.options.checkboxName($element); if (name) { $checkbox.attr('name', name); } - $label.prepend($checkbox); + $div.prepend($checkbox); var selected = $element.prop('selected') || false; $checkbox.val(value); if (value === this.options.selectAllValue) { $li.addClass("multiselect-item multiselect-all"); - $checkbox.parent().parent() + $checkbox.parent().parent().parent() .addClass('multiselect-all'); } @@ -1045,7 +1062,7 @@ $checkbox.val(this.options.selectAllValue); $li.addClass("multiselect-item multiselect-all"); - $checkbox.parent().parent() + $checkbox.parent().parent().parent() .addClass('multiselect-all'); this.$ul.prepend($li); @@ -1381,7 +1398,7 @@ var justVisible = typeof justVisible === 'undefined' ? true : justVisible; var allLis = $("li:not(.divider):not(.disabled):not(.multiselect-group)", this.$ul); - var visibleLis = $("li:not(.divider):not(.disabled):not(.multiselect-group):not(.multiselect-filter-hidden):not(.multiselect-collapisble-hidden)", this.$ul).filter(':visible'); + var visibleLis = $("li:not(.divider):not(.disabled):not(.multiselect-group):not(.multiselect-filter-hidden):not(.multiselect-collapsible-hidden)", this.$ul).filter(':visible'); if(justVisible) { $('input:enabled' , visibleLis).prop('checked', true); @@ -1426,7 +1443,7 @@ var justVisible = typeof justVisible === 'undefined' ? true : justVisible; var allLis = $("li:not(.divider):not(.disabled):not(.multiselect-group)", this.$ul); - var visibleLis = $("li:not(.divider):not(.disabled):not(.multiselect-group):not(.multiselect-filter-hidden):not(.multiselect-collapisble-hidden)", this.$ul).filter(':visible'); + var visibleLis = $("li:not(.divider):not(.disabled):not(.multiselect-group):not(.multiselect-filter-hidden):not(.multiselect-collapsible-hidden)", this.$ul).filter(':visible'); if(justVisible) { $('input[type="checkbox"]:enabled' , visibleLis).prop('checked', false); From 5510843106275e9d56f060d4957f9e5c34a08d5b Mon Sep 17 00:00:00 2001 From: adeeb1 Date: Wed, 3 Jul 2019 17:06:27 -0700 Subject: [PATCH 04/10] Increase label width to improve selection on the dropdown menu. Fix styles. and remove old styles. --- dist/css/bootstrap-multiselect.css | 2 +- dist/js/bootstrap-multiselect.js | 20 ++++++++++---------- dist/less/bootstrap-multiselect.less | 27 +++++++-------------------- 3 files changed, 18 insertions(+), 31 deletions(-) diff --git a/dist/css/bootstrap-multiselect.css b/dist/css/bootstrap-multiselect.css index 6a6b68a2..11b49566 100644 --- a/dist/css/bootstrap-multiselect.css +++ b/dist/css/bootstrap-multiselect.css @@ -1 +1 @@ -span.multiselect-native-select{position:relative}span.multiselect-native-select select{border:0!important;clip:rect(0 0 0 0)!important;height:1px!important;margin:-1px -1px -1px -3px!important;overflow:hidden!important;padding:0!important;position:absolute!important;width:1px!important;left:50%;top:30px}.multiselect-container{position:absolute;list-style-type:none;margin:0;padding:0}.multiselect-container .input-group{margin:5px}.multiselect-container .multiselect-reset .input-group{width:93%}.multiselect-container>li{padding:0}.multiselect-container>li>a.multiselect-all label{font-weight:700}.multiselect-container>li.multiselect-group label{margin:0;padding:3px 20px;height:100%;font-weight:700}.multiselect-container>li.multiselect-group-clickable label{cursor:pointer}.multiselect-container>li>a{padding:0}.multiselect-container>li>a>label{margin:0;height:100%;cursor:pointer;font-weight:400;padding:3px 20px 3px 40px}.multiselect-container>li>a>label.checkbox,.multiselect-container>li>a>label.radio{margin:0}.multiselect-container>li>a>label>input[type=checkbox]{margin-bottom:5px}.btn-group>.btn-group:nth-child(2)>.multiselect.btn{border-top-left-radius:4px;border-bottom-left-radius:4px}.form-inline .multiselect-container label.checkbox,.form-inline .multiselect-container label.radio{padding:3px 20px 3px 40px}.form-inline .multiselect-container li a label.checkbox input[type=checkbox],.form-inline .multiselect-container li a label.radio input[type=radio]{margin-left:-20px;margin-right:0} \ No newline at end of file +span.multiselect-native-select{position:relative}span.multiselect-native-select select{border:0!important;clip:rect(0 0 0 0)!important;height:1px!important;margin:-1px -1px -1px -3px!important;overflow:hidden!important;padding:0!important;position:absolute!important;width:1px!important;left:50%;top:30px}.multiselect-container{position:absolute;list-style-type:none;margin:0;padding:0}.multiselect-container .input-group{margin:5px}.multiselect-container .multiselect-reset .input-group{width:93%}.multiselect-container>li>a.multiselect-all label{font-weight:700}.multiselect-container>li.multiselect-group label{margin:0;width:100%;height:100%;font-weight:700}.multiselect-container>li.multiselect-group-clickable label{cursor:pointer}.multiselect-container>li>div>label{margin:0;width:100%;height:100%;cursor:pointer;font-weight:400}.btn-group>.btn-group:nth-child(2)>.multiselect.btn{border-top-left-radius:4px;border-bottom-left-radius:4px}.form-inline .multiselect-container li a label.checkbox input[type="checkbox"],.form-inline .multiselect-container li a label.radio input[type="radio"]{margin-left:-20px;margin-right:0}.multiselect-filter{padding-right:1rem} \ No newline at end of file diff --git a/dist/js/bootstrap-multiselect.js b/dist/js/bootstrap-multiselect.js index f1d79c59..ed1dd0f4 100644 --- a/dist/js/bootstrap-multiselect.js +++ b/dist/js/bootstrap-multiselect.js @@ -439,9 +439,9 @@ resetText: 'Reset', templates: { button: '', - ul: '', - filter: '
  • ', - filterClearBtn: '', + ul: '', + filter: '
  • ', + filterClearBtn: '
    ', li: '', divider: '', liGroup: '', @@ -840,11 +840,11 @@ }); if (visible) { - $inputs.hide() + $inputs.attr('hidden', true) .addClass('multiselect-collapsible-hidden'); } else { - $inputs.show() + $inputs.removeAttr('hidden') .removeClass('multiselect-collapsible-hidden'); } }, this)); @@ -891,7 +891,7 @@ // Hide all children items when collapseOptGroupsByDefault is true if (this.options.collapseOptGroupsByDefault && $(element).parent().prop("tagName").toLowerCase() === "optgroup") { $li.addClass("multiselect-collapsible-hidden"); - $li.hide(); + $li.attr('hidden', true); } if (this.options.enableHTML) { @@ -1093,7 +1093,7 @@ this.query = ''; this.$filter.find('.multiselect-search').val(''); - $('li', this.$ul).show().removeClass('multiselect-filter-hidden'); + $('li', this.$ul).removeAttr('hidden').removeClass('multiselect-filter-hidden'); this.updateSelectAll(); @@ -1179,13 +1179,13 @@ else { // Show group name when at least one of its items is visible. if (showElement) { - $(currentGroup).show() + $(currentGroup).removeAttr('hidden') .removeClass('multiselect-filter-hidden'); } // Show all group items when group name satisfies filter. if (!showElement && currentGroupVisible) { - $(element).show() + $(element).removeAttr('hidden') .removeClass('multiselect-filter-hidden'); } } @@ -1212,7 +1212,7 @@ */ destroy: function() { this.$container.remove(); - this.$select.show(); + this.$select.removeAttr('hidden'); // reset original state this.$select.prop('disabled', this.options.wasDisabled); diff --git a/dist/less/bootstrap-multiselect.less b/dist/less/bootstrap-multiselect.less index deec16fe..89a77610 100644 --- a/dist/less/bootstrap-multiselect.less +++ b/dist/less/bootstrap-multiselect.less @@ -75,15 +75,13 @@ span.multiselect-native-select select{ } > li { - padding: 0; - > a.multiselect-all label { font-weight: bold; } &.multiselect-group label { margin: 0; - padding: 3px 20px 3px 20px; + width: 100%; height: 100%; font-weight: bold; } @@ -92,23 +90,13 @@ span.multiselect-native-select select{ cursor: pointer; } - > a { - padding: 0; - + > div { > label { margin: 0; + width: 100%; height: 100%; cursor: pointer; font-weight: normal; - padding: 3px 20px 3px 40px; - - &.radio, &.checkbox { - margin: 0; - } - - > input[type="checkbox"] { - margin-bottom:5px; - } } } } @@ -120,11 +108,6 @@ span.multiselect-native-select select{ } .form-inline .multiselect-container{ - - label.checkbox, label.radio{ - padding: 3px 20px 3px 40px; - } - li a label{ &.checkbox input[type="checkbox"], &.radio input[type="radio"]{ @@ -133,3 +116,7 @@ span.multiselect-native-select select{ } } } + +.multiselect-filter { + padding-right: 1rem; +} \ No newline at end of file From 18a2b9c4601cb3ac931bb835dbf50d0f7af05732 Mon Sep 17 00:00:00 2001 From: adeeb1 Date: Wed, 3 Jul 2019 17:11:26 -0700 Subject: [PATCH 05/10] Fix the filter clear button. --- dist/js/bootstrap-multiselect.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/js/bootstrap-multiselect.js b/dist/js/bootstrap-multiselect.js index ed1dd0f4..1e8a9754 100644 --- a/dist/js/bootstrap-multiselect.js +++ b/dist/js/bootstrap-multiselect.js @@ -1162,11 +1162,11 @@ // Toggle current element (group or group item) according to showElement boolean. if(!showElement){ - $(element).css('display', 'none'); + $(element).attr('hidden', true); $(element).addClass('multiselect-filter-hidden'); } if(showElement){ - $(element).css('display', 'block'); + $(element).removeAttr('hidden'); $(element).removeClass('multiselect-filter-hidden'); } From 461b561d6c9bb81f2cb854f32c6a056cf564714a Mon Sep 17 00:00:00 2001 From: Alvin Giles Date: Tue, 10 Dec 2019 13:00:29 -0500 Subject: [PATCH 06/10] Fix issue with collapsible optgroups in Bootstrap 4 --- dist/css/bootstrap-multiselect.css | 2 +- dist/js/bootstrap-multiselect.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dist/css/bootstrap-multiselect.css b/dist/css/bootstrap-multiselect.css index 11b49566..6283cb97 100644 --- a/dist/css/bootstrap-multiselect.css +++ b/dist/css/bootstrap-multiselect.css @@ -1 +1 @@ -span.multiselect-native-select{position:relative}span.multiselect-native-select select{border:0!important;clip:rect(0 0 0 0)!important;height:1px!important;margin:-1px -1px -1px -3px!important;overflow:hidden!important;padding:0!important;position:absolute!important;width:1px!important;left:50%;top:30px}.multiselect-container{position:absolute;list-style-type:none;margin:0;padding:0}.multiselect-container .input-group{margin:5px}.multiselect-container .multiselect-reset .input-group{width:93%}.multiselect-container>li>a.multiselect-all label{font-weight:700}.multiselect-container>li.multiselect-group label{margin:0;width:100%;height:100%;font-weight:700}.multiselect-container>li.multiselect-group-clickable label{cursor:pointer}.multiselect-container>li>div>label{margin:0;width:100%;height:100%;cursor:pointer;font-weight:400}.btn-group>.btn-group:nth-child(2)>.multiselect.btn{border-top-left-radius:4px;border-bottom-left-radius:4px}.form-inline .multiselect-container li a label.checkbox input[type="checkbox"],.form-inline .multiselect-container li a label.radio input[type="radio"]{margin-left:-20px;margin-right:0}.multiselect-filter{padding-right:1rem} \ No newline at end of file +span.multiselect-native-select{position:relative}span.multiselect-native-select select{border:0!important;clip:rect(0 0 0 0)!important;height:1px!important;margin:-1px -1px -1px -3px!important;overflow:hidden!important;padding:0!important;position:absolute!important;width:1px!important;left:50%;top:30px}.multiselect-container{position:absolute;list-style-type:none;margin:0;padding:0}.multiselect-container .input-group{margin:5px}.multiselect-container .multiselect-reset .input-group{width:93%}.multiselect-container>li>a.multiselect-all label{font-weight:700}.multiselect-container>li.multiselect-group label{margin:0;width:100%;height:100%;font-weight:700}.multiselect-container>li.multiselect-group-clickable label{cursor:pointer}.multiselect-container>li>div>label{margin:0;width:100%;height:100%;cursor:pointer;font-weight:400}.btn-group>.btn-group:nth-child(2)>.multiselect.btn{border-top-left-radius:4px;border-bottom-left-radius:4px}.form-inline .multiselect-container li a label.checkbox input[type="checkbox"],.form-inline .multiselect-container li a label.radio input[type="radio"]{margin-left:-20px;margin-right:0}.multiselect-filter{padding-right:1rem} .optgroup-container{display:inline-flex;} \ No newline at end of file diff --git a/dist/js/bootstrap-multiselect.js b/dist/js/bootstrap-multiselect.js index 1e8a9754..cbfaafae 100644 --- a/dist/js/bootstrap-multiselect.js +++ b/dist/js/bootstrap-multiselect.js @@ -829,7 +829,7 @@ } if (this.options.enableCollapsibleOptGroups && this.options.multiple) { - $("li.multiselect-group .caret-container", this.$ul).on("click", $.proxy(function(event) { + $("li.multiselect-group .optgroup-container", this.$ul).on("click", $.proxy(function(event) { var $li = $(event.target).closest('li'); var $inputs = $li.nextUntil("li.multiselect-group") .not('.multiselect-filter-hidden'); @@ -961,7 +961,7 @@ createOptgroup: function(group) { var label = $(group).attr("label"); var value = $(group).attr("value"); - var $li = $('
  • '); + var $li = $('
  • '); var classes = this.options.optionClass(group); $li.addClass(classes); @@ -974,11 +974,11 @@ } if (this.options.enableCollapsibleOptGroups && this.options.multiple) { - $('a', $li).append(''); + $('.optgroup-container', $li).append(''); } if (this.options.enableClickableOptGroups && this.options.multiple) { - $('a label', $li).prepend(''); + $('.optgroup-container label', $li).prepend(''); } if ($(group).is(':disabled')) { From 55fa65f77cf23b7f51dd132344706f793cb6de12 Mon Sep 17 00:00:00 2001 From: Alvin Giles Date: Tue, 10 Dec 2019 13:01:07 -0500 Subject: [PATCH 07/10] Fixed tests for updated dropdown structure with bootstrap 4. --- tests/spec/bootstrap-multiselect.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/spec/bootstrap-multiselect.js b/tests/spec/bootstrap-multiselect.js index a2e9e7ff..be1f786a 100644 --- a/tests/spec/bootstrap-multiselect.js +++ b/tests/spec/bootstrap-multiselect.js @@ -1090,12 +1090,12 @@ describe('Bootstrap Multiselect "Dataprovider"', function() { expect($('#multiselect option[value="5"]').attr('title')).toBe('Option 5 Title'); expect($('#multiselect option[value="6"]').attr('title')).toBe('Option 6 Title'); - expect($('#multiselect-container input[value="1"]').closest('label').attr('title')).toBe('Option 1 Title'); - expect($('#multiselect-container input[value="2"]').closest('label').attr('title')).toBe('Option 2 Title'); - expect($('#multiselect-container input[value="3"]').closest('label').attr('title')).toBe('Option 3 Title'); - expect($('#multiselect-container input[value="4"]').closest('label').attr('title')).toBe('Option 4 Title'); - expect($('#multiselect-container input[value="5"]').closest('label').attr('title')).toBe('Option 5 Title'); - expect($('#multiselect-container input[value="6"]').closest('label').attr('title')).toBe('Option 6 Title'); + expect($('#multiselect-container input[value="1"]').siblings('label').attr('title')).toBe('Option 1 Title'); + expect($('#multiselect-container input[value="2"]').siblings('label').attr('title')).toBe('Option 2 Title'); + expect($('#multiselect-container input[value="3"]').siblings('label').attr('title')).toBe('Option 3 Title'); + expect($('#multiselect-container input[value="4"]').siblings('label').attr('title')).toBe('Option 4 Title'); + expect($('#multiselect-container input[value="5"]').siblings('label').attr('title')).toBe('Option 5 Title'); + expect($('#multiselect-container input[value="6"]').siblings('label').attr('title')).toBe('Option 6 Title'); }); it("Should be able to define data attributes.", function() { @@ -1976,7 +1976,7 @@ describe('Bootstrap Multiselect "Specific Issues".', function() { selection.addRange(range); if (document.getSelection().type === 'Range') { - $('#multiselect-container').find('a:first label').trigger('click'); + $('#multiselect-container').find('.form-check:first label').trigger('click'); expect($('#multiselect-container').find('input:first').prop('checked')).toBe(true); } From 22ab2eb7985b0f8719d60bb9a5d9c3bfcea4189e Mon Sep 17 00:00:00 2001 From: adeeb1 <4312320+adeeb1@users.noreply.github.com> Date: Mon, 27 Apr 2020 12:35:34 -0700 Subject: [PATCH 08/10] Disable the numberDisplayed option with -1 instead of 0. --- dist/js/bootstrap-multiselect.js | 2 +- index.html | 6 +- types/bootstrap-multiselect/index.d.ts | 90 +++++++++++++------------- 3 files changed, 49 insertions(+), 49 deletions(-) diff --git a/dist/js/bootstrap-multiselect.js b/dist/js/bootstrap-multiselect.js index cbfaafae..21f0fbb6 100644 --- a/dist/js/bootstrap-multiselect.js +++ b/dist/js/bootstrap-multiselect.js @@ -268,7 +268,7 @@ return this.allSelectedText; } } - else if (this.numberDisplayed != 0 && options.length > this.numberDisplayed) { + else if (this.numberDisplayed != -1 && options.length > this.numberDisplayed) { return options.length + ' ' + this.nSelectedText; } else { diff --git a/index.html b/index.html index fa4385fc..aea5e686 100644 --- a/index.html +++ b/index.html @@ -861,7 +861,7 @@

    Configuration Options

    This option will collapse all optgroups by default.

    There is also an example in the Further Examples section demonstrating an alternative way of collapsing optgroups by default.

    - +