Реализация Заполнить пробелы с помощью drag & drop jQuery в HTML

Я реализую функцию Заполнить пробелы.

введите описание изображения здесь

Codepen Link

Здесь у меня есть список ответов выше i.e один, два, три и т.д. и пустые пространства ниже, где эти ответы будут заполнены.

Вещи, которые выполняются

1) Перетащите параметры из списка ответов и заполните пустые поля. Готово

2) Если я перетащил ответ из заполненного поля в пустой поле, предыдущее значение должно быть пустым. Готово

Теперь возникает проблема

1) Если я перетащил ответ из заполненного поля в другой заполненный ящик, то как переключить значения и положение обоих полей. Я думал, что мы можем получить позицию предыдущего и текущего, а затем поменять позицию, но не знаем, как ее реализовать.

2) Если я перетащил значение из списка ответов в заполненный ящик, то как их поменять

Вот что я сделал до сих пор:

$(document).ready(function() {
  var arr;
  $("span").droppable({
    accept: "ul > li",
    classes: {
      "ui-droppable-hover": "ui-state-hover"
    },
    drop: function(event, ui) {
      arr = [];
      var dragedElement = ui.draggable.text();
      $(this).addClass("ui-state-highlight");
      $(this).html(dragedElement);
      $('span').each(function() {
        arr.push($(this).text());
      });
      //console.log(JSON.stringify(arr));

      var matched = arr.filter((value) => value == dragedElement);
      //console.log(JSON.stringify(matched));

      $('span').each(function() {
        if ($(this).text() == matched[1]) {
          $(this).addClass('matched');
          //localStorage.setItem('prevValue', $(this).text());
          $('span.matched').text('');
          $(this).removeClass("ui-state-highlight");
          $(this).removeClass('matched');
        }
      });

      $(this).html(dragedElement);
      $(this).addClass("ui-state-highlight");

    }
  });

  $("ul > li").draggable({
    revert: "invalid"
  });
})
span {
  width: 100px;
  display: inline-block;
  height: 20px;
  background: #ffffff;
}

body {
  font: 13px Verdana;
}

ul {
  list-style: none;
  padding: 10px;
  background: yellow;
}

ul li {
  display: inline-block;
  margin: 0 10px;
  padding: 10px;
  background: rgb(0, 255, 213);
}

p {
  padding: 10px;
  background: rgb(255, 145, 0);
}
<link rel="stylesheet" href="#" onclick="location.href='https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.css'; return false;" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<ul>
  <li>one</li>
  <li>two</li>
  <li>three</li>
  <li>four</li>
  <li>five</li>
  <li>six</li>
</ul>
<p>hello
  <span></span>hello
  <span></span>hello
  <span></span>
</p>

Ответ 1

Я думаю, вам не нужно перетаскивать заполненный ответ на другой ответ, потому что у пользователей есть несколько параметров и может перетаскивать каждую опцию, чтобы ответить, и когда пользователь делает это, он изменяет последний вариант. Это не имеет смысла, когда пользователь перетаскивает опцию после перехода на ответ. Для этого сценария вы можете сделать это следующим образом:

$(document).ready(function() {
  $("span").droppable({
    accept: "ul > li",
    classes: {
      "ui-droppable-hover": "ui-state-hover"
    },
    drop: function(event, ui) {
      var dragedElement = ui.draggable.text();
      $(this).addClass("ui-state-highlight");
      $(this).html(dragedElement);
      $(this).addClass('matched');  
    }
  });

  $("ul li").draggable({
    helper:"clone",
    revert: "invalid"
  });

})

Онлайн-демонстрация (jsFiddle)

Edit

Если вы хотите перетащить ответы, вы можете сделать это следующим образом:

$(document).ready(function() {
  // This code used for set order attribute for options
var numberOfItems = $("#options").find('li').length;
$.each($("#options").find('li'), function(index, item) {
    $(item).attr("order", index);
    var removeBotton = $('<i class="fa fa-times" style="display:none"></i>');
    removeBotton.click(function(){
        addToOlderPlace($(this).parent());        
      });
    $(item).append(removeBotton);

});

  $("span").droppable({
    accept: "li",
    classes: {
      "ui-droppable-hover": "ui-state-hover"
    },
    drop: function(event, ui) {
    // Check for existing another option
    if($(this).find('li').length > 0)
    addToOlderPlace($(this).find('li'));

      $(this).addClass("ui-state-highlight");
      $(this).addClass('matched');  

      $(ui.draggable).find('i').attr("style","");
      $(this).append($(ui.draggable));    

    }
  });

  $("li").draggable({
    helper:"clone",
    revert: "invalid"
  }); 


  // This function used for find old place of option
  // This function used for find old place of item


  function addToOlderPlace($item) {
        var indexItem = $item.attr('order');
        var itemList = $("#options").find('li');
        $item.find('i').hide();         

        if (indexItem === "0")
            $("#options").prepend($item);
        else if (Number(indexItem) === (Number(numberOfItems)-1))        
               $("#options").append($item);                       
        else
            $(itemList[indexItem - 1]).after($item);
    }

})

Онлайн-демонстрация (jsFiddle)

Ответ 2

Я сделал скрипку некоторое время назад, чтобы продемонстрировать, как решить проблему такого типа. Включение функции tolerance:intersect в функции drop/droppable является ключом к решению.

В этом фрагменте я не подражал вашему коду, но представил пример из моей скрипки, чтобы вы могли видеть, как вы можете применить это решение к своему собственному коду.

$("#launchPad").height($(window).height() - 20);
var dropSpace = $(window).width() - $("#launchPad").width();
$("#dropZone").width(dropSpace - 70);
$("#dropZone").height($("#launchPad").height());

$(".card").draggable({
    appendTo: "#launchPad",
    cursor: "move",
    helper: 'clone',
    revert: "invalid",

});

$("#launchPad").droppable({
    tolerance: "intersect",
    accept: ".card",
    activeClass: "ui-state-default",
    hoverClass: "ui-state-hover",
    drop: function(event, ui) {
        $("#launchPad").append($(ui.draggable));
    }
});

$(".stackDrop1").droppable({
    tolerance: "intersect",
    accept: ".card",
    activeClass: "ui-state-default",
    hoverClass: "ui-state-hover",
    drop: function(event, ui) {        
        $(this).append($(ui.draggable));
    }
});

$(".stackDrop2").droppable({
    tolerance: "intersect",
    accept: ".card",
    activeClass: "ui-state-default",
    hoverClass: "ui-state-hover",
    drop: function(event, ui) {        
        $(this).append($(ui.draggable));
    }
});
body {
  margin: 0;
}

#launchPad {
  width: 200px;
  float: left;
  border: 1px solid #eaeaea;
  background-color: #f5f5f5;
}

#dropZone {
  float: right;
  border: 1px solid #eaeaea;
  background-color: #ffffcc;
}

.card {
  width: 150px;
  padding: 5px 10px;
  margin: 5px;
  border: 1px solid #ccc;
  background-color: #eaeaea;
}

.stack {
  width: 180px;
  border: 1px solid #ccc;
  background-color: #f5f5f5;
  margin: 20px;
}

.stackHdr {
  background-color: #eaeaea;
  border: 1px solid #fff;
  padding: 5px
}

.stackDrop1,
.stackDrop2 {
  min-height: 100px;
  padding: 15px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<link href="#" onclick="location.href='https://code.jquery.com/ui/1.12.1/themes/smoothness/jquery-ui.css'; return false;" type="text/css">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<link href="#" onclick="location.href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css'; return false;" rel="stylesheet" />


<div id="launchPad">
  <div class="card draggable">
    apple
  </div>
  <div class="card draggable">
    orange
  </div>
  <div class="card draggable">
    banana
  </div>
  <div class="card draggable">
    car
  </div>
  <div class="card draggable">
    bus
  </div>
</div>

<div id="dropZone">
  <div class="stack">
    <div class="stackHdr">
      Drop here
    </div>
    <div class="stackDrop1 droppable">

    </div>
  </div>

  <div class="stack">
    <div class="stackHdr">
      Or here
    </div>
    <div class="stackDrop2 droppable">

    </div>
  </div>
</div>