Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add scroll position return on select1. Add optgroup capability for s… #72

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
189 changes: 151 additions & 38 deletions src/jquery.bootstrap-duallistbox.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
/*
* Bootstrap Duallistbox - v3.0.2
* 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 ($, window, document, undefined) {
// Create the defaults once
var pluginName = 'bootstrapDualListbox',
defaults = {
bootstrap2Compatible: false,
filterTextClear: 'show all',
filterTextClear: 'Clear Filter',
filterPlaceHolder: 'Filter',
moveSelectedLabel: 'Move selected',
moveAllLabel: 'Move all',
Expand All @@ -21,7 +29,8 @@
infoText: 'Showing all {0}', // text when all options are visible / false for no info text
infoTextFiltered: '<span class="label label-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
filterOnValues: false, // filter by selector's values, boolean
selectOnGroup: true // select all children when group clicked
},
// Selections are invisible on android if the containing select is styled with CSS
// http://code.google.com/p/android/issues/detail?id=16922
Expand Down Expand Up @@ -112,65 +121,116 @@
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')));
}
var $item = $(item);
var selected = $item.prop('selected');
var ingroup = $item.parent().is('optgroup');

var list = selected ? dualListbox.elements.select2 : dualListbox.elements.select1;

if (selected) { dualListbox.selectedElements++; }

var tip = list;
if (ingroup) {
var $grp = $item.parent();
var label = $grp.attr('label');
var grpin = list.find('optgroup[label=' + label + ']');
if (grpin.length === 0) {
grpin = $('<optgroup/>').attr('label', label).on('click', { dlb: dualListbox }, selected? unselectGroup: selectGroup);
list.append(grpin);
}
tip = grpin;
}
tip.append($item.clone(true).prop('selected', $item.data('_selected')));
});

if (dualListbox.settings.showFilterInputs) {
filter(dualListbox, 1);
filter(dualListbox, 2);
filter(dualListbox, 1, false);
filter(dualListbox, 2, false);
}
refreshInfo(dualListbox);
}

function filter(dualListbox, selectIndex) {
if (!dualListbox.settings.showFilterInputs) {
return;
}

saveSelections(dualListbox, selectIndex);
function filter(dualListbox, selectIndex, moveToTop) {
if (!dualListbox.settings.showFilterInputs) {
return;
}

dualListbox.elements['select'+selectIndex].empty().scrollTop(0);
var regex = new RegExp($.trim(dualListbox.elements['filterInput'+selectIndex].val()), 'gi'),
allOptions = dualListbox.element.find('option'),
saveSelections(dualListbox, selectIndex);
if (moveToTop !== false) {
dualListbox.elements['select' + selectIndex].empty().scrollTop(0);
}
else {
dualListbox.elements['select' + selectIndex].empty();
}
var regex = new RegExp($.trim(dualListbox.elements['filterInput' + selectIndex].val()), 'gi'),
options = dualListbox.element;

if (selectIndex === 1) {
options = allOptions.not(':selected');
options = options.find('option').not(':selected');
} else {
options = options.find('option:selected');
}

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);
var $item = $(item),
isFiltered = true;
var ingroup = $item.parent().is('optgroup');
if (item.text.match(regex) || (ingroup && $item.parent().attr('label').match(regex)) || (dualListbox.settings.filterOnValues && $item.attr('value').match(regex) )) {
isFiltered = false;
var list = dualListbox.elements['select' + selectIndex];
var tip = list;
if (ingroup) {
var $grp = $item.parent();
var label = $grp.attr('label');
var grpin = list.find('optgroup[label="' + label + '"]');
if (grpin.length === 0) {
grpin = $('<optgroup/>').attr('label', label).on('click', { dlb: dualListbox }, (selectIndex === 1) ? selectGroup : unselectGroup);
list.append(grpin);
}
tip = grpin;
}
tip.append($item.clone(true).prop('selected', $item.data('_selected')));
}
dualListbox.element.find('option').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'));
dualListbox.element.find('option').eq($item.data('original-index')).data('_selected', $item.prop('selected'));
});
}

function sortOptions(select) {
select.find('option').sort(function(a, b) {
return ($(a).data('original-index') > $(b).data('original-index')) ? 1 : -1;
}).appendTo(select);
var $newgroups = $();
var options = select.find('option');
options.sort(function(a, b) {
return ($(a).data('original-index') > $(b).data('original-index')) ? 1 : -1;
});
options.each(function (index, item) {
var $item = $(item);
var tip = select;
var ingroup = $item.parent().is('optgroup');
if (ingroup) {
var $grp = $item.parent();
var label = $grp.attr('label');
var grpin = select.find('optgroup[label=' + label + ']');
if (grpin.length === 0) {
grpin = $('<optgroup/>').attr('label', label);
$newgroups.append(grpin);
select.append(grpin);
}
else {
grpin.appendTo(select);
}
tip = grpin;
}
$item.appendTo(tip);
});
return $newgroups;
}

function clearSelections(dualListbox) {
Expand All @@ -180,6 +240,7 @@
}

function move(dualListbox) {
var scrollPos = dualListbox.elements.select1.scrollTop();
if (dualListbox.settings.preserveSelectionOnMove === 'all' && !dualListbox.settings.moveOnSelect) {
saveSelections(dualListbox, 1);
saveSelections(dualListbox, 2);
Expand All @@ -195,8 +256,9 @@
});

refreshSelects(dualListbox);
dualListbox.elements.select1.scrollTop(scrollPos);
triggerChangeEvent(dualListbox);
sortOptions(dualListbox.elements.select2);
sortOptions(dualListbox.elements.select2).on('click', {dlb: dualListbox}, unselectGroup);
}

function remove(dualListbox) {
Expand All @@ -216,7 +278,31 @@

refreshSelects(dualListbox);
triggerChangeEvent(dualListbox);
sortOptions(dualListbox.elements.select1);
sortOptions(dualListbox.elements.select1).on('click', { dlb: dualListbox }, selectGroup);
}

function selectGroup(e)
{
$(this).find('option').each(function (index, item) {
var $item = $(item);
if (!$item.data('filtered1')) {
changeSelectionState(e.data.dlb, $item.data('original-index'), true);
}
});
move(e.data.dlb);
e.preventDefault();
}

function unselectGroup(e)
{
$(this).find('option').each(function (index, item) {
var $item = $(item);
if (!$item.data('filtered2')) {
changeSelectionState(e.data.dlb, $item.data('original-index'), false);
}
});
remove(e.data.dlb);
e.preventDefault();
}

function moveAll(dualListbox) {
Expand Down Expand Up @@ -314,7 +400,6 @@
' <label></label>' +
' <span class="info-container">' +
' <span class="info"></span>' +
' <button type="button" class="btn clear1 pull-right"></button>' +
' </span>' +
' <input class="filter" type="text">' +
' <div class="btn-group buttons">' +
Expand All @@ -325,14 +410,19 @@
' <button type="button" class="btn move">' +
' <i></i>' +
' </button>' +
' <button type="button" class="btn clear1">' +
' <span class="fa-stack fa-lg">' +
' <i class="fa fa-filter fa-stack-1x"></i>' +
' <i class="fa fa-ban fa-stack-2x text-danger"></i>' +
' </span>' +
' </button>' +
' </div>' +
' <select multiple="multiple"></select>' +
' </div>' +
' <div class="box2">' +
' <label></label>' +
' <span class="info-container">' +
' <span class="info"></span>' +
' <button type="button" class="btn clear2 pull-right"></button>' +
' </span>' +
' <input class="filter" type="text">' +
' <div class="btn-group buttons">' +
Expand All @@ -343,6 +433,12 @@
' <i></i>' +
' <i></i>' +
' </button>' +
' <button type="button" class="btn clear2">' +
' <span class="fa-stack fa-lg">' +
' <i class="fa fa-filter fa-stack-1x"></i>' +
' <i class="fa fa-ban fa-stack-2x text-danger"></i>' +
' </span>' +
' </button>' +
' </div>' +
' <select multiple="multiple"></select>' +
' </div>' +
Expand Down Expand Up @@ -412,6 +508,7 @@

bindEvents(this);
refreshSelects(this);
this.setSelectOnGroup(this.settings.selectOnGroup);

return this.element;
},
Expand All @@ -428,7 +525,7 @@
} else {
this.container.removeClass('row-fluid bs2compatible').addClass('row');
this.container.find('.box1, .box2').removeClass('span6').addClass('col-md-6');
this.container.find('.clear1, .clear2').removeClass('btn-mini').addClass('btn-default btn-xs');
//this.container.find('.clear1, .clear2').removeClass('btn-mini').addClass('btn-default btn-xs');
this.container.find('input, select').addClass('form-control');
this.container.find('.btn').addClass('btn-default');
this.container.find('.moveall > i, .move > i').removeClass('icon-arrow-right').addClass('glyphicon glyphicon-arrow-right');
Expand Down Expand Up @@ -575,6 +672,22 @@
}
return this.element;
},
setSelectOnGroup: function(value, refresh) {
this.settings.selectOnGroup = value;
if (this.settings.selectOnGroup) {
this.container.addClass('selectongroup');
this.elements.select1.find('optgroup').on('click', { dlb: this }, selectGroup);
this.elements.select2.find('optgroup').on('click', { dlb: this }, unselectGroup);
} else {
this.container.removeClass('selectongroup');
this.elements.select1.find('optgroup').off('click', selectGroup);
this.elements.select2.find('optgroup').off('click', unselectGroup);
}
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setShowFilterInputs: function(value, refresh) {
if (!value) {
this.setNonSelectedFilter('');
Expand Down