Commit e9ccd61b authored by Mike Eggleston's avatar Mike Eggleston

Update bootstrap-multiselect.js

This allows for the handling of optgroups as a header inside of the dropdown.
parent 29f64e4d
...@@ -18,50 +18,50 @@ ...@@ -18,50 +18,50 @@
*/ */
!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.options = this.getOptions(options);
this.$select = $(select); 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) // Manually add the multiple attribute, if its not already set.
.append('<button type="button" class="multiselect dropdown-toggle ' + this.options.buttonClass + '" data-toggle="dropdown">' + this.options.buttonText($('option:selected', select)) + '</button>') if (!this.$select.attr('multiple')) {
.append('<ul class="dropdown-menu"></ul>'); 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) { if (this.options.buttonWidth) {
$('button', this.$container).css({ $('button', this.$container).css({
...@@ -69,191 +69,206 @@ ...@@ -69,191 +69,206 @@
}); });
} }
// Set max height of dropdown menu to activate auto scrollbar. // Set max height of dropdown menu to activate auto scrollbar.
if (this.options.maxHeight) { if (this.options.maxHeight) {
$('ul', this.$container).css({ $('ul', this.$container).css({
'max-height': this.options.maxHeight + 'px', 'max-height': this.options.maxHeight + 'px',
'overflow-y': 'auto', 'overflow-y': 'auto',
'overflow-x': 'hidden' 'overflow-x': 'hidden'
}); });
} }
this.buildDrowdown(select, this.options); this.buildDrowdown(select, this.options);
this.$select this.$select
.hide() .hide()
.after(this.$container); .after(this.$container);
}; };
Multiselect.prototype = { Multiselect.prototype = {
defaults: { defaults: {
// Default text function will either print 'None selected' in case no option is selected, // 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. // 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. // If more than 3 options are selected, the number of selected options is printed.
buttonText: function(options) { buttonText: function(options) {
if (options.length == 0) { if (options.length == 0) {
return 'None selected <b class="caret"></b>'; return 'None selected <b class="caret"></b>';
} }
else if (options.length > 3) { else if (options.length > 3) {
return options.length + ' selected <b class="caret"></b>'; return options.length + ' selected <b class="caret"></b>';
} }
else { else {
var selected = ''; var selected = '';
options.each(function() { options.each(function() {
selected += $(this).text() + ', '; 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. // Is triggered on change of the selected options.
onChange: function(option, checked) { onChange: function(option, checked) {
}, },
buttonClass: 'btn', buttonClass: 'btn',
buttonWidth: 'auto', buttonWidth: 'auto',
buttonContainer: '<div class="btn-group" />', buttonContainer: '<div class="btn-group" />',
// Maximum height of thet dropdown menu. // Maximum height of thet dropdown menu.
// If maximum height is exceeded a scrollbar will be displayed. // If maximum height is exceeded a scrollbar will be displayed.
maxHeight: 400 maxHeight: 400,
}, showGroups: false,
},
isMobile: function() { isMobile: function() {
return navigator.userAgent.match(/Android|webOS|iPhone|iPad|iPod|BlackBerry/i); return navigator.userAgent.match(/Android|webOS|iPhone|iPad|iPod|BlackBerry/i);
}, },
constructor: Multiselect, constructor: Multiselect,
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');
}
},
buildDrowdown: function(select, options){ buildDrowdown: function(select, options){
// Build the dropdown. // Build the dropdown.
$('option', this.$select).each($.proxy(function(index, element) { if ((this.options.showGroups) && ($('optgroup', this.$select).length > 0)) {
if ($(element).is(':selected')) { $('optgroup', this.$select).each($.proxy(function(index, group) {
$(element).attr('selected', 'selected'); var groupName = $(group).prop('label');
$(element).prop('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', group).each($.proxy(function(index, element) {
this.createOptionValue(element);
$('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>'); }, this));
}, this));
var selected = $(element).prop('selected') || false; } else {
var checkbox = $('ul li input[value="' + $(element).val() + '"]', this.$container); $('option', this.$select).each($.proxy(function(index, element) {
this.createOptionValue(element);
if ($(element).is(':disabled')) { }, this));
checkbox.attr('disabled', 'disabled').prop('disabled', 'disabled').parents('li').addClass('disabled') }
}
// Bind the change event on the dropdown elements.
checkbox.prop('checked', selected); $('ul li input[type="checkbox"]', this.$container).on('change', $.proxy(function(event) {
var checked = $(event.target).prop('checked') || false;
if (selected) {
checkbox.parents('li').addClass('active'); if (checked) {
} $(event.target).parents('li').addClass('active');
}, this)); }
else {
// Bind the change event on the dropdown elements. $(event.target).parents('li').removeClass('active');
$('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) {
$(event.target).parents('li').addClass('active'); if (checked) {
} option.attr('selected', 'selected');
else { option.prop('selected', 'selected');
$(event.target).parents('li').removeClass('active'); }
} else {
option.removeAttr('selected');
var option = $('option[value="' + $(event.target).val() + '"]', this.$select); }
if (checked) { var options = $('option:selected', this.$select);
option.attr('selected', 'selected'); $('button', this.$container).html(this.options.buttonText(options));
option.prop('selected', 'selected');
} this.options.onChange(option, checked);
else { }, this));
option.removeAttr('selected');
} $('ul li a', this.$container).on('click', function(event) {
event.stopPropagation();
var options = $('option:selected', this.$select); });
$('button', this.$container).html(this.options.buttonText(options)); },
this.options.onChange(option, checked); // Destroy - unbind - the plugin.
}, this)); destroy: function() {
this.$container.remove();
$('ul li a', this.$container).on('click', function(event) { this.$select.show();
event.stopPropagation(); },
});
}, // Refreshs the checked options based on the current state of the select.
refresh: function() {
// Destroy - unbind - the plugin. $('option', this.$select).each($.proxy(function(index, element) {
destroy: function() { if ($(element).is(':selected')) {
this.$container.remove(); $('ul li input[value="' + $(element).val() + '"]', this.$container).prop('checked', true);
this.$select.show(); $('ul li input[value="' + $(element).val() + '"]', this.$container).parents('li').addClass('active');
}, }
else {
// Refreshs the checked options based on the current state of the select. $('ul li input[value="' + $(element).val() + '"]', this.$container).prop('checked', false);
refresh: function() { $('ul li input[value="' + $(element).val() + '"]', this.$container).parents('li').removeClass('active');
$('option', this.$select).each($.proxy(function(index, element) { }
if ($(element).is(':selected')) { }, this));
$('ul li input[value="' + $(element).val() + '"]', this.$container).prop('checked', true);
$('ul li input[value="' + $(element).val() + '"]', this.$container).parents('li').addClass('active'); $('button', this.$container).html(this.options.buttonText($('option:selected', this.$select)));
} },
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) { select: function(value) {
var option = $('option[value="' + value + '"]', this.$select); var option = $('option[value="' + value + '"]', this.$select);
var checkbox = $('ul li input[value="' + value + '"]', this.$container); var checkbox = $('ul li input[value="' + value + '"]', this.$container);
checkbox.parents('li').addClass('active'); checkbox.parents('li').addClass('active');
checkbox.prop('checked', true); checkbox.prop('checked', true);
option.attr('selected', 'selected'); option.attr('selected', 'selected');
option.prop('selected', 'selected'); option.prop('selected', 'selected');
var options = $('option:selected', this.$select); var options = $('option:selected', this.$select);
$('button', this.$container).html(this.options.buttonText(options)); $('button', this.$container).html(this.options.buttonText(options));
}, },
deselect: function(value) { deselect: function(value) {
var option = $('option[value="' + value + '"]', this.$select); var option = $('option[value="' + value + '"]', this.$select);
var checkbox = $('ul li input[value="' + value + '"]', this.$container); var checkbox = $('ul li input[value="' + value + '"]', this.$container);
checkbox.parents('li').removeClass('active'); checkbox.parents('li').removeClass('active');
checkbox.prop('checked', false); checkbox.prop('checked', false);
option.removeAttr('selected'); option.removeAttr('selected');
option.removeProp('selected'); option.removeProp('selected');
var options = $('option:selected', this.$select); var options = $('option:selected', this.$select);
$('button', this.$container).html(this.options.buttonText(options)); $('button', this.$container).html(this.options.buttonText(options));
}, },
rebuild: function() { rebuild: function() {
$('ul', this.$container).html(''); $('ul', this.$container).html('');
this.buildDrowdown(this.$select, this.options); this.buildDrowdown(this.$select, this.options);
}, },
// Get options by merging defaults and given options. // Get options by merging defaults and given options.
getOptions: function(options) { getOptions: function(options) {
return $.extend({}, this.defaults, options); return $.extend({}, this.defaults, options);
} }
}; };
$.fn.multiselect = function (option, parameter) { $.fn.multiselect = function (option, parameter) {
return this.each(function () { return this.each(function () {
var data = $(this).data('multiselect'), var data = $(this).data('multiselect'),
options = typeof option == 'object' && option; options = typeof option == 'object' && option;
if (!data) { if (!data) {
$(this).data('multiselect', (data = new Multiselect(this, options))); $(this).data('multiselect', (data = new Multiselect(this, options)));
} }
if (typeof option == 'string') { if (typeof option == 'string') {
data[option](parameter); 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