Commit 0a857a08 authored by David Stutz's avatar David Stutz

Fixed #109, #113.

Moved CSS declarations into separate LESS file. Filter will now be
rebuild, too.
parent 29f1ab30
This source diff could not be displayed because it is too large. You can view the blob instead.
.multiselect-container{position:absolute;list-style-type:none;margin:0;padding:0}.multiselect-container input[type="text"]{width:70%}.multiselect-container .input-prepend{padding:3px}.multiselect-container>li{padding:0}.multiselect-container>li>label{margin:0;padding:3px 20px 3px 20px;height:100%;cursor:pointer}.multiselect-container>li>label.multiselect-header{margin:0;padding:3px 20px 3px 20px;height:100%}.multiselect-container>li>label>input[type="checkbox"]{margin-bottom:5px}
\ No newline at end of file
......@@ -7,6 +7,7 @@
<meta name="copyright" content="David Stutz" />
<link rel="stylesheet" href="css/bootstrap-2.3.2.min.css" type="text/css">
<link rel="stylesheet" href="css/bootstrap-multiselect.css" type="text/css">
<link rel="stylesheet" href="css/prettify.css" type="text/css">
<script type="text/javascript" src="js/jquery-2.0.1.min.js"></script>
......@@ -587,7 +588,8 @@
});
$('#example12').multiselect({
buttonContainer: '<span />'
buttonContainer: '<span />',
enableFiltering: true
});
$('#example12-rebuild').on('click', function() {
$('#example12').multiselect('rebuild');
......@@ -1297,7 +1299,7 @@
<div class="add-styling">
<table class="table table-striped">
<tr>
<td>
<td width="30%">
<select id="example15" multiple="multiple">
<optgroup label="Mathematics">
<option value="analysis">Analysis</option>
......@@ -1314,10 +1316,10 @@
</optgroup>
</select>
</td>
<td>
<td width="30%">
Text alignment combined with fixed width and bold, underlined text for option group headers.
</td>
<td>
<td width="40%">
<pre class="prettyprint linenums">
.multiselect {
text-align: left;
......
......@@ -16,494 +16,515 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
!function ($) {
"use strict"; // jshint ;_;
if(typeof ko != 'undefined' && ko.bindingHandlers && !ko.bindingHandlers.multiselect){
ko.bindingHandlers.multiselect = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {},
update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var ms = $(element).data('multiselect');
if (!ms) {
$(element).multiselect(ko.utils.unwrapObservable(valueAccessor()));
}
else if (allBindingsAccessor().options && allBindingsAccessor().options().length !== ms.originalOptions.length) {
ms.updateOriginalOptions();
$(element).multiselect('rebuild');
}
}
};
}
function Multiselect(select, options) {
this.options = this.getOptions(options);
this.$select = $(select);
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' : '') + '" style="position:absolute; list-style-type: none;margin:0;padding:0;"></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) {
$('.multiselect-container', this.$container).css({
'max-height': this.options.maxHeight + 'px',
'overflow-y': 'auto',
'overflow-x': 'hidden'
});
$('input[type="text"]', this.$container).width('75%');
}
// Enable filtering.
if (this.options.enableFiltering || this.options.enableCaseInsensitiveFiltering) {
$('.multiselect-container', this.$container).prepend('<div class="input-prepend" style="padding:3px;"><span class="add-on"><i class="icon-search"></i></span><input class="multiselect-search" type="text" placeholder="' + this.options.filterPlaceholder + '"></div>');
$('.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;
}
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), 300, this);
}, this));
}
this.buildDropdown();
this.updateButtonText();
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() {
var label = ($(this).attr('label') !== undefined) ? $(this).attr('label') : $(this).text();
selected += label + ', ';
});
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',
dropRight: false,
selectedClass: 'active',
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,
includeSelectAllOption: false,
selectAllText: ' Select all',
selectAllValue: 'multiselect-all',
enableFiltering: false,
enableCaseInsensitiveFiltering: false,
filterPlaceholder: 'Search',
filterBehavior: 'text' // possible options: 'text', 'value', 'both'
},
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);
}
// Support the label attribute on options.
var label = $(element).attr('label') || $(element).text();
var value = $(element).val();
var inputType = this.options.multiple ? "checkbox" : "radio";
var $li = $('<li><a href="javascript:void(0);" style="padding:0;"><label style="margin:0;padding:3px 20px 3px 20px;height:100%;cursor:pointer;"><input style="margin-bottom:5px;" 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');
}
$('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');
}
$checkbox.prop('checked', selected);
if (selected && this.options.selectedClass) {
$checkbox.parents('li').addClass(this.options.selectedClass);
}
},
toggleActiveState: function (shouldBeActive) {
if (this.$select.attr('disabled') == undefined) {
$('button.multiselect.dropdown-toggle', this.$container).removeClass('disabled');
}
else {
$('button.multiselect.dropdown-toggle', this.$container).addClass('disabled');
}
},
// Build the dropdown and bind event handling.
buildDropdown: 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>');
}
this.toggleActiveState();
this.$select.children().each($.proxy(function (index, element) {
// Support optgroups and options without a group simultaneously.
var tag = $(element).prop('tagName').toLowerCase();
if (tag == 'optgroup') {
var group = element;
var groupName = $(group).prop('label');
// Add a header for the group.
var $li = $('<li><label style="margin:0;padding:3px 20px 3px 20px;height:100%;" 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));
}
else if (tag == 'option') {
this.createOptionValue(element);
}
else {
// Ignore illegal tags.
}
}, this));
// Bind the change event on the dropdown elements.
$('.multiselect-container li input', this.$container).on('change', $.proxy(function (event) {
var checked = $(event.target).prop('checked') || false;
var isSelectAllOption = $(event.target).val() == this.options.selectAllValue;
// Apply or unapply the configured selected class.
if (this.options.selectedClass) {
if (checked) {
$(event.target).parents('li').addClass(this.options.selectedClass);
}
else {
$(event.target).parents('li').removeClass(this.options.selectedClass);
}
}
var $option = $('option', this.$select).filter(function() {
return $(this).val() == $(event.target).val();
});
var $optionsNotThis = $('option', this.$select).not($option);
var $checkboxesNotThis = $('input', this.$container).not($(event.target));
// Toggle all options if the select all option was changed.
if (isSelectAllOption) {
$checkboxesNotThis.filter(function () { return $(this).is(':checked') != checked; }).trigger('click');
}
if (checked) {
$option.prop('selected', true);
if (this.options.multiple) {
$option.attr('selected', 'selected');
}
else {
if (this.options.selectedClass) {
$($checkboxesNotThis).parents('li').removeClass(this.options.selectedClass);
}
$($checkboxesNotThis).prop('checked', false);
$optionsNotThis.removeAttr('selected').prop('selected', false);
// It's a single selection, so close.
$(this.$container).find(".multiselect.dropdown-toggle").click();
}
if (this.options.selectedClass == "active") {
$optionsNotThis.parents("a").css("outline", "");
}
}
else {
$option.removeAttr('selected').prop('selected', false);
}
this.updateButtonText();
this.options.onChange($option, checked);
this.$select.change();
}, this));
$('.multiselect-container li a', this.$container).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')) return;
if ((event.keyCode == 9 || event.keyCode == 27) && this.$container.hasClass('open')) {
// Close on tab or escape.
$(this.$container).find(".multiselect.dropdown-toggle").click();
}
else {
var $items = $(this.$container).find("li:not(.divider):visible a");
if (!$items.length) {
return;
}
var index = $items.index($items.filter(':focus'));
// Navigation up.
if (event.keyCode == 38 && index > 0) {
index--;
}
// Navigate down.
else if (event.keyCode == 40 && index < $items.length - 1) {
index++;
}
else if (!~index) {
index = 0;
}
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');
$checkbox.prop("checked", !$checkbox.prop("checked"));
$checkbox.change();
}
event.stopPropagation();
event.preventDefault();
}
}, this));
},
// 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) {
var $input = $('.multiselect-container li input', this.$container).filter(function () {
return $(this).val() == $(element).val();
});
if ($(element).is(':selected')) {
$input.prop('checked', true);
if (this.options.selectedClass) {
$input.parents('li').addClass(this.options.selectedClass);
}
}
else {
$input.prop('checked', false);
if (this.options.selectedClass) {
$input.parents('li').removeClass(this.options.selectedClass);
}
}
if ($(element).is(":disabled")) {
$input.attr('disabled', 'disabled').prop('disabled', true).parents('li').addClass('disabled');
}
else {
$input.removeAttr('disabled').prop('disabled', false).parents('li').removeClass('disabled');
}
}, this));
this.updateButtonText();
},
// Select an option by its value.
select: function(value) {
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;
});
if (this.options.selectedClass) {
$checkbox.parents('li').addClass(this.options.selectedClass);
}
$checkbox.prop('checked', true);
$option.attr('selected', 'selected').prop('selected', true);
this.updateButtonText();
this.options.onChange($option, checked);
},
// Deselect an option by its value.
deselect: function(value) {
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;
});
if (this.options.selectedClass) {
$checkbox.parents('li').removeClass(this.options.selectedClass);
}
$checkbox.prop('checked', false);
$option.removeAttr('selected').prop('selected', false);
this.updateButtonText();
},
// Rebuild the whole dropdown menu.
rebuild: function() {
$('.multiselect-container', this.$container).html('');
this.buildDropdown(this.$select, this.options);
this.updateButtonText();
},
// Get options by merging defaults and given options.
getOptions: function(options) {
return $.extend({}, this.defaults, options);
},
updateButtonText: function() {
var options = this.getSelected();
$('button', this.$container).html(this.options.buttonText(options, this.$select));
},
// Get all selected options.
getSelected: function () {
return $('option:selected[value!="' + this.options.selectAllValue + '"]', this.$select);
},
updateOriginalOptions: function() {
this.originalOptions = this.$select.clone()[0].options;
},
asyncFunction: function (callback, timeout, self) {
var args = Array.prototype.slice.call(arguments, 3);
return setTimeout(function () {
callback.apply(self || window, args);
}, timeout);
}
};
!function($) {"use strict";// jshint ;_;
if ( typeof ko != 'undefined' && ko.bindingHandlers && !ko.bindingHandlers.multiselect) {
ko.bindingHandlers.multiselect = {
init : function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
},
update : function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var ms = $(element).data('multiselect');
if (!ms) {
$(element).multiselect(ko.utils.unwrapObservable(valueAccessor()));
}
else
if (allBindingsAccessor().options && allBindingsAccessor().options().length !== ms.originalOptions.length) {
ms.updateOriginalOptions();
$(element).multiselect('rebuild');
}
}
};
}
function Multiselect(select, options) {
this.options = this.getOptions(options);
this.$select = $(select);
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>');
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) {
// 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) {
this.buildFilter();
}
this.buildDropdown();
this.updateButtonText();
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() {
var label = ($(this).attr('label') !== undefined) ? $(this).attr('label') : $(this).text();
selected += label + ', ';
});
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',
dropRight : false,
selectedClass : 'active',
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,
includeSelectAllOption : false,
selectAllText : ' Select all',
selectAllValue : 'multiselect-all',
enableFiltering : false,
enableCaseInsensitiveFiltering : false,
filterPlaceholder : 'Search',
// possible options: 'text', 'value', 'both'
filterBehavior : 'text'
},
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);
}
// Support the label attribute on options.
var label = $(element).attr('label') || $(element).text();
var value = $(element).val();
var inputType = this.options.multiple ? "checkbox" : "radio";
var $li = $('<li><a href="javascript:void(0);"><label><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');
}
$('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');
}
$checkbox.prop('checked', selected);
if (selected && this.options.selectedClass) {
$checkbox.parents('li').addClass(this.options.selectedClass);
}
},
toggleActiveState : function(shouldBeActive) {
if (this.$select.attr('disabled') == undefined) {
$('button.multiselect.dropdown-toggle', this.$container).removeClass('disabled');
}
else {
$('button.multiselect.dropdown-toggle', this.$container).addClass('disabled');
}
},
// Build the dropdown and bind event handling.
buildDropdown : 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>');
}
this.toggleActiveState();
this.$select.children().each($.proxy(function(index, element) {
// Support optgroups and options without a group simultaneously.
var tag = $(element).prop('tagName').toLowerCase();
if (tag == 'optgroup') {
var group = element;
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));
}
else
if (tag == 'option') {
this.createOptionValue(element);
}
else {
// Ignore illegal tags.
}
}, this));
// Bind the change event on the dropdown elements.
$('.multiselect-container li input', this.$container).on('change', $.proxy(function(event) {
var checked = $(event.target).prop('checked') || false;
var isSelectAllOption = $(event.target).val() == this.options.selectAllValue;
// Apply or unapply the configured selected class.
if (this.options.selectedClass) {
if (checked) {
$(event.target).parents('li').addClass(this.options.selectedClass);
}
else {
$(event.target).parents('li').removeClass(this.options.selectedClass);
}
}
var $option = $('option', this.$select).filter(function() {
return $(this).val() == $(event.target).val();
});
var $optionsNotThis = $('option', this.$select).not($option);
var $checkboxesNotThis = $('input', this.$container).not($(event.target));
// Toggle all options if the select all option was changed.
if (isSelectAllOption) {
$checkboxesNotThis.filter(function() {
return $(this).is(':checked') != checked;
}).trigger('click');
}
if (checked) {
$option.prop('selected', true);
if (this.options.multiple) {
$option.attr('selected', 'selected');
}
else {
if (this.options.selectedClass) {
$($checkboxesNotThis).parents('li').removeClass(this.options.selectedClass);
}
$($checkboxesNotThis).prop('checked', false);
$optionsNotThis.removeAttr('selected').prop('selected', false);
// It's a single selection, so close.
$(this.$container).find(".multiselect.dropdown-toggle").click();
}
if (this.options.selectedClass == "active") {
$optionsNotThis.parents("a").css("outline", "");
}
}
else {
$option.removeAttr('selected').prop('selected', false);
}
this.updateButtonText();
this.options.onChange($option, checked);
this.$select.change();
}, this));
$('.multiselect-container li a', this.$container).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'))
return;
if ((event.keyCode == 9 || event.keyCode == 27) && this.$container.hasClass('open')) {
// Close on tab or escape.
$(this.$container).find(".multiselect.dropdown-toggle").click();
}
else {
var $items = $(this.$container).find("li:not(.divider):visible a");
if (!$items.length) {
return;
}
var index = $items.index($items.filter(':focus'));
// Navigation up.
if (event.keyCode == 38 && index > 0) {
index--;
}
// Navigate down.
else
if (event.keyCode == 40 && index < $items.length - 1) {
index++;
}
else
if (!~index) {
index = 0;
}
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');
$checkbox.prop("checked", !$checkbox.prop("checked"));
$checkbox.change();
}
event.stopPropagation();
event.preventDefault();
}
}, this));
},
// Build and bind filter.
buildFilter: function() {
$('.multiselect-container', this.$container).prepend('<div class="input-prepend"><span class="add-on"><i class="icon-search"></i></span><input class="multiselect-search" type="text" placeholder="' + this.options.filterPlaceholder + '"></div>');
$('.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;
}
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), 300, this);
}, this));
},
// 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) {
var $input = $('.multiselect-container li input', this.$container).filter(function() {
return $(this).val() == $(element).val();
});
if ($(element).is(':selected')) {
$input.prop('checked', true);
if (this.options.selectedClass) {
$input.parents('li').addClass(this.options.selectedClass);
}
}
else {
$input.prop('checked', false);
if (this.options.selectedClass) {
$input.parents('li').removeClass(this.options.selectedClass);
}
}
if ($(element).is(":disabled")) {
$input.attr('disabled', 'disabled').prop('disabled', true).parents('li').addClass('disabled');
}
else {
$input.removeAttr('disabled').prop('disabled', false).parents('li').removeClass('disabled');
}
}, this));
this.updateButtonText();
},
// Select an option by its value.
select : function(value) {
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;
});
if (this.options.selectedClass) {
$checkbox.parents('li').addClass(this.options.selectedClass);
}
$checkbox.prop('checked', true);
$option.attr('selected', 'selected').prop('selected', true);
this.updateButtonText();
this.options.onChange($option, checked);
},
// Deselect an option by its value.
deselect : function(value) {
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;
});
if (this.options.selectedClass) {
$checkbox.parents('li').removeClass(this.options.selectedClass);
}
$checkbox.prop('checked', false);
$option.removeAttr('selected').prop('selected', false);
this.updateButtonText();
},
// Rebuild the whole dropdown menu.
rebuild : function() {
$('.multiselect-container', this.$container).html('');
this.buildDropdown(this.$select, this.options);
this.updateButtonText();
// Enable filtering.
if (this.options.enableFiltering || this.options.enableCaseInsensitiveFiltering) {
this.buildFilter();
}
},
// Get options by merging defaults and given options.
getOptions : function(options) {
return $.extend({}, this.defaults, options);
},
updateButtonText : function() {
var options = this.getSelected();
$('button', this.$container).html(this.options.buttonText(options, this.$select));
},
// Get all selected options.
getSelected : function() {
return $('option:selected[value!="' + this.options.selectAllValue + '"]', this.$select);
},
updateOriginalOptions : function() {
this.originalOptions = this.$select.clone()[0].options;
},
asyncFunction : function(callback, timeout, self) {
var args = Array.prototype.slice.call(arguments, 3);
return setTimeout(function() {
callback.apply(self || window, args);
}, timeout);
}
};
$.fn.multiselect = function(option, parameter) {
return this.each(function() {
var data = $(this).data('multiselect'),
options = typeof option == 'object' && option;
var data = $(this).data('multiselect'), options = typeof option == 'object' && option;
// Initialize the multiselect.
if (!data) {
$(this).data('multiselect', (data = new Multiselect(this, options)));
$(this).data('multiselect', ( data = new Multiselect(this, options)));
}
// Call multiselect method.
if (typeof option == 'string') {
if ( typeof option == 'string') {
data[option](parameter);
}
});
};
$.fn.multiselect.Constructor = Multiselect;
$(function() {
$("select[data-role=multiselect]").multiselect();
});
$.fn.multiselect.Constructor = Multiselect;
$(function() {
$("select[data-role=multiselect]").multiselect();
});
}(window.jQuery);
......@@ -7,6 +7,7 @@
<meta name="copyright" content="David Stutz" />
<link rel="stylesheet" href="css/bootstrap-3.3.2.min.css" type="text/css">
<link rel="stylesheet" href="css/bootstrap-multiselect.css" type="text/css">
<link rel="stylesheet" href="css/prettify.css" type="text/css">
<script type="text/javascript" src="js/jquery-2.0.1.min.js"></script>
......
.multiselect-container {
position: absolute;
list-style-type: none;
margin: 0;
padding: 0;
input[type="text"] {
width: 70%;
}
.input-prepend {
padding: 3px;
}
> li {
padding: 0;
> label {
margin: 0;
padding: 3px 20px 3px 20px;
height: 100%;
cursor: pointer;
&.multiselect-header {
margin: 0;
padding: 3px 20px 3px 20px;
height: 100%;
}
> input[type="checkbox"] {
margin-bottom:5px;
}
}
}
}
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