Commit c7607fbd authored by David Stutz's avatar David Stutz

Some fixes and more tests for clickable and collapisble option groups.

parent 3c219fcc
...@@ -726,7 +726,7 @@ ...@@ -726,7 +726,7 @@
}, this)); }, this));
if (this.options.enableClickableOptGroups && this.options.multiple) { if (this.options.enableClickableOptGroups && this.options.multiple) {
$("li.multiselect-group input", this.$ul).on("change", $.proxy(function(event) {console.log('test') $("li.multiselect-group input", this.$ul).on("change", $.proxy(function(event) {
event.stopPropagation(); event.stopPropagation();
var $target = $(event.target); var $target = $(event.target);
...@@ -763,32 +763,14 @@ ...@@ -763,32 +763,14 @@
$(this).toggleClass('hidden', true); $(this).toggleClass('hidden', true);
}); });
$("li.multiselect-group > a > .caret-container", this.$ul).on("click", $.proxy(function(event) { $("li.multiselect-group .caret-container", this.$ul).on("click", $.proxy(function(event) {
event.stopPropagation(); event.stopPropagation();
var $li = $(event.target).closest('li'); var $li = $(event.target).closest('li');
var $inputs = $li.nextUntil("li.multiselect-group"); var $inputs = $li.nextUntil("li.multiselect-group");
var selected = true; $inputs.toggleClass('hidden');
$inputs.each(function() {
selected = selected && $(this).hasClass('hidden');
});
$inputs.toggleClass('hidden', !selected);
}, this)); }, this));
// Set the initial selection state of the groups.
$('li.multiselect-group', this.$ul).each(function() {
var $group = $(this).nextUntil("li.multiselect-group", ':not(.disabled)');
var $inputs = $group.find("input");
var selected = true;
$inputs.each(function() {
selected = selected && $(this).prop("checked");
});
$(this).find('input').prop("checked", selected);
});
$("li.multiselect-all", this.$ul).css('background', '#f3f3f3').css('border-bottom', '1px solid #eaeaea'); $("li.multiselect-all", this.$ul).css('background', '#f3f3f3').css('border-bottom', '1px solid #eaeaea');
$("li.multiselect-all > a > label.checkbox", this.$ul).css('padding', '3px 20px 3px 35px'); $("li.multiselect-all > a > label.checkbox", this.$ul).css('padding', '3px 20px 3px 35px');
$("li.multiselect-group > a > input", this.$ul).css('margin', '4px 0px 5px -20px'); $("li.multiselect-group > a > input", this.$ul).css('margin', '4px 0px 5px -20px');
...@@ -1250,11 +1232,11 @@ ...@@ -1250,11 +1232,11 @@
if(justVisible) { if(justVisible) {
visibleCheckboxes.prop('checked', true); visibleCheckboxes.prop('checked', true);
$("li:not(.divider):not(.disabled)", this.$ul).filter(":visible").addClass(this.options.selectedClass); $("li:not(.divider):not(.disabled):not(.multiselect-group)", this.$ul).filter(":visible").addClass(this.options.selectedClass);
} }
else { else {
allCheckboxes.prop('checked', true); allCheckboxes.prop('checked', true);
$("li:not(.divider):not(.disabled)", this.$ul).addClass(this.options.selectedClass); $("li:not(.divider):not(.disabled):not(.multiselect-group)", this.$ul).addClass(this.options.selectedClass);
} }
if (allCheckboxesCount === visibleCheckboxesCount || justVisible === false) { if (allCheckboxesCount === visibleCheckboxesCount || justVisible === false) {
......
...@@ -241,7 +241,7 @@ ...@@ -241,7 +241,7 @@
<table class="table layout-fixed"> <table class="table layout-fixed">
<tbody> <tbody>
<tr> <tr>
<td><code id="configuration-options-multiple">multiple</code></td> <td width="30%"><code id="configuration-options-multiple">multiple</code></td>
<td> <td>
<p> <p>
<code>multiple</code> is not a real configuration option. It refers to the <code>multiple</code> attribute of the <code>select</code> the plugin is applied on. When the <code>multiple</code> attribute of the <code>select</code> is present, the plugin uses checkboxes to allow multiple selections. If it is not present, the plugin uses radio buttons to allow single selections. When using the plugin for single selections (without the <code>multiple</code> attribute present), the first option will automatically be selected if no other option is selected in advance. See <a href="https://github.com/davidstutz/bootstrap-multiselect/issues/129">#129</a> for how to avoid this behavior. <code>multiple</code> is not a real configuration option. It refers to the <code>multiple</code> attribute of the <code>select</code> the plugin is applied on. When the <code>multiple</code> attribute of the <code>select</code> is present, the plugin uses checkboxes to allow multiple selections. If it is not present, the plugin uses radio buttons to allow single selections. When using the plugin for single selections (without the <code>multiple</code> attribute present), the first option will automatically be selected if no other option is selected in advance. See <a href="https://github.com/davidstutz/bootstrap-multiselect/issues/129">#129</a> for how to avoid this behavior.
...@@ -658,6 +658,52 @@ ...@@ -658,6 +658,52 @@
}); });
}); });
&lt;/script&gt; &lt;/script&gt;
</pre>
<p>
Combining the above with <code>enableFiltering</code> and <code>includeSelectAllOption</code>:
</p>
<p class="alert alert-warning">
Again, note, that the behavior of combining <code>enableCollapsibleOptGroups</code>, <code>enableCollapsibleOptGroups</code>, <code>enableFiltering</code> and <code>includeSelectAllOption</code> is not thoroughly tested. <b>Experiment with the example below to get some intuition.</b>
</p>
<div class="example">
<script type="text/javascript">
$(document).ready(function() {
$('#example-enableCollapsibleOptGroups-enableClickableOptGroups-enableFiltering-includeSelectAllOption').multiselect({
enableClickableOptGroups: true,
enableCollapsibleOptGroups: true,
enableFiltering: true,
includeSelectAllOption: true
});
});
</script>
<select id="example-enableCollapsibleOptGroups-enableClickableOptGroups-enableFiltering-includeSelectAllOption" multiple="multiple">
<optgroup label="Group 1">
<option value="1-1" disabled>Option 1.1</option>
<option value="1-2" selected="selected">Option 1.2</option>
<option value="1-3" selected="selected">Option 1.3</option>
</optgroup>
<optgroup label="Group 2">
<option value="2-1">Option 2.1</option>
<option value="2-2">Option 2.2</option>
<option value="2-3">Option 2.3</option>
</optgroup>
</select>
</div>
<div class="highlight">
<pre class="prettyprint linenums">
&lt;script type=&quot;text/javascript&quot;&gt;
$(document).ready(function() {
$('#example-enableCollapsibleOptGroups-enableClickableOptGroups-enableFiltering-includeSelectAllOption').multiselect({
enableClickableOptGroups: true,
enableCollapsibleOptGroups: true,
enableFiltering: true,
includeSelectAllOption: true
});
});
&lt;/script&gt;
</pre> </pre>
</td> </td>
</tr> </tr>
......
...@@ -295,7 +295,7 @@ describe('Bootstrap Multiselect "Clickable Optgroups"', function() { ...@@ -295,7 +295,7 @@ describe('Bootstrap Multiselect "Clickable Optgroups"', function() {
}); });
}); });
it('Should correctly create labels for optgroups.', function() { it('Should correctly create inputs for optgroups.', function() {
expect($('#multiselect-container li.multiselect-group').length).toBe(10); expect($('#multiselect-container li.multiselect-group').length).toBe(10);
expect($('#multiselect-container li.multiselect-group input').length).toBe(10); expect($('#multiselect-container li.multiselect-group input').length).toBe(10);
...@@ -348,6 +348,248 @@ describe('Bootstrap Multiselect "Clickable Optgroups"', function() { ...@@ -348,6 +348,248 @@ describe('Bootstrap Multiselect "Clickable Optgroups"', function() {
}); });
}); });
describe('Bootstrap Multiselect "Collapsible Optgroups"', function() {
// Count the number of onChanges fired.
var fired = 0;
beforeEach(function() {
var $select = $('<select id="multiselect" multiple="multiple"></select>');
for (var i = 1; i < 11; i++) {
var $optgroup = $('<optgroup label="Group ' + i + '"></optgroup>');
for (var j = 1; j < 11; j++) {
$optgroup.append('<option value="' + i + '-' + j + '">Option ' + i + '.' + j + '</option>');
}
$select.append($optgroup);
}
$('body').append($select);
$select.multiselect({
buttonContainer: '<div id="multiselect-container"></div>',
enableCollapsibleOptGroups: true,
onChange: function(option, checked) {
fired++;
}
});
});
it('Should correctly create headers for optgroups.', function() {
expect($('#multiselect-container li.multiselect-group').length).toBe(10);
$('#multiselect-container label.multiselect-group').each(function() {
expect($('input', $(this)).length).toBe(10);
});
});
if ('Should not create inputs.', function() {
expect($('#multiselect-container li.multiselect-group input').length).toBe(0);
});
it('Groups should not be clickable.', function() {
expect($('#multiselect option:selected').length).toBe(0);
var i = 0;
$('#multiselect-container li.multiselect-group').each(function() {
$('label', $(this)).click();
expect($('option:selected', $('#multiselect optgroup')[i]).length).toBe(0);
expect($('#multiselect option:selected').length).toBe(0);
$('label', $(this)).click();
i++;
});
});
it('Should be collapsible.', function() {
var $group = $('#multiselect-container li.multiselect-group:first');
$('.caret-container', $group).click();
var $lis = $group.nextUntil('li.multiselect-group');
$lis.each(function() {
expect($(this).hasClass('hidden')).toBe(false);
});
$('.caret-container', $group).click();
var $lis = $group.nextUntil('li.multiselect-group');
$lis.each(function() {
expect($(this).hasClass('hidden')).toBe(true);
});
});
afterEach(function() {
$('#multiselect').multiselect('destroy');
$('#multiselect').remove();
});
});
describe('Bootstrap Multiselect "Clickable+Collapsible Optgroups"', function() {
// Count the number of onChanges fired.
var fired = 0;
beforeEach(function() {
var $select = $('<select id="multiselect" multiple="multiple"></select>');
for (var i = 1; i < 11; i++) {
var $optgroup = $('<optgroup label="Group ' + i + '"></optgroup>');
for (var j = 1; j < 11; j++) {
$optgroup.append('<option value="' + i + '-' + j + '">Option ' + i + '.' + j + '</option>');
}
$select.append($optgroup);
}
$('body').append($select);
$select.multiselect({
buttonContainer: '<div id="multiselect-container"></div>',
enableClickableOptGroups: true,
enableCollapsibleOptGroups: true,
onChange: function(option, checked) {
fired++;
}
});
});
it('Should correctly create inputs for optgroups.', function() {
expect($('#multiselect-container li.multiselect-group').length).toBe(10);
expect($('#multiselect-container li.multiselect-group input').length).toBe(10);
$('#multiselect-container label.multiselect-group').each(function() {
expect($('input', $(this)).length).toBe(10);
});
});
it('Groups should be clickable.', function() {
expect($('#multiselect option:selected').length).toBe(0);
var i = 0;
$('#multiselect-container li.multiselect-group').each(function() {
$('label', $(this)).click();
expect($('option:selected', $('#multiselect optgroup')[i]).length).toBe(10);
expect($('#multiselect option:selected').length).toBe(10);
$('label', $(this)).click();
i++;
});
});
it('Clickable groups should fire onChange only once.', function() {
expect($('#multiselect option:selected').length).toBe(0);
fired = 0;
expect(fired).toBe(0);
var i = 0;
$('#multiselect-container li.multiselect-group').each(function() {
$('label', $(this)).click();
// Selected
expect(fired).toBe(1);
fired = 0;
$('label', $(this)).click();
// Deselected
expect(fired).toBe(1);
fired = 0;
i++;
});
});
it('Should be collapsible.', function() {
var $group = $('#multiselect-container li.multiselect-group:first');
$('.caret-container', $group).click();
var $lis = $group.nextUntil('li.multiselect-group');
$lis.each(function() {
expect($(this).hasClass('hidden')).toBe(false);
});
$('.caret-container', $group).click();
var $lis = $group.nextUntil('li.multiselect-group');
$lis.each(function() {
expect($(this).hasClass('hidden')).toBe(true);
});
});
afterEach(function() {
$('#multiselect').multiselect('destroy');
$('#multiselect').remove();
});
});
describe('Bootstrap Multiselect "Clickable+Collapsible+SelectAll Optgroups"', function() {
// Count the number of onChanges fired.
var fired = 0;
beforeEach(function() {
var $select = $('<select id="multiselect" multiple="multiple"></select>');
for (var i = 1; i < 11; i++) {
var $optgroup = $('<optgroup label="Group ' + i + '"></optgroup>');
for (var j = 1; j < 11; j++) {
$optgroup.append('<option value="' + i + '-' + j + '">Option ' + i + '.' + j + '</option>');
}
$select.append($optgroup);
}
$('body').append($select);
$select.multiselect({
buttonContainer: '<div id="multiselect-container"></div>',
enableClickableOptGroups: true,
enableCollapsibleOptGroups: true,
includeSelectAllOption: true,
selectAllValue: 'multiselect-all',
onChange: function(option, checked) {
fired++;
}
});
});
it('Should handle option groups differently, i.e. not set class to active.', function() {
// Otherwise they are hidden.
$('#multiselect-container li.multiselect-group .caret-container').click();
$('#multiselect-container input[value="multiselect-all"]').click();
$groups = $('#multiselect-container li.multiselect-group');
$groups.each(function() {
expect($(this).hasClass('active')).toBe(false);
});
$lis = $('#multiselect-container li:not(.multiselect-group)');
$lis.each(function() {
expect($(this).hasClass('active')).toBe(true);
});
});
it('Should select all options (including option groups).', function() {
//$('#multiselect-container li.multiselect-group .caret-container').click();
$('#multiselect-container input[value="multiselect-all"]').click();
$lis = $('#multiselect-container li');
$lis.each(function() {
expect($('input', this).prop('checked')).toBe(true);
});
});
afterEach(function() {
$('#multiselect').multiselect('destroy');
$('#multiselect').remove();
});
});
describe('Bootstrap Multiselect "Dataprovider"', function() { describe('Bootstrap Multiselect "Dataprovider"', function() {
beforeEach(function() { beforeEach(function() {
var $select = $('<select id="multiselect" multiple="multiple"></select>'); var $select = $('<select id="multiselect" multiple="multiple"></select>');
...@@ -714,6 +956,55 @@ describe('Bootstrap Multiselect Specific Issues.', function() { ...@@ -714,6 +956,55 @@ describe('Bootstrap Multiselect Specific Issues.', function() {
$('#multiselect').remove(); $('#multiselect').remove();
$selection.remove(); $selection.remove();
}); });
it('#679', function() {
var $select = $('<select id="multiselect" multiple="multiple"></select>');
for (var i = 1; i < 11; i++) {
var $optgroup = $('<optgroup label="Group ' + i + '"></optgroup>');
for (var j = 1; j < 11; j++) {
$optgroup.append('<option value="' + i + '-' + j + '">Option ' + i + '.' + j + '</option>');
}
$select.append($optgroup);
}
$('body').append($select);
var fired = 0;
$select.multiselect({
buttonContainer: '<div id="multiselect-container"></div>',
enableClickableOptGroups: true,
enableCollapsibleOptGroups: true,
onChange: function(option, checked) {
fired++;
}
});
expect($('#multiselect option:selected').length).toBe(0);
expect(fired).toBe(0);
var i = 0;
$('#multiselect-container li.multiselect-group').each(function() {
$('label', $(this)).click();
// Selected
expect(fired).toBe(1);
fired = 0;
$('label', $(this)).click();
// Deselected
expect(fired).toBe(1);
fired = 0;
i++;
});
$('#multiselect').multiselect('destroy');
$('#multiselect').remove();
});
}); });
describe('Knockout Binding.', function() { describe('Knockout Binding.', function() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment