title: Multi-select in the nestedSortable jQuery UI plugin?
body: <p>EDIT 3: Just to summarize what became quite a long question in the hope that someone might find it easier to get the gist of it and be able to help more easily:</p>
  
  <p>What I want is to get the jsfiddle # 2 below (under EDIT 2) to work, in the sense that it should correctly drop multiple items in the right place, when selected and dragged.</p>
  
  <p>Original question:</p>
  
  <p>I'm trying to figure out how to make nestedSortable allow multiple items to be selected. I cannot find any information about it anywhere by Googling, and I cannot figure it out myself.</p>
  
  <p>If anyone knows how to do this, that would be great. I have been looking at this as an example of how to get drag and drop with multiple items to work - this was hard to find in itself!</p>
  
  <p>jsfiddle #1, multi-select with drag and drop but only in a flat element structure:
  <a href="http://jsfiddle.net/2n9xkmg3/" rel="nofollow noreferrer">http://jsfiddle.net/2n9xkmg3/</a></p>
  
  <p>Main jQuery code here:</p>
  
  <pre><code>$(function () {
      $('.droptrue').on('click', 'li', function () {
          $(this).toggleClass('selected');
      });
  
      $("ul.droptrue").sortable({
          connectWith: 'ul.droptrue',
          opacity: 0.6,
          revert: true,
          helper: function (e, item) {
              console.log('parent-helper');
              console.log(item);
              if(!item.hasClass('selected'))
                 item.addClass('selected');
              var elements = $('.selected').not('.ui-sortable-placeholder').clone();
              var helper = $('&lt;ul/&gt;');
              item.siblings('.selected').addClass('hidden');
              return helper.append(elements);
          },
          start: function (e, ui) {
              var elements = ui.item.siblings('.selected.hidden').not('.ui-sortable-placeholder');
              ui.item.data('items', elements);
          },
          receive: function (e, ui) {
              ui.item.before(ui.item.data('items'));
          },
          stop: function (e, ui) {
              ui.item.siblings('.selected').removeClass('hidden');
              $('.selected').removeClass('selected');
          },
          update: updatePostOrder
      });
  
      $("#sortable1, #sortable2").disableSelection();
      $("#sortable1, #sortable2").css('minHeight', $("#sortable1").height() + "px");
      updatePostOrder();
  });
  
  function updatePostOrder() {
      var arr = [];
      $("#sortable2 li").each(function () {
          arr.push($(this).attr('id'));
      });
      $('#postOrder').val(arr.join(','));
  }
  </code></pre>
  
  <p>The suggestion for that example I found in a comment in another Stack overflow question:</p>
  
  <p><a href="https://stackoverflow.com/questions/5677993/how-do-i-drag-multiple-elements-with-javascript-or-jquery">How do I drag multiple elements at once with JavaScript or jQuery?</a></p>
  
  <p>So how could I make that multi-select work in nestedSortable plugin?</p>
  
  <p>See <a href="https://github.com/ilikenwf/nestedSortable" rel="nofollow noreferrer">https://github.com/ilikenwf/nestedSortable</a> for information about that plugin.</p>
  
  <p>Basically what I want to achieve is dragging and dropping of items (like files and folders, but could be other things too) in a web application, similar to what DropBox and Google Drive has with multiple dragging and dropping of files and folders in their web interfaces.</p>
  
  <p>Except...I need this with the nesting like in the nestedSortable plugin.</p>
  
  <p>Since so many web sites have functionality like that, I pretty much thought there would be a ready-made solution out there, but it has proven remarkably hard to find an answer to even the flat structure dragging and dropping of multiple items, let alone the combination with the nested structure. But there are quite a few of those examples in various web sites too, I just don't know how to achieve it.</p>
  
  <p>Any help greatly appreciated!</p>
  
  <p>EDIT: added the link to the plugin above.</p>
  
  <p>EDIT 2:</p>
  
  <p>I felt like the question needed a much more clear example in order to get help on this issue. So I created a full jsfiddle of my own.</p>
  
  <p>This one takes the jsfiddle referred to above and I have then tried to create a new one, based on the nestedSortable plugin example file: <a href="https://github.com/ilikenwf/nestedSortable/blob/2.0alpha/example.html" rel="nofollow noreferrer">https://github.com/ilikenwf/nestedSortable/blob/2.0alpha/example.html</a></p>
  
  <p>Here is my new jsfiddle:</p>
  
  <p>jsfiddle #2, ATTEMPT at multi-select with drag and drop in a nested structure:</p>
  
  <p><a href="http://jsfiddle.net/anderszvensson/w141dLLt/1/" rel="nofollow noreferrer">http://jsfiddle.net/anderszvensson/w141dLLt/1/</a></p>
  
  <p>I started with that example of a nested sortable list. Then I tried to incorporate the multi-select from the jsfiddle #1 (the one that only handles multi-select drag and drop for flat structures).</p>
  
  <p>The parts I have incorporated so far are only the toggleClass for <code>.selected</code> on the <code>&lt;li&gt;</code> elements, also adding a border for when an <code>&lt;li&gt;</code> is selected, and the <code>helper</code> option.</p>
  
  <p>This does make it work in part, but not completely. That is, dragging multiple elements shows that it does bring all the selected elements in the dragging.</p>
  
  <p>However, only one of the elements is still dropped/received. I am not able to get it to actually move/drop all the elements in the drag.</p>
  
  <p>I hope this helps, so that someone better than me at jQuery could figure out how to make the drag and drop of multiple elements work in this nestedSortable plugin.</p>
  
  <p>For clarity, here is the code from jsfiddle #2 (my own attempt):</p>
  
  <p>HTML:</p>
  
  <pre><code>&lt;body&gt;
      &lt;header&gt;
          &lt;h1&gt;nestedSortable jQuery Plugin&lt;/h1&gt;
  
          &lt;h2&gt;2.0&lt;/h2&gt;
      &lt;/header&gt;
  
      &lt;section&gt;
          &lt;p&gt;This is the demo page for the nestedSortable jQuery plugin.&lt;/p&gt;
  
          &lt;p&gt;&lt;strong&gt;Follow the development, read the docs and download the
          latest version directly from the &lt;a href="https://github.com/ilikenwf/nestedSortable"&gt;GitHub
          page&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
      &lt;/section&gt;&lt;!-- END section --&gt;
  
      &lt;section id="demo"&gt;
          &lt;ol class="sortable ui-sortable mjs-nestedSortable-branch mjs-nestedSortable-expanded"&gt;
             &lt;li style="display: list-item;" class="mjs-nestedSortable-branch mjs-nestedSortable-expanded" id="menuItem_2"&gt;
             &lt;div class="menuDiv"&gt;
                 &lt;span title="Click to show/hide children" class="disclose ui-icon ui-icon-minusthick"&gt;
                 &lt;span&gt;&lt;/span&gt;
                 &lt;/span&gt;
                 &lt;span title="Click to show/hide item editor" data-id="2" class="expandEditor ui-icon ui-icon-triangle-1-n"&gt;
                 &lt;span&gt;&lt;/span&gt;
                 &lt;/span&gt;
                 &lt;span&gt;
                 &lt;span data-id="2" class="itemTitle"&gt;a&lt;/span&gt;
                 &lt;span title="Click to delete item." data-id="2" class="deleteMenu ui-icon ui-icon-closethick"&gt;
                 &lt;span&gt;&lt;/span&gt;
                 &lt;/span&gt;
                 &lt;/span&gt;
                 &lt;div id="menuEdit2" class="menuEdit hidden"&gt;
                     &lt;p&gt;
                         Content or form, or nothing here. Whatever you want.
                     &lt;/p&gt;
                 &lt;/div&gt;
             &lt;/div&gt;
             &lt;ol&gt;
                 &lt;li style="display: list-item;" class="mjs-nestedSortable-branch mjs-nestedSortable-expanded" id="menuItem_4"&gt;
                 &lt;div class="menuDiv"&gt;
                     &lt;span title="Click to show/hide children" class="disclose ui-icon ui-icon-minusthick"&gt;
                     &lt;span&gt;&lt;/span&gt;
                     &lt;/span&gt;
                     &lt;span title="Click to show/hide item editor" data-id="4" class="expandEditor ui-icon ui-icon-triangle-1-n"&gt;
                     &lt;span&gt;&lt;/span&gt;
                     &lt;/span&gt;
                     &lt;span&gt;
                     &lt;span data-id="4" class="itemTitle"&gt;c&lt;/span&gt;
                     &lt;span title="Click to delete item." data-id="4" class="deleteMenu ui-icon ui-icon-closethick"&gt;
                     &lt;span&gt;&lt;/span&gt;
                     &lt;/span&gt;
                     &lt;/span&gt;
                     &lt;div id="menuEdit4" class="menuEdit hidden"&gt;
                         &lt;p&gt;
                             Content or form, or nothing here. Whatever you want.
                         &lt;/p&gt;
                     &lt;/div&gt;
                 &lt;/div&gt;
                 &lt;ol&gt;
                     &lt;li class="mjs-nestedSortable-leaf" id="menuItem_6"&gt;
                     &lt;div class="menuDiv"&gt;
                         &lt;span title="Click to show/hide children" class="disclose ui-icon ui-icon-minusthick"&gt;
                         &lt;span&gt;&lt;/span&gt;
                         &lt;/span&gt;
                         &lt;span title="Click to show/hide item editor" data-id="6" class="expandEditor ui-icon ui-icon-triangle-1-n"&gt;
                         &lt;span&gt;&lt;/span&gt;
                         &lt;/span&gt;
                         &lt;span&gt;
                         &lt;span data-id="6" class="itemTitle"&gt;e&lt;/span&gt;
                         &lt;span title="Click to delete item." data-id="6" class="deleteMenu ui-icon ui-icon-closethick"&gt;
                         &lt;span&gt;&lt;/span&gt;
                         &lt;/span&gt;
                         &lt;/span&gt;
                         &lt;div id="menuEdit6" class="menuEdit hidden"&gt;
                             &lt;p&gt;
                                 Content or form, or nothing here. Whatever you want.
                             &lt;/p&gt;
                         &lt;/div&gt;
                     &lt;/div&gt;
                     &lt;/li&gt;
                 &lt;/ol&gt;
                 &lt;/li&gt;
                 &lt;li style="display: list-item;" class="mjs-nestedSortable-leaf" id="menuItem_5"&gt;
                 &lt;div class="menuDiv"&gt;
                     &lt;span title="Click to show/hide children" class="disclose ui-icon ui-icon-minusthick"&gt;
                     &lt;span&gt;&lt;/span&gt;
                     &lt;/span&gt;
                     &lt;span title="Click to show/hide item editor" data-id="5" class="expandEditor ui-icon ui-icon-triangle-1-n"&gt;
                     &lt;span&gt;&lt;/span&gt;
                     &lt;/span&gt;
                     &lt;span&gt;
                     &lt;span data-id="5" class="itemTitle"&gt;d&lt;/span&gt;
                     &lt;span title="Click to delete item." data-id="5" class="deleteMenu ui-icon ui-icon-closethick"&gt;
                     &lt;span&gt;&lt;/span&gt;
                     &lt;/span&gt;
                     &lt;/span&gt;
                     &lt;div id="menuEdit5" class="menuEdit hidden"&gt;
                         &lt;p&gt;
                             Content or form, or nothing here. Whatever you want.
                         &lt;/p&gt;
                     &lt;/div&gt;
                 &lt;/div&gt;
                 &lt;/li&gt;
             &lt;/ol&gt;
             &lt;/li&gt;
             &lt;ol&gt;
             &lt;/ol&gt;
             &lt;li style="display: list-item;" class="mjs-nestedSortable-leaf" id="menuItem_7"&gt;
             &lt;div class="menuDiv"&gt;
                 &lt;span title="Click to show/hide children" class="disclose ui-icon ui-icon-minusthick"&gt;
                 &lt;span&gt;&lt;/span&gt;
                 &lt;/span&gt;
                 &lt;span title="Click to show/hide item editor" data-id="7" class="expandEditor ui-icon ui-icon-triangle-1-n"&gt;
                 &lt;span&gt;&lt;/span&gt;
                 &lt;/span&gt;
                 &lt;span&gt;
                 &lt;span data-id="7" class="itemTitle"&gt;f&lt;/span&gt;
                 &lt;span title="Click to delete item." data-id="7" class="deleteMenu ui-icon ui-icon-closethick"&gt;
                 &lt;span&gt;&lt;/span&gt;
                 &lt;/span&gt;
                 &lt;/span&gt;
                 &lt;div id="menuEdit7" class="menuEdit hidden"&gt;
                     &lt;p&gt;
                        Content or form, or nothing here. Whatever you want.
                     &lt;/p&gt;
                 &lt;/div&gt;
             &lt;/div&gt;
             &lt;/li&gt;
             &lt;li class="mjs-nestedSortable-leaf" id="menuItem_3"&gt;
             &lt;div class="menuDiv"&gt;
                 &lt;span title="Click to show/hide children" class="disclose ui-icon ui-icon-minusthick"&gt;
                 &lt;span&gt;&lt;/span&gt;
                 &lt;/span&gt;
                 &lt;span title="Click to show/hide item editor" data-id="3" class="expandEditor ui-icon ui-icon-triangle-1-n"&gt;
                 &lt;span&gt;&lt;/span&gt;
                 &lt;/span&gt;
                 &lt;span&gt;
                 &lt;span data-id="3" class="itemTitle"&gt;b&lt;/span&gt;
                 &lt;span title="Click to delete item." data-id="3" class="deleteMenu ui-icon ui-icon-closethick"&gt;
                 &lt;span&gt;&lt;/span&gt;
                 &lt;/span&gt;
                 &lt;/span&gt;
                 &lt;div id="menuEdit3" class="menuEdit hidden"&gt;
                     &lt;p&gt;
                         Content or form, or nothing here. Whatever you want.
                     &lt;/p&gt;
                 &lt;/div&gt;
             &lt;/div&gt;
             &lt;/li&gt;
         &lt;/ol&gt;
  
          &lt;h3&gt;Try the custom methods:&lt;/h3&gt;
  
          &lt;p&gt;&lt;br&gt;
          &lt;input id="serialize" name="serialize" type="submit" value=
          "Serialize"&gt;&lt;/p&gt;
          &lt;pre id="serializeOutput"&gt;
          &lt;/pre&gt;
  
          &lt;p&gt;&lt;input id="toArray" name="toArray" type="submit" value=
          "To array"&gt;&lt;/p&gt;
          &lt;pre id="toArrayOutput"&gt;
          &lt;/pre&gt;
  
          &lt;p&gt;&lt;input id="toHierarchy" name="toHierarchy" type="submit" value=
          "To hierarchy"&gt;&lt;/p&gt;
          &lt;pre id="toHierarchyOutput"&gt;
          &lt;/pre&gt;
  
          &lt;p&gt;&lt;em&gt;Note: This demo has the &lt;code&gt;maxLevels&lt;/code&gt; option set to '4'.&lt;/em&gt;&lt;/p&gt;
      &lt;/section&gt;&lt;!-- END #demo --&gt;
  
      &lt;section id="license"&gt;
          &lt;h4&gt;License&lt;/h4&gt;
  
          &lt;p&gt;This work is licensed under the MIT License.&lt;br&gt;
          Which means you can do pretty much whatever you want with it.&lt;/p&gt;
  
          &lt;p&gt;&amp;copy; 2010&amp;dash;2014 Manuele J Sarfatti&lt;/p&gt;
      &lt;/section&gt;&lt;!-- END #documentation --&gt;
  &lt;/body&gt;
  </code></pre>
  
  <p>JS:</p>
  
  <pre><code>$().ready(function(){
              $('li.mjs-nestedSortable-leaf').on('click', function () {               
                  $(this).toggleClass('selected');
              });
              var ns = $('ol.sortable').nestedSortable({
                  forcePlaceholderSize: true,
                  handle: 'div',
                  helper: function (e, item) {
                      console.log('parent-helper');
                      console.log(item);
                      if(!item.hasClass('selected'))
                         item.addClass('selected');
                      var elements = $('.selected').not('.ui-sortable-placeholder').clone();
                      var helper = $('&lt;ul/&gt;');
                      item.siblings('.selected').addClass('hidden');
                      return helper.append(elements);
                      },
                  start: function (e, ui) {
                      var elements = ui.item.siblings('.selected.hidden').not('.ui-sortable-placeholder');
                      ui.item.data('items', elements);
                  },
                  receive: function (e, ui) {
                      ui.item.before(ui.item.data('items'));
                  },
                  stop: function (e, ui) {
                      ui.item.siblings('.selected').removeClass('hidden');
                      $('.selected').removeClass('selected');
                  },                  
                  items: 'li',
                  opacity: .6,
                  placeholder: 'placeholder',
                  revert: 250,
                  tabSize: 25,
                  tolerance: 'pointer',
                  toleranceElement: '&gt; div',
                  maxLevels: 4,
                  isTree: true,
                  expandOnHover: 700,
                  startCollapsed: false,
                  change: function(){
                      console.log('Relocated item');
                  }
              });
  
              $('.expandEditor').attr('title','Click to show/hide item editor');
              $('.disclose').attr('title','Click to show/hide children');
              $('.deleteMenu').attr('title', 'Click to delete item.');
  
              $('.disclose').on('click', function() {
                  $(this).closest('li').toggleClass('mjs-nestedSortable-collapsed').toggleClass('mjs-nestedSortable-expanded');
                  $(this).toggleClass('ui-icon-plusthick').toggleClass('ui-icon-minusthick');
              });
  
              $('.expandEditor, .itemTitle').click(function(){
                  var id = $(this).attr('data-id');
                  $('#menuEdit'+id).toggle();
                  $(this).toggleClass('ui-icon-triangle-1-n').toggleClass('ui-icon-triangle-1-s');
              });
  
              $('.deleteMenu').click(function(){
                  var id = $(this).attr('data-id');
                  $('#menuItem_'+id).remove();
              });
  
              $('#serialize').click(function(){
                  serialized = $('ol.sortable').nestedSortable('serialize');
                  $('#serializeOutput').text(serialized+'\n\n');
              })
  
              $('#toHierarchy').click(function(e){
                  hiered = $('ol.sortable').nestedSortable('toHierarchy', {startDepthCount: 0});
                  hiered = dump(hiered);
                  (typeof($('#toHierarchyOutput')[0].textContent) != 'undefined') ?
                  $('#toHierarchyOutput')[0].textContent = hiered : $('#toHierarchyOutput')[0].innerText = hiered;
              })
  
              $('#toArray').click(function(e){
                  arraied = $('ol.sortable').nestedSortable('toArray', {startDepthCount: 0});
                  arraied = dump(arraied);
                  (typeof($('#toArrayOutput')[0].textContent) != 'undefined') ?
                  $('#toArrayOutput')[0].textContent = arraied : $('#toArrayOutput')[0].innerText = arraied;
              });
          });         
  
          function dump(arr,level) {
              var dumped_text = "";
              if(!level) level = 0;
  
              //The padding given at the beginning of the line.
              var level_padding = "";
              for(var j=0;j&lt;level+1;j++) level_padding += "    ";
  
              if(typeof(arr) == 'object') { //Array/Hashes/Objects
                  for(var item in arr) {
                      var value = arr[item];
  
                      if(typeof(value) == 'object') { //If it is an array,
                          dumped_text += level_padding + "'" + item + "' ...\n";
                          dumped_text += dump(value,level+1);
                      } else {
                          dumped_text += level_padding + "'" + item + "' =&gt; \"" + value + "\"\n";
                      }
                  }
              } else { //Strings/Chars/Numbers etc.
                  dumped_text = "===&gt;"+arr+"&lt;===("+typeof(arr)+")";
              }
              return dumped_text;
          }
  </code></pre>
  
  <p>CSS:</p>
  
  <pre><code>html {
              background-color: #eee;
          }
  
          body {
              -webkit-border-radius: 10px;
              -moz-border-radius: 10px;
              border-radius: 10px;
              color: #444;
              background-color: #fff;
              font-size: 13px;
              font-family: Freesans, sans-serif;
              padding: 2em 4em;
              width: 860px;
              margin: 15px auto;
              box-shadow: 1px 1px 8px #444;
              -mox-box-shadow: 1px 1px 8px #444;
              -webkit-box-shadow: 1px -1px 8px #444;
          }
  
          a,a:visited {
              color: #4183C4;
              text-decoration: none;
          }
  
          a:hover {
              text-decoration: underline;
          }
  
          pre,code {
              font-size: 12px;
          }
  
          pre {
              width: 100%;
              overflow: auto;
          }
  
          small {
              font-size: 90%;
          }
  
          small code {
              font-size: 11px;
          }
  
          .placeholder {
              outline: 1px dashed #4183C4;
          }
  
          .mjs-nestedSortable-error {
              background: #fbe3e4;
              border-color: transparent;
          }
  
          #tree {
              width: 550px;
              margin: 0;
          }
  
          ol {
              max-width: 450px;
              padding-left: 25px;
          }
  
          ol.sortable,ol.sortable ol {
              list-style-type: none;
          }
  
          .sortable li div {
              border: 1px solid #d4d4d4;
              -webkit-border-radius: 3px;
              -moz-border-radius: 3px;
              border-radius: 3px;
              cursor: move;
              border-color: #D4D4D4 #D4D4D4 #BCBCBC;
              margin: 0;
              padding: 3px;
          }
  
          li.mjs-nestedSortable-collapsed.mjs-nestedSortable-hovering div {
              border-color: #999;
          }
  
          .disclose, .expandEditor {
              cursor: pointer;
              width: 20px;
              display: none;
          }
  
          .sortable li.mjs-nestedSortable-collapsed &gt; ol {
              display: none;
          }
  
          .sortable li.mjs-nestedSortable-branch &gt; div &gt; .disclose {
              display: inline-block;
          }
  
          .sortable span.ui-icon {
              display: inline-block;
              margin: 0;
              padding: 0;
          }
  
          .menuDiv {
              background: #EBEBEB;
          }
  
          .menuEdit {
              background: #FFF;
          }
  
          .itemTitle {
              vertical-align: middle;
              cursor: pointer;
          }
  
          .deleteMenu {
              float: right;
              cursor: pointer;
          }
  
          h1 {
              font-size: 2em;
              margin-bottom: 0;
          }
  
          h2 {
              font-size: 1.2em;
              font-weight: 400;
              font-style: italic;
              margin-top: .2em;
              margin-bottom: 1.5em;
          }
  
          h3 {
              font-size: 1em;
              margin: 1em 0 .3em;
          }
  
          p,ol,ul,pre,form {
              margin-top: 0;
              margin-bottom: 1em;
          }
  
          dl {
              margin: 0;
          }
  
          dd {
              margin: 0;
              padding: 0 0 0 1.5em;
          }
  
          code {
              background: #e5e5e5;
          }
  
          input {
              vertical-align: text-bottom;
          }
  
          .notice {
              color: #c33;
          }
  
          .selected { 
              border: solid #000 1px;
          }
  </code></pre>