使用 JQuery Multisortable 加过滤列表

Using JQuery Multisortable plus filtering a list

那么,问题来了...

我有两个列表。我希望用户能够从左侧的一个列表中拖动以在右侧构建一个新列表,但也想让他们能够过滤左侧列表。左边的列表可能很长,所以我也希望他们能够多 select 和拖动。

对于多select我正在使用jQuery multisortable

这里 jsFiddle 展示了我正在努力实现的目标。

最终目标是为构建的列表构建逗号分隔的字符串。如果您在“a”上过滤列表,multiselect 结果,您会看到所有列表项都被拖到正确的列表中 - 甚至是被过滤器隐藏的过滤项目之间的那些 - 如何做我绕过这个?

感谢任何帮助!

以下示例使用 Bootstrap 4

编辑:查看 DOM 我可以看到 JQuery 过滤器在 SHIFT 键用于多个 select 项,因此尝试添加选项...

items: '> li:not("multiselectable-shift")'

...对于可排序的,仍然没有快乐。使用 control 键或 meta kay 都可以,只是 shift 键有问题。

<script>
  jQuery(function($) {
    $('ul.connectedSortable').multisortable({
      selectedClass: 'highlight'
    });
    $('ul#sortable1').sortable({
      connectWith: 'ul#sortable2',
      update: function() {
        callListIds = "";
        $("ul#sortable2 li").each(function() {
          callListIds += $(this).attr("id") + ",";
        })
        callListIds = callListIds.replace(/,\s*$/, "");
        $("#listIdResult").html(callListIds);
      }
    });
    $('ul#sortable2').sortable({
      connectWith: 'ul#sortable1',
      update: function() {
        callListIds = "";
        $("ul#sortable2 li").each(function() {
          callListIds += $(this).attr("id") + ",";
        })
        callListIds = callListIds.replace(/,\s*$/, "");
        $("#listIdResult").html(callListIds);
      }
    });
  });
// Search field
$(document).ready(function() {
  $("#search").on("keyup", function() {
    var value = $(this).val().toLowerCase();
    $("#sortable1 li").filter(function() {
      $(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
    });
  });
}); </script>
.highlight { 
  background-color: #AABFF3;
} 
<html lang="en">
<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
  <link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet" />
  <script   src="https://rawgithub.com/shvetsgroup/jquery.multisortable/master/src/jquery.multisortable.js"></script>
  <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" />
  <style>
    .highlight {  background-color: #AABFF3; }
  </style>
</head>
  <body>
    <input type="hidden" name="callListIds" id="callListIds" value="">
    <div class="d-flex justify-content-center w-90 mx-auto d-block pt-5">
      <div class="container w-40 float-left">
        <input type="search" class="form-control" name="search" id="search" placeholder="search...">
        <ul id="sortable1" class="connectedSortable list-group" style="min-height:100%">
          <li id="ls1" class="list-group-item w-100 p-1">ABC</li>
          <li id="ls2" class="list-group-item w-100 p-1">DEF</li>
          <li id="ls3" class="list-group-item w-100 p-1">AGH</li>
          <li id="ls4" class="list-group-item w-100 p-1">HIJ</li>
          <li id="ls5" class="list-group-item w-100 p-1">KLM</li>
          <li id="ls6" class="list-group-item w-100 p-1">AOP</li>
        </ul>
      </div>
      <div class="container w-40 float-right border ml-1">
        <ul id="sortable2" class="connectedSortable list-group" style="min-height:100%">
        </ul>
      </div>
    </div>
    <p class="p-2 text-center">Resulting comma delimited String:
      <span id="listIdResult"></span></p>
    </body

基本上,代码中存在逻辑问题 [https://github.com/shvetsgroup/jquery.multisortable/blob/master/src/jquery.multisortable.js 44-56]:

if (e.shiftKey) {
  var last_shift_range = parent.find('.multiselectable-shift');

  last_shift_range.removeClass(options.selectedClass).removeClass('multiselectable-shift');

  var shift_range;
  if (prevIndex < myIndex) {
    shift_range = item.prevUntil('.multiselectable-previous').add(prev).add(item);
  }
  else if (prevIndex > myIndex) {
    shift_range = item.nextUntil('.multiselectable-previous').add(prev).add(item);
  }
  shift_range.addClass(options.selectedClass).addClass('multiselectable-shift');
}

基本上,它在创建范围时忽略了 items 选项。所以当你这样配置时:

$(el).multiselect({
  items: "li:visible"
});

Shift 单击事件将创建一个范围并包括所有列表项,无论它们是否可见。我尝试了一些解决方法并将 Fiddle 改进为:

https://jsfiddle.net/Twisty/sjg5u1ty/56/

JavaScript

jQuery(function($) {
  $.fn.filterList = function(t) {
    console.log("Filter For:", t);
    $("> li", this).each(function(i, el) {
      $(el).toggle($(el).text().toLowerCase().indexOf(t.toLowerCase()) > -1);
    });
    $(this).multisortable("option", "items", "> li:visible").multisortable("refresh");
  }

  function listToString(el) {
    return $(el).sortable("toArray").toString();
  }

  $('ul.sortable').multisortable({
    selectedClass: 'highlight'
  }).sortable({
    connectWith: ".sortable",
    update: function(e, ui) {
      $("#listIdResult").html(listToString(this));
    }
  });

  $("#search").on("input", function(e) {
    $("#sort-1").filterList($(this).val());
  });
});

理论上,这应该有效,但实际上无效。过滤列表后,它应该更新选项并刷新可以选择的内容。我不确定这可以用预设的插件“修复”,因为它已经 7 年没有更新了,我怀疑是否会有修复。

可能有更好的答案,但我现在没有。如果我遇到任何问题,将调查并更新此答案。