Commit 614bd4b5 authored by David Stutz's avatar David Stutz

Merge pull request #439 from Tyf0x/shift-select-improvement

Shift + Click range selection improvements. Fixes #431.
parents 847873e4 1bb4af91
...@@ -99,6 +99,7 @@ ...@@ -99,6 +99,7 @@
this.originalOptions = this.$select.clone()[0].options; this.originalOptions = this.$select.clone()[0].options;
this.query = ''; this.query = '';
this.searchTimeout = null; this.searchTimeout = null;
this.lastToggledInput = null
this.options.multiple = this.$select.attr('multiple') === "multiple"; this.options.multiple = this.$select.attr('multiple') === "multiple";
this.options.onChange = $.proxy(this.options.onChange, this); this.options.onChange = $.proxy(this.options.onChange, this);
...@@ -261,7 +262,7 @@ ...@@ -261,7 +262,7 @@
ul: '<ul class="multiselect-container dropdown-menu"></ul>', 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>', 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>', 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 href="javascript:void(0);"><label></label></a></li>', li: '<li><a tabindex="0"><label></label></a></li>',
divider: '<li class="multiselect-item divider"></li>', divider: '<li class="multiselect-item divider"></li>',
liGroup: '<li class="multiselect-item multiselect-group"><label></label></li>' liGroup: '<li class="multiselect-item multiselect-group"><label></label></li>'
} }
...@@ -451,50 +452,69 @@ ...@@ -451,50 +452,69 @@
} }
}, this)); }, this));
$('li a', this.$ul).on('touchstart click', function(event) { $('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(); event.stopPropagation();
var $target = $(event.target); var $target = $(event.target);
if (document.getSelection().type === 'Range') { if (event.shiftKey && this.options.multiple) {
var $input = $(this).find("input:first"); if($target.is("label")){ // Handles checkbox selection manually (see https://github.com/davidstutz/bootstrap-multiselect/issues/431)
event.preventDefault();
$input.prop("checked", !$input.prop("checked")) $target = $target.find("input");
.trigger("change"); $target.prop("checked", !$target.prop("checked"));
} }
if (event.shiftKey) {
var checked = $target.prop('checked') || false; var checked = $target.prop('checked') || false;
if (checked) { if (this.lastToggledInput !== null && this.lastToggledInput !== $target) { // Make sure we actually have a range
var prev = $target.closest('li') var from = $target.closest("li").index();
.siblings('li[class="active"]:first'); var to = this.lastToggledInput.closest("li").index();
var currentIdx = $target.closest('li') if (from > to) { // Swap the indices
.index(); var tmp = to;
var prevIdx = prev.index(); to = from;
from = tmp;
if (currentIdx > prevIdx) {
$target.closest("li").prevUntil(prev).each(
function() {
$(this).find("input:first").prop("checked", true)
.trigger("change");
}
);
} }
else {
$target.closest("li").nextUntil(prev).each( // Make sure we grab all elements since slice excludes the last index
function() { ++to;
$(this).find("input:first").prop("checked", true)
.trigger("change"); // 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(); $target.blur();
}); }, this));
// Keyboard support. // Keyboard support.
this.$container.off('keydown.multiselect').on('keydown.multiselect', $.proxy(function(event) { this.$container.off('keydown.multiselect').on('keydown.multiselect', $.proxy(function(event) {
......
...@@ -596,7 +596,7 @@ describe('Bootstrap Multiselect Specific Issues', function() { ...@@ -596,7 +596,7 @@ describe('Bootstrap Multiselect Specific Issues', function() {
selection.addRange(range); selection.addRange(range);
if (document.getSelection().type === 'Range') { if (document.getSelection().type === 'Range') {
$('#multiselect-container').find('a:first').trigger('click'); $('#multiselect-container').find('a:first label').trigger('click');
expect($('#multiselect-container').find('input:first').prop('checked')).toBe(true); expect($('#multiselect-container').find('input:first').prop('checked')).toBe(true);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment