Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
B
bootstrap-multiselect
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
bootstrap-multiselect
Commits
8d43ff18
Commit
8d43ff18
authored
Sep 24, 2013
by
David Stutz
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
#162 and tests.
parent
03e9818a
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
163 additions
and
99 deletions
+163
-99
bootstrap-multiselect.js
js/bootstrap-multiselect.js
+59
-54
tests.html
tests.html
+104
-45
No files found.
js/bootstrap-multiselect.js
View file @
8d43ff18
/**
* bootstrap-multiselect.js
1.0.0
* bootstrap-multiselect.js
* https://github.com/davidstutz/bootstrap-multiselect
*
* Copyright 2012, 2013 David Stutz
...
...
@@ -9,17 +9,15 @@
*/
!
function
(
$
)
{
"
use strict
"
;
// jshint ;_;
if
(
typeof
ko
!=
'
undefined
'
&&
ko
.
bindingHandlers
&&
!
ko
.
bindingHandlers
.
multiselect
)
{
if
(
typeof
ko
!=
'
undefined
'
&&
ko
.
bindingHandlers
&&
!
ko
.
bindingHandlers
.
multiselect
)
{
ko
.
bindingHandlers
.
multiselect
=
{
init
:
function
(
element
,
valueAccessor
,
allBindingsAccessor
,
viewModel
,
bindingContext
)
{
},
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
)
{
else
if
(
allBindingsAccessor
().
options
&&
allBindingsAccessor
().
options
().
length
!==
ms
.
originalOptions
.
length
)
{
ms
.
updateOriginalOptions
();
$
(
element
).
multiselect
(
'
rebuild
'
);
}
...
...
@@ -90,9 +88,9 @@
if
(
options
.
length
==
0
)
{
return
this
.
nonSelectedText
+
'
<b class="caret"></b>
'
;
}
else
else
{
if
(
options
.
length
>
3
)
{
return
options
.
length
+
'
'
+
this
.
no
nSelectedText
+
'
<b class="caret"></b>
'
;
return
options
.
length
+
'
'
+
this
.
nSelectedText
+
'
<b class="caret"></b>
'
;
}
else
{
var
selected
=
''
;
...
...
@@ -103,6 +101,7 @@
});
return
selected
.
substr
(
0
,
selected
.
length
-
2
)
+
'
<b class="caret"></b>
'
;
}
}
},
// Like the buttonText option to update the title of the button.
buttonTitle
:
function
(
options
,
select
)
{
...
...
@@ -175,7 +174,22 @@
}
},
toggleActiveState
:
function
(
shouldBeActive
)
{
// Create optgroup.
createOptgroup
:
function
(
group
)
{
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
));
},
toggleActiveState
:
function
()
{
if
(
this
.
$select
.
attr
(
'
disabled
'
)
==
undefined
)
{
$
(
'
button.multiselect.dropdown-toggle
'
,
this
.
$container
).
removeClass
(
'
disabled
'
);
}
...
...
@@ -202,26 +216,12 @@
// 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
));
this
.
createOptgroup
(
element
);
}
else
if
(
tag
==
'
option
'
)
{
else
if
(
tag
==
'
option
'
)
{
this
.
createOptionValue
(
element
);
}
else
{
// Ignore illegal tags.
}
// Other illegal tags will be ignored.
},
this
));
// Bind the change event on the dropdown elements.
...
...
@@ -239,6 +239,7 @@
}
}
// Get the corresponding option.
var
$option
=
$
(
'
option
'
,
this
.
$select
).
filter
(
function
()
{
return
$
(
this
).
val
()
==
$
(
event
.
target
).
val
();
});
...
...
@@ -257,15 +258,16 @@
$option
.
prop
(
'
selected
'
,
true
);
if
(
this
.
options
.
multiple
)
{
// Simply select additional option.
$option
.
attr
(
'
selected
'
,
'
selected
'
);
}
else
{
// Unselect all other options and corresponding checkboxes.
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.
...
...
@@ -275,9 +277,9 @@
if
(
this
.
options
.
selectedClass
==
"
active
"
)
{
$optionsNotThis
.
parents
(
"
a
"
).
css
(
"
outline
"
,
""
);
}
}
else
{
// Unselect option.
$option
.
removeAttr
(
'
selected
'
).
prop
(
'
selected
'
,
false
);
}
...
...
@@ -319,12 +321,10 @@
index
--
;
}
// Navigate down.
else
if
(
event
.
keyCode
==
40
&&
index
<
$items
.
length
-
1
)
{
else
if
(
event
.
keyCode
==
40
&&
index
<
$items
.
length
-
1
)
{
index
++
;
}
else
if
(
!~
index
)
{
else
if
(
!~
index
)
{
index
=
0
;
}
...
...
@@ -358,8 +358,7 @@
$
(
'
.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.
// This is useful to catch "keydown" events after the browser has updated the control.
clearTimeout
(
this
.
searchTimeout
);
this
.
searchTimeout
=
this
.
asyncFunction
(
$
.
proxy
(
function
()
{
...
...
@@ -445,18 +444,21 @@
this
.
updateButtonText
();
},
// Select an option by its value.
// Select an option by its value
or multiple options using an array of values
.
select
:
function
(
selectValues
)
{
if
(
selectValues
&&
!
$
.
isArray
(
selectValues
))
{
selectValues
=
[
selectValues
];
}
for
(
var
i
=
0
;
i
<
selectValues
.
length
;
i
++
)
{
for
(
var
i
=
0
;
i
<
selectValues
.
length
;
i
++
)
{
var
value
=
selectValues
[
i
];
// Find corresponding option.
var
$option
=
$
(
'
option
'
,
this
.
$select
).
filter
(
function
()
{
return
$
(
this
).
val
()
==
value
;
});
// Find corresponding checkbox.
var
$checkbox
=
$
(
'
.multiselect-container li input
'
,
this
.
$container
).
filter
(
function
()
{
return
$
(
this
).
val
()
==
value
;
});
...
...
@@ -474,15 +476,17 @@
this
.
updateButtonText
();
},
// Deselect an option by its value.
// Deselect an option by its value
or using an array of values
.
deselect
:
function
(
deselectValues
)
{
if
(
deselectValues
&&
!
$
.
isArray
(
deselectValues
))
{
deselectValues
=
[
deselectValues
];
}
for
(
var
i
=
0
;
i
<
deselectValues
.
length
;
i
++
)
{
for
(
var
i
=
0
;
i
<
deselectValues
.
length
;
i
++
)
{
var
value
=
deselectValues
[
i
];
// Find option and corresponding checkbox.
var
$option
=
$
(
'
option
'
,
this
.
$select
).
filter
(
function
()
{
return
$
(
this
).
val
()
==
value
;
});
...
...
@@ -508,7 +512,7 @@
$
(
'
.multiselect-container
'
,
this
.
$container
).
html
(
''
);
this
.
buildSelectAll
();
this
.
buildDropdown
(
this
.
$select
,
this
.
options
);
this
.
buildDropdown
();
this
.
updateButtonText
();
// Enable filtering.
...
...
@@ -520,7 +524,6 @@
// Build select using the given data as options.
dataprovider
:
function
(
dataprovider
)
{
var
optionDOM
=
""
;
dataprovider
.
forEach
(
function
(
option
)
{
optionDOM
+=
'
<option value="
'
+
option
.
value
+
'
">
'
+
option
.
label
+
'
</option>
'
;
});
...
...
@@ -534,6 +537,7 @@
return
$
.
extend
({},
this
.
defaults
,
options
);
},
// Update button text and button title.
updateButtonText
:
function
()
{
var
options
=
this
.
getSelected
();
...
...
@@ -580,6 +584,7 @@
$
.
fn
.
multiselect
.
Constructor
=
Multiselect
;
// Automatically init selects by their data-role.
$
(
function
()
{
$
(
"
select[data-role=multiselect]
"
).
multiselect
();
});
...
...
tests.html
View file @
8d43ff18
...
...
@@ -37,6 +37,23 @@
</td>
<td>
Everything fine.
</td>
</tr>
<tr
id=
"test-build-optgroups-tr"
class=
"success"
>
<th>
Test build with optgroups
</th>
<td>
<select
id=
"test-build-optgroups-select"
multiple=
"multiple"
>
<optgroup
label=
"1,2"
>
<option
value=
"1"
selected=
"selected"
>
1
</option>
<option
value=
"2"
>
2
</option>
</optgroup>
<optgroup
label=
"3,4,5"
>
<option
value=
"3"
>
3
</option>
<option
value=
"4"
>
4
</option>
<option
value=
"5"
>
5
</option>
</optgroup>
</select>
</td>
<td>
Everything fine.
</td>
</tr>
<tr
id=
"test-build-selected-tr"
class=
"success"
>
<th>
Test build with selected options
</th>
<td>
...
...
@@ -83,103 +100,145 @@
$
(
document
).
ready
(
function
()
{
// Test build of multiselect.
var
build
=
function
()
{
$
(
'
#test-build-select
'
)
.
multiselect
();
var
build
=
function
(
select
,
tr
)
{
select
.
multiselect
();
if
(
$
(
'
#test-build-select
'
)
.
length
==
0
)
{
if
(
select
.
length
==
0
)
{
return
'
Select not present anymore.
'
;
}
if
(
$
(
'
#test-build-select
'
)
.
css
(
'
display
'
)
!=
'
none
'
)
{
if
(
select
.
css
(
'
display
'
)
!=
'
none
'
)
{
return
'
Select still visible (expected <code>display: none;</code>).
'
;
}
if
(
$
(
'
#test-build-tr button.multiselect
'
).
length
==
0
)
{
if
(
$
(
'
button.multiselect
'
,
tr
).
length
==
0
)
{
return
'
Multiselect button not present.
'
;
}
if
(
$
(
'
#test-build-select option
'
).
length
!=
5
)
{
if
(
$
(
'
option
'
,
select
).
length
!=
5
)
{
return
'
Not all options present anymore.
'
;
}
if
(
$
(
'
#test-build-tr ul.multiselect-container
'
).
length
==
0
)
{
if
(
$
(
'
ul.multiselect-container
'
,
tr
).
length
==
0
)
{
return
'
Unordered list <code>.multiselect-container</code> not present.
'
;
}
if
(
$
(
'
#test-build-tr ul.multiselect-container li
'
).
length
!=
5
)
{
if
(
$
(
'
ul.multiselect-container li
'
,
tr
).
length
!=
5
)
{
return
'
No list item for each option present.
'
;
}
if
(
$
(
'
#test-build-tr ul.multiselect-container li a
'
).
length
!=
5
)
{
if
(
$
(
'
ul.multiselect-container li a
'
,
tr
).
length
!=
5
)
{
return
'
Not all list items come with an anchor inside.
'
;
}
return
false
;
}();
}(
$
(
'
#test-build-select
'
),
$
(
'
#test-build-tr
'
)
);
if
(
build
)
{
$
(
'
#test-build-tr
'
).
addClass
(
'
erro
r
'
);
$
(
'
#test-build-tr
'
).
removeClass
(
'
success
'
).
addClass
(
'
dange
r
'
);
$
(
'
#test-build-tr td
'
).
last
().
html
(
build
);
}
var
buildSelected
=
function
()
{
$
(
'
#test-build-selected-select
'
).
multiselect
();
// Test build with optgroups.
var
buildOptgroups
=
function
(
select
,
tr
)
{
select
.
multiselect
();
if
(
$
(
'
optgroup
'
,
select
).
length
!=
2
)
{
return
'
Optgroups not present anymore (2 expected).
'
;
}
var
first
=
$
(
'
optgroup
'
,
select
).
get
(
0
);
var
second
=
$
(
'
optgroup
'
,
select
).
get
(
1
);
if
(
$
(
'
option
'
,
$
(
first
)).
length
!=
2
)
{
return
'
First optgroup does not have 2 options.
'
;
}
if
(
$
(
'
option
'
,
$
(
second
)).
length
!=
3
)
{
return
'
Second optgroup does not have 3 options.
'
;
}
// Check the corresponding labels.
if
(
$
(
'
label.multiselect-group
'
,
tr
).
length
!=
2
)
{
return
'
Expected 2 labels within the unordered list.
'
;
}
// Check labeling of groups.
var
firstLabel
=
$
(
'
label.multiselect-group
'
,
tr
).
get
(
0
);
var
secondLabel
=
$
(
'
label.multiselect-group
'
,
tr
).
get
(
1
);
if
(
$
(
firstLabel
).
text
()
!=
$
(
first
).
prop
(
'
label
'
))
{
return
'
First group labeled incorrectly.
'
;
}
if
(
$
(
secondLabel
).
text
()
!=
$
(
second
).
prop
(
'
label
'
))
{
return
'
Second group labeled incorrectly.
'
;
}
}(
$
(
'
#test-build-optgroups-select
'
),
$
(
'
#test-build-optgroups-tr
'
));
if
(
buildOptgroups
)
{
$
(
'
#test-build-optgroups-tr
'
).
removeClass
(
'
success
'
).
addClass
(
'
danger
'
);
$
(
'
#test-build-optgroups-tr td
'
).
last
().
html
(
build
);
}
var
buildSelected
=
function
(
select
,
tr
)
{
select
.
multiselect
();
if
(
$
(
'
#test-build-selected-select option:selected
'
).
length
!=
1
)
{
if
(
$
(
'
option:selected
'
,
select
).
length
!=
1
)
{
return
'
Multiselect did not adopt selected options (1 selected option).
'
;
}
if
(
$
(
'
#test-build-selected-tr ul.multiselect-container li.active
'
).
length
!=
1
)
{
if
(
$
(
'
ul.multiselect-container li.active
'
,
tr
).
length
!=
1
)
{
return
'
Corresponding list item not set to <code>.active</code>.
'
;
}
return
false
;
}();
}(
$
(
'
#test-build-selected-select
'
),
$
(
'
#test-build-selected-tr
'
)
);
if
(
buildSelected
)
{
$
(
'
#test-build-selected-tr
'
).
addClass
(
'
erro
r
'
);
$
(
'
#test-build-selected-tr
'
).
removeClass
(
'
success
'
).
addClass
(
'
dange
r
'
);
$
(
'
#test-build-selected-tr td
'
).
last
().
html
(
buildSelected
);
}
// Test select.
var
select
=
function
()
{
$
(
'
#test-deselect-select
'
)
.
multiselect
();
var
select
=
function
(
select
,
tr
)
{
select
.
multiselect
();
// Check for no selected options and no active li's.
if
(
$
(
'
test-select-select option:selected
'
).
length
>
0
)
{
if
(
$
(
'
option:selected
'
,
select
).
length
>
0
)
{
return
'
There are already selected options (0 expected).
'
;
}
if
(
$
(
'
#test-select-tr ul.multiselect-container li.active
'
).
length
>
0
)
{
if
(
$
(
'
ul.multiselect-container li.active
'
,
tr
).
length
>
0
)
{
return
'
There are already active list items (0 expected).
'
;
}
$
(
'
#test-select-select
'
)
.
multiselect
(
'
select
'
,
1
);
select
.
multiselect
(
'
select
'
,
1
);
if
(
$
(
'
#test-select-select option:selected
'
).
length
!=
1
)
{
if
(
$
(
'
option:selected
'
,
select
).
length
!=
1
)
{
return
'
Just selected an option - option not marked selected.
'
;
}
if
(
$
(
'
#test-select-tr ul.multiselect-container li.active
'
).
length
!=
1
)
{
if
(
$
(
'
ul.multiselect-container li.active
'
,
tr
).
length
!=
1
)
{
return
'
Just selected an option - list item not set active.
'
;
}
if
(
$
(
'
#test-select-select option:selected
'
).
first
().
val
()
!=
1
)
{
if
(
$
(
'
option:selected
'
,
select
).
first
().
val
()
!=
1
)
{
return
'
Wrong option selected.
'
;
}
$
(
'
#test-select-select
'
)
.
multiselect
(
'
select
'
,
[
2
,
3
]);
select
.
multiselect
(
'
select
'
,
[
2
,
3
]);
if
(
$
(
'
#test-select-select option:selected
'
).
length
!=
3
)
{
if
(
$
(
'
option:selected
'
,
select
).
length
!=
3
)
{
return
'
Just selected two additional options - options not marked selected.
'
;
}
if
(
$
(
'
#test-select-tr ul.multiselect-container li.active
'
).
length
!=
3
)
{
if
(
$
(
'
ul.multiselect-container li.active
'
,
tr
).
length
!=
3
)
{
return
'
Just selected two additional options - list items not set active.
'
;
}
var
second
=
$
(
'
#test-select-select option:selected
'
).
get
(
1
),
third
=
$
(
'
#test-select-select option:selected
'
).
get
(
2
);
var
second
=
$
(
'
option:selected
'
,
select
).
get
(
1
),
third
=
$
(
'
option:selected
'
,
select
).
get
(
2
);
if
(
second
==
undefined
||
second
.
length
==
0
)
{
return
'
Could not get second option.
'
;
...
...
@@ -192,53 +251,53 @@
if
(
$
(
second
).
val
()
!=
2
||
$
(
third
).
val
()
!=
3
)
{
return
'
Wrong options selected.
'
;
}
}();
}(
$
(
'
#test-select-select
'
),
$
(
'
#test-select-tr
'
)
);
if
(
select
)
{
$
(
'
#test-select-tr
'
).
addClass
(
'
erro
r
'
);
$
(
'
#test-select-tr
'
).
removeClass
(
'
success
'
).
addClass
(
'
dange
r
'
);
$
(
'
#test-select-tr td
'
).
last
().
html
(
select
);
}
// Test deselect.
var
deselect
=
function
()
{
$
(
'
#test-deselect-select
'
)
.
multiselect
();
var
deselect
=
function
(
select
,
tr
)
{
select
.
multiselect
();
// Check for no selected options and no active li's.
if
(
$
(
'
#test-deselect-select option:selected
'
).
length
!=
3
)
{
if
(
$
(
'
option:selected
'
,
select
).
length
!=
3
)
{
return
'
There should be 3 options selected.
'
;
}
if
(
$
(
'
#test-deselect-tr ul.multiselect-container li.active
'
).
length
!=
3
)
{
if
(
$
(
'
ul.multiselect-container li.active
'
,
tr
).
length
!=
3
)
{
return
'
There should be 3 list items set to active.
'
;
}
$
(
'
#test-deselect-select
'
)
.
multiselect
(
'
deselect
'
,
1
);
select
.
multiselect
(
'
deselect
'
,
1
);
if
(
$
(
'
#test-deselect-select option:selected
'
).
length
!=
2
)
{
if
(
$
(
'
option:selected
'
,
select
).
length
!=
2
)
{
return
'
Just deselected an option - option not marked deselected.
'
;
}
if
(
$
(
'
#test-deselect-tr ul.multiselect-container li.active
'
).
length
!=
2
)
{
if
(
$
(
'
ul.multiselect-container li.active
'
,
tr
).
length
!=
2
)
{
return
'
Just deselected an option - list item not set inactive.
'
;
}
if
(
$
(
'
#test-deselect-select option:selected
'
).
first
().
val
()
!=
2
)
{
if
(
$
(
'
option:selected
'
,
select
).
first
().
val
()
!=
2
)
{
return
'
Wrong option deselected.
'
;
}
$
(
'
#test-deselect-select
'
)
.
multiselect
(
'
deselect
'
,
[
2
,
3
]);
select
.
multiselect
(
'
deselect
'
,
[
2
,
3
]);
if
(
$
(
'
#test-deselect-select option:selected
'
).
length
>
0
)
{
if
(
$
(
'
option:selected
'
,
select
).
length
>
0
)
{
return
'
Just deselected two additional options - options not marked deselected.
'
;
}
if
(
$
(
'
#test-deselect-tr ul.multiselect-container li.active
'
).
length
>
0
)
{
if
(
$
(
'
ul.multiselect-container li.active
'
,
tr
).
length
>
0
)
{
return
'
Just deselected two additional options - list items not set unactive.
'
;
}
}();
}(
$
(
'
#test-deselect-select
'
),
$
(
'
#test-deselect-tr
'
)
);
if
(
deselect
)
{
$
(
'
#test-deselect-tr
'
).
addClass
(
'
erro
r
'
);
$
(
'
#test-deselect-tr
'
).
removeClass
(
'
success
'
).
addClass
(
'
dange
r
'
);
$
(
'
#test-deselect-tr td
'
).
last
().
html
(
deselect
);
}
});
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment