4

Scenario: Drag one or more elements and drop them in another list, but do not remove dragged elements from source list.

To allow for multiple dragging, I have used the code posted by Aaron Blenkush here.

Demo

I have made changes to fit my needs, like fixing the Shift issue.

  $("ul").on('click', 'li', function (e) {
      if (e.ctrlKey || e.metaKey) { //meta key for mac users
          $(this).toggleClass("ui-selected");
          $(this).parent().parent().siblings().children('ul').children().removeClass('ui-selected');
    }
    else if (e.shiftKey) {
        // $(this).toggleClass("selected");               
        var list = $(this).parent();
        var first = list.find('.ui-selected').first().index();
        // var last = list.find('.selected').last().index();
        var last = $(this).index();

        if (first == -1 || last == -1) {
            return false;
        }

        if (last < first) {
            firstHolder = first;
            first = last;
            last = firstHolder;
        }

        for (i = first; i <= last ; i++) {
            list.children().eq(i).addClass("ui-selected");
        }
    }
    else {                
        $(this).addClass("ui-selected").siblings().removeClass('ui-selected'); //select only clicked element and unselecting other elements

        //to Remove selected Class from 2nd UL li
        $(this).parent().parent().siblings().children('ul').children().removeClass('ui-selected');
    }
})
   .sortable({
       connectWith: "ul",
       delay: 150, //Needed to prevent accidental drag when trying to select
       revert: 0,
       cursor: "move",
       disabled: false,
       placeholder: 'placeholder',
       //  handle: ".handle",
       helper: function (e, item) {
           //Basically, if you grab an unhighlighted item to drag, it will deselect (unhighlight) everything else
           if (!item.hasClass('ui-selected')) {
               item.addClass('ui-selected').siblings().removeClass('ui-selected');
           }

           //////////////////////////////////////////////////////////////////////
           //HERE'S HOW TO PASS THE SELECTED ITEMS TO THE `stop()` FUNCTION:

           //Clone the selected items into an array
           var elements = item.parent().children('.ui-selected').clone();

           //Add a property to `item` called 'multidrag` that contains the selected items, then remove the selected items from the source list
           item.data('multidrag', elements)
               //.siblings('.ui-selected').remove();

           //Now the selected items exist in memory, attached to the `item`, so we can access them later when we get to the `stop()` callback

           //Create the helper
           var helper = $('<li/>');
           return helper.append(elements);
       },
       start: function(event, ui) {
           //$(ui.item).show();
           var elements = ui.item.data('multidrag');
           ui.item.after(elements);
           //clone = $(ui.item).clone();
           //before = $(ui.item).prev();
       },
       stop: function (e, ui) {
           //Now we access those items that we stored in `item`s data!
           var elements = ui.item.data('multidrag');

           //`elements` now contains the originally selected items from the source list (the dragged items)!!

           //Finally I insert the selected items after the `item`, then remove the `item`, since item is a duplicate of one of the selected items.
           ui.item.after(elements).remove();
         //  $(ui.item).show();
           //$(this).sortable('cancel');
       }
   });

Issue: It removes the dropped element from the source list.

I have researched a bit on this issue. Some say to use a clone in the helper method, but when I pass to a function that returns multiple elements I can't use clone. In Firebug when I drag elements it puts style=display:none on them but when I drop elements it removes them from the source list.

Update

i have made some changes in accepted answer to make it simpler

Updated Answer

there are some issues like when li dropped from 1st list to 2nd list. and you drag back that li from 2nd to first it will remove element

solution cld be when item gets dropped in to 2nd list remove ui-selected class.

i hope it will help some one :)

Community
  • 1
  • 1
Salman
  • 1,266
  • 5
  • 21
  • 41

1 Answers1

2

Well I was messing with it for a while.. The following if the best I could come up with in that time..

var selected;
var selectedCurrent;
var temp;
var received = false;
$("ul").on('mousedown', 'li', function (e) {
if($(this).next('li').hasClass('pholder'))
        $(this).next('li').remove();
if ((e.ctrlKey || e.metaKey) && selected != undefined) {
    if($(this).text() != selectedCurrent.text()) 
         selectedCurrent.after(selected.clone().addClass('pholder temp').hide());
}
selectedCurrent = $(this);
selected = $(this).clone().removeClass('selected');
});
$("ul").on('click', 'li', function (e) {
if(temp != undefined)
    $('.temp').remove();        
if (e.ctrlKey || e.metaKey) {
    if($(this).next('li').hasClass('pholder'))
        $(this).next('li').remove();
    else
        $(this).after($(this).clone().addClass('pholder').hide());
    $(this).toggleClass("selected");
} else {
    $(this).addClass("selected").siblings().removeClass('selected');
    $('.pholder').remove();
}
}).sortable({
connectWith: "ul",
delay: 150,
revert: 0,
helper: function (e, item) {
    if (!item.hasClass('selected')) {
        item.addClass('selected').siblings().removeClass('selected');
    }
    var elements = item.parent().children('.selected').clone();
    item.data('multidrag', elements).siblings('.selected').remove();
    var helper = $('<li/>');
    return helper.append(elements);
},
stop: function (e, ui) {
    if(!received){
        selected.remove();
        $('.pholder').remove(); 
    }
    else{
        received = false;
        $('.pholder').removeClass('pholder');
    }
    var elements = ui.item.data('multidrag');
    ui.item.after(elements).remove();
    $('.selected').removeClass('selected');
},
start: function(event, ui){
    ui.item.after(selected);
    $('.pholder').show();
},
receive: function(event, ui){
        received = true;
}
});

Fiddle

http://jsfiddle.net/hQnWG/749/

Update

http://jsfiddle.net/hQnWG/752/

Update 2 - Gets rid of duplicates in list.

http://jsfiddle.net/hQnWG/754/

Trevor
  • 16,080
  • 9
  • 52
  • 83
  • there is one issue. if you select all three li with ctrl it duplicate li between first and second that increase count of li. – Salman Nov 14 '13 at 11:06
  • @user751959 Yeah I was afraid there would probably be some bugs.. I'll look into it though. – Trevor Nov 14 '13 at 13:33
  • @user751959 I came up with a more robust update. http://jsfiddle.net/hQnWG/752/ The only thing I can find now is that say if you have multiple `One`'s in the list or multiple of any number and you move both of them to the other list then only one of the `One`'s stays in the original list and not both.. I don't know why you would want multiple of the same thing in a list anyway so I'll come up with once more fiddle where if there are duplicates in the list it removes them. – Trevor Nov 14 '13 at 19:31
  • @user751959 one last update that gets rid of duplicates... http://jsfiddle.net/hQnWG/754/ – Trevor Nov 14 '13 at 19:58
  • i have tried it with ur code . its so complex i come up with simpler solution . [http://jsfiddle.net/abUF2/1/](http://jsfiddle.net/abUF2/1/) – Salman Nov 16 '13 at 09:31