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