连接到 fancytree 的 sortable 在拖放时忘记了它的位置

sortable connected to fancytree is forgetting its position upon drag and drop

我正在尝试以特定方式连接 fancytree and a JQueryUI sortable,这样就可以实现:

  1. fancytree 节点可以在 fancytree 中重新排列
  2. 可排序项可以在可排序项中重新排列
  3. 可以将 fancytree 节点作为克隆拖放到 sortable 上,并且
  4. 可以将可排序的项目作为克隆放在 fancytree 上以创建新的 fancytree 节点

我现在拥有的代码可以完成所有这些工作,但有一个问题我正在解决;当我将一个可排序节点拖到 fancytree 时,它​​不会保留其在可排序节点中的位置;它移动到最后。

我正在寻找的是:正是这个示例代码中显示的行为,但是当从 sortable 拖动到 fancytree 时,sortable 项目保留其位置。

这是一个 fiddle 我的代码:

这是代码本身(与 fiddle 相同,也许可以节省一些点击...):

<html>
    <head>
    <meta charset="UTF-8">
    <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
    <script
        src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"
         integrity="sha256-VazP97ZCwtekAsvgPBSUwPFKdrwD3unUfSGVYrahUqU="
         crossorigin="anonymous"></script>
    <link href="https://cdn.jsdelivr.net/npm/jquery.fancytree@2.27/dist/skin-win8/ui.fancytree.min.css" rel="stylesheet">
    <!-- <script src="https://cdn.jsdelivr.net/npm/jquery.fancytree@2.27/dist/jquery.fancytree-all-deps.min.js"></script> -->
    <script src="https://cdn.jsdelivr.net/npm/jquery.fancytree@2.27/dist/jquery.fancytree-all.min.js"></script>
    </head>
    <body>
    <div id="tree"></div>

    <ul id="mylist">
        <li class="ui-state-default tonga">Item 1</li>
        <li class="ui-state-default tonga">Item 2</li>
        <li class="ui-state-default tonga">Item 3</li>
        <li class="ui-state-default tonga">Item 4</li>
        <li class="ui-state-default tonga">Item 5</li>
        <li class="ui-state-default tonga">Item 6</li>
        <li class="ui-state-default tonga">Item 7</li>
    </ul>

    <script type="text/javascript">
     $(function(){  // on page load
         $("#tree").fancytree({
         debugLevel: 0,
         selectMode: 1,
         extensions: ["dnd"],
         source: [
             {title: "Node 1", key: "1", "baloney": 44},
             {title: "Folder 2", key: "2", folder: true, children: [
             {title: "Node 2.1", key: "3", myOwnAttr: "abc"},
             {title: "Node 2.2", key: "4"}
             ]}
         ],
         dnd: {
             dragStart: function(node, data) {
             return true;
             },
             dragEnter: function(node, data) {
             return true;
             },
             dragDrop: function(node, data) {
             if ( !data.otherNode ) {
                 // it's a draggable from outside the fancytree
                 node.addNode({title: "Hello butt"}, data.hitMode);
                 return;
             } else {
                 // SOLUTION: this line enables reorder inside tree
                 data.otherNode.moveTo(node, data.hitMode);
             }
             },
             initHelper: function(sourceNode, data) {
             var helper = data.ui.helper;
             var foo = $(helper).find(".fancytree-title")[0].innerHTML;
             $(helper).find(".fancytree-drag-helper-img").remove();
             $(helper).find(".fancytree-title").replaceWith('<li class="ui-state-default tonga">'+foo+"</li>");
             },
             updateHelper: function(sourceNode, data) {
             },
             draggable: {
             appendTo: "body",
             connectToSortable: "#mylist",
             revert: "invalid",
             containment: "document"
             }
         },
         });

         $("#mylist").sortable(
         {
             connectWith: "#mylist",
             //containment: "parent"
         }
         ).disableSelection();

         $(".tonga").draggable({
         revert: true,
         helper: "clone",
         connectToFancytree: true
         });

         $(".tonga").draggable({
         revert: false,
         helper: "original",
         connectToSortable: "#mylist"
         });
     });
    </script>

    </body>
</html>

我想我已经明白了。一些事情需要返工。

首先需要处理sortable对象的out事件,存储item是否已经超出sortable的范围,也就是因为某些原因重新排序列表:

$("#mylist").sortable({
  connectWith: "#mylist",
  out: function(event, ui) {
    // store the original index of the sortable item only if we are moving the mouse (extra events fire which mess this up)
    if (event.originalEvent.type === "mousemove") {
      $(ui.item).data('drugout', true);
    }
  }
}).disableSelection();

