Drag drop grid without sortable

by Malin Jayakody

HTML

<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.min.js"></script>
<ul class="select-list">
  <li class="header">Object List</li>
  <li data-slots="1" class="s1">Object 1</li>
  <li data-slots="2" class="s2">Object 2</li>
  <li data-slots="3" class="s3">Object 3</li>
</ul>
<ul class="drop-list" id="sortable">
  <li>Slot 1</li>
  <li>Slot 2</li>
  <li>Slot 3</li>
  <li>Slot 4</li>
  <li>Slot 5</li>
  <li>Slot 6</li>
  <li>Slot 7</li>
  <li>Slot 8</li>
  <li>Slot 9</li>
  <li>Slot 10</li>
  <li>Slot 11</li>
  <li>Slot 12</li>
  <li>Slot 13</li>
</ul>

CSS

ul {
   list-style-type: none;
   margin: 0;
   padding: 0;
   float: left;
 }
 
 li {
   width: 150px;
 }
 
 li.header {
   height: 20px;
   font-weight: bold;
 }
 
 .select-list li {
   margin-bottom: 10px;
 }
 
 .drop-list {
   margin-left: 20px;
 }
 
 .drop-list li {
   background-color: #ccc;
   border-left: 1px solid black;
   border-right: 1px solid black;
   border-top: 1px solid black;
 }
 
 .drop-list li.dragover {
   background-color: #fff;
 }
 
 .drop-list li:last-child {
   border-bottom: 1px solid black;
 }
 
 li.s1 {
   background-color: #FFE5E5;
 }
 
 li.s2 {
   background-color: #C6D4FF;
 }
 
 li.s3 {
   background-color: #C6FFE3;
 }

JavaScript

(function($, undefined) {
  // document ready function
  $(function() {
    init();

    $('ul.select-list').on({
      'dragstart': dragstart,
      'dragend': dragend
    }, 'li');

    $('ul.drop-list').on({
      'dragenter dragover': dragover,
      'dragleave': dragleave,
      'drop': drop
    }, 'li.dropzone');
  });

  // Initializes the lists
  function init() {
    $('ul.select-list').find('li').not('[class="header"]').each(function() {
      var height = getSlotHeight() * $(this).data('slots');
      $(this).height(height);
    }).attr('draggable', true);

    $('ul.drop-list').find('li').each(function() {
      $(this).height(getSlotHeight());
    }).addClass('dropzone');
  }

  // Get the height of the grid
  function getSlotHeight() {
    return 20;
  }

  /**
   * Checks whether target is a kompatible dropzone
   * A dropzone needs the dropzone class
   * and needs to have enough consequent slots to drop the object into
   */
  function isDropZone(target, draggedObj) {
    var isDropZone = true;
    var slots = draggedObj.data('slots');
    for (var i = 1; i < slots; i++) {
      target = target.next();
      if (target.size() == 0 || !target.hasClass('dropzone')) {
        isDropZone = false;
        break;
      }
    }
    return isDropZone;
  }

  /* 
   * The following events are executed in the order the handlers are declared
   * dragstart being first and dragend being last
   */

  // dragstart event handler
  function dragstart(e) {
    e.stopPropagation();
    var dt = e.originalEvent.dataTransfer;
    dt.effectAllowed = 'move';
    dt.setData('text/html', '');
    $('ul.select-list').data({
      draggedObj: $(this)
    });
  }

  // dragover event handler
  function dragover(e) {
    e.preventDefault();
    e.stopPropagation();
    var data = $('ul.select-list').data();
    if (!data.draggedObj || !isDropZone($(this), data.draggedObj)) {
      e.originalEvent.dataTransfer.dropEffect = 'none';
      return;
    }
   ...