Commit 13219440 authored by David Stutz's avatar David Stutz

Some more modularity and tests.

......@@ -24,29 +24,54 @@
<p>Bootstrap Multiselect is a JQuery based plugin to provide an intuitive user interface for using select inputs with the multiple attribute present. Instead of a select a bootstrap button will be shown as dropdown menu containing the single options as checkboxes.</p>
</div>
</div>
<div class="container">
<script>
$('.dropdown input, .dropdown label').click(function (event) {
event.stopPropagation();
});
</script>
<p class="alert alert-info">
<b>Note:</b> The option names may have changed due to the latest updates.
</p>
<div class="page-header">
<h1>Getting Started</h1>
</div>
<pre class="prettyprint linenums">
&lt;!-- Include Twitter Bootstrap and jQuery: --&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;css/bootstrap.min.css&quot; type=&quot;text/css&quot;/&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;js/jquery.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;js/bootstrap.min.js&quot;&gt;&lt;/script&gt;
&lt;!-- Include the plugin's CSS and JS: --&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;js/bootstrap-multiselect.js&quot;&gt;&lt;/script&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;css/bootstrap-multiselect.css&quot; type=&quot;text/css&quot;/&gt;
&lt;!-- Build your select: --&gt;
&lt;select class=&quot;multiselect&quot; multiple=&quot;multiple&quot;&gt;
&lt;option value=&quot;cheese&quot;&gt;Cheese&lt;/option&gt;
&lt;option value=&quot;tomatoes&quot;&gt;Tomatoes&lt;/option&gt;
&lt;option value=&quot;mozarella&quot;&gt;Mozzarella&lt;/option&gt;
&lt;option value=&quot;mushrooms&quot;&gt;Mushrooms&lt;/option&gt;
&lt;option value=&quot;pepperoni&quot;&gt;Pepperoni&lt;/option&gt;
&lt;option value=&quot;onions&quot;&gt;Onions&lt;/option&gt;
&lt;/select&gt;
&lt;!-- Initialize the plugin: --&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
$(document).ready(function() {
$(&#39;.multiselect&#39;).multiselect();
});
&lt;/script&gt;
</pre>
<div class="page-header">
<h1>Examples</h1>
</div>
<ul class="dropdown-menu">
<li><a href="">1</a></li>
<li><a href="">2</a></li>
<li><a href="">3</a></li>
</ul>
<script type="text/javascript">
$(document).ready(function() {
window.prettyPrint() && prettyPrint();
......@@ -466,80 +491,11 @@
</td>
</tr>
</table>
<div class="page-header">
<h1>Code</h1>
</div>
<p>
Basic markup used in the above examples:
</p>
<pre class="prettyprint linenums">
&lt;link rel=&quot;stylesheet&quot; href=&quot;css/bootstrap.min.css&quot; type=&quot;text/css&quot;/&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;css/bootstrap-multiselect.css&quot; type=&quot;text/css&quot;/&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;js/jquery.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;js/bootstrap.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;js/bootstrap-multiselect.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
$(document).ready(function() {
$(&#39;.multiselect&#39;).multiselect({
buttonClass: &apos;btn&apos;,
buttonWidth: &apos;auto&apos;,
buttonContainer: &apos;&lt;div class=&quot;btn-group&quot; /&gt;&apos;,
maxHeight: false,
buttonText: function(options) {
if (options.length == 0) {
return &apos;None selected &lt;b class="caret"&gt;&lt;/b&gt;&apos;;
}
else if (options.length > 3) {
return options.length + &apos; selected &lt;b class="caret"&gt;&lt;/b&gt;&apos;;
}
else {
var selected = &apos;&apos;;
options.each(function() {
selected += $(this).text() + &apos;, &apos;;
});
return selected.substr(0, selected.length -2) + &apos; &lt;b class="caret"&gt;&lt;/b&gt;&apos;;
}
}
});
});
&lt;/script&gt;
&lt;select class=&quot;multiselect&quot; multiple=&quot;multiple&quot;&gt;
&lt;option value=&quot;cheese&quot;&gt;Cheese&lt;/option&gt;
&lt;option value=&quot;tomatoes&quot;&gt;Tomatoes&lt;/option&gt;
&lt;option value=&quot;mozarella&quot;&gt;Mozzarella&lt;/option&gt;
&lt;option value=&quot;mushrooms&quot;&gt;Mushrooms&lt;/option&gt;
&lt;option value=&quot;pepperoni&quot;&gt;Pepperoni&lt;/option&gt;
&lt;option value=&quot;onions&quot;&gt;Onions&lt;/option&gt;
&lt;/select&gt;
&lt;div class=&quot;input-group btn-group&quot;&gt;
&lt;span class="input-group-addon"&gt;&lt;b class="glyphicon glyphicon-list-alt"&gt;&lt;/b&gt;&lt;/span&gt;
&lt;select class=&quot;multiselect&quot; multiple=&quot;multiple&quot;&gt;
&lt;option value=&quot;cheese&quot;&gt;Cheese&lt;/option&gt;
&lt;option value=&quot;tomatoes&quot;&gt;Tomatoes&lt;/option&gt;
&lt;option value=&quot;mozarella&quot;&gt;Mozzarella&lt;/option&gt;
&lt;option value=&quot;mushrooms&quot;&gt;Mushrooms&lt;/option&gt;
&lt;option value=&quot;pepperoni&quot;&gt;Pepperoni&lt;/option&gt;
&lt;option value=&quot;onions&quot;&gt;Onions&lt;/option&gt;
&lt;/select&gt;
&lt;button class=&quot;btn btn-danger&quot;&gt;Cancel&lt;/button&gt;
&lt;button class=&quot;btn btn-success&quot;&gt;Save&lt;/button&gt;
&lt;/div&gt;
</pre>
<div class="page-header">
<h1>Methods</h1>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#example8').multiselect();
......@@ -724,6 +680,7 @@ $(&quot;#multiselect&quot;).multiselect('dataprovider', data);
<h1>Further Examples</h1>
</div>
<script type="text/javascript">
// Example 21: select all and deselect all buttons.
/**
* Gets whether all the options are selected
* @param {jQuery} $el
......@@ -779,6 +736,8 @@ $(&quot;#multiselect&quot;).multiselect('dataprovider', data);
}
$(document).ready(function() {
// Example 21: confirm a prompt to uncheck an option.
$('#example21').multiselect();
$("#example21-toggle").click(function(e) {
e.preventDefault();
......@@ -818,22 +777,50 @@ $(&quot;#multiselect&quot;).multiselect('dataprovider', data);
}
}
});
$('#example30-select-all').on('click', function() {
$('#example30').multiselect('select', 'multiselect-all');
});
$('#example30-deselect-all').on('click', function() {
$('#example30').multiselect('deselect', 'multiselect-all');
});
$('#example30').multiselect();
var firstConfigurationSet = {
includeSelectAllOption: false,
enableFiltering: false,
enableCasInsensitiveFiltering: false
};
var secondConfigurationSet = {
includeSelectAllOption: true,
enableFiltering: true,
enableCasInsensitiveFiltering: true
};
var set = 1;
$('#example33').multiselect(firstConfigurationSet);
function rebuildMultiselect(options) {
$('#example33').multiselect('setOptions', options);
$('#example33').multiselect('rebuild');
}
$('#example33-configuration-set').on('click', function(event) {
switch (set) {
case 2:
rebuildMultiselect(firstConfigurationSet);
$(this).text('Configuration Set 1');
set = 1;
break;
case 1:
default:
rebuildMultiselect(secondConfigurationSet);
$(this).text('Configuration Set 2');
set = 2;
break;
}
});
});
</script>
<table class="table table-striped">
<tbody>
<tr>
<td style="width:250px">
<td style="width:300px">
<div class="btn-group">
<select id="example21" multiple="multiple">
<option value="cheese">Cheese</option>
......@@ -916,14 +903,14 @@ $(&quot;#multiselect&quot;).multiselect('dataprovider', data);
</tr>
<tr>
<td>
<select id="example22" multiple="multiple">
<option value="cheese">Cheese</option>
<option value="tomatoes">Tomatoes</option>
<option value="mozarella">Mozzarella</option>
<option value="mushrooms">Mushrooms</option>
<option value="pepperoni">Pepperoni</option>
<option value="onions">Onions</option>
</select>
<select id="example22" multiple="multiple">
<option value="cheese">Cheese</option>
<option value="tomatoes">Tomatoes</option>
<option value="mozarella">Mozzarella</option>
<option value="mushrooms">Mushrooms</option>
<option value="pepperoni">Pepperoni</option>
<option value="onions">Onions</option>
</select>
</td>
<td>
<pre class="prettyprint linenums">
......@@ -963,22 +950,28 @@ $(&quot;#multiselect&quot;).multiselect('dataprovider', data);
</pre>
</td>
</tr>
<tr>
<td>
<div class="btn-group">
<select id="example33" multiple="multiple">
<option value="cheese">Cheese</option>
<option value="tomatoes">Tomatoes</option>
<option value="mozarella">Mozzarella</option>
<option value="mushrooms">Mushrooms</option>
<option value="pepperoni">Pepperoni</option>
<option value="onions">Onions</option>
</select>
<button id="example33-configuration-set" class="btn btn-primary">Configuration Set 2</button>
</div>
</td>
</tr>
</tbody>
</table>
<div class="page-header">
<h1>Options</h1>
</div>
<table class="table table-striped">
<thead>
<tr>
......
......@@ -7,7 +7,9 @@
* Dual licensed under the BSD-3-Clause and the Apache License, Version 2.0.
* See the README.
*/
!function($) {"use strict";// jshint ;_;
!function($) {
"use strict";// jshint ;_;
if (typeof ko != 'undefined' && ko.bindingHandlers && !ko.bindingHandlers.multiselect) {
ko.bindingHandlers.multiselect = {
......@@ -27,59 +29,32 @@
function Multiselect(select, options) {
this.options = this.getOptions(options);
this.options = this.mergeOptions(options);
this.$select = $(select);
// Initialization.
// We have to clone to create a new reference.
this.originalOptions = this.$select.clone()[0].options;
//we have to clone to create a new reference
this.query = '';
this.searchTimeout = null;
this.options.multiple = this.$select.attr('multiple') == "multiple";
this.$container = $(this.options.buttonContainer).append('<button type="button" class="multiselect dropdown-toggle ' + this.options.buttonClass + '" data-toggle="dropdown">' + this.options.buttonText(this.getSelected(), this.$select) + '</button>')
.append('<ul class="multiselect-container dropdown-menu' + (this.options.dropRight ? ' pull-right' : '') + '"></ul>');
// Manually add button width if set.
if (this.options.buttonWidth) {
$('button', this.$container).css({
'width' : this.options.buttonWidth
});
}
// Keep the tab index from the select.
var tabindex = this.$select.attr('tabindex');
if (tabindex) {
$('button', this.$container).attr('tabindex', tabindex);
}
// Set max height of dropdown menu to activate auto scrollbar.
if (this.options.maxHeight) {
// TODO: Add a class for this option to move the css declarations.
$('.multiselect-container', this.$container).css({
'max-height' : this.options.maxHeight + 'px',
'overflow-y' : 'auto',
'overflow-x' : 'hidden'
});
}
// Enable filtering.
if (this.options.enableFiltering || this.options.enableCaseInsensitiveFiltering) {
var enableFilterLength = Math.max(this.options.enableFiltering, this.options.enableCaseInsensitiveFiltering);
if (this.$select.find('option').length >= enableFilterLength) {
this.buildFilter();
}
}
this.options.multiple = this.$select.attr('multiple') == "multiple";
// Build select all if enabled.
this.buildContainer();
this.buildButton();
this.buildSelectAll();
this.buildDropdown();
this.buildDropdownOptions();
this.buildFilter();
this.updateButtonText();
this.$select.hide().after(this.$container);
};
Multiselect.prototype = {
// Default options.
defaults: {
// Default text function will either print 'None selected' in case no
// option is selected, or a list of the selected options up to a length of 3 selected options.
......@@ -135,83 +110,76 @@
nonSelectedText: 'None selected',
nSelectedText: 'selected'
},
// Templates.
templates: {
button: '<button type="button" class="multiselect dropdown-toggle" data-toggle="dropdown"></button>',
ul: '<ul class="multiselect-container dropdown-menu"></ul>',
filter: '<div class="input-group"><span class="input-group-addon"><i class="glyphicon glyphicon-search"></i></span><input class="form-control multiselect-search" type="text"></div>',
li: '<li><a href="javascript:void(0);"><label><input /></label></a></li>',
liGroup: '<li><label class="multiselect-group"></label></li>'
},
constructor: Multiselect,
// Will build an dropdown element for the given option.
createOptionValue: function(element) {
if ($(element).is(':selected')) {
$(element).attr('selected', 'selected').prop('selected', true);
buildContainer: function() {
this.$container = $(this.options.buttonContainer);
},
buildButton: function() {
// Build button.
this.$button = $(this.templates.button).addClass(this.options.buttonClass);
// Adopt active state.
if (this.$select.attr('disabled') == undefined) {
this.$button.removeClass('disabled');
}
// Support the label attribute on options.
var label = $(element).attr('label') || $(element).html();
var value = $(element).val();
var inputType = this.options.multiple ? "checkbox" : "radio";
var $li = $('<li><a href="javascript:void(0);"><label class="' + inputType + '"><input type="' + inputType + '" /></label></a></li>');
var selected = $(element).prop('selected') || false;
var $checkbox = $('input', $li);
$checkbox.val(value);
if (value == this.options.selectAllValue) {
$checkbox.parent().parent().addClass('multiselect-all');
else {
this.$button.addClass('disabled');
}
$('label', $li).append(" " + label);
$('.multiselect-container', this.$container).append($li);
if ($(element).is(':disabled')) {
$checkbox.attr('disabled', 'disabled').prop('disabled', true).parents('li').addClass('disabled');
// Manually add button width if set.
if (this.options.buttonWidth) {
this.$button.css({
'width' : this.options.buttonWidth
});
}
$checkbox.prop('checked', selected);
if (selected && this.options.selectedClass) {
$checkbox.parents('li').addClass(this.options.selectedClass);
// Keep the tab index from the select.
var tabindex = this.$select.attr('tabindex');
if (tabindex) {
this.$button.attr('tabindex', tabindex);
}
this.$container.prepend(this.$button)
},
// Create optgroup.
createOptgroup: function(group) {
var groupName = $(group).prop('label');
// Add a header for the group.
var $li = $('<li><label class="multiselect-group"></label></li>');
$('label', $li).text(groupName);
$('.multiselect-container', this.$container).append($li);
// Add the options of the group.
$('option', group).each($.proxy(function(index, element) {
this.createOptionValue(element);
}, this));
},
toggleActiveState: function() {
if (this.$select.attr('disabled') == undefined) {
$('button.multiselect.dropdown-toggle', this.$container).removeClass('disabled');
}
else {
$('button.multiselect.dropdown-toggle', this.$container).addClass('disabled');
// Build dropdown container ul.
buildDropdown: function() {
// Build ul.
this.$ul = $(this.templates.ul);
if (this.options.dropRight) {
this.$ul.addClass('pull-right');
}
},
// Add the select all option to the select.
buildSelectAll: function() {
var alreadyHasSelectAll = this.$select[0][0] ? this.$select[0][0].value == this.options.selectAllValue : false;
// If options.includeSelectAllOption === true, add the include all checkbox.
if (this.options.includeSelectAllOption && this.options.multiple && !alreadyHasSelectAll) {
this.$select.prepend('<option value="' + this.options.selectAllValue + '">' + this.options.selectAllText + '</option>');
// Set max height of dropdown menu to activate auto scrollbar.
if (this.options.maxHeight) {
// TODO: Add a class for this option to move the css declarations.
this.$ul.css({
'max-height': this.options.maxHeight + 'px',
'overflow-y': 'auto',
'overflow-x': 'hidden'
});
}
this.$container.append(this.$ul)
},
// Build the dropdown and bind event handling.
buildDropdown: function() {
this.toggleActiveState();
buildDropdownOptions: function() {
this.$select.children().each($.proxy(function(index, element) {
// Support optgroups and options without a group simultaneously.
var tag = $(element).prop('tagName').toLowerCase();
......@@ -225,7 +193,7 @@
}, this));
// Bind the change event on the dropdown elements.
$('.multiselect-container li input', this.$container).on('change', $.proxy(function(event) {
$('li input', this.$ul).on('change', $.proxy(function(event) {
var checked = $(event.target).prop('checked') || false;
var isSelectAllOption = $(event.target).val() == this.options.selectAllValue;
......@@ -240,9 +208,8 @@
}
// Get the corresponding option.
var $option = $('option', this.$select).filter(function() {
return $(this).val() == $(event.target).val();
});
var value = $(event.target).val();
var $option = this.getOptionByValue(value);
var $optionsNotThis = $('option', this.$select).not($option);
var $checkboxesNotThis = $('input', this.$container).not($(event.target));
......@@ -271,7 +238,7 @@
$optionsNotThis.removeAttr('selected').prop('selected', false);
// It's a single selection, so close.
$(this.$container).find(".multiselect.dropdown-toggle").click();
this.$button.click();
}
if (this.options.selectedClass == "active") {
......@@ -284,9 +251,7 @@
}
this.updateButtonText();
this.options.onChange($option, checked);
this.$select.change();
if(this.options.preventInputChangeEvent) {
......@@ -294,18 +259,19 @@
}
}, this));
$('.multiselect-container li a', this.$container).on('touchstart click', function(event) {
$('li a', this.$ul).on('touchstart click', function(event) {
event.stopPropagation();
$(event.target).blur();
});
// Keyboard support.
this.$container.on('keydown', $.proxy(function(event) {
if ($('input[type="text"]', this.$container).is(':focus'))
if ($('input[type="text"]', this.$container).is(':focus')) {
return;
}
if ((event.keyCode == 9 || event.keyCode == 27) && this.$container.hasClass('open')) {
// Close on tab or escape.
$(this.$container).find(".multiselect.dropdown-toggle").click();
this.$button.click();
}
else {
var $items = $(this.$container).find("li:not(.divider):visible a");
......@@ -331,13 +297,6 @@
var $current = $items.eq(index);
$current.focus();
// Override style for items in li:active.
if (this.options.selectedClass == "active") {
$current.css("outline", "thin dotted #333").css("outline", "5px auto -webkit-focus-ring-color");
$items.not($current).css("outline", "");
}
if (event.keyCode == 32 || event.keyCode == 13) {
var $checkbox = $current.find('input');
......@@ -350,59 +309,132 @@
}
}, this));
},
// Will build an dropdown element for the given option.
createOptionValue: function(element) {
if ($(element).is(':selected')) {
$(element).attr('selected', 'selected').prop('selected', true);
}
// Build and bind filter.
buildFilter: function() {
$('.multiselect-container', this.$container).prepend('<div class="input-group"><span class="input-group-addon"><i class="glyphicon glyphicon-search"></i></span><input class="form-control multiselect-search" type="text" placeholder="' + this.options.filterPlaceholder + '"></div>');
// Support the label attribute on options.
var label = $(element).attr('label') || $(element).html();
var value = $(element).val();
var inputType = this.options.multiple ? "checkbox" : "radio";
$('.multiselect-search', this.$container).val(this.query).on('click', function(event) {
event.stopPropagation();
}).on('keydown', $.proxy(function(event) {
// This is useful to catch "keydown" events after the browser has updated the control.
clearTimeout(this.searchTimeout);
this.searchTimeout = this.asyncFunction($.proxy(function() {
if (this.query != event.target.value) {
this.query = event.target.value;
$.each($('.multiselect-container li', this.$container), $.proxy(function(index, element) {
var value = $('input', element).val();
if (value != this.options.selectAllValue) {
var text = $('label', element).text();
var value = $('input', element).val();
if (value && text && value != this.options.selectAllValue) {
// by default lets assume that element is not
// interesting for this search
var showElement = false;
var filterCandidate = '';
if ((this.options.filterBehavior == 'text' || this.options.filterBehavior == 'both')) {
filterCandidate = text;
}
if ((this.options.filterBehavior == 'value' || this.options.filterBehavior == 'both')) {
filterCandidate = value;
}
var $li = $(this.templates.li);
$('label', $li).addClass(inputType);
$('input', $li).attr('type', inputType);
if (this.options.enableCaseInsensitiveFiltering && filterCandidate.toLowerCase().indexOf(this.query.toLowerCase()) > -1) {
showElement = true;
}
else if (filterCandidate.indexOf(this.query) > -1) {
showElement = true;
}
var selected = $(element).prop('selected') || false;
var $checkbox = $('input', $li);
$checkbox.val(value);
if (showElement) {
$(element).show();
}
else {
$(element).hide();
if (value == this.options.selectAllValue) {
$checkbox.parent().parent().addClass('multiselect-all');
}
$('label', $li).append(" " + label);
this.$ul.append($li);
if ($(element).is(':disabled')) {
$checkbox.attr('disabled', 'disabled').prop('disabled', true).parents('li').addClass('disabled');
}
$checkbox.prop('checked', selected);
if (selected && this.options.selectedClass) {
$checkbox.parents('li').addClass(this.options.selectedClass);
}
},
// Create optgroup.
createOptgroup: function(group) {
var groupName = $(group).prop('label');
// Add a header for the group.
var $li = $(this.templates.liGroup);
$('label', $li).text(groupName);
this.$ul.append($li);
// Add the options of the group.
$('option', group).each($.proxy(function(index, element) {
this.createOptionValue(element);
}, this));
},
// Add the select all option to the select.
buildSelectAll: function() {
var alreadyHasSelectAll = this.$select[0][0] ? this.$select[0][0].value == this.options.selectAllValue : false;
// If options.includeSelectAllOption === true, add the include all checkbox.
if (this.options.includeSelectAllOption && this.options.multiple && !alreadyHasSelectAll) {
this.$select.prepend('<option value="' + this.options.selectAllValue + '">' + this.options.selectAllText + '</option>');
}
},
// Build and bind filter.
buildFilter: function() {
// Build filter if filtering OR case insensitive filtering is enabled and the number of options exceeds (or equals) enableFilterLength.
if (this.options.enableFiltering || this.options.enableCaseInsensitiveFiltering) {
var enableFilterLength = Math.max(this.options.enableFiltering, this.options.enableCaseInsensitiveFiltering);
if (this.$select.find('option').length >= enableFilterLength) {
this.$filter = $(this.templates.filter).attr('placeholder', this.options.filterPlaceholder);
this.$ul.prepend(this.$filter);
this.$filter.val(this.query).on('click', function(event) {
event.stopPropagation();
}).on('keydown', $.proxy(function(event) {
// This is useful to catch "keydown" events after the browser has updated the control.
clearTimeout(this.searchTimeout);
this.searchTimeout = this.asyncFunction($.proxy(function() {
if (this.query != event.target.value) {
this.query = event.target.value;
$.each($('li', this.$ul), $.proxy(function(index, element) {
var value = $('input', element).val();
if (value != this.options.selectAllValue) {
var text = $('label', element).text();
var value = $('input', element).val();
if (value && text && value != this.options.selectAllValue) {
// by default lets assume that element is not
// interesting for this search
var showElement = false;
var filterCandidate = '';
if ((this.options.filterBehavior == 'text' || this.options.filterBehavior == 'both')) {
filterCandidate = text;
}
if ((this.options.filterBehavior == 'value' || this.options.filterBehavior == 'both')) {
filterCandidate = value;
}
if (this.options.enableCaseInsensitiveFiltering && filterCandidate.toLowerCase().indexOf(this.query.toLowerCase()) > -1) {
showElement = true;
}
else if (filterCandidate.indexOf(this.query) > -1) {
showElement = true;
}
if (showElement) {
$(element).show();
}
else {
$(element).hide();
}
}
}
}
}, this));
}
}, this));
}
}, this), 300, this);
}, this));
}, this), 300, this);
}, this));
}
}
},
// Destroy - unbind - the plugin.
......@@ -414,7 +446,7 @@
// Refreshs the checked options based on the current state of the select.
refresh: function() {
$('option', this.$select).each($.proxy(function(index, element) {
var $input = $('.multiselect-container li input', this.$container).filter(function() {
var $input = $('li input', this.$ul).filter(function() {
return $(this).val() == $(element).val();
});
......@@ -454,14 +486,8 @@
var value = selectValues[i];
// Find corresponding option.
var $option = $('option', this.$select).filter(function() {
return $(this).val() == value;
});
// Find corresponding checkbox.
var $checkbox = $('.multiselect-container li input', this.$container).filter(function() {
return $(this).val() == value;
});
var $option = this.getOptionByValue(value);
var $checkbox = this.getInputByValue(value);
if (this.options.selectedClass) {
$checkbox.parents('li').addClass(this.options.selectedClass);
......@@ -486,13 +512,8 @@
var value = deselectValues[i];
// Find option and corresponding checkbox.
var $option = $('option', this.$select).filter(function() {
return $(this).val() == value;
});
var $checkbox = $('.multiselect-container li input', this.$container).filter(function() {
return $(this).val() == value;
});
var $option = this.getOptionByValue(value);
var $checkbox = this.getInputByValue(value);
if (this.options.selectedClass) {
$checkbox.parents('li').removeClass(this.options.selectedClass);
......@@ -509,16 +530,15 @@
// Rebuild the whole dropdown menu.
rebuild: function() {
$('.multiselect-container', this.$container).html('');
this.$ul.html('');
// Important to distinguish between radios and checkboxes.
this.options.multiple = this.$select.attr('multiple') == "multiple";
this.buildSelectAll();
this.buildDropdown();
this.buildDropdownOptions();
this.updateButtonText();
// Enable filtering.
if (this.options.enableFiltering || this.options.enableCaseInsensitiveFiltering) {
this.buildFilter();
}
this.buildFilter();
},
// Build select using the given data as options.
......@@ -532,8 +552,13 @@
this.rebuild();
},
// Set options.
setOptions: function(options) {
this.options = this.mergeOptions(options);
},
// Get options by merging defaults and given options.
getOptions: function(options) {
mergeOptions: function(options) {
return $.extend({}, this.defaults, options);
},
......@@ -553,7 +578,21 @@
getSelected: function() {
return $('option:selected[value!="' + this.options.selectAllValue + '"]', this.$select);
},
// Get the corresponding option by ts value.
getOptionByValue: function(value) {
return $('option', this.$select).filter(function() {
return $(this).val() == value;
});
},
// Get an input in the dropdown by its value.
getInputByValue: function(value) {
return $('li input', this.$ul).filter(function() {
return $(this).val() == value;
});
},
updateOriginalOptions: function() {
this.originalOptions = this.$select.clone()[0].options;
},
......
......@@ -67,6 +67,32 @@
</td>
<td>Everything fine.</td>
</tr>
<tr id="test-build-select-all-tr" class="success">
<th>Test build with select all</th>
<td>
<select id="test-build-select-all-select" multiple="multiple">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
</td>
<td>Everything fine.</td>
</tr>
<tr id="test-build-filter-tr" class="success">
<th>Test build with filter</th>
<td>
<select id="test-build-filter-select" multiple="multiple">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
</td>
<td>Everything fine.</td>
</tr>
<tr id="test-select-tr" class="success">
<th>Test select</th>
<td>
......@@ -93,6 +119,40 @@
</td>
<td>Everything fine.</td>
</tr>
<tr id="test-max-height-tr" class="success">
<th>Test max height</th>
<td>
<select id="test-max-height-select" multiple="multiple">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
<option value="13">13</option>
</select>
</td>
<td>Everything fine.</td>
</tr>
<tr id="test-select-all-tr" class="success">
<th>Test select all</th>
<td>
<select id="test-select-all-select" multiple="multiple">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
</td>
<td>Everything fine.</td>
</tr>
</tbody>
</table>
</div>
......@@ -174,6 +234,8 @@
if ($(secondLabel).text() != $(second).prop('label')) {
return 'Second group labeled incorrectly.';
}
return false;
}($('#test-build-optgroups-select'), $('#test-build-optgroups-tr'));
if (buildOptgroups) {
......@@ -200,6 +262,41 @@
$('#test-build-selected-tr td').last().html(buildSelected);
}
var buildSelectAll = function(select, tr ) {
var value = 'multiselect-select-all';
select.multiselect({
includeSelectAllOption: true,
selectAllValue: value
});
if ($('.multiselect-container input[value="' + value + '"]', tr).length != 1) {
return 'Expected exactly one input with value ' + value + ' as select all option.';
}
return false;
}($('#test-build-select-all-select'), $('#test-build-select-all-tr'));
if (buildSelectAll) {
$('#test-build-select-all-tr').removeClass('success').addClass('danger');
$('#test-build-select-all-tr td').last().html(buildSelectAll);
}
var buildFilter = function(select, tr) {
select.multiselect({
enableFiltering: true
});
if ($('.multiselect-search', tr).length != 1) {
return 'No search input present.';
}
}($('#test-build-filter-select'), $('#test-build-filter-tr'));
if (buildFilter) {
$('#test-build-filter-tr').removeClass('success').addClass('danger');
$('#test-build-filter-tr td').last().html(buildFilter);
}
// Test select.
var select = function(select, tr) {
select.multiselect();
......@@ -251,6 +348,8 @@
if ($(second).val() != 2 || $(third).val() != 3) {
return 'Wrong options selected.';
}
return false;
}($('#test-select-select'), $('#test-select-tr'));
if (select) {
......@@ -294,12 +393,65 @@
if ($('ul.multiselect-container li.active', tr).length > 0) {
return 'Just deselected two additional options - list items not set unactive.';
}
return false;
}($('#test-deselect-select'), $('#test-deselect-tr'));
if (deselect) {
$('#test-deselect-tr').removeClass('success').addClass('danger');
$('#test-deselect-tr td').last().html(deselect);
}
var maxHeight = function(select, tr) {
select.multiselect({
maxHeight: 100,
});
var height = $('.multiselect-container', tr).css('max-height');
if (height != '100px') {
return 'Max height not set correctly (set: ' + height + ').';
}
return false;
}($('#test-max-height-select'), $('#test-max-height-tr'));
if (maxHeight) {
$('#test-max-height-tr').removeClass('success').addClass('danger');
$('#test-max-height-tr td').last().html(maxHeight);
}
var selectAll = function(select, tr) {
var value = 'multiselect-select-all';
select.multiselect({
includeSelectAllOption: true,
selectAllValue: value
});
if ($('option:selected', select).length > 0) {
return 'Test expected 0 selected options as initial state (found ' + $('option:selected', select).length + ').';
}
// Trigger select all.
$('.multiselect-container input[value="' + value + '"]', tr).click();
if ($('option:selected', select).length != $('option', select).length) {
return 'Not all options selected.';
}
$('.multiselect-container input[value="' + value + '"]', tr).click();
if ($('option:selected', select).length > 0) {
return 'There is some option selected (0 expected).';
}
return false;
}($('#test-select-all-select'), $('#test-select-all-tr'));
if (selectAll) {
$('#test-select-all-tr').removeClass('success').addClass('danger');
$('#test-select-all-tr td').last().html(selectAll);
}
});
</script>
</body>
......
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