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
dbb66a49
Commit
dbb66a49
authored
Jul 19, 2016
by
Daniel Fuzari
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
multiselect-pt-br
parent
8603bd73
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
1630 additions
and
0 deletions
+1630
-0
bootstrap-multiselect.js
dist/js/bootstrap-multiselect.js
+1630
-0
No files found.
dist/js/bootstrap-multiselect.js
View file @
dbb66a49
/**
* Bootstrap Multiselect (https://github.com/davidstutz/bootstrap-multiselect)
*
* Apache License, Version 2.0:
* Copyright (c) 2012 - 2015 David Stutz
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a
* copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* BSD 3-Clause License:
* Copyright (c) 2012 - 2015 David Stutz
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of David Stutz nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
!
function
(
$
)
{
"
use strict
"
;
// jshint ;_;
if
(
typeof
ko
!==
'
undefined
'
&&
ko
.
bindingHandlers
&&
!
ko
.
bindingHandlers
.
multiselect
)
{
ko
.
bindingHandlers
.
multiselect
=
{
after
:
[
'
options
'
,
'
value
'
,
'
selectedOptions
'
,
'
enable
'
,
'
disable
'
],
init
:
function
(
element
,
valueAccessor
,
allBindings
,
viewModel
,
bindingContext
)
{
var
$element
=
$
(
element
);
var
config
=
ko
.
toJS
(
valueAccessor
());
$element
.
multiselect
(
config
);
if
(
allBindings
.
has
(
'
options
'
))
{
var
options
=
allBindings
.
get
(
'
options
'
);
if
(
ko
.
isObservable
(
options
))
{
ko
.
computed
({
read
:
function
()
{
options
();
setTimeout
(
function
()
{
var
ms
=
$element
.
data
(
'
multiselect
'
);
if
(
ms
)
ms
.
updateOriginalOptions
();
//Not sure how beneficial this is.
$element
.
multiselect
(
'
rebuild
'
);
},
1
);
},
disposeWhenNodeIsRemoved
:
element
});
}
}
//value and selectedOptions are two-way, so these will be triggered even by our own actions.
//It needs some way to tell if they are triggered because of us or because of outside change.
//It doesn't loop but it's a waste of processing.
if
(
allBindings
.
has
(
'
value
'
))
{
var
value
=
allBindings
.
get
(
'
value
'
);
if
(
ko
.
isObservable
(
value
))
{
ko
.
computed
({
read
:
function
()
{
value
();
setTimeout
(
function
()
{
$element
.
multiselect
(
'
refresh
'
);
},
1
);
},
disposeWhenNodeIsRemoved
:
element
}).
extend
({
rateLimit
:
100
,
notifyWhenChangesStop
:
true
});
}
}
//Switched from arrayChange subscription to general subscription using 'refresh'.
//Not sure performance is any better using 'select' and 'deselect'.
if
(
allBindings
.
has
(
'
selectedOptions
'
))
{
var
selectedOptions
=
allBindings
.
get
(
'
selectedOptions
'
);
if
(
ko
.
isObservable
(
selectedOptions
))
{
ko
.
computed
({
read
:
function
()
{
selectedOptions
();
setTimeout
(
function
()
{
$element
.
multiselect
(
'
refresh
'
);
},
1
);
},
disposeWhenNodeIsRemoved
:
element
}).
extend
({
rateLimit
:
100
,
notifyWhenChangesStop
:
true
});
}
}
var
setEnabled
=
function
(
enable
)
{
setTimeout
(
function
()
{
if
(
enable
)
$element
.
multiselect
(
'
enable
'
);
else
$element
.
multiselect
(
'
disable
'
);
});
};
if
(
allBindings
.
has
(
'
enable
'
))
{
var
enable
=
allBindings
.
get
(
'
enable
'
);
if
(
ko
.
isObservable
(
enable
))
{
ko
.
computed
({
read
:
function
()
{
setEnabled
(
enable
());
},
disposeWhenNodeIsRemoved
:
element
}).
extend
({
rateLimit
:
100
,
notifyWhenChangesStop
:
true
});
}
else
{
setEnabled
(
enable
);
}
}
if
(
allBindings
.
has
(
'
disable
'
))
{
var
disable
=
allBindings
.
get
(
'
disable
'
);
if
(
ko
.
isObservable
(
disable
))
{
ko
.
computed
({
read
:
function
()
{
setEnabled
(
!
disable
());
},
disposeWhenNodeIsRemoved
:
element
}).
extend
({
rateLimit
:
100
,
notifyWhenChangesStop
:
true
});
}
else
{
setEnabled
(
!
disable
);
}
}
ko
.
utils
.
domNodeDisposal
.
addDisposeCallback
(
element
,
function
()
{
$element
.
multiselect
(
'
destroy
'
);
});
},
update
:
function
(
element
,
valueAccessor
,
allBindings
,
viewModel
,
bindingContext
)
{
var
$element
=
$
(
element
);
var
config
=
ko
.
toJS
(
valueAccessor
());
$element
.
multiselect
(
'
setOptions
'
,
config
);
$element
.
multiselect
(
'
rebuild
'
);
}
};
}
function
forEach
(
array
,
callback
)
{
for
(
var
index
=
0
;
index
<
array
.
length
;
++
index
)
{
callback
(
array
[
index
],
index
);
}
}
/**
* Constructor to create a new multiselect using the given select.
*
* @param {jQuery} select
* @param {Object} options
* @returns {Multiselect}
*/
function
Multiselect
(
select
,
options
)
{
this
.
$select
=
$
(
select
);
// Placeholder via data attributes
if
(
this
.
$select
.
attr
(
"
data-placeholder
"
))
{
options
.
nonSelectedText
=
this
.
$select
.
data
(
"
placeholder
"
);
}
this
.
options
=
this
.
mergeOptions
(
$
.
extend
({},
options
,
this
.
$select
.
data
()));
// Initialization.
// We have to clone to create a new reference.
this
.
originalOptions
=
this
.
$select
.
clone
()[
0
].
options
;
this
.
query
=
''
;
this
.
searchTimeout
=
null
;
this
.
lastToggledInput
=
null
;
this
.
options
.
multiple
=
this
.
$select
.
attr
(
'
multiple
'
)
===
"
multiple
"
;
this
.
options
.
onChange
=
$
.
proxy
(
this
.
options
.
onChange
,
this
);
this
.
options
.
onDropdownShow
=
$
.
proxy
(
this
.
options
.
onDropdownShow
,
this
);
this
.
options
.
onDropdownHide
=
$
.
proxy
(
this
.
options
.
onDropdownHide
,
this
);
this
.
options
.
onDropdownShown
=
$
.
proxy
(
this
.
options
.
onDropdownShown
,
this
);
this
.
options
.
onDropdownHidden
=
$
.
proxy
(
this
.
options
.
onDropdownHidden
,
this
);
this
.
options
.
onInitialized
=
$
.
proxy
(
this
.
options
.
onInitialized
,
this
);
// Build select all if enabled.
this
.
buildContainer
();
this
.
buildButton
();
this
.
buildDropdown
();
this
.
buildSelectAll
();
this
.
buildDropdownOptions
();
this
.
buildFilter
();
this
.
updateButtonText
();
this
.
updateSelectAll
(
true
);
if
(
this
.
options
.
disableIfEmpty
&&
$
(
'
option
'
,
this
.
$select
).
length
<=
0
)
{
this
.
disable
();
}
this
.
$select
.
hide
().
after
(
this
.
$container
);
this
.
options
.
onInitialized
(
this
.
$select
,
this
.
$container
);
}
Multiselect
.
prototype
=
{
defaults
:
{
/**
* Default text function will either print 'Todos' in case no
* option is selected or a list of the selected options up to a length
* of 3 selected options.
*
* @param {jQuery} options
* @param {jQuery} select
* @returns {String}
*/
buttonText
:
function
(
options
,
select
)
{
if
(
this
.
disabledText
.
length
>
0
&&
(
this
.
disableIfEmpty
||
select
.
prop
(
'
disabled
'
))
&&
options
.
length
==
0
)
{
return
this
.
disabledText
;
}
else
if
(
options
.
length
===
0
)
{
return
this
.
nonSelectedText
;
}
else
if
(
this
.
allSelectedText
&&
options
.
length
===
$
(
'
option
'
,
$
(
select
)).
length
&&
$
(
'
option
'
,
$
(
select
)).
length
!==
1
&&
this
.
multiple
)
{
if
(
this
.
selectAllNumber
)
{
return
this
.
allSelectedText
+
'
(
'
+
options
.
length
+
'
)
'
;
}
else
{
return
this
.
allSelectedText
;
}
}
else
if
(
options
.
length
>
this
.
numberDisplayed
)
{
return
options
.
length
+
'
'
+
this
.
nSelectedText
;
}
else
{
var
selected
=
''
;
var
delimiter
=
this
.
delimiterText
;
options
.
each
(
function
()
{
var
label
=
(
$
(
this
).
attr
(
'
label
'
)
!==
undefined
)
?
$
(
this
).
attr
(
'
label
'
)
:
$
(
this
).
text
();
selected
+=
label
+
delimiter
;
});
return
selected
.
substr
(
0
,
selected
.
length
-
2
);
}
},
/**
* Updates the title of the button similar to the buttonText function.
*
* @param {jQuery} options
* @param {jQuery} select
* @returns {@exp;selected@call;substr}
*/
buttonTitle
:
function
(
options
,
select
)
{
if
(
options
.
length
===
0
)
{
return
this
.
nonSelectedText
;
}
else
{
var
selected
=
''
;
var
delimiter
=
this
.
delimiterText
;
options
.
each
(
function
()
{
var
label
=
(
$
(
this
).
attr
(
'
label
'
)
!==
undefined
)
?
$
(
this
).
attr
(
'
label
'
)
:
$
(
this
).
text
();
selected
+=
label
+
delimiter
;
});
return
selected
.
substr
(
0
,
selected
.
length
-
2
);
}
},
/**
* Create a label.
*
* @param {jQuery} element
* @returns {String}
*/
optionLabel
:
function
(
element
){
return
$
(
element
).
attr
(
'
label
'
)
||
$
(
element
).
text
();
},
/**
* Create a class.
*
* @param {jQuery} element
* @returns {String}
*/
optionClass
:
function
(
element
)
{
return
$
(
element
).
attr
(
'
class
'
)
||
''
;
},
/**
* Triggered on change of the multiselect.
*
* Not triggered when selecting/deselecting options manually.
*
* @param {jQuery} option
* @param {Boolean} checked
*/
onChange
:
function
(
option
,
checked
)
{
},
/**
* Triggered when the dropdown is shown.
*
* @param {jQuery} event
*/
onDropdownShow
:
function
(
event
)
{
},
/**
* Triggered when the dropdown is hidden.
*
* @param {jQuery} event
*/
onDropdownHide
:
function
(
event
)
{
},
/**
* Triggered after the dropdown is shown.
*
* @param {jQuery} event
*/
onDropdownShown
:
function
(
event
)
{
},
/**
* Triggered after the dropdown is hidden.
*
* @param {jQuery} event
*/
onDropdownHidden
:
function
(
event
)
{
},
/**
* Triggered on select all.
*/
onSelectAll
:
function
(
checked
)
{
},
/**
* Triggered after initializing.
*
* @param {jQuery} $select
* @param {jQuery} $container
*/
onInitialized
:
function
(
$select
,
$container
)
{
},
enableHTML
:
false
,
buttonClass
:
'
btn btn-default
'
,
inheritClass
:
false
,
buttonWidth
:
'
auto
'
,
buttonContainer
:
'
<div class="btn-group" />
'
,
dropRight
:
false
,
dropUp
:
false
,
selectedClass
:
'
active
'
,
// Maximum height of the dropdown menu.
// If maximum height is exceeded a scrollbar will be displayed.
maxHeight
:
false
,
checkboxName
:
false
,
includeSelectAllOption
:
false
,
includeSelectAllIfMoreThan
:
0
,
selectAllText
:
'
Selecionar todos
'
,
selectAllValue
:
'
multiselect-all
'
,
selectAllName
:
false
,
selectAllNumber
:
true
,
selectAllJustVisible
:
true
,
enableFiltering
:
false
,
enableCaseInsensitiveFiltering
:
false
,
enableFullValueFiltering
:
false
,
enableClickableOptGroups
:
false
,
enableCollapsibelOptGroups
:
false
,
filterPlaceholder
:
'
Pesquisar
'
,
// possible options: 'text', 'value', 'both'
filterBehavior
:
'
text
'
,
includeFilterClearBtn
:
true
,
preventInputChangeEvent
:
false
,
nonSelectedText
:
'
Todos
'
,
nSelectedText
:
'
selecionado(s)
'
,
allSelectedText
:
'
Todos selecionados
'
,
numberDisplayed
:
3
,
disableIfEmpty
:
false
,
disabledText
:
''
,
delimiterText
:
'
,
'
,
templates
:
{
button
:
'
<button type="button" class="multiselect dropdown-toggle" data-toggle="dropdown"><span class="multiselect-selected-text"></span> <b class="caret"></b></button>
'
,
ul
:
'
<ul class="multiselect-container dropdown-menu"></ul>
'
,
filter
:
'
<li class="multiselect-item filter"><div class="input-group"><span class="input-group-addon"><i class="glyphicon glyphicon-search"></i></span><input class="form-control multiselect-search" type="text"></div></li>
'
,
filterClearBtn
:
'
<span class="input-group-btn"><button class="btn btn-default multiselect-clear-filter" type="button"><i class="glyphicon glyphicon-remove-circle"></i></button></span>
'
,
li
:
'
<li><a tabindex="0"><label></label></a></li>
'
,
divider
:
'
<li class="multiselect-item divider"></li>
'
,
liGroup
:
'
<li class="multiselect-item multiselect-group"><label></label></li>
'
}
},
constructor
:
Multiselect
,
/**
* Builds the container of the multiselect.
*/
buildContainer
:
function
()
{
this
.
$container
=
$
(
this
.
options
.
buttonContainer
);
this
.
$container
.
on
(
'
show.bs.dropdown
'
,
this
.
options
.
onDropdownShow
);
this
.
$container
.
on
(
'
hide.bs.dropdown
'
,
this
.
options
.
onDropdownHide
);
this
.
$container
.
on
(
'
shown.bs.dropdown
'
,
this
.
options
.
onDropdownShown
);
this
.
$container
.
on
(
'
hidden.bs.dropdown
'
,
this
.
options
.
onDropdownHidden
);
},
/**
* Builds the button of the multiselect.
*/
buildButton
:
function
()
{
this
.
$button
=
$
(
this
.
options
.
templates
.
button
).
addClass
(
this
.
options
.
buttonClass
);
if
(
this
.
$select
.
attr
(
'
class
'
)
&&
this
.
options
.
inheritClass
)
{
this
.
$button
.
addClass
(
this
.
$select
.
attr
(
'
class
'
));
}
// Adopt active state.
if
(
this
.
$select
.
prop
(
'
disabled
'
))
{
this
.
disable
();
}
else
{
this
.
enable
();
}
// Manually add button width if set.
if
(
this
.
options
.
buttonWidth
&&
this
.
options
.
buttonWidth
!==
'
auto
'
)
{
this
.
$button
.
css
({
'
width
'
:
this
.
options
.
buttonWidth
,
'
overflow
'
:
'
hidden
'
,
'
text-overflow
'
:
'
ellipsis
'
});
this
.
$container
.
css
({
'
width
'
:
this
.
options
.
buttonWidth
});
}
// Keep the tab index from the select.
var
tabindex
=
this
.
$select
.
attr
(
'
tabindex
'
);
if
(
tabindex
)
{
this
.
$button
.
attr
(
'
tabindex
'
,
tabindex
);
}
this
.
$container
.
prepend
(
this
.
$button
);
},
/**
* Builds the ul representing the dropdown menu.
*/
buildDropdown
:
function
()
{
// Build ul.
this
.
$ul
=
$
(
this
.
options
.
templates
.
ul
);
if
(
this
.
options
.
dropRight
)
{
this
.
$ul
.
addClass
(
'
pull-right
'
);
}
// 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.
this
.
$ul
.
css
({
'
max-height
'
:
this
.
options
.
maxHeight
+
'
px
'
,
'
overflow-y
'
:
'
auto
'
,
'
overflow-x
'
:
'
hidden
'
});
}
if
(
this
.
options
.
dropUp
)
{
var
height
=
Math
.
min
(
this
.
options
.
maxHeight
,
$
(
'
option[data-role!="divider"]
'
,
this
.
$select
).
length
*
26
+
$
(
'
option[data-role="divider"]
'
,
this
.
$select
).
length
*
19
+
(
this
.
options
.
includeSelectAllOption
?
26
:
0
)
+
(
this
.
options
.
enableFiltering
||
this
.
options
.
enableCaseInsensitiveFiltering
?
44
:
0
));
var
moveCalc
=
height
+
34
;
this
.
$ul
.
css
({
'
max-height
'
:
height
+
'
px
'
,
'
overflow-y
'
:
'
auto
'
,
'
overflow-x
'
:
'
hidden
'
,
'
margin-top
'
:
"
-
"
+
moveCalc
+
'
px
'
});
}
this
.
$container
.
append
(
this
.
$ul
);
},
/**
* Build the dropdown options and binds all nessecary events.
*
* Uses createDivider and createOptionValue to create the necessary options.
*/
buildDropdownOptions
:
function
()
{
this
.
$select
.
children
().
each
(
$
.
proxy
(
function
(
index
,
element
)
{
var
$element
=
$
(
element
);
// Support optgroups and options without a group simultaneously.
var
tag
=
$element
.
prop
(
'
tagName
'
)
.
toLowerCase
();
if
(
$element
.
prop
(
'
value
'
)
===
this
.
options
.
selectAllValue
)
{
return
;
}
if
(
tag
===
'
optgroup
'
)
{
this
.
createOptgroup
(
element
);
}
else
if
(
tag
===
'
option
'
)
{
if
(
$element
.
data
(
'
role
'
)
===
'
divider
'
)
{
this
.
createDivider
();
}
else
{
this
.
createOptionValue
(
element
);
}
}
// Other illegal tags will be ignored.
},
this
));
// Bind the change event on the dropdown elements.
$
(
'
li input
'
,
this
.
$ul
).
on
(
'
change
'
,
$
.
proxy
(
function
(
event
)
{
var
$target
=
$
(
event
.
target
);
var
checked
=
$target
.
prop
(
'
checked
'
)
||
false
;
var
isSelectAllOption
=
$target
.
val
()
===
this
.
options
.
selectAllValue
;
// Apply or unapply the configured selected class.
if
(
this
.
options
.
selectedClass
)
{
if
(
checked
)
{
$target
.
closest
(
'
li
'
)
.
addClass
(
this
.
options
.
selectedClass
);
}
else
{
$target
.
closest
(
'
li
'
)
.
removeClass
(
this
.
options
.
selectedClass
);
}
}
// Get the corresponding option.
var
value
=
$target
.
val
();
var
$option
=
this
.
getOptionByValue
(
value
);
var
$optionsNotThis
=
$
(
'
option
'
,
this
.
$select
).
not
(
$option
);
var
$checkboxesNotThis
=
$
(
'
input
'
,
this
.
$container
).
not
(
$target
);
if
(
isSelectAllOption
)
{
if
(
checked
)
{
this
.
selectAll
(
this
.
options
.
selectAllJustVisible
);
}
else
{
this
.
deselectAll
(
this
.
options
.
selectAllJustVisible
);
}
}
else
{
if
(
checked
)
{
$option
.
prop
(
'
selected
'
,
true
);
if
(
this
.
options
.
multiple
)
{
// Simply select additional option.
$option
.
prop
(
'
selected
'
,
true
);
}
else
{
// Unselect all other options and corresponding checkboxes.
if
(
this
.
options
.
selectedClass
)
{
$
(
$checkboxesNotThis
).
closest
(
'
li
'
).
removeClass
(
this
.
options
.
selectedClass
);
}
$
(
$checkboxesNotThis
).
prop
(
'
checked
'
,
false
);
$optionsNotThis
.
prop
(
'
selected
'
,
false
);
// It's a single selection, so close.
this
.
$button
.
click
();
}
if
(
this
.
options
.
selectedClass
===
"
active
"
)
{
$optionsNotThis
.
closest
(
"
a
"
).
css
(
"
outline
"
,
""
);
}
}
else
{
// Unselect option.
$option
.
prop
(
'
selected
'
,
false
);
}
// To prevent select all from firing onChange: #575
this
.
options
.
onChange
(
$option
,
checked
);
}
this
.
$select
.
change
();
this
.
updateButtonText
();
this
.
updateSelectAll
();
if
(
this
.
options
.
preventInputChangeEvent
)
{
return
false
;
}
},
this
));
$
(
'
li a
'
,
this
.
$ul
).
on
(
'
mousedown
'
,
function
(
e
)
{
if
(
e
.
shiftKey
)
{
// Prevent selecting text by Shift+click
return
false
;
}
});
$
(
'
li a
'
,
this
.
$ul
).
on
(
'
touchstart click
'
,
$
.
proxy
(
function
(
event
)
{
event
.
stopPropagation
();
var
$target
=
$
(
event
.
target
);
if
(
event
.
shiftKey
&&
this
.
options
.
multiple
)
{
if
(
$target
.
is
(
"
label
"
)){
// Handles checkbox selection manually (see https://github.com/davidstutz/bootstrap-multiselect/issues/431)
event
.
preventDefault
();
$target
=
$target
.
find
(
"
input
"
);
$target
.
prop
(
"
checked
"
,
!
$target
.
prop
(
"
checked
"
));
}
var
checked
=
$target
.
prop
(
'
checked
'
)
||
false
;
if
(
this
.
lastToggledInput
!==
null
&&
this
.
lastToggledInput
!==
$target
)
{
// Make sure we actually have a range
var
from
=
$target
.
closest
(
"
li
"
).
index
();
var
to
=
this
.
lastToggledInput
.
closest
(
"
li
"
).
index
();
if
(
from
>
to
)
{
// Swap the indices
var
tmp
=
to
;
to
=
from
;
from
=
tmp
;
}
// Make sure we grab all elements since slice excludes the last index
++
to
;
// Change the checkboxes and underlying options
var
range
=
this
.
$ul
.
find
(
"
li
"
).
slice
(
from
,
to
).
find
(
"
input
"
);
range
.
prop
(
'
checked
'
,
checked
);
if
(
this
.
options
.
selectedClass
)
{
range
.
closest
(
'
li
'
)
.
toggleClass
(
this
.
options
.
selectedClass
,
checked
);
}
for
(
var
i
=
0
,
j
=
range
.
length
;
i
<
j
;
i
++
)
{
var
$checkbox
=
$
(
range
[
i
]);
var
$option
=
this
.
getOptionByValue
(
$checkbox
.
val
());
$option
.
prop
(
'
selected
'
,
checked
);
}
}
// Trigger the select "change" event
$target
.
trigger
(
"
change
"
);
}
// Remembers last clicked option
if
(
$target
.
is
(
"
input
"
)
&&
!
$target
.
closest
(
"
li
"
).
is
(
"
.multiselect-item
"
)){
this
.
lastToggledInput
=
$target
;
}
$target
.
blur
();
},
this
));
// Keyboard support.
this
.
$container
.
off
(
'
keydown.multiselect
'
).
on
(
'
keydown.multiselect
'
,
$
.
proxy
(
function
(
event
)
{
if
(
$
(
'
input[type="text"]
'
,
this
.
$container
).
is
(
'
:focus
'
))
{
return
;
}
if
(
event
.
keyCode
===
9
&&
this
.
$container
.
hasClass
(
'
open
'
))
{
this
.
$button
.
click
();
}
else
{
var
$items
=
$
(
this
.
$container
).
find
(
"
li:not(.divider):not(.disabled) a
"
).
filter
(
"
:visible
"
);
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
();
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
));
if
(
this
.
options
.
enableClickableOptGroups
&&
this
.
options
.
multiple
)
{
$
(
'
li.multiselect-group
'
,
this
.
$ul
).
on
(
'
click
'
,
$
.
proxy
(
function
(
event
)
{
event
.
stopPropagation
();
console
.
log
(
'
test
'
);
var
group
=
$
(
event
.
target
).
parent
();
// Search all option in optgroup
var
$options
=
group
.
nextUntil
(
'
li.multiselect-group
'
);
var
$visibleOptions
=
$options
.
filter
(
"
:visible:not(.disabled)
"
);
// check or uncheck items
var
allChecked
=
true
;
var
optionInputs
=
$visibleOptions
.
find
(
'
input
'
);
var
values
=
[];
optionInputs
.
each
(
function
()
{
allChecked
=
allChecked
&&
$
(
this
).
prop
(
'
checked
'
);
values
.
push
(
$
(
this
).
val
());
});
if
(
!
allChecked
)
{
this
.
select
(
values
,
false
);
}
else
{
this
.
deselect
(
values
,
false
);
}
this
.
options
.
onChange
(
optionInputs
,
!
allChecked
);
},
this
));
}
if
(
this
.
options
.
enableCollapsibleOptGroups
&&
this
.
options
.
multiple
)
{
$
(
"
li.multiselect-group input
"
,
this
.
$ul
).
off
();
$
(
"
li.multiselect-group
"
,
this
.
$ul
).
siblings
().
not
(
"
li.multiselect-group, li.multiselect-all
"
,
this
.
$ul
).
each
(
function
()
{
$
(
this
).
toggleClass
(
'
hidden
'
,
true
);
});
$
(
"
li.multiselect-group
"
,
this
.
$ul
).
on
(
"
click
"
,
$
.
proxy
(
function
(
group
)
{
group
.
stopPropagation
();
},
this
));
$
(
"
li.multiselect-group > a > b
"
,
this
.
$ul
).
on
(
"
click
"
,
$
.
proxy
(
function
(
t
)
{
t
.
stopPropagation
();
var
n
=
$
(
t
.
target
).
closest
(
'
li
'
);
var
r
=
n
.
nextUntil
(
"
li.multiselect-group
"
);
var
i
=
true
;
r
.
each
(
function
()
{
i
=
i
&&
$
(
this
).
hasClass
(
'
hidden
'
);
});
r
.
toggleClass
(
'
hidden
'
,
!
i
);
},
this
));
$
(
"
li.multiselect-group > a > input
"
,
this
.
$ul
).
on
(
"
change
"
,
$
.
proxy
(
function
(
t
)
{
t
.
stopPropagation
();
var
n
=
$
(
t
.
target
).
closest
(
'
li
'
);
var
r
=
n
.
nextUntil
(
"
li.multiselect-group
"
,
'
:not(.disabled)
'
);
var
s
=
r
.
find
(
"
input
"
);
var
i
=
true
;
s
.
each
(
function
()
{
i
=
i
&&
$
(
this
).
prop
(
"
checked
"
);
});
s
.
prop
(
"
checked
"
,
!
i
).
trigger
(
"
change
"
);
},
this
));
// Set the initial selection state of the groups.
$
(
'
li.multiselect-group
'
,
this
.
$ul
).
each
(
function
()
{
var
r
=
$
(
this
).
nextUntil
(
"
li.multiselect-group
"
,
'
:not(.disabled)
'
);
var
s
=
r
.
find
(
"
input
"
);
var
i
=
true
;
s
.
each
(
function
()
{
i
=
i
&&
$
(
this
).
prop
(
"
checked
"
);
});
$
(
this
).
find
(
'
input
'
).
prop
(
"
checked
"
,
i
);
});
// Update the group checkbox based on new selections among the
// corresponding children.
$
(
"
li input
"
,
this
.
$ul
).
on
(
"
change
"
,
$
.
proxy
(
function
(
t
)
{
t
.
stopPropagation
();
var
n
=
$
(
t
.
target
).
closest
(
'
li
'
);
var
r1
=
n
.
prevUntil
(
"
li.multiselect-group
"
,
'
:not(.disabled)
'
);
var
r2
=
n
.
nextUntil
(
"
li.multiselect-group
"
,
'
:not(.disabled)
'
);
var
s1
=
r1
.
find
(
"
input
"
);
var
s2
=
r2
.
find
(
"
input
"
);
var
i
=
$
(
t
.
target
).
prop
(
'
checked
'
);
s1
.
each
(
function
()
{
i
=
i
&&
$
(
this
).
prop
(
"
checked
"
);
});
s2
.
each
(
function
()
{
i
=
i
&&
$
(
this
).
prop
(
"
checked
"
);
});
n
.
prevAll
(
'
.multiselect-group
'
).
find
(
'
input
'
).
prop
(
'
checked
'
,
i
);
},
this
));
$
(
"
li.multiselect-all
"
,
this
.
$ul
).
css
(
'
background
'
,
'
#f3f3f3
'
).
css
(
'
border-bottom
'
,
'
1px solid #eaeaea
'
);
$
(
"
li.multiselect-group > a, li.multiselect-all > a > label.checkbox
"
,
this
.
$ul
).
css
(
'
padding
'
,
'
3px 20px 3px 35px
'
);
$
(
"
li.multiselect-group > a > input
"
,
this
.
$ul
).
css
(
'
margin
'
,
'
4px 0px 5px -20px
'
);
}
},
/**
* Create an option using the given select option.
*
* @param {jQuery} element
*/
createOptionValue
:
function
(
element
)
{
var
$element
=
$
(
element
);
if
(
$element
.
is
(
'
:selected
'
))
{
$element
.
prop
(
'
selected
'
,
true
);
}
// Support the label attribute on options.
var
label
=
this
.
options
.
optionLabel
(
element
);
var
classes
=
this
.
options
.
optionClass
(
element
);
var
value
=
$element
.
val
();
var
inputType
=
this
.
options
.
multiple
?
"
checkbox
"
:
"
radio
"
;
var
$li
=
$
(
this
.
options
.
templates
.
li
);
var
$label
=
$
(
'
label
'
,
$li
);
$label
.
addClass
(
inputType
);
$li
.
addClass
(
classes
);
if
(
this
.
options
.
enableHTML
)
{
$label
.
html
(
"
"
+
label
);
}
else
{
$label
.
text
(
"
"
+
label
);
}
var
$checkbox
=
$
(
'
<input/>
'
).
attr
(
'
type
'
,
inputType
);
if
(
this
.
options
.
checkboxName
)
{
$checkbox
.
attr
(
'
name
'
,
this
.
options
.
checkboxName
);
}
$label
.
prepend
(
$checkbox
);
var
selected
=
$element
.
prop
(
'
selected
'
)
||
false
;
$checkbox
.
val
(
value
);
if
(
value
===
this
.
options
.
selectAllValue
)
{
$li
.
addClass
(
"
multiselect-item multiselect-all
"
);
$checkbox
.
parent
().
parent
()
.
addClass
(
'
multiselect-all
'
);
}
$label
.
attr
(
'
title
'
,
$element
.
attr
(
'
title
'
));
this
.
$ul
.
append
(
$li
);
if
(
$element
.
is
(
'
:disabled
'
))
{
$checkbox
.
attr
(
'
disabled
'
,
'
disabled
'
)
.
prop
(
'
disabled
'
,
true
)
.
closest
(
'
a
'
)
.
attr
(
"
tabindex
"
,
"
-1
"
)
.
closest
(
'
li
'
)
.
addClass
(
'
disabled
'
);
}
$checkbox
.
prop
(
'
checked
'
,
selected
);
if
(
selected
&&
this
.
options
.
selectedClass
)
{
$checkbox
.
closest
(
'
li
'
)
.
addClass
(
this
.
options
.
selectedClass
);
}
},
/**
* Creates a divider using the given select option.
*
* @param {jQuery} element
*/
createDivider
:
function
(
element
)
{
var
$divider
=
$
(
this
.
options
.
templates
.
divider
);
this
.
$ul
.
append
(
$divider
);
},
/**
* Creates an optgroup.
*
* @param {jQuery} group
*/
createOptgroup
:
function
(
group
)
{
if
(
this
.
options
.
enableCollapsibleOptGroups
&&
this
.
options
.
multiple
)
{
var
label
=
$
(
group
).
attr
(
"
label
"
);
var
value
=
$
(
group
).
attr
(
"
value
"
);
var
r
=
$
(
'
<li class="multiselect-item multiselect-group"><a href="javascript:void(0);"><input type="checkbox" value="
'
+
value
+
'
"/><b>
'
+
label
+
'
<b class="caret"></b></b></a></li>
'
);
if
(
this
.
options
.
enableClickableOptGroups
)
{
r
.
addClass
(
"
multiselect-group-clickable
"
)
}
this
.
$ul
.
append
(
r
);
if
(
$
(
group
).
is
(
"
:disabled
"
))
{
r
.
addClass
(
"
disabled
"
)
}
$
(
"
option
"
,
group
).
each
(
$
.
proxy
(
function
(
$
,
group
)
{
this
.
createOptionValue
(
group
)
},
this
))
}
else
{
var
groupName
=
$
(
group
).
prop
(
'
label
'
);
// Add a header for the group.
var
$li
=
$
(
this
.
options
.
templates
.
liGroup
);
if
(
this
.
options
.
enableHTML
)
{
$
(
'
label
'
,
$li
).
html
(
groupName
);
}
else
{
$
(
'
label
'
,
$li
).
text
(
groupName
);
}
if
(
this
.
options
.
enableClickableOptGroups
)
{
$li
.
addClass
(
'
multiselect-group-clickable
'
);
}
this
.
$ul
.
append
(
$li
);
if
(
$
(
group
).
is
(
'
:disabled
'
))
{
$li
.
addClass
(
'
disabled
'
);
}
// Add the options of the group.
$
(
'
option
'
,
group
).
each
(
$
.
proxy
(
function
(
index
,
element
)
{
this
.
createOptionValue
(
element
);
},
this
));
}
},
/**
* Build the select all.
*
* Checks if a select all has already been created.
*/
buildSelectAll
:
function
()
{
if
(
typeof
this
.
options
.
selectAllValue
===
'
number
'
)
{
this
.
options
.
selectAllValue
=
this
.
options
.
selectAllValue
.
toString
();
}
var
alreadyHasSelectAll
=
this
.
hasSelectAll
();
if
(
!
alreadyHasSelectAll
&&
this
.
options
.
includeSelectAllOption
&&
this
.
options
.
multiple
&&
$
(
'
option
'
,
this
.
$select
).
length
>
this
.
options
.
includeSelectAllIfMoreThan
)
{
// Check whether to add a divider after the select all.
if
(
this
.
options
.
includeSelectAllDivider
)
{
this
.
$ul
.
prepend
(
$
(
this
.
options
.
templates
.
divider
));
}
var
$li
=
$
(
this
.
options
.
templates
.
li
);
$
(
'
label
'
,
$li
).
addClass
(
"
checkbox
"
);
if
(
this
.
options
.
enableHTML
)
{
$
(
'
label
'
,
$li
).
html
(
"
"
+
this
.
options
.
selectAllText
);
}
else
{
$
(
'
label
'
,
$li
).
text
(
"
"
+
this
.
options
.
selectAllText
);
}
if
(
this
.
options
.
selectAllName
)
{
$
(
'
label
'
,
$li
).
prepend
(
'
<input type="checkbox" name="
'
+
this
.
options
.
selectAllName
+
'
" />
'
);
}
else
{
$
(
'
label
'
,
$li
).
prepend
(
'
<input type="checkbox" />
'
);
}
var
$checkbox
=
$
(
'
input
'
,
$li
);
$checkbox
.
val
(
this
.
options
.
selectAllValue
);
$li
.
addClass
(
"
multiselect-item multiselect-all
"
);
$checkbox
.
parent
().
parent
()
.
addClass
(
'
multiselect-all
'
);
this
.
$ul
.
prepend
(
$li
);
$checkbox
.
prop
(
'
checked
'
,
false
);
}
},
/**
* Builds the filter.
*/
buildFilter
:
function
()
{
// Build filter if filtering OR case insensitive filtering is enabled and the number of options exceeds (or equals) enableFilterLength.
if
(
this
.
options
.
enableFiltering
||
this
.
options
.
enableCaseInsensitiveFiltering
)
{
var
enableFilterLength
=
Math
.
max
(
this
.
options
.
enableFiltering
,
this
.
options
.
enableCaseInsensitiveFiltering
);
if
(
this
.
$select
.
find
(
'
option
'
).
length
>=
enableFilterLength
)
{
this
.
$filter
=
$
(
this
.
options
.
templates
.
filter
);
$
(
'
input
'
,
this
.
$filter
).
attr
(
'
placeholder
'
,
this
.
options
.
filterPlaceholder
);
// Adds optional filter clear button
if
(
this
.
options
.
includeFilterClearBtn
){
var
clearBtn
=
$
(
this
.
options
.
templates
.
filterClearBtn
);
clearBtn
.
on
(
'
click
'
,
$
.
proxy
(
function
(
event
){
clearTimeout
(
this
.
searchTimeout
);
this
.
$filter
.
find
(
'
.multiselect-search
'
).
val
(
''
);
$
(
'
li
'
,
this
.
$ul
).
show
().
removeClass
(
"
filter-hidden
"
);
this
.
updateSelectAll
();
},
this
));
this
.
$filter
.
find
(
'
.input-group
'
).
append
(
clearBtn
);
}
this
.
$ul
.
prepend
(
this
.
$filter
);
this
.
$filter
.
val
(
this
.
query
).
on
(
'
click
'
,
function
(
event
)
{
event
.
stopPropagation
();
}).
on
(
'
input keydown
'
,
$
.
proxy
(
function
(
event
)
{
// Cancel enter key default behaviour
if
(
event
.
which
===
13
)
{
event
.
preventDefault
();
}
// 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
;
var
currentGroup
,
currentGroupVisible
;
$
.
each
(
$
(
'
li
'
,
this
.
$ul
),
$
.
proxy
(
function
(
index
,
element
)
{
var
value
=
$
(
'
input
'
,
element
).
length
>
0
?
$
(
'
input
'
,
element
).
val
()
:
""
;
var
text
=
$
(
'
label
'
,
element
).
text
();
var
filterCandidate
=
''
;
if
((
this
.
options
.
filterBehavior
===
'
text
'
))
{
filterCandidate
=
text
;
}
else
if
((
this
.
options
.
filterBehavior
===
'
value
'
))
{
filterCandidate
=
value
;
}
else
if
(
this
.
options
.
filterBehavior
===
'
both
'
)
{
filterCandidate
=
text
+
'
\n
'
+
value
;
}
if
(
value
!==
this
.
options
.
selectAllValue
&&
text
)
{
// By default lets assume that element is not
// interesting for this search.
var
showElement
=
false
;
if
(
this
.
options
.
enableCaseInsensitiveFiltering
)
{
filterCandidate
=
filterCandidate
.
toLowerCase
();
this
.
query
=
this
.
query
.
toLowerCase
();
}
if
(
this
.
options
.
enableFullValueFiltering
&&
this
.
options
.
filterBehavior
!==
'
both
'
)
{
var
valueToMatch
=
filterCandidate
.
trim
().
substring
(
0
,
this
.
query
.
length
);
if
(
this
.
query
.
indexOf
(
valueToMatch
)
>
-
1
)
{
showElement
=
true
;
}
}
else
if
(
filterCandidate
.
indexOf
(
this
.
query
)
>
-
1
)
{
showElement
=
true
;
}
// Toggle current element (group or group item) according to showElement boolean.
$
(
element
).
toggle
(
showElement
).
toggleClass
(
'
filter-hidden
'
,
!
showElement
);
// Differentiate groups and group items.
if
(
$
(
element
).
hasClass
(
'
multiselect-group
'
))
{
// Remember group status.
currentGroup
=
element
;
currentGroupVisible
=
showElement
;
}
else
{
// Show group name when at least one of its items is visible.
if
(
showElement
)
{
$
(
currentGroup
).
show
().
removeClass
(
'
filter-hidden
'
);
}
// Show all group items when group name satisfies filter.
if
(
!
showElement
&&
currentGroupVisible
)
{
$
(
element
).
show
().
removeClass
(
'
filter-hidden
'
);
}
}
}
},
this
));
}
this
.
updateSelectAll
();
},
this
),
300
,
this
);
},
this
));
}
}
},
/**
* Unbinds the whole plugin.
*/
destroy
:
function
()
{
this
.
$container
.
remove
();
this
.
$select
.
show
();
this
.
$select
.
data
(
'
multiselect
'
,
null
);
},
/**
* Refreshs the multiselect based on the selected options of the select.
*/
refresh
:
function
()
{
var
inputs
=
$
.
map
(
$
(
'
li input
'
,
this
.
$ul
),
$
);
$
(
'
option
'
,
this
.
$select
).
each
(
$
.
proxy
(
function
(
index
,
element
)
{
var
$elem
=
$
(
element
);
var
value
=
$elem
.
val
();
var
$input
;
for
(
var
i
=
inputs
.
length
;
0
<
i
--
;
/**/
)
{
if
(
value
!==
(
$input
=
inputs
[
i
]).
val
())
continue
;
// wrong li
if
(
$elem
.
is
(
'
:selected
'
))
{
$input
.
prop
(
'
checked
'
,
true
);
if
(
this
.
options
.
selectedClass
)
{
$input
.
closest
(
'
li
'
)
.
addClass
(
this
.
options
.
selectedClass
);
}
}
else
{
$input
.
prop
(
'
checked
'
,
false
);
if
(
this
.
options
.
selectedClass
)
{
$input
.
closest
(
'
li
'
)
.
removeClass
(
this
.
options
.
selectedClass
);
}
}
if
(
$elem
.
is
(
"
:disabled
"
))
{
$input
.
attr
(
'
disabled
'
,
'
disabled
'
)
.
prop
(
'
disabled
'
,
true
)
.
closest
(
'
li
'
)
.
addClass
(
'
disabled
'
);
}
else
{
$input
.
prop
(
'
disabled
'
,
false
)
.
closest
(
'
li
'
)
.
removeClass
(
'
disabled
'
);
}
break
;
// assumes unique values
}
},
this
));
this
.
updateButtonText
();
this
.
updateSelectAll
();
},
/**
* Select all options of the given values.
*
* If triggerOnChange is set to true, the on change event is triggered if
* and only if one value is passed.
*
* @param {Array} selectValues
* @param {Boolean} triggerOnChange
*/
select
:
function
(
selectValues
,
triggerOnChange
)
{
if
(
!
$
.
isArray
(
selectValues
))
{
selectValues
=
[
selectValues
];
}
for
(
var
i
=
0
;
i
<
selectValues
.
length
;
i
++
)
{
var
value
=
selectValues
[
i
];
if
(
value
===
null
||
value
===
undefined
)
{
continue
;
}
var
$option
=
this
.
getOptionByValue
(
value
);
var
$checkbox
=
this
.
getInputByValue
(
value
);
if
(
$option
===
undefined
||
$checkbox
===
undefined
)
{
continue
;
}
if
(
!
this
.
options
.
multiple
)
{
this
.
deselectAll
(
false
);
}
if
(
this
.
options
.
selectedClass
)
{
$checkbox
.
closest
(
'
li
'
)
.
addClass
(
this
.
options
.
selectedClass
);
}
$checkbox
.
prop
(
'
checked
'
,
true
);
$option
.
prop
(
'
selected
'
,
true
);
if
(
triggerOnChange
)
{
this
.
options
.
onChange
(
$option
,
true
);
}
}
this
.
updateButtonText
();
this
.
updateSelectAll
();
},
/**
* Clears all selected items.
*/
clearSelection
:
function
()
{
this
.
deselectAll
(
false
);
this
.
updateButtonText
();
this
.
updateSelectAll
();
},
/**
* Deselects all options of the given values.
*
* If triggerOnChange is set to true, the on change event is triggered, if
* and only if one value is passed.
*
* @param {Array} deselectValues
* @param {Boolean} triggerOnChange
*/
deselect
:
function
(
deselectValues
,
triggerOnChange
)
{
if
(
!
$
.
isArray
(
deselectValues
))
{
deselectValues
=
[
deselectValues
];
}
for
(
var
i
=
0
;
i
<
deselectValues
.
length
;
i
++
)
{
var
value
=
deselectValues
[
i
];
if
(
value
===
null
||
value
===
undefined
)
{
continue
;
}
var
$option
=
this
.
getOptionByValue
(
value
);
var
$checkbox
=
this
.
getInputByValue
(
value
);
if
(
$option
===
undefined
||
$checkbox
===
undefined
)
{
continue
;
}
if
(
this
.
options
.
selectedClass
)
{
$checkbox
.
closest
(
'
li
'
)
.
removeClass
(
this
.
options
.
selectedClass
);
}
$checkbox
.
prop
(
'
checked
'
,
false
);
$option
.
prop
(
'
selected
'
,
false
);
if
(
triggerOnChange
)
{
this
.
options
.
onChange
(
$option
,
false
);
}
}
this
.
updateButtonText
();
this
.
updateSelectAll
();
},
/**
* Selects all enabled & visible options.
*
* If justVisible is true or not specified, only visible options are selected.
*
* @param {Boolean} justVisible
* @param {Boolean} triggerOnSelectAll
*/
selectAll
:
function
(
justVisible
,
triggerOnSelectAll
)
{
justVisible
=
(
this
.
options
.
enableCollapsibleOptGroups
&&
this
.
options
.
multiple
)
?
false
:
justVisible
;
var
justVisible
=
typeof
justVisible
===
'
undefined
'
?
true
:
justVisible
;
var
allCheckboxes
=
$
(
"
li input[type='checkbox']:enabled
"
,
this
.
$ul
);
var
visibleCheckboxes
=
allCheckboxes
.
filter
(
"
:visible
"
);
var
allCheckboxesCount
=
allCheckboxes
.
length
;
var
visibleCheckboxesCount
=
visibleCheckboxes
.
length
;
if
(
justVisible
)
{
visibleCheckboxes
.
prop
(
'
checked
'
,
true
);
$
(
"
li:not(.divider):not(.disabled)
"
,
this
.
$ul
).
filter
(
"
:visible
"
).
addClass
(
this
.
options
.
selectedClass
);
}
else
{
allCheckboxes
.
prop
(
'
checked
'
,
true
);
$
(
"
li:not(.divider):not(.disabled)
"
,
this
.
$ul
).
addClass
(
this
.
options
.
selectedClass
);
}
if
(
allCheckboxesCount
===
visibleCheckboxesCount
||
justVisible
===
false
)
{
$
(
"
option:not([data-role='divider']):enabled
"
,
this
.
$select
).
prop
(
'
selected
'
,
true
);
}
else
{
var
values
=
visibleCheckboxes
.
map
(
function
()
{
return
$
(
this
).
val
();
}).
get
();
$
(
"
option:enabled
"
,
this
.
$select
).
filter
(
function
(
index
)
{
return
$
.
inArray
(
$
(
this
).
val
(),
values
)
!==
-
1
;
}).
prop
(
'
selected
'
,
true
);
}
if
(
triggerOnSelectAll
)
{
this
.
options
.
onSelectAll
();
}
},
/**
* Deselects all options.
*
* If justVisible is true or not specified, only visible options are deselected.
*
* @param {Boolean} justVisible
*/
deselectAll
:
function
(
justVisible
)
{
justVisible
=
(
this
.
options
.
enableCollapsibleOptGroups
&&
this
.
options
.
multiple
)
?
false
:
justVisible
;
justVisible
=
typeof
justVisible
===
'
undefined
'
?
true
:
justVisible
;
if
(
justVisible
)
{
var
visibleCheckboxes
=
$
(
"
li input[type='checkbox']:not(:disabled)
"
,
this
.
$ul
).
filter
(
"
:visible
"
);
visibleCheckboxes
.
prop
(
'
checked
'
,
false
);
var
values
=
visibleCheckboxes
.
map
(
function
()
{
return
$
(
this
).
val
();
}).
get
();
$
(
"
option:enabled
"
,
this
.
$select
).
filter
(
function
(
index
)
{
return
$
.
inArray
(
$
(
this
).
val
(),
values
)
!==
-
1
;
}).
prop
(
'
selected
'
,
false
);
if
(
this
.
options
.
selectedClass
)
{
$
(
"
li:not(.divider):not(.disabled)
"
,
this
.
$ul
).
filter
(
"
:visible
"
).
removeClass
(
this
.
options
.
selectedClass
);
}
}
else
{
$
(
"
li input[type='checkbox']:enabled
"
,
this
.
$ul
).
prop
(
'
checked
'
,
false
);
$
(
"
option:enabled
"
,
this
.
$select
).
prop
(
'
selected
'
,
false
);
if
(
this
.
options
.
selectedClass
)
{
$
(
"
li:not(.divider):not(.disabled)
"
,
this
.
$ul
).
removeClass
(
this
.
options
.
selectedClass
);
}
}
},
/**
* Rebuild the plugin.
*
* Rebuilds the dropdown, the filter and the select all option.
*/
rebuild
:
function
()
{
this
.
$ul
.
html
(
''
);
// Important to distinguish between radios and checkboxes.
this
.
options
.
multiple
=
this
.
$select
.
attr
(
'
multiple
'
)
===
"
multiple
"
;
this
.
buildSelectAll
();
this
.
buildDropdownOptions
();
this
.
buildFilter
();
this
.
updateButtonText
();
this
.
updateSelectAll
(
true
);
if
(
this
.
options
.
disableIfEmpty
&&
$
(
'
option
'
,
this
.
$select
).
length
<=
0
)
{
this
.
disable
();
}
else
{
this
.
enable
();
}
if
(
this
.
options
.
dropRight
)
{
this
.
$ul
.
addClass
(
'
pull-right
'
);
}
},
/**
* The provided data will be used to build the dropdown.
*/
dataprovider
:
function
(
dataprovider
)
{
var
groupCounter
=
0
;
var
$select
=
this
.
$select
.
empty
();
$
.
each
(
dataprovider
,
function
(
index
,
option
)
{
var
$tag
;
if
(
$
.
isArray
(
option
.
children
))
{
// create optiongroup tag
groupCounter
++
;
$tag
=
$
(
'
<optgroup/>
'
).
attr
({
label
:
option
.
label
||
'
Group
'
+
groupCounter
,
disabled
:
!!
option
.
disabled
});
forEach
(
option
.
children
,
function
(
subOption
)
{
// add children option tags
$tag
.
append
(
$
(
'
<option/>
'
).
attr
({
value
:
subOption
.
value
,
label
:
subOption
.
label
||
subOption
.
value
,
title
:
subOption
.
title
,
selected
:
!!
subOption
.
selected
,
disabled
:
!!
subOption
.
disabled
}));
});
}
else
{
$tag
=
$
(
'
<option/>
'
).
attr
({
value
:
option
.
value
,
label
:
option
.
label
||
option
.
value
,
title
:
option
.
title
,
class
:
option
.
class
,
selected
:
!!
option
.
selected
,
disabled
:
!!
option
.
disabled
});
$tag
.
text
(
option
.
label
||
option
.
value
);
}
$select
.
append
(
$tag
);
});
this
.
rebuild
();
},
/**
* Enable the multiselect.
*/
enable
:
function
()
{
this
.
$select
.
prop
(
'
disabled
'
,
false
);
this
.
$button
.
prop
(
'
disabled
'
,
false
)
.
removeClass
(
'
disabled
'
);
},
/**
* Disable the multiselect.
*/
disable
:
function
()
{
this
.
$select
.
prop
(
'
disabled
'
,
true
);
this
.
$button
.
prop
(
'
disabled
'
,
true
)
.
addClass
(
'
disabled
'
);
},
/**
* Set the options.
*
* @param {Array} options
*/
setOptions
:
function
(
options
)
{
this
.
options
=
this
.
mergeOptions
(
options
);
},
/**
* Merges the given options with the default options.
*
* @param {Array} options
* @returns {Array}
*/
mergeOptions
:
function
(
options
)
{
return
$
.
extend
(
true
,
{},
this
.
defaults
,
this
.
options
,
options
);
},
/**
* Checks whether a select all checkbox is present.
*
* @returns {Boolean}
*/
hasSelectAll
:
function
()
{
return
$
(
'
li.multiselect-all
'
,
this
.
$ul
).
length
>
0
;
},
/**
* Updates the select all checkbox based on the currently displayed and selected checkboxes.
*/
updateSelectAll
:
function
(
notTriggerOnSelectAll
)
{
if
(
this
.
hasSelectAll
())
{
var
allBoxes
=
$
(
"
li:not(.multiselect-item):not(.filter-hidden) input:enabled
"
,
this
.
$ul
);
var
allBoxesLength
=
allBoxes
.
length
;
var
checkedBoxesLength
=
allBoxes
.
filter
(
"
:checked
"
).
length
;
var
selectAllLi
=
$
(
"
li.multiselect-all
"
,
this
.
$ul
);
var
selectAllInput
=
selectAllLi
.
find
(
"
input
"
);
if
(
checkedBoxesLength
>
0
&&
checkedBoxesLength
===
allBoxesLength
)
{
selectAllInput
.
prop
(
"
checked
"
,
true
);
selectAllLi
.
addClass
(
this
.
options
.
selectedClass
);
this
.
options
.
onSelectAll
(
true
);
}
else
{
selectAllInput
.
prop
(
"
checked
"
,
false
);
selectAllLi
.
removeClass
(
this
.
options
.
selectedClass
);
if
(
checkedBoxesLength
===
0
)
{
if
(
!
notTriggerOnSelectAll
)
{
this
.
options
.
onSelectAll
(
false
);
}
}
}
}
},
/**
* Update the button text and its title based on the currently selected options.
*/
updateButtonText
:
function
()
{
var
options
=
this
.
getSelected
();
// First update the displayed button text.
if
(
this
.
options
.
enableHTML
)
{
$
(
'
.multiselect .multiselect-selected-text
'
,
this
.
$container
).
html
(
this
.
options
.
buttonText
(
options
,
this
.
$select
));
}
else
{
$
(
'
.multiselect .multiselect-selected-text
'
,
this
.
$container
).
text
(
this
.
options
.
buttonText
(
options
,
this
.
$select
));
}
// Now update the title attribute of the button.
$
(
'
.multiselect
'
,
this
.
$container
).
attr
(
'
title
'
,
this
.
options
.
buttonTitle
(
options
,
this
.
$select
));
},
/**
* Get all selected options.
*
* @returns {jQUery}
*/
getSelected
:
function
()
{
return
$
(
'
option
'
,
this
.
$select
).
filter
(
"
:selected
"
);
},
/**
* Gets a select option by its value.
*
* @param {String} value
* @returns {jQuery}
*/
getOptionByValue
:
function
(
value
)
{
var
options
=
$
(
'
option
'
,
this
.
$select
);
var
valueToCompare
=
value
.
toString
();
for
(
var
i
=
0
;
i
<
options
.
length
;
i
=
i
+
1
)
{
var
option
=
options
[
i
];
if
(
option
.
value
===
valueToCompare
)
{
return
$
(
option
);
}
}
},
/**
* Get the input (radio/checkbox) by its value.
*
* @param {String} value
* @returns {jQuery}
*/
getInputByValue
:
function
(
value
)
{
var
checkboxes
=
$
(
'
li input
'
,
this
.
$ul
);
var
valueToCompare
=
value
.
toString
();
for
(
var
i
=
0
;
i
<
checkboxes
.
length
;
i
=
i
+
1
)
{
var
checkbox
=
checkboxes
[
i
];
if
(
checkbox
.
value
===
valueToCompare
)
{
return
$
(
checkbox
);
}
}
},
/**
* Used for knockout integration.
*/
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
);
},
setAllSelectedText
:
function
(
allSelectedText
)
{
this
.
options
.
allSelectedText
=
allSelectedText
;
this
.
updateButtonText
();
}
};
$
.
fn
.
multiselect
=
function
(
option
,
parameter
,
extraOptions
)
{
return
this
.
each
(
function
()
{
var
data
=
$
(
this
).
data
(
'
multiselect
'
);
var
options
=
typeof
option
===
'
object
'
&&
option
;
// Initialize the multiselect.
if
(
!
data
)
{
data
=
new
Multiselect
(
this
,
options
);
$
(
this
).
data
(
'
multiselect
'
,
data
);
}
// Call multiselect method.
if
(
typeof
option
===
'
string
'
)
{
data
[
option
](
parameter
,
extraOptions
);
if
(
option
===
'
destroy
'
)
{
$
(
this
).
data
(
'
multiselect
'
,
false
);
}
}
});
};
$
.
fn
.
multiselect
.
Constructor
=
Multiselect
;
$
(
function
()
{
$
(
"
select[data-role=multiselect]
"
).
multiselect
();
});
}(
window
.
jQuery
);
\ No newline at end of file
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