Please note - this answer is incorrect, but I'm leaving it as it shows the extent of what can be done with jQuery UI selectable, and why it doesn't work. See accepted answer for a custom-rolled, working solution.
Thanks to Frédéric Hamidi for the pointer to this forum thread, I have solved this as below. My additional requirements not mentioned in the question, were that the selectable elements have to be in multiple containers (ultimately this will be dates in a calendar, contained in individual months).
Given the following HTML:
<div id="selectable">
<div>
<span id="a1">1</span>
<span id="a2">2</span>
<span id="a3">3</span>
<span id="a4">4</span>
<span id="a5">5</span>
<span id="a6">6</span>
<span id="a7">7</span>
<span id="a8">8</span>
<span id="a9">9</span>
<span id="a10">10</span>
</div>
<div>
<span id="b1">1</span>
<span id="b2">2</span>
<span id="b3">3</span>
<span id="b4">4</span>
<span id="b5">5</span>
<span id="b6">6</span>
<span id="b7">7</span>
<span id="b8">8</span>
<span id="b9">9</span>
<span id="b10">10</span>
</div>
</div>
Then this javascript solves it. Note, the linked post uses slice(start, end)
but I can't do that due to my multiple container requirement. So I've looped over all sortable elements with an each()
, and toggled selecting
based on if we've reached the first and not yet reached the last element.
I set filter: 'span'
in order to prevent other child elements of #selectable
becoming selectable.
$(function() {
var rangeSelecting = function(event, ui) {
var start = $(".ui-selecting", this).first();
var end = $(".ui-selecting", this).last();
var selecting = false;
$(this).find('span').removeClass("range-selecting").each(function() {
var $this = $(this);
var this_id = $this.attr('id');
if (start.attr('id') === this_id) selecting = true;
if (selecting) $this.addClass('range-selecting');
if (end.attr('id') === this_id) selecting = false;
});
}
$("#selectable").selectable({
filter: 'span',
selecting: rangeSelecting,
unselecting: rangeSelecting,
stop: function(event, ui) { $(".range-selecting", this).addClass("ui-selected").removeClass("range-selecting"); }
});
});</p>
See this jsfiddle for a working example.