Skip to content

Commit 6241c2e

Browse files
committed
Merge pull request #17 from Devristo/master
KnockoutJS data binding support.
2 parents 0bafa7c + 00ebed1 commit 6241c2e

File tree

1 file changed

+200
-163
lines changed

1 file changed

+200
-163
lines changed

js/bootstrap-multiselect.js

Lines changed: 200 additions & 163 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
/**
22
* bootstrap-multiselect.js 1.0.0
33
* https://github.com/davidstutz/bootstrap-multiselect
4-
*
5-
* Copyright 2012 David Stutz
6-
*
4+
*
5+
* Copyright 2012 David Stutz
6+
*
77
* Licensed under the Apache License, Version 2.0 (the "License");
88
* you may not use this file except in compliance with the License.
99
* You may obtain a copy of the License at
@@ -18,163 +18,200 @@
1818
*/
1919
!function ($) {
2020

21-
"use strict"; // jshint ;_;
22-
23-
function Multiselect(select, options) {
24-
25-
this.options = this.getOptions(options);
26-
this.select = $(select);
27-
this.container = $(this.options.buttonContainer)
28-
.append('<button type="button" style="width:' + this.options.buttonWidth + '" class="dropdown-toggle ' + this.options.buttonClass + '" data-toggle="dropdown">' + this.options.buttonText($('option:selected', select)) + '</button>')
29-
.append('<ul class="dropdown-menu"></ul>');
30-
31-
// Set max height of dropdown menu to activate auto scrollbar.
32-
if (this.options.maxHeight) {
33-
$('ul', this.container).css({
34-
'max-height': this.options.maxHeight + 'px',
35-
'overflow-y': 'auto',
36-
'overflow-x': 'hidden',
37-
});
38-
}
39-
40-
// Manually add the multiple attribute, if its not already set.
41-
if (!this.select.attr('multiple')) {
42-
this.select.attr('multiple', true);
43-
}
44-
45-
// Build the dropdown.
46-
$('option', this.select).each($.proxy(function(index, element) {
47-
if ($(element).is(':selected')) {
48-
$(element).attr('selected', 'selected');
49-
$(element).prop('selected', 'selected');
50-
}
51-
52-
$('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>');
53-
54-
var selected = $(element).prop('selected') || false;
55-
var checkbox = $('ul li input[value="' + $(element).val() + '"]', this.container);
56-
57-
checkbox.prop('checked', selected);
58-
59-
if (selected) {
60-
checkbox.parents('li').addClass('active');
61-
}
62-
}, this));
63-
64-
this.select.hide()
65-
.after(this.container);
66-
67-
// Bind the change event on the dropdown elements.
68-
$('ul li input[type="checkbox"]', this.container).on('change', $.proxy(function(event) {
69-
var checked = $(event.target).prop('checked') || false;
70-
71-
if (checked) {
72-
$(event.target).parents('li').addClass('active');
73-
}
74-
else {
75-
$(event.target).parents('li').removeClass('active');
76-
}
77-
78-
var option = $('option[value="' + $(event.target).val() + '"]', this.select);
79-
80-
if (checked) {
81-
option.attr('selected', 'selected');
82-
option.prop('selected', 'selected');
83-
}
84-
else {
85-
option.removeAttr('selected');
86-
}
87-
console.log(option);
88-
var options = $('option:selected', this.select);
89-
$('button', this.container).html(this.options.buttonText(options));
90-
91-
this.options.onChange(option, checked);
92-
}, this));
93-
94-
$('ul li a', this.container).on('click', function(event) {
95-
event.stopPropagation();
96-
});
97-
};
98-
99-
Multiselect.prototype = {
100-
101-
defaults: {
102-
// Default text function will either print 'None selected' in case no option is selected,
103-
// or a list of the selected options up to a length of 3 selected options.
104-
// If more than 3 options are selected, the number of selected options is printed.
105-
buttonText: function(options) {
106-
if (options.length == 0) {
107-
return 'None selected <b class="caret"></b>';
108-
}
109-
else if (options.length > 3) {
110-
return options.length + ' selected <b class="caret"></b>';
111-
}
112-
else {
113-
var selected = '';
114-
options.each(function() {
115-
selected += $(this).text() + ', ';
116-
});
117-
return selected.substr(0, selected.length -2) + ' <b class="caret"></b>';
118-
}
119-
},
120-
// Is triggered on change of the selected options.
121-
onChange: function() {
122-
123-
},
124-
buttonClass: 'btn',
125-
buttonWidth: 'auto',
126-
buttonContainer: '<div class="btn-group" />',
127-
// Maximum height of thet dropdown menu.
128-
// If maximum height is exceeded a scrollbar will be displayed.
129-
maxHeight: 400,
130-
},
131-
132-
constructor: Multiselect,
133-
134-
reset: function() {
135-
136-
},
137-
138-
// Destroy - unbind - the plugin.
139-
destroy: function() {
140-
this.container.remove();
141-
this.select.show();
142-
},
143-
144-
// Refreshs the checked options based on the current state of the select.
145-
refresh: function() {
146-
$('option', this.select).each($.proxy(function(index, element) {
147-
if ($(element).is(':selected')) {
148-
$('ul li input[value="' + $(element).val() + '"]', this.container).prop('checked', true);
149-
$('ul li input[value="' + $(element).val() + '"]', this.container).parents('li').addClass('active');
150-
}
151-
else {
152-
$('ul li input[value="' + $(element).val() + '"]', this.container).prop('checked', false);
153-
$('ul li input[value="' + $(element).val() + '"]', this.container).parents('li').removeClass('active');
154-
}
155-
}, this));
156-
157-
$('button', this.container).html(this.options.buttonText($('option:selected', this.select)));
158-
},
159-
160-
// Get options by merging defaults and given options.
161-
getOptions: function(options) {
162-
return $.extend({}, this.defaults, options);
163-
}
164-
};
165-
166-
$.fn.multiselect = function (option) {
167-
return this.each(function () {
168-
var data = $(this).data('multiselect'),
169-
options = typeof option == 'object' && option;
170-
171-
if (!data) {
172-
$(this).data('multiselect', (data = new Multiselect(this, options)));
173-
}
174-
175-
if (typeof option == 'string') {
176-
data[option]();
177-
}
178-
});
179-
}
180-
}(window.jQuery);
21+
"use strict"; // jshint ;_;
22+
23+
if(ko && ko.bindingHandlers && !ko.bindingHandlers.multiselect){
24+
ko.bindingHandlers.multiselect = {
25+
init: function (element) {
26+
var ms = $(element).data('multiselect');
27+
28+
if(!ms)
29+
throw new Error("Bootstrap-multiselect's multiselect() has to be called on element before applying the Knockout View model!");
30+
31+
var prev = ms.options.onChange;
32+
33+
ms.options.onChange = function(option, checked){
34+
// We dont want to refresh the multiselect since it would delete / recreate all items
35+
$(element).data('blockRefresh', true);
36+
37+
// Force the binding to be updated by triggering the change event on the select element
38+
$(element).trigger('change');
39+
40+
// Call any defined change handler
41+
return prev(option, checked);
42+
}
43+
},
44+
update: function (element) {
45+
var blockRefresh = $(element).data('blockRefresh') || false;
46+
if (!blockRefresh) { $(element).multiselect("refresh"); }
47+
$.data(element, 'blockRefresh', false);
48+
}
49+
};
50+
}
51+
52+
function Multiselect(select, options) {
53+
54+
this.options = this.getOptions(options);
55+
this.select = $(select);
56+
this.container = $(this.options.buttonContainer)
57+
.append('<button type="button" class="dropdown-toggle ' + this.options.buttonClass + '" data-toggle="dropdown">' + this.options.buttonText($('option:selected', select)) + '</button>')
58+
.append('<ul class="dropdown-menu"></ul>');
59+
60+
// Set max height of dropdown menu to activate auto scrollbar.
61+
if (this.options.maxHeight) {
62+
$('ul', this.container).css({
63+
'max-height': this.options.maxHeight + 'px',
64+
'overflow-y': 'auto',
65+
'overflow-x': 'hidden',
66+
});
67+
}
68+
69+
// Manually add the multiple attribute, if its not already set.
70+
if (!this.select.attr('multiple')) {
71+
this.select.attr('multiple', true);
72+
}
73+
74+
this.addOptions(select, options);
75+
76+
this.select
77+
.hide()
78+
.after(this.container);
79+
};
80+
81+
Multiselect.prototype = {
82+
addOptions: function(select, options){
83+
84+
85+
// Build the dropdown.
86+
$('option', this.select).each($.proxy(function(index, element) {
87+
if ($(element).is(':selected')) {
88+
$(element).attr('selected', 'selected');
89+
$(element).prop('selected', 'selected');
90+
}
91+
92+
$('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>');
93+
94+
var selected = $(element).prop('selected') || false;
95+
var checkbox = $('ul li input[value="' + $(element).val() + '"]', this.container);
96+
97+
checkbox.prop('checked', selected);
98+
99+
if (selected) {
100+
checkbox.parents('li').addClass('active');
101+
}
102+
}, this));
103+
104+
// Bind the change event on the dropdown elements.
105+
$('ul li input[type="checkbox"]', this.container).on('change', $.proxy(function(event) {
106+
var checked = $(event.target).prop('checked') || false;
107+
108+
if (checked) {
109+
$(event.target).parents('li').addClass('active');
110+
}
111+
else {
112+
$(event.target).parents('li').removeClass('active');
113+
}
114+
115+
var option = $('option[value="' + $(event.target).val() + '"]', this.select);
116+
117+
if (checked) {
118+
option.attr('selected', 'selected');
119+
option.prop('selected', 'selected');
120+
}
121+
else {
122+
option.removeAttr('selected');
123+
}
124+
console.log(option);
125+
var options = $('option:selected', this.select);
126+
$('button', this.container).html(this.options.buttonText(options));
127+
128+
this.options.onChange(option, checked);
129+
}, this));
130+
131+
$('ul li a', this.container).on('click', function(event) {
132+
event.stopPropagation();
133+
});
134+
},
135+
defaults: {
136+
// Default text function will either print 'None selected' in case no option is selected,
137+
// or a list of the selected options up to a length of 3 selected options.
138+
// If more than 3 options are selected, the number of selected options is printed.
139+
buttonText: function(options) {
140+
if (options.length == 0) {
141+
return 'None selected <b class="caret"></b>';
142+
}
143+
else if (options.length > 3) {
144+
return options.length + ' selected <b class="caret"></b>';
145+
}
146+
else {
147+
var selected = '';
148+
options.each(function() {
149+
selected += $(this).text() + ', ';
150+
});
151+
return selected.substr(0, selected.length -2) + ' <b class="caret"></b>';
152+
}
153+
},
154+
// Is triggered on change of the selected options.
155+
onChange: function() {
156+
157+
},
158+
buttonClass: 'btn',
159+
buttonWidth: 'auto',
160+
buttonContainer: '<div class="btn-group" />',
161+
// Maximum height of thet dropdown menu.
162+
// If maximum height is exceeded a scrollbar will be displayed.
163+
maxHeight: 400,
164+
},
165+
166+
constructor: Multiselect,
167+
168+
reset: function() {
169+
170+
},
171+
172+
// Destroy - unbind - the plugin.
173+
destroy: function() {
174+
this.container.remove();
175+
this.select.show();
176+
},
177+
178+
// Refreshs the checked options based on the current state of the select.
179+
refresh: function() {
180+
$('ul', this.container).html('');
181+
this.addOptions(this.select, this.options);
182+
183+
$('option', this.select).each($.proxy(function(index, element) {
184+
if ($(element).is(':selected')) {
185+
$('ul li input[value="' + $(element).val() + '"]', this.container).prop('checked', true);
186+
$('ul li input[value="' + $(element).val() + '"]', this.container).parents('li').addClass('active');
187+
}
188+
else {
189+
$('ul li input[value="' + $(element).val() + '"]', this.container).prop('checked', false);
190+
$('ul li input[value="' + $(element).val() + '"]', this.container).parents('li').removeClass('active');
191+
}
192+
}, this));
193+
194+
$('button', this.container).html(this.options.buttonText($('option:selected', this.select)));
195+
},
196+
197+
// Get options by merging defaults and given options.
198+
getOptions: function(options) {
199+
return $.extend({}, this.defaults, options);
200+
}
201+
};
202+
203+
$.fn.multiselect = function (option) {
204+
return this.each(function () {
205+
var data = $(this).data('multiselect'),
206+
options = typeof option == 'object' && option;
207+
208+
if (!data) {
209+
$(this).data('multiselect', (data = new Multiselect(this, options)));
210+
}
211+
212+
if (typeof option == 'string') {
213+
data[option]();
214+
}
215+
});
216+
}
217+
}(window.jQuery);

0 commit comments

Comments
 (0)