Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enable Shift-Multiselect in jQuery UI Selectable

I want to enable multiselect capabilities in a jQuery UI Selectable table by holding shift.

I probably should do something like this if shift is held down on mouseclick

  • Get topmost selected element
  • Get clicked element
  • Select all elements in between

but i can't find how to do this in a clean way...

At the moment i got this inside the selectable configuration:

start: function(e)
        {
            var oTarget = jQuery(e.target);
            if(!oTarget.is('tr')) oTarget = oTarget.parents('tr');
        }

So oTarget is the clicked element (and e.currentTarget is the whole table) but now what? How can i find which elements are already selected in a way that can tell me if the clicked element is over or below the selected ones and select everything in between?

I've solved it now like this, added to the selectable element:

jQuery(table).mousedown(function(e)
    {
        //Enable multiselect with shift key
        if(e.shiftKey)
        {
            var oTarget = jQuery(e.target);
            if(!oTarget.is('.ui-selectee')) oTarget = oTarget.parents('.ui-selectee');

            var iNew = jQuery(e.currentTarget).find('.ui-selectee').index(oTarget);
            var iCurrent = jQuery(e.currentTarget).find('.ui-selectee').index(jQuery(e.currentTarget).find('.ui-selected'));

            if (iCurrent < iNew) {
                iHold = iNew;
                iNew = iCurrent;
                iCurrent = iHold;
            }

            if(iNew != '-1')
            {
                jQuery(e.currentTarget).find('.ui-selected').removeClass('ui-selected');
                for (i=iNew;i<=iCurrent;i++) {
                    jQuery(e.currentTarget).find('.ui-selectee').eq(i).addClass('ui-selected');
                }
                e.stopImmediatePropagation();
                e.stopPropagation();
                e.preventDefault();
                return false;
            }
        }
    }).selectable(...)
like image 429
bardiir Avatar asked Feb 21 '12 09:02

bardiir


3 Answers

You can do it without plugins like this:

var prev = -1; // here we will store index of previous selection
$('tbody').selectable({
    selecting: function(e, ui) { // on select
        var curr = $(ui.selecting.tagName, e.target).index(ui.selecting); // get selecting item index
        if(e.shiftKey && prev > -1) { // if shift key was pressed and there is previous - select them all
            $(ui.selecting.tagName, e.target).slice(Math.min(prev, curr), 1 + Math.max(prev, curr)).addClass('ui-selected');
            prev = -1; // and reset prev
        } else {
            prev = curr; // othervise just save prev
        }
    }
});

Here is live demo: http://jsfiddle.net/mac2000/DJFaL/1/embedded/result/

like image 191
mac Avatar answered Nov 20 '22 14:11

mac


I wrote simple plugin for that functionality. It's not dependent on jQuery ui Selectable plugin and as far as i know works fine with it.

You can find plugin code and simple example here: http://jsfiddle.net/bMgpc/170/

Going to write simple description below.

Basic usage:

$('ul').multiSelect();

If you hold "Ctrl" or "Command Key" then you can select/unselect elements one by one.

ul - parent that holds inner elements to be selected.

There are number of options available:

  • keepSelection - true|false - quite an important flag. If set to true (default), then selection won't be cleared if you click on already selected element (as it works in with multiple prop)
  • multiselect - true|false -if false you can select only one element
  • selected - 'selected' - class that will be added to selected element
  • filter: - ' > *' - what elements are we going to select
  • unselectOn - false|'selector' - if set then if clicked on set selector selectio would be removed
  • start: false|function - callback on start
  • stop: false|function - callback on stop
  • unselecting: false|function - callback when clicked on set "unselectOn" option

It's a dev version plugin, so use with care

like image 33
Kane Cohen Avatar answered Nov 20 '22 16:11

Kane Cohen


After looking around I was unable to find a solution to this problem while still using jQuery UI's Selectable function, so I wrote one up. Essentially it taps into the selected / unselected callbacks of Selectable to manage DOM state while still honoring the callbacks as per the standard Selectable API. It supports the following use case:

  • Click one of the elements (shift+click, cntl+click, or click+drag also) anywhere in the list
  • Shift+click another element in the list
  • All elements between plus the two end points become selected

Usage for a table:

$('table').shiftSelectable({filter: 'tr'});

A few notes. (1) It currently only supports sibling elements. (2) It will pass through configuration options as you will see in the table example as well as the Selectable methods. (3) I heart underscore.js so it is used even though for this it is not essential. Feel free to swap out its simple checks and extends if you don't want to use this awesome library. And no, I have no affiliation with underscore.js. :)

table fiddle example

list fiddle example

Hope this helps someone else! Cheers.

like image 5
construct-pylons Avatar answered Nov 20 '22 16:11

construct-pylons