然后需要将一些事件侦听器添加到可拖动对象中。 start 处理程序存储可拖动项的原始索引。 stop 处理程序确定该项目是否已超出可排序范围。如果该项目已超出可排序范围,则它会将该项目重新插入到其先前的索引处,从而有效地保留列表的顺序:

$(".tonga").draggable({
    revert: true,
    helper: "clone",
    connectToFancytree: true,
    start: function(event, ui) {
      $(event.target).data('previndex', $(event.target).index());
    },
    stop: function(event, ui) {
       if ($(event.target).data('drugout')) {
           var originalIndex = $(event.target).data('previndex');
          $("#mylist li:last").insertBefore($("#mylist li:eq(" + originalIndex + ")"));
       }
    }
});

这个 JSFiddle 有一个工作示例。

$(function() { // on page load
  $("#tree").fancytree({
    debugLevel: 0,
    selectMode: 1,
    extensions: ["dnd"],
    source: [{
        title: "Node 1",
        key: "1",
        "baloney": 44
      },
      {
        title: "Folder 2",
        key: "2",
        folder: true,
        children: [{
            title: "Node 2.1",
            key: "3",
            myOwnAttr: "abc"
          },
          {
            title: "Node 2.2",
            key: "4"
          }
        ]
      }
    ],
    dnd: {
      dragStart: function(node, data) {
        return true;
      },
      dragEnter: function(node, data) {
        return true;
      },
      dragDrop: function(node, data) {
        if (!data.otherNode) {
          // it's a draggable from outside the fancytree
          node.addNode({
            title: "Hello butt"
          }, data.hitMode);
          return;
        } else {
          // SOLUTION: this line enables reorder inside tree
          data.otherNode.moveTo(node, data.hitMode);
        }
      },
      initHelper: function(sourceNode, data) {
        var helper = data.ui.helper;
        var foo = $(helper).find(".fancytree-title")[0].innerHTML;
        $(helper).find(".fancytree-drag-helper-img").remove();
        $(helper).find(".fancytree-title").replaceWith('<li class="ui-state-default tonga">' + foo + "</li>");
      },
      updateHelper: function(sourceNode, data) {},
      draggable: {
        appendTo: "body",
        connectToSortable: "#mylist",
        revert: "invalid",
        containment: "document"
      }
    },
  });

  $("#mylist").sortable({
    connectWith: "#mylist",
    out: function(event, ui) {
      if (event.originalEvent.type === "mousemove") {
        $(ui.item).data('drugout', true);
      }
    }
  }).disableSelection();

  $(".tonga").draggable({
    revert: true,
    helper: "clone",
    connectToFancytree: true,
    start: function(event, ui) {
      $(event.target).data('previndex', $(event.target).index());
    },
    stop: function(event, ui) {
      if ($(event.target).data('drugout')) {
        var originalIndex = $(event.target).data('previndex');
        $("#mylist li:last").insertBefore($("#mylist li:eq(" + originalIndex + ")"));
      }
    }
  });

  $(".tonga").draggable({
    revert: false,
    helper: "original",
    connectToSortable: "#mylist"
  });
});
<head>
  <meta charset="UTF-8">
  <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
  <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js" integrity="sha256-VazP97ZCwtekAsvgPBSUwPFKdrwD3unUfSGVYrahUqU=" crossorigin="anonymous"></script>
  <link href="https://cdn.jsdelivr.net/npm/jquery.fancytree@2.27/dist/skin-win8/ui.fancytree.min.css" rel="stylesheet">
  <!-- <script src="https://cdn.jsdelivr.net/npm/jquery.fancytree@2.27/dist/jquery.fancytree-all-deps.min.js"></script> -->
  <script src="https://cdn.jsdelivr.net/npm/jquery.fancytree@2.27/dist/jquery.fancytree-all.min.js"></script>
</head>

<body>
  <div id="tree"></div>
  <ul id="mylist">
    <li class="ui-state-default tonga">Item 1</li>
    <li class="ui-state-default tonga">Item 2</li>
    <li class="ui-state-default tonga">Item 3</li>
    <li class="ui-state-default tonga">Item 4</li>
    <li class="ui-state-default tonga">Item 5</li>
    <li class="ui-state-default tonga">Item 6</li>
    <li class="ui-state-default tonga">Item 7</li>
  </ul>
</body>