Commit ab01734d authored by Chris Hynes's avatar Chris Hynes
parents 531a3cde 2f3a71cc
......@@ -156,11 +156,11 @@ If the width is defined using CSS the option should be set to false.
**buttonText**
Defining the text of the button. Must be a function returning a string. All currently selected options are passed as parameter.
Defining the text of the button. Must be a function returning a string. All currently selected options and the select are passed as parameter.
$(document).ready(function() {
$('.multiselect').multiselect({
buttonText: function(options) {
buttonText: function(options, select) {
if (options.length == 0) {
return 'None selected <b class="caret"></b>';
}
......
......@@ -92,6 +92,8 @@
$('#example16').multiselect('select', option.val());
}
});
$('#example19').multiselect();
});
</script>
<p>
......@@ -285,6 +287,30 @@
Using the <code>onChange</code> option to prevent user from deselecting selected options.
</td>
</tr>
<tr>
<td>
<div class="btn-group">
<select id="example19" multiple="multiple">
<optgroup label="Mathematics">
<option value="analysis">Analysis</option>
<option value="algebra">Linear Algebra</option>
<option value="discrete">Discrete Mathematics</option>
<option value="numerical">Numerical Analysis</option>
<option value="probability">Probability Theory</option>
</optgroup>
<optgroup label="Computer Science">
<option value="programming">Introduction to Programming</option>
<option value="automata">Automata Theory</option>
<option value="complexity">Complexity Theory</option>
<option value="software">Software Engineering</option>
</optgroup>
</select>
</div>
</td>
<td>
Option groups are detected automatically and for each option group an header element is added: <code>&lt;optgroup label=&quot;Mathematics&quot;&gt;...&lt;/optgroup&gt;</code>
</td>
</tr>
</table>
<div class="page-header">
<h1>Code</h1>
......@@ -305,6 +331,8 @@
$(&#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;;
......@@ -413,6 +441,11 @@
});
});
</script>
<style type="text/css">
.multiselect-group {
font-weight: bold;
}
</style>
<table class="table table-striped">
<tbody>
<tr>
......@@ -532,13 +565,13 @@
<tbody>
<tr>
<td><code>buttonText</code></td>
<td>A function returning the string displayed if options are selected. All currently selected options are passed as argument. In addition HTML can be added to the button, for example the caret icon seen in the examples.</td>
<td>A function returning the string displayed if options are selected. All currently selected options and the select are passed as argument. In addition HTML can be added to the button, for example the caret icon seen in the examples.</td>
<td>
<pre class="prettyprint linenums">
&lt;script type=&quot;text/javascript&quot;&gt;
$(document).ready(function() {
$(&#39;.multiselect&#39;).multiselect({
buttonText: function(options) {
buttonText: function(options, select) {
if (options.length == 0) {
return &apos;None selected &lt;b class="caret"&gt;&lt;/b&gt;&apos;;
}
......@@ -666,6 +699,10 @@
position: absolute;
right: 5px;
}
.add-styling .multiselect-group {
font-weight: bold;
text-decoration: underline;
}
</style>
<script type="text/javascript">
$(document).ready(function() {
......@@ -691,25 +728,36 @@
<tr>
<td>
<select id="example15" 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>
<optgroup label="Mathematics">
<option value="analysis">Analysis</option>
<option value="algebra">Linear Algebra</option>
<option value="discrete">Discrete Mathematics</option>
<option value="numerical">Numerical Analysis</option>
<option value="probability">Probability Theory</option>
</optgroup>
<optgroup label="Computer Science">
<option value="programming">Introduction to Programming</option>
<option value="automata">Automata Theory</option>
<option value="complexity">Complexity Theory</option>
<option value="software">Software Engineering</option>
</optgroup>
</select>
</td>
<td>
Text alignment combined with fixed width.
Text alignment combined with fixed width and bold, underlined text for option group headers.
</td>
<td>
<pre class="prettyprint linenums">
.multiselect {
text-align: left;
}
.multiselect b.caret {
float: right;
}
.multiselect {
text-align: left;
}
.multiselect b.caret {
float: right;
}
.multiselect-group {
font-weight: bold;
text-decoration: underline;
}
</pre>
</td>
</tr>
......@@ -717,10 +765,10 @@
</div>
</p>
<hr>
<div>
<p>
&copy; 2012
<a href="http://davidstutz.de">David Stutz</a> - <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License v2.0</a>
</div>
</p>
</div>
</body>
</html>
\ No newline at end of file
......@@ -18,265 +18,262 @@
*/
!function ($) {
"use strict"; // jshint ;_;
if(typeof ko != 'undefined' && ko.bindingHandlers && !ko.bindingHandlers.multiselect){
ko.bindingHandlers.multiselect = {
init: function (element) {
var ms = $(element).data('multiselect');
if(!ms)
throw new Error("Bootstrap-multiselect's multiselect() has to be called on element before applying the Knockout View model!");
var prev = ms.options.onChange;
ms.options.onChange = function(option, checked){
// We dont want to refresh the multiselect since it would delete / recreate all items
$(element).data('blockRefresh', true);
// Force the binding to be updated by triggering the change event on the select element
$(element).trigger('change');
// Call any defined change handler
return prev(option, checked);
}
},
update: function (element) {
var blockRefresh = $(element).data('blockRefresh') || false;
if (!blockRefresh) { $(element).multiselect("rebuild"); }
$.data(element, 'blockRefresh', false);
}
};
}
function Multiselect(select, options) {
this.options = this.getOptions(options);
this.$select = $(select);
// Manually add the multiple attribute, if its not already set.
if (!this.$select.attr('multiple')) {
this.$select.attr('multiple', true);
}
this.$container = $(this.options.buttonContainer)
.append('<button type="button" class="multiselect dropdown-toggle ' + this.options.buttonClass + '" data-toggle="dropdown">' + this.options.buttonText($('option:selected', select)) + '</button>')
.append('<ul class="dropdown-menu"></ul>');
if (this.options.buttonWidth) {
$('button', this.$container).css({
'width': this.options.buttonWidth
});
}
// Set max height of dropdown menu to activate auto scrollbar.
if (this.options.maxHeight) {
$('ul', this.$container).css({
'max-height': this.options.maxHeight + 'px',
'overflow-y': 'auto',
'overflow-x': 'hidden'
});
}
this.buildDropdown(select, this.options);
this.$select
.hide()
.after(this.$container);
};
Multiselect.prototype = {
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.
// If more than 3 options are selected, the number of selected options is printed.
buttonText: function(options) {
if (options.length == 0) {
return 'None selected <b class="caret"></b>';
}
else if (options.length > 3) {
return options.length + ' selected <b class="caret"></b>';
}
else {
var selected = '';
options.each(function() {
selected += $(this).text() + ', ';
});
return selected.substr(0, selected.length -2) + ' <b class="caret"></b>';
}
},
// Is triggered on change of the selected options.
onChange: function(option, checked) {
},
buttonClass: 'btn',
buttonWidth: 'auto',
buttonContainer: '<div class="btn-group" />',
// Maximum height of thet dropdown menu.
// If maximum height is exceeded a scrollbar will be displayed.
maxHeight: 400
},
isMobile: function() {
return navigator.userAgent.match(/Android|webOS|iPhone|iPad|iPod|BlackBerry/i);
},
constructor: Multiselect,
buildDropdown: function(select, options){
// Build the dropdown.
$('option', this.$select).each($.proxy(function(index, element) {
if ($(element).is(':selected')) {
$(element).attr('selected', 'selected');
$(element).prop('selected', 'selected');
}
$('ul', this.$container).append('<li><a href="javascript:void(0);" style="padding:0;" tabindex="-1"><label style="margin:0;padding:3px 20px 3px 20px;width:100%;height:100%;cursor:pointer;"><input style="margin-bottom:5px;" type="checkbox" value="' + $(element).val() + '" tabindex="-1" /> ' + $(element).text() + '</label></a></li>');
var selected = $(element).prop('selected') || false;
var checkbox = $('ul li input[value="' + $(element).val() + '"]', this.$container);
if ($(element).is(':disabled')) {
checkbox.attr('disabled', 'disabled').prop('disabled', 'disabled').parents('li').addClass('disabled')
}
checkbox.prop('checked', selected);
}, this));
// Bind the change event on the dropdown elements.
$('ul li input[type="checkbox"]', this.$container).on('change', $.proxy(function(event) {
var checked = $(event.target).prop('checked') || false;
var option = $('option[value="' + $(event.target).val() + '"]', this.$select);
if (checked) {
option.attr('selected', 'selected');
option.prop('selected', 'selected');
}
else {
option.removeAttr('selected');
}
var options = $('option:selected', this.$select);
$('button', this.$container).html(this.options.buttonText(options));
this.options.onChange(option, checked);
}, this));
$('ul li a', this.$container).on('click', function(event) {
event.stopPropagation();
});
this.$container.on('keydown', function(e) {
if ((e.keyCode == 9 || e.keyCode == 27) && $(this).hasClass('open'))
{
// close on tab or escape
$(this).find(".multiselect.dropdown-toggle").click();
}
else
{
var $items = $(this).find("li:not(.divider):visible a");
if (!$items.length)
return;
var index = $items.index($items.filter(':focus'));
if (e.keyCode == 38 && index > 0) // up
index--;
else if (e.keyCode == 40 && index < $items.length - 1) // down
index++;
else if (!~index)
index = 0;
var $current = $items.eq(index);
$current.focus();
if (e.keyCode == 32 || e.keyCode == 13)
{
var $checkbox = $current.find('input[type="checkbox"]');
$checkbox.prop("checked", !$checkbox.prop("checked"));
}
e.stopPropagation();
e.preventDefault();
}
});
},
// Destroy - unbind - the plugin.
destroy: function() {
this.$container.remove();
this.$select.show();
},
// Refreshs the checked options based on the current state of the select.
refresh: function() {
$('option', this.$select).each($.proxy(function(index, element) {
if ($(element).is(':selected')) {
$('ul li input[value="' + $(element).val() + '"]', this.$container).prop('checked', true);
$('ul li input[value="' + $(element).val() + '"]', this.$container).parents('li').addClass('active');
}
else {
$('ul li input[value="' + $(element).val() + '"]', this.$container).prop('checked', false);
$('ul li input[value="' + $(element).val() + '"]', this.$container).parents('li').removeClass('active');
}
}, this));
$('button', this.$container).html(this.options.buttonText($('option:selected', this.$select)));
},
select: function(value) {
var option = $('option[value="' + value + '"]', this.$select);
var checkbox = $('ul li input[value="' + value + '"]', this.$container);
checkbox.prop('checked', true);
option.attr('selected', 'selected');
option.prop('selected', 'selected');
var options = $('option:selected', this.$select);
$('button', this.$container).html(this.options.buttonText(options));
},
deselect: function(value) {
var option = $('option[value="' + value + '"]', this.$select);
var checkbox = $('ul li input[value="' + value + '"]', this.$container);
checkbox.prop('checked', false);
option.removeAttr('selected');
option.removeProp('selected');
var options = $('option:selected', this.$select);
$('button', this.$container).html(this.options.buttonText(options));
},
rebuild: function() {
$('ul', this.$container).html('');
this.buildDropdown(this.$select, this.options);
},
// Get options by merging defaults and given options.
getOptions: function(options) {
return $.extend({}, this.defaults, options);
}
};
$.fn.multiselect = function (option, parameter) {
return this.each(function () {
var data = $(this).data('multiselect'),
options = typeof option == 'object' && option;
if (!data) {
$(this).data('multiselect', (data = new Multiselect(this, options)));
}
if (typeof option == 'string') {
data[option](parameter);
}
});
}
"use strict"; // jshint ;_;
if(typeof ko != 'undefined' && ko.bindingHandlers && !ko.bindingHandlers.multiselect){
ko.bindingHandlers.multiselect = {
init: function (element) {
var ms = $(element).data('multiselect');
if(!ms)
throw new Error("Bootstrap-multiselect's multiselect() has to be called on element before applying the Knockout View model!");
var prev = ms.options.onChange;
ms.options.onChange = function(option, checked){
// We dont want to refresh the multiselect since it would delete / recreate all items
$(element).data('blockRefresh', true);
// Force the binding to be updated by triggering the change event on the select element
$(element).trigger('change');
// Call any defined change handler
return prev(option, checked);
}
},
update: function (element) {
var blockRefresh = $(element).data('blockRefresh') || false;
if (!blockRefresh) { $(element).multiselect("rebuild"); }
$.data(element, 'blockRefresh', false);
}
};
}
function Multiselect(select, options) {
this.options = this.getOptions(options);
this.$select = $(select);
// Manually add the multiple attribute, if its not already set.
if (!this.$select.attr('multiple')) {
this.$select.attr('multiple', true);
}
this.$container = $(this.options.buttonContainer)
.append('<button type="button" class="multiselect dropdown-toggle ' + this.options.buttonClass + '" data-toggle="dropdown">' + this.options.buttonText($('option:selected', select), this.$select) + '</button>')
.append('<ul class="dropdown-menu"></ul>');
if (this.options.buttonWidth) {
$('button', this.$container).css({
'width': this.options.buttonWidth
});
}
// Set max height of dropdown menu to activate auto scrollbar.
if (this.options.maxHeight) {
$('ul', this.$container).css({
'max-height': this.options.maxHeight + 'px',
'overflow-y': 'auto',
'overflow-x': 'hidden'
});
}
this.buildDrowdown();
this.$select
.hide()
.after(this.$container);
};
Multiselect.prototype = {
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.
// If more than 3 options are selected, the number of selected options is printed.
buttonText: function(options, select) {
if (options.length == 0) {
return 'None selected <b class="caret"></b>';
}
else if (options.length > 3) {
return options.length + ' selected <b class="caret"></b>';
}
else {
var selected = '';
options.each(function() {
selected += $(this).text() + ', ';
});
return selected.substr(0, selected.length -2) + ' <b class="caret"></b>';
}
},
// Is triggered on change of the selected options.
onChange: function(option, checked) {
},
buttonClass: 'btn',
buttonWidth: 'auto',
buttonContainer: '<div class="btn-group" />',
// Maximum height of the dropdown menu.
// If maximum height is exceeded a scrollbar will be displayed.
maxHeight: false,
},
constructor: Multiselect,
// Will build an dropdown element for the given option.
createOptionValue: function(element) {
if ($(element).is(':selected')) {
$(element).attr('selected', 'selected');
$(element).prop('selected', 'selected');
}
$('ul', this.$container).append('<li><a href="javascript:void(0);" style="padding:0;"><label style="margin:0;padding:3px 20px 3px 20px;width:100%;height:100%;cursor:pointer;"><input style="margin-bottom:5px;" type="checkbox" value="' + $(element).val() + '" /> ' + $(element).text() + '</label></a></li>');
var selected = $(element).prop('selected') || false;
var checkbox = $('ul li input[value="' + $(element).val() + '"]', this.$container);
if ($(element).is(':disabled')) {
checkbox.attr('disabled', 'disabled').prop('disabled', 'disabled').parents('li').addClass('disabled')
}
checkbox.prop('checked', selected);
if (selected) {
checkbox.parents('li').addClass('active');
}
},
// Build the dropdown and bind event handling.
buildDrowdown: function() {
if ($('optgroup', this.$select).length > 0) {
$('optgroup', this.$select).each($.proxy(function(index, group) {
var groupName = $(group).prop('label');
// Add a header for the group.
$('ul', this.$container).append('<li><label style="margin:0;padding:3px 20px 3px 20px;width:100%;height:100%;" class="multiselect-group"> ' + groupName + '</label></li>');
// Add the options of the group.
$('option', group).each($.proxy(function(index, element) {
this.createOptionValue(element);
}, this));
}, this));
}
else {
$('option', this.$select).each($.proxy(function(index, element) {
this.createOptionValue(element);
}, this));
}
// Bind the change event on the dropdown elements.
$('ul li input[type="checkbox"]', this.$container).on('change', $.proxy(function(event) {
var checked = $(event.target).prop('checked') || false;
if (checked) {
$(event.target).parents('li').addClass('active');
}
else {
$(event.target).parents('li').removeClass('active');
}
var option = $('option[value="' + $(event.target).val() + '"]', this.$select);
if (checked) {
option.attr('selected', 'selected');
option.prop('selected', 'selected');
}
else {
option.removeAttr('selected');
}
var options = $('option:selected', this.$select);
$('button', this.$container).html(this.options.buttonText(options, this.$select));
this.options.onChange(option, checked);
}, this));
$('ul li a', this.$container).on('click', function(event) {
event.stopPropagation();
});
},
// Destroy - unbind - the plugin.
destroy: function() {
this.$container.remove();
this.$select.show();
},
// Refreshs the checked options based on the current state of the select.
refresh: function() {
$('option', this.$select).each($.proxy(function(index, element) {
if ($(element).is(':selected')) {
$('ul li input[value="' + $(element).val() + '"]', this.$container).prop('checked', true);
$('ul li input[value="' + $(element).val() + '"]', this.$container).parents('li').addClass('active');
}
else {
$('ul li input[value="' + $(element).val() + '"]', this.$container).prop('checked', false);
$('ul li input[value="' + $(element).val() + '"]', this.$container).parents('li').removeClass('active');
}
}, this));
$('button', this.$container).html(this.options.buttonText($('option:selected', this.$select), this.$select));
},
// Select an option by its value.
select: function(value) {
var option = $('option[value="' + value + '"]', this.$select);
var checkbox = $('ul li input[value="' + value + '"]', this.$container);
checkbox.parents('li').addClass('active');
checkbox.prop('checked', true);
option.attr('selected', 'selected');
option.prop('selected', 'selected');
var options = $('option:selected', this.$select);
$('button', this.$container).html(this.options.buttonText(options, this.$select));
},
// Deselect an option by its value.
deselect: function(value) {
var option = $('option[value="' + value + '"]', this.$select);
var checkbox = $('ul li input[value="' + value + '"]', this.$container);
checkbox.parents('li').removeClass('active');
checkbox.prop('checked', false);
option.removeAttr('selected');
option.removeProp('selected');
var options = $('option:selected', this.$select);
$('button', this.$container).html(this.options.buttonText(options, this.$select));
},
// Rebuild the whole dropdown menu.
rebuild: function() {
$('ul', this.$container).html('');
this.buildDrowdown(this.$select, this.options);
},
// Get options by merging defaults and given options.
getOptions: function(options) {
return $.extend({}, this.defaults, options);
}
};
$.fn.multiselect = function (option, parameter) {
return this.each(function () {
var data = $(this).data('multiselect'),
options = typeof option == 'object' && option;
// Initialize the multiselect.
if (!data) {
$(this).data('multiselect', (data = new Multiselect(this, options)));
}
// Call multiselect method.
if (typeof option == 'string') {
data[option](parameter);
}
});
}
}(window.jQuery);
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