added bootstrap-duallist plugin & demo

This commit is contained in:
REJack 2019-07-28 13:50:35 +02:00
parent 8f5b3d68b9
commit 2804a35d13
No known key found for this signature in database
GPG key ID: 9F3976CC630CC888
8 changed files with 1056 additions and 12 deletions

View file

@ -215,6 +215,11 @@ const Plugins = [
from: 'node_modules/flag-icon-css/flags',
to: 'plugins/flag-icon-css/flags'
},
// bootstrap4-duallistbox
{
from: 'node_modules/bootstrap4-duallistbox/dist',
to: 'plugins/bootstrap4-duallistbox/'
},
// AdminLTE Dist

28
package-lock.json generated
View file

@ -3133,6 +3133,10 @@
"resolved": "https://registry.npmjs.org/bootstrap-slider/-/bootstrap-slider-10.6.1.tgz",
"integrity": "sha512-lA6SwGr33YcKHtpt0lYjwspc4RCgM2bdrFdHU1U77Lal6gZGjVF/Ii9/Mff0b1dyZ4RvSAzaOlSsuY1d5wCtdA=="
},
"bootstrap4-duallistbox": {
"version": "4.0.1",
"resolved": "github:istvan-ujjmeszaros/bootstrap-duallistbox#b3295efa2dc1ca6d6f14531ee0f073c3a45e554f"
},
"boxen": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz",
@ -5166,9 +5170,9 @@
},
"dependencies": {
"lodash": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
"dev": true
}
}
@ -6982,9 +6986,9 @@
},
"dependencies": {
"lodash": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
"dev": true
}
}
@ -8031,9 +8035,9 @@
}
},
"lodash": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
"dev": true
},
"lodash.isfinite": {
@ -8477,9 +8481,9 @@
}
},
"lodash": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
"dev": true
},
"nan": {

View file

@ -54,6 +54,7 @@
"bootstrap": "^4.3.1",
"bootstrap-colorpicker": "^3.1.2",
"bootstrap-slider": "^10.6.1",
"bootstrap4-duallistbox": "^4.0.1",
"chart.js": "^2.8.0",
"datatables.net": "^1.10.19",
"datatables.net-bs4": "^1.10.19",

View file

@ -21,6 +21,8 @@
<link rel="stylesheet" href="../../plugins/tempusdominus-bootstrap-4/css/tempusdominus-bootstrap-4.min.css">
<!-- Select2 -->
<link rel="stylesheet" href="../../plugins/select2/css/select2.min.css">
<!-- Bootstrap4 Duallistbox -->
<link rel="stylesheet" href="../../plugins/bootstrap4-duallistbox/bootstrap-duallistbox.min.css">
<!-- Theme style -->
<link rel="stylesheet" href="../../dist/css/adminlte.min.css">
<!-- Google Font: Source Sans Pro -->
@ -700,6 +702,45 @@
</div>
<!-- /.card -->
<div class="card card-default">
<div class="card-header">
<h3 class="card-title">Bootstrap Duallistbox</h3>
<div class="card-tools">
<button type="button" class="btn btn-tool" data-widget="collapse"><i class="fas fa-minus"></i></button>
<button type="button" class="btn btn-tool" data-widget="remove"><i class="fas fa-remove"></i></button>
</div>
</div>
<!-- /.card-header -->
<div class="card-body">
<div class="row">
<div class="col-12">
<div class="form-group">
<label>Multiple</label>
<select class="duallistbox" multiple="multiple">
<option selected>Alabama</option>
<option>Alaska</option>
<option>California</option>
<option>Delaware</option>
<option>Tennessee</option>
<option>Texas</option>
<option>Washington</option>
</select>
</div>
<!-- /.form-group -->
</div>
<!-- /.col -->
</div>
<!-- /.row -->
</div>
<!-- /.card-body -->
<div class="card-footer">
Visit <a href="https://select2.github.io/">Select2 documentation</a> for more examples and information about
the plugin.
</div>
</div>
<!-- /.card -->
<div class="row">
<div class="col-md-6">
@ -1055,6 +1096,8 @@
<script src="../../plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Select2 -->
<script src="../../plugins/select2/js/select2.full.min.js"></script>
<!-- Bootstrap4 Duallistbox -->
<script src="../../plugins/bootstrap4-duallistbox/jquery.bootstrap-duallistbox.min.js"></script>
<!-- InputMask -->
<script src="../../plugins/inputmask/jquery.inputmask.bundle.js"></script>
<script src="../../plugins/moment/moment.min.js"></script>
@ -1116,6 +1159,9 @@
$('#timepicker').datetimepicker({
format: 'LT'
})
//Bootstrap Duallistbox
$('.duallistbox').bootstrapDualListbox()
//Colorpicker
$('.my-colorpicker1').colorpicker()

View file

@ -0,0 +1,87 @@
/*
* Bootstrap Duallistbox - v4.0.1
* A responsive dual listbox widget optimized for Twitter Bootstrap. It works on all modern browsers and on touch devices.
* http://www.virtuosoft.eu/code/bootstrap-duallistbox/
*
* Made by István Ujj-Mészáros
* Under Apache License v2.0 License
*/
.bootstrap-duallistbox-container .buttons {
width: 100%;
margin-bottom: -1px;
}
.bootstrap-duallistbox-container label {
display: block;
}
.bootstrap-duallistbox-container .info {
display: inline-block;
margin-bottom: 5px;
font-size: 11px;
}
.bootstrap-duallistbox-container .clear1,
.bootstrap-duallistbox-container .clear2 {
display: none;
font-size: 10px;
}
.bootstrap-duallistbox-container .box1.filtered .clear1,
.bootstrap-duallistbox-container .box2.filtered .clear2 {
display: inline-block;
}
.bootstrap-duallistbox-container .move,
.bootstrap-duallistbox-container .remove {
width: 50%;
box-sizing: content-box;
}
.bootstrap-duallistbox-container .btn-group .btn {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.bootstrap-duallistbox-container:not(.moveonselect) select {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.bootstrap-duallistbox-container .moveall,
.bootstrap-duallistbox-container .removeall {
width: 50%;
box-sizing: content-box;
}
.bootstrap-duallistbox-container.bs2compatible .btn-group > .btn + .btn {
margin-left: 0;
}
.bootstrap-duallistbox-container select {
width: 100%;
height: 300px;
padding: 0;
}
.bootstrap-duallistbox-container .filter {
display: inline-block;
width: 100%;
height: 31px;
margin: 0 0 5px 0;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.bootstrap-duallistbox-container .filter.placeholder {
color: #aaa;
}
.bootstrap-duallistbox-container.moveonselect .move,
.bootstrap-duallistbox-container.moveonselect .remove {
display:none;
}
.bootstrap-duallistbox-container.moveonselect .moveall,
.bootstrap-duallistbox-container.moveonselect .removeall {
width: 100%;
}

View file

@ -0,0 +1 @@
.bootstrap-duallistbox-container .buttons{width:100%;margin-bottom:-1px}.bootstrap-duallistbox-container label{display:block}.bootstrap-duallistbox-container .info{display:inline-block;margin-bottom:5px;font-size:11px}.bootstrap-duallistbox-container .clear1,.bootstrap-duallistbox-container .clear2{display:none;font-size:10px}.bootstrap-duallistbox-container .box1.filtered .clear1,.bootstrap-duallistbox-container .box2.filtered .clear2{display:inline-block}.bootstrap-duallistbox-container .move,.bootstrap-duallistbox-container .remove{width:50%;box-sizing:content-box}.bootstrap-duallistbox-container .btn-group .btn{border-bottom-left-radius:0;border-bottom-right-radius:0}.bootstrap-duallistbox-container:not(.moveonselect) select{border-top-left-radius:0;border-top-right-radius:0}.bootstrap-duallistbox-container .moveall,.bootstrap-duallistbox-container .removeall{width:50%;box-sizing:content-box}.bootstrap-duallistbox-container.bs2compatible .btn-group>.btn+.btn{margin-left:0}.bootstrap-duallistbox-container select{width:100%;height:300px;padding:0}.bootstrap-duallistbox-container .filter{display:inline-block;width:100%;height:31px;margin:0 0 5px 0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.bootstrap-duallistbox-container .filter.placeholder{color:#aaa}.bootstrap-duallistbox-container.moveonselect .move,.bootstrap-duallistbox-container.moveonselect .remove{display:none}.bootstrap-duallistbox-container.moveonselect .moveall,.bootstrap-duallistbox-container.moveonselect .removeall{width:100%}

View file

@ -0,0 +1,890 @@
/*
* Bootstrap Duallistbox - v4.0.1
* A responsive dual listbox widget optimized for Twitter Bootstrap. It works on all modern browsers and on touch devices.
* http://www.virtuosoft.eu/code/bootstrap-duallistbox/
*
* Made by István Ujj-Mészáros
* Under Apache License v2.0 License
*/
(function(factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else if (typeof module === 'object' && module.exports) {
module.exports = function(root, jQuery) {
if (jQuery === undefined) {
if (typeof window !== 'undefined') {
jQuery = require('jquery');
}
else {
jQuery = require('jquery')(root);
}
}
factory(jQuery);
return jQuery;
};
} else {
factory(jQuery);
}
}(function($) {
// Create the defaults once
var pluginName = 'bootstrapDualListbox',
defaults = {
filterTextClear: 'show all',
filterPlaceHolder: 'Filter',
moveSelectedLabel: 'Move selected',
moveAllLabel: 'Move all',
removeSelectedLabel: 'Remove selected',
removeAllLabel: 'Remove all',
moveOnSelect: true, // true/false (forced true on androids, see the comment later)
moveOnDoubleClick: true, // true/false (forced false on androids, cause moveOnSelect is forced to true)
preserveSelectionOnMove: false, // 'all' / 'moved' / false
selectedListLabel: false, // 'string', false
nonSelectedListLabel: false, // 'string', false
helperSelectNamePostfix: '_helper', // 'string_of_postfix' / false
selectorMinimalHeight: 100,
showFilterInputs: true, // whether to show filter inputs
nonSelectedFilter: '', // string, filter the non selected options
selectedFilter: '', // string, filter the selected options
infoText: 'Showing all {0}', // text when all options are visible / false for no info text
infoTextFiltered: '<span class="badge badge-warning">Filtered</span> {0} from {1}', // when not all of the options are visible due to the filter
infoTextEmpty: 'Empty list', // when there are no options present in the list
filterOnValues: false, // filter by selector's values, boolean
sortByInputOrder: false,
eventMoveOverride: false, // boolean, allows user to unbind default event behaviour and run their own instead
eventMoveAllOverride: false, // boolean, allows user to unbind default event behaviour and run their own instead
eventRemoveOverride: false, // boolean, allows user to unbind default event behaviour and run their own instead
eventRemoveAllOverride: false, // boolean, allows user to unbind default event behaviour and run their own instead
btnClass: 'btn-outline-secondary', // sets the button style class for all the buttons
btnMoveText: '&gt;', // string, sets the text for the "Move" button
btnRemoveText: '&lt;', // string, sets the text for the "Remove" button
btnMoveAllText: '&gt;&gt;', // string, sets the text for the "Move All" button
btnRemoveAllText: '&lt;&lt;' // string, sets the text for the "Remove All" button
},
// Selections are invisible on android if the containing select is styled with CSS
// http://code.google.com/p/android/issues/detail?id=16922
isBuggyAndroid = /android/i.test(navigator.userAgent.toLowerCase());
// The actual plugin constructor
function BootstrapDualListbox(element, options) {
this.element = $(element);
// jQuery has an extend method which merges the contents of two or
// more objects, storing the result in the first object. The first object
// is generally empty as we don't want to alter the default options for
// future instances of the plugin
this.settings = $.extend({}, defaults, options);
this._defaults = defaults;
this._name = pluginName;
this.init();
}
function triggerChangeEvent(dualListbox) {
dualListbox.element.trigger('change');
}
function updateSelectionStates(dualListbox) {
dualListbox.element.find('option').each(function(index, item) {
var $item = $(item);
if (typeof($item.data('original-index')) === 'undefined') {
$item.data('original-index', dualListbox.elementCount++);
}
if (typeof($item.data('_selected')) === 'undefined') {
$item.data('_selected', false);
}
});
}
function changeSelectionState(dualListbox, original_index, selected) {
dualListbox.element.find('option').each(function(index, item) {
var $item = $(item);
if ($item.data('original-index') === original_index) {
$item.prop('selected', selected);
if(selected){
$item.attr('data-sortindex', dualListbox.sortIndex);
dualListbox.sortIndex++;
} else {
$item.removeAttr('data-sortindex');
}
}
});
}
function formatString(s, args) {
console.log(s, args);
return s.replace(/{(\d+)}/g, function(match, number) {
return typeof args[number] !== 'undefined' ? args[number] : match;
});
}
function refreshInfo(dualListbox) {
if (!dualListbox.settings.infoText) {
return;
}
var visible1 = dualListbox.elements.select1.find('option').length,
visible2 = dualListbox.elements.select2.find('option').length,
all1 = dualListbox.element.find('option').length - dualListbox.selectedElements,
all2 = dualListbox.selectedElements,
content = '';
if (all1 === 0) {
content = dualListbox.settings.infoTextEmpty;
} else if (visible1 === all1) {
content = formatString(dualListbox.settings.infoText, [visible1, all1]);
} else {
content = formatString(dualListbox.settings.infoTextFiltered, [visible1, all1]);
}
dualListbox.elements.info1.html(content);
dualListbox.elements.box1.toggleClass('filtered', !(visible1 === all1 || all1 === 0));
if (all2 === 0) {
content = dualListbox.settings.infoTextEmpty;
} else if (visible2 === all2) {
content = formatString(dualListbox.settings.infoText, [visible2, all2]);
} else {
content = formatString(dualListbox.settings.infoTextFiltered, [visible2, all2]);
}
dualListbox.elements.info2.html(content);
dualListbox.elements.box2.toggleClass('filtered', !(visible2 === all2 || all2 === 0));
}
function refreshSelects(dualListbox) {
dualListbox.selectedElements = 0;
dualListbox.elements.select1.empty();
dualListbox.elements.select2.empty();
dualListbox.element.find('option').each(function(index, item) {
var $item = $(item);
if ($item.prop('selected')) {
dualListbox.selectedElements++;
dualListbox.elements.select2.append($item.clone(true).prop('selected', $item.data('_selected')));
} else {
dualListbox.elements.select1.append($item.clone(true).prop('selected', $item.data('_selected')));
}
});
if (dualListbox.settings.showFilterInputs) {
filter(dualListbox, 1);
filter(dualListbox, 2);
}
refreshInfo(dualListbox);
}
function filter(dualListbox, selectIndex) {
if (!dualListbox.settings.showFilterInputs) {
return;
}
saveSelections(dualListbox, selectIndex);
dualListbox.elements['select'+selectIndex].empty().scrollTop(0);
var regex,
allOptions = dualListbox.element.find('option'),
options = dualListbox.element;
if (selectIndex === 1) {
options = allOptions.not(':selected');
} else {
options = options.find('option:selected');
}
try {
regex = new RegExp($.trim(dualListbox.elements['filterInput'+selectIndex].val()), 'gi');
}
catch(e) {
// a regex to match nothing
regex = new RegExp('/a^/', 'gi');
}
options.each(function(index, item) {
var $item = $(item),
isFiltered = true;
if (item.text.match(regex) || (dualListbox.settings.filterOnValues && $item.attr('value').match(regex) ) ) {
isFiltered = false;
dualListbox.elements['select'+selectIndex].append($item.clone(true).prop('selected', $item.data('_selected')));
}
allOptions.eq($item.data('original-index')).data('filtered'+selectIndex, isFiltered);
});
refreshInfo(dualListbox);
}
function saveSelections(dualListbox, selectIndex) {
var options = dualListbox.element.find('option');
dualListbox.elements['select'+selectIndex].find('option').each(function(index, item) {
var $item = $(item);
options.eq($item.data('original-index')).data('_selected', $item.prop('selected'));
});
}
function sortOptionsByInputOrder(select){
var selectopt = select.children('option');
selectopt.sort(function(a,b){
var an = parseInt(a.getAttribute('data-sortindex')),
bn = parseInt(b.getAttribute('data-sortindex'));
if(an > bn) {
return 1;
}
if(an < bn) {
return -1;
}
return 0;
});
selectopt.detach().appendTo(select);
}
function sortOptions(select) {
select.find('option').sort(function(a, b) {
return ($(a).data('original-index') > $(b).data('original-index')) ? 1 : -1;
}).appendTo(select);
}
function clearSelections(dualListbox) {
dualListbox.elements.select1.find('option').each(function() {
dualListbox.element.find('option').data('_selected', false);
});
}
function move(dualListbox) {
if (dualListbox.settings.preserveSelectionOnMove === 'all' && !dualListbox.settings.moveOnSelect) {
saveSelections(dualListbox, 1);
saveSelections(dualListbox, 2);
} else if (dualListbox.settings.preserveSelectionOnMove === 'moved' && !dualListbox.settings.moveOnSelect) {
saveSelections(dualListbox, 1);
}
dualListbox.elements.select1.find('option:selected').each(function(index, item) {
var $item = $(item);
if (!$item.data('filtered1')) {
changeSelectionState(dualListbox, $item.data('original-index'), true);
}
});
refreshSelects(dualListbox);
triggerChangeEvent(dualListbox);
if(dualListbox.settings.sortByInputOrder){
sortOptionsByInputOrder(dualListbox.elements.select2);
} else {
sortOptions(dualListbox.elements.select2);
}
}
function remove(dualListbox) {
if (dualListbox.settings.preserveSelectionOnMove === 'all' && !dualListbox.settings.moveOnSelect) {
saveSelections(dualListbox, 1);
saveSelections(dualListbox, 2);
} else if (dualListbox.settings.preserveSelectionOnMove === 'moved' && !dualListbox.settings.moveOnSelect) {
saveSelections(dualListbox, 2);
}
dualListbox.elements.select2.find('option:selected').each(function(index, item) {
var $item = $(item);
if (!$item.data('filtered2')) {
changeSelectionState(dualListbox, $item.data('original-index'), false);
}
});
refreshSelects(dualListbox);
triggerChangeEvent(dualListbox);
sortOptions(dualListbox.elements.select1);
if(dualListbox.settings.sortByInputOrder){
sortOptionsByInputOrder(dualListbox.elements.select2);
}
}
function moveAll(dualListbox) {
if (dualListbox.settings.preserveSelectionOnMove === 'all' && !dualListbox.settings.moveOnSelect) {
saveSelections(dualListbox, 1);
saveSelections(dualListbox, 2);
} else if (dualListbox.settings.preserveSelectionOnMove === 'moved' && !dualListbox.settings.moveOnSelect) {
saveSelections(dualListbox, 1);
}
dualListbox.element.find('option').each(function(index, item) {
var $item = $(item);
if (!$item.data('filtered1')) {
$item.prop('selected', true);
$item.attr('data-sortindex', dualListbox.sortIndex);
dualListbox.sortIndex++;
}
});
refreshSelects(dualListbox);
triggerChangeEvent(dualListbox);
}
function removeAll(dualListbox) {
if (dualListbox.settings.preserveSelectionOnMove === 'all' && !dualListbox.settings.moveOnSelect) {
saveSelections(dualListbox, 1);
saveSelections(dualListbox, 2);
} else if (dualListbox.settings.preserveSelectionOnMove === 'moved' && !dualListbox.settings.moveOnSelect) {
saveSelections(dualListbox, 2);
}
dualListbox.element.find('option').each(function(index, item) {
var $item = $(item);
if (!$item.data('filtered2')) {
$item.prop('selected', false);
$item.removeAttr('data-sortindex');
}
});
refreshSelects(dualListbox);
triggerChangeEvent(dualListbox);
}
function bindEvents(dualListbox) {
dualListbox.elements.form.submit(function(e) {
if (dualListbox.elements.filterInput1.is(':focus')) {
e.preventDefault();
dualListbox.elements.filterInput1.focusout();
} else if (dualListbox.elements.filterInput2.is(':focus')) {
e.preventDefault();
dualListbox.elements.filterInput2.focusout();
}
});
dualListbox.element.on('bootstrapDualListbox.refresh', function(e, mustClearSelections){
dualListbox.refresh(mustClearSelections);
});
dualListbox.elements.filterClear1.on('click', function() {
dualListbox.setNonSelectedFilter('', true);
});
dualListbox.elements.filterClear2.on('click', function() {
dualListbox.setSelectedFilter('', true);
});
if (dualListbox.settings.eventMoveOverride === false) {
dualListbox.elements.moveButton.on('click', function() {
move(dualListbox);
});
}
if (dualListbox.settings.eventMoveAllOverride === false) {
dualListbox.elements.moveAllButton.on('click', function() {
moveAll(dualListbox);
});
}
if (dualListbox.settings.eventRemoveOverride === false) {
dualListbox.elements.removeButton.on('click', function() {
remove(dualListbox);
});
}
if (dualListbox.settings.eventRemoveAllOverride === false) {
dualListbox.elements.removeAllButton.on('click', function() {
removeAll(dualListbox);
});
}
dualListbox.elements.filterInput1.on('change keyup', function() {
filter(dualListbox, 1);
});
dualListbox.elements.filterInput2.on('change keyup', function() {
filter(dualListbox, 2);
});
}
BootstrapDualListbox.prototype = {
init: function () {
// Add the custom HTML template
this.container = $('' +
'<div class="bootstrap-duallistbox-container row">' +
' <div class="box1 col-md-6">' +
' <label></label>' +
' <span class="info-container">' +
' <span class="info"></span>' +
' <button type="button" class="btn btn-sm clear1" style="float:right!important;"></button>' +
' </span>' +
' <input class="form-control filter" type="text">' +
' <div class="btn-group buttons">' +
' <button type="button" class="btn moveall"></button>' +
' <button type="button" class="btn move"></button>' +
' </div>' +
' <select multiple="multiple"></select>' +
' </div>' +
' <div class="box2 col-md-6">' +
' <label></label>' +
' <span class="info-container">' +
' <span class="info"></span>' +
' <button type="button" class="btn btn-sm clear2" style="float:right!important;"></button>' +
' </span>' +
' <input class="form-control filter" type="text">' +
' <div class="btn-group buttons">' +
' <button type="button" class="btn remove"></button>' +
' <button type="button" class="btn removeall"></button>' +
' </div>' +
' <select multiple="multiple"></select>' +
' </div>' +
'</div>')
.insertBefore(this.element);
// Cache the inner elements
this.elements = {
originalSelect: this.element,
box1: $('.box1', this.container),
box2: $('.box2', this.container),
filterInput1: $('.box1 .filter', this.container),
filterInput2: $('.box2 .filter', this.container),
filterClear1: $('.box1 .clear1', this.container),
filterClear2: $('.box2 .clear2', this.container),
label1: $('.box1 > label', this.container),
label2: $('.box2 > label', this.container),
info1: $('.box1 .info', this.container),
info2: $('.box2 .info', this.container),
select1: $('.box1 select', this.container),
select2: $('.box2 select', this.container),
moveButton: $('.box1 .move', this.container),
removeButton: $('.box2 .remove', this.container),
moveAllButton: $('.box1 .moveall', this.container),
removeAllButton: $('.box2 .removeall', this.container),
form: $($('.box1 .filter', this.container)[0].form)
};
// Set select IDs
this.originalSelectName = this.element.attr('name') || '';
var select1Id = 'bootstrap-duallistbox-nonselected-list_' + this.originalSelectName,
select2Id = 'bootstrap-duallistbox-selected-list_' + this.originalSelectName;
this.elements.select1.attr('id', select1Id);
this.elements.select2.attr('id', select2Id);
this.elements.label1.attr('for', select1Id);
this.elements.label2.attr('for', select2Id);
// Apply all settings
this.selectedElements = 0;
this.sortIndex = 0;
this.elementCount = 0;
this.setFilterTextClear(this.settings.filterTextClear);
this.setFilterPlaceHolder(this.settings.filterPlaceHolder);
this.setMoveSelectedLabel(this.settings.moveSelectedLabel);
this.setMoveAllLabel(this.settings.moveAllLabel);
this.setRemoveSelectedLabel(this.settings.removeSelectedLabel);
this.setRemoveAllLabel(this.settings.removeAllLabel);
this.setMoveOnSelect(this.settings.moveOnSelect);
this.setMoveOnDoubleClick(this.settings.moveOnDoubleClick);
this.setPreserveSelectionOnMove(this.settings.preserveSelectionOnMove);
this.setSelectedListLabel(this.settings.selectedListLabel);
this.setNonSelectedListLabel(this.settings.nonSelectedListLabel);
this.setHelperSelectNamePostfix(this.settings.helperSelectNamePostfix);
this.setSelectOrMinimalHeight(this.settings.selectorMinimalHeight);
updateSelectionStates(this);
this.setShowFilterInputs(this.settings.showFilterInputs);
this.setNonSelectedFilter(this.settings.nonSelectedFilter);
this.setSelectedFilter(this.settings.selectedFilter);
this.setInfoText(this.settings.infoText);
this.setInfoTextFiltered(this.settings.infoTextFiltered);
this.setInfoTextEmpty(this.settings.infoTextEmpty);
this.setFilterOnValues(this.settings.filterOnValues);
this.setSortByInputOrder(this.settings.sortByInputOrder);
this.setEventMoveOverride(this.settings.eventMoveOverride);
this.setEventMoveAllOverride(this.settings.eventMoveAllOverride);
this.setEventRemoveOverride(this.settings.eventRemoveOverride);
this.setEventRemoveAllOverride(this.settings.eventRemoveAllOverride);
this.setBtnClass(this.settings.btnClass);
this.setBtnMoveText(this.settings.btnMoveText);
this.setBtnRemoveText(this.settings.btnRemoveText);
this.setBtnMoveAllText(this.settings.btnMoveAllText);
this.setBtnRemoveAllText(this.settings.btnRemoveAllText);
// Hide the original select
this.element.hide();
bindEvents(this);
refreshSelects(this);
return this.element;
},
setFilterTextClear: function(value, refresh) {
this.settings.filterTextClear = value;
this.elements.filterClear1.html(value);
this.elements.filterClear2.html(value);
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setFilterPlaceHolder: function(value, refresh) {
this.settings.filterPlaceHolder = value;
this.elements.filterInput1.attr('placeholder', value);
this.elements.filterInput2.attr('placeholder', value);
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setMoveSelectedLabel: function(value, refresh) {
this.settings.moveSelectedLabel = value;
this.elements.moveButton.attr('title', value);
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setMoveAllLabel: function(value, refresh) {
this.settings.moveAllLabel = value;
this.elements.moveAllButton.attr('title', value);
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setRemoveSelectedLabel: function(value, refresh) {
this.settings.removeSelectedLabel = value;
this.elements.removeButton.attr('title', value);
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setRemoveAllLabel: function(value, refresh) {
this.settings.removeAllLabel = value;
this.elements.removeAllButton.attr('title', value);
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setMoveOnSelect: function(value, refresh) {
if (isBuggyAndroid) {
value = true;
}
this.settings.moveOnSelect = value;
if (this.settings.moveOnSelect) {
this.container.addClass('moveonselect');
var self = this;
this.elements.select1.on('change', function() {
move(self);
});
this.elements.select2.on('change', function() {
remove(self);
});
this.elements.moveButton.detach();
this.elements.removeButton.detach();
} else {
this.container.removeClass('moveonselect');
this.elements.select1.off('change');
this.elements.select2.off('change');
this.elements.moveButton.insertAfter(this.elements.moveAllButton);
this.elements.removeButton.insertBefore(this.elements.removeAllButton);
}
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setMoveOnDoubleClick: function(value, refresh) {
if (isBuggyAndroid) {
value = false;
}
this.settings.moveOnDoubleClick = value;
if (this.settings.moveOnDoubleClick) {
this.container.addClass('moveondoubleclick');
var self = this;
this.elements.select1.on('dblclick', function() {
move(self);
});
this.elements.select2.on('dblclick', function() {
remove(self);
});
} else {
this.container.removeClass('moveondoubleclick');
this.elements.select1.off('dblclick');
this.elements.select2.off('dblclick');
}
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setPreserveSelectionOnMove: function(value, refresh) {
// We are forcing to move on select and disabling preserveSelectionOnMove on Android
if (isBuggyAndroid) {
value = false;
}
this.settings.preserveSelectionOnMove = value;
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setSelectedListLabel: function(value, refresh) {
this.settings.selectedListLabel = value;
if (value) {
this.elements.label2.show().html(value);
} else {
this.elements.label2.hide().html(value);
}
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setNonSelectedListLabel: function(value, refresh) {
this.settings.nonSelectedListLabel = value;
if (value) {
this.elements.label1.show().html(value);
} else {
this.elements.label1.hide().html(value);
}
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setHelperSelectNamePostfix: function(value, refresh) {
this.settings.helperSelectNamePostfix = value;
if (value) {
this.elements.select1.attr('name', this.originalSelectName + value + '1');
this.elements.select2.attr('name', this.originalSelectName + value + '2');
} else {
this.elements.select1.removeAttr('name');
this.elements.select2.removeAttr('name');
}
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setSelectOrMinimalHeight: function(value, refresh) {
this.settings.selectorMinimalHeight = value;
var height = this.element.height();
if (this.element.height() < value) {
height = value;
}
this.elements.select1.height(height);
this.elements.select2.height(height);
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setShowFilterInputs: function(value, refresh) {
if (!value) {
this.setNonSelectedFilter('');
this.setSelectedFilter('');
refreshSelects(this);
this.elements.filterInput1.hide();
this.elements.filterInput2.hide();
} else {
this.elements.filterInput1.show();
this.elements.filterInput2.show();
}
this.settings.showFilterInputs = value;
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setNonSelectedFilter: function(value, refresh) {
if (this.settings.showFilterInputs) {
this.settings.nonSelectedFilter = value;
this.elements.filterInput1.val(value);
if (refresh) {
refreshSelects(this);
}
return this.element;
}
},
setSelectedFilter: function(value, refresh) {
if (this.settings.showFilterInputs) {
this.settings.selectedFilter = value;
this.elements.filterInput2.val(value);
if (refresh) {
refreshSelects(this);
}
return this.element;
}
},
setInfoText: function(value, refresh) {
this.settings.infoText = value;
if (value) {
this.elements.info1.show();
this.elements.info2.show();
} else {
this.elements.info1.hide();
this.elements.info2.hide();
}
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setInfoTextFiltered: function(value, refresh) {
this.settings.infoTextFiltered = value;
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setInfoTextEmpty: function(value, refresh) {
this.settings.infoTextEmpty = value;
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setFilterOnValues: function(value, refresh) {
this.settings.filterOnValues = value;
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setSortByInputOrder: function(value, refresh){
this.settings.sortByInputOrder = value;
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setEventMoveOverride: function(value, refresh) {
this.settings.eventMoveOverride = value;
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setEventMoveAllOverride: function(value, refresh) {
this.settings.eventMoveAllOverride = value;
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setEventRemoveOverride: function(value, refresh) {
this.settings.eventRemoveOverride = value;
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setEventRemoveAllOverride: function(value, refresh) {
this.settings.eventRemoveAllOverride = value;
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setBtnClass: function(value, refresh) {
this.settings.btnClass = value;
this.elements.moveButton.attr('class', 'btn move').addClass(value);
this.elements.removeButton.attr('class', 'btn remove').addClass(value);
this.elements.moveAllButton.attr('class', 'btn moveall').addClass(value);
this.elements.removeAllButton.attr('class', 'btn removeall').addClass(value);
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setBtnMoveText: function(value, refresh) {
this.settings.btnMoveText = value;
this.elements.moveButton.html(value);
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setBtnRemoveText: function(value, refresh) {
this.settings.btnMoveText = value;
this.elements.removeButton.html(value);
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setBtnMoveAllText: function(value, refresh) {
this.settings.btnMoveText = value;
this.elements.moveAllButton.html(value);
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setBtnRemoveAllText: function(value, refresh) {
this.settings.btnMoveText = value;
this.elements.removeAllButton.html(value);
if (refresh) {
refreshSelects(this);
}
return this.element;
},
getContainer: function() {
return this.container;
},
refresh: function(mustClearSelections) {
updateSelectionStates(this);
if (!mustClearSelections) {
saveSelections(this, 1);
saveSelections(this, 2);
} else {
clearSelections(this);
}
refreshSelects(this);
},
destroy: function() {
this.container.remove();
this.element.show();
$.data(this, 'plugin_' + pluginName, null);
return this.element;
}
};
// A really lightweight plugin wrapper around the constructor,
// preventing against multiple instantiations
$.fn[ pluginName ] = function (options) {
var args = arguments;
// Is the first parameter an object (options), or was omitted, instantiate a new instance of the plugin.
if (options === undefined || typeof options === 'object') {
return this.each(function () {
// If this is not a select
if (!$(this).is('select')) {
$(this).find('select').each(function(index, item) {
// For each nested select, instantiate the Dual List Box
$(item).bootstrapDualListbox(options);
});
} else if (!$.data(this, 'plugin_' + pluginName)) {
// Only allow the plugin to be instantiated once so we check that the element has no plugin instantiation yet
// if it has no instance, create a new one, pass options to our plugin constructor,
// and store the plugin instance in the elements jQuery data object.
$.data(this, 'plugin_' + pluginName, new BootstrapDualListbox(this, options));
}
});
// If the first parameter is a string and it doesn't start with an underscore or "contains" the `init`-function,
// treat this as a call to a public method.
} else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
// Cache the method call to make it possible to return a value
var returns;
this.each(function () {
var instance = $.data(this, 'plugin_' + pluginName);
// Tests that there's already a plugin-instance and checks that the requested public method exists
if (instance instanceof BootstrapDualListbox && typeof instance[options] === 'function') {
// Call the method of our plugin instance, and pass it the supplied arguments.
returns = instance[options].apply(instance, Array.prototype.slice.call(args, 1));
}
});
// If the earlier cached method gives a value back return the value,
// otherwise return this to preserve chainability.
return returns !== undefined ? returns : this;
}
};
}));

File diff suppressed because one or more lines are too long