web-dev-qa-db-ja.com

jQueryのソート可能なリストと固定/ロックされたアイテム

それらのアイテムがリストの特定の場所に留まるように、JQueryソート可能リストのリストアイテムをロックすることは可能ですか?.

例えば、

ロックされたアイテムを含むこの疑似リストを検討してください...

item A
item B(locked)
item C(locked)
item D
item E
item F
item G(locked)

したがって、ユーザーがアイテムのDをリストの先頭にドラッグアンドドロップすると、アイテムAが固定/ロックされたアイテムBとCに「ジャンプ」するように、アイテムB、C、Gを修正します。次の結果で...

item D
item B(locked)
item C(locked)
item A
item E
item F
item G(locked)

私は運がなければこのようなものを探していました。出来ますか..?

30
laroma

_jQuery.Ui.sortable_を拡張しました:

概観

_jQuery.Ui.sortable_fixed機能を備えたウィジェット拡張。この機能により、ユーザーはリスト内の要素を修正できます。
.fixedsortable()コンストラクターを使用して、機能を拡張した.sortable()クラスを作成します。 originalメソッドとextendedメソッドも使用できます。

コード

https://Gist.github.com/3758329#file_fixedsortable.js > _fixedsortable.js_

http://jsfiddle.net/omnosis/jQkdb/

使用法

一般:

使用するには、fixedプロパティをソート可能なリストのoptiosに追加します。

_$("#list").fixedsortable({
   fixed: (value)
})
_

値は次のいずれかです。

  • integer例:_3_
  • 整数の配列の例:_[1,2,5]_
  • html要素またはhtml要素のリスト
  • a css selector
  • jqueryオブジェクト

HTML:

_<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script> //the jquery 
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js"></script> //the original jquery-ui   
<script type="text/javascript" src="https://raw.github.com/Gist/3758329/91749ff63cbc5056264389588a8ab64238484d74/fixedsortable.js"></script> //the extended sortable
...
<ul id="sortable1">
    <li>oranges</li>
    <li class="static">apples</li>
    <li>bananas</li>
    <li>pineapples</li>
    <li>grapes</li>
    <li class="static">pears</li>
    <li>mango</li>
</ul>

<ul id="sortable2">
    <li>bananas</li>
    <li foo="asd">oranges</li>
    <li foo="dsa">apples</li>
    <li>pineapples</li>
    <li>grapes</li>
    <li>pears</li>
    <li>mango</li>
</ul>

<ul id="sortable3">
    <li>bananas</li>
    <li>oranges</li>
    <li>apples</li>
    <li>pineapples</li>
    <li>grapes</li>
    <li>pears</li>
    <li>mango</li>
</ul>
_

Javascript

_$(function() {
    $("#sortable1").fixedsortable({
        fixed: "> .static"
    });

    $("#sortable2").fixedsortable({
        fixed: $("li[foo]").css("background","red")
    });

    $("#sortable3").fixedsortable({
        fixed: 2
    })
});
_

ノート:

_.sortable_ではなく_.fixedsortable_を使用するように主張する場合は、jquery.uiの代わりにこれを使用できます https://Gist.github.com/3758329#file_sortable.js 図書館。これは_jQuery.ui_の完全な置き換えですが、今後の更新のため、これを使用することはお勧めしません。

私はこれに12時間以上取り組んできました:(私は非常識です。

26

これはバグのないバージョンで、ドラッグすると更新されます。これは、並べ替えの開始時にアイテムの現在の望ましい位置を生成します。つまり、必要なときにいつでもクラスを変更し、ウィジェットのリストアイテムを更新すれば、問題ありません。

また、sortableの組み込みitemsプロパティを使用して、固定アイテムをドラッグしないようにし、リストの上部と下部にある並べ替えの問題を整理します。

固定アイテムを移動しようとしましたが、特にグループ内に複数の固定アイテムがある場合、ひどいバグのある動作が発生しました。最終的な解決策は、リストからすべての修正された項目を切り離し、ヘルパー要素を前面に追加し、修正された要素を目的の位置に再挿入します。これにより、すべてのバグが修正されたようです。

ここでデモを試してください: http://jsfiddle.net/PQrqS/1/

HTML:

<ul id="sortable">
    <li>oranges</li>
    <li class="static">apples</li>
    <li>bananas</li>
    <li>pineapples</li>
    <li>grapes</li>
    <li class="static">pears</li>
    <li>mango</li>
</ul>

CSS:

.static { color:red; }

li { background-color:whitesmoke; border:1px solid silver; width:100px; padding:2px; margin:2px; }

JavaScript:

$('#sortable').sortable({
    items: ':not(.static)',
    start: function(){
        $('.static', this).each(function(){
            var $this = $(this);
            $this.data('pos', $this.index());
        });
    },
    change: function(){
        $sortable = $(this);
        $statics = $('.static', this).detach();
        $helper = $('<li></li>').prependTo(this);
        $statics.each(function(){
            var $this = $(this);
            var target = $this.data('pos');

            $this.insertAfter($('li', $sortable).eq(target));
        });
        $helper.remove();
    }
});
58
DarthJDG

これをチェックしてください: アイテムをjQuery UI Sortableリストの所定の位置に残すよう強制する

また、私はここに複数の固定要素を使用して上記のソリューションを実装しました: http://jsfiddle.net/enBnH/12/ (廃止、以下を参照)自明だと思います。

編集:

私は、lockto値を生成するプロセスを自動化し、「fixed」クラスのlisにIDを追加しました(参照できるようにIDを追加する必要があることに注意してください)

ここで完全なソリューションを参照してください: http://jsfiddle.net/enBnH/44/

編集

さて、上記で膨大なエラーが発生した後、私は自分でつまらないことを書き直しました: http://jsfiddle.net/thomas4g/GPMZZ/15/

注:上記は機能しますが、@ DarthJDGの答えは私にはずっと良いようです。私は誰かが私の行動を好むかもしれない犯罪に私を任せています(より良いバージョンがあるので、私はものを削除しないことを学びました:P)

9
Thomas Shields

これは@DarthJDGコードに基づいています。ただし、すべてのIDを取得するわけではなく、並べ替えがテーブルで機能しませんでした。したがって、リストとテーブルの両方で機能し、配列にIDを保持する彼のソリューションを更新することができました。

JavaScript:

var fixed = '.static'; //class which will be locked
var items = 'li'; //tags that will be sorted

$('ul').sortable({
  cancel: fixed,
  items: items,
  start: function () {
    $(fixed, this).each(function () {
      var $this = $(this);
      $this.data('pos', $this.index());
    });
  },
  change: function () {
    var $sortable = $(this);
    var $statics = $(fixed, this).detach();
    var tagName = $statics.prop('tagName');
    var $helper = $('<'+tagName+'/>').prependTo(this);
    $statics.each(function () {
      var $this = $(this);
      var target = $this.data('pos');
      $this.insertAfter($(items, $sortable).eq(target));
    });
    $helper.remove();
  }
});

デモ: http://plnkr.co/edit/hMeIiRFT97e9FGk7hmbs

4
sarunast

items パラメータを使用すると、次のように目的を達成できます。

$("#mytable tbody").sortable({items: 'tr.sortable'});

.sortable CSSクラスを持つ行のみがソートできるようになりました。

1行目のみをロックしたい場合は、次のようにします。

$("#mytable tbody").sortable({items: 'tr:not(:first)'});

可能性は無限大...

3

接続された並べ替え可能アイテムと固定アイテム

いくつかの接続されたソータブルがあるときに問題に遭遇しました。 @sarunastと@DarthJDGによって提案されたコードは、あるリストから別のリストにアイテムをドラッグするときに誤った動作をします。したがって、少し変更し、両方の位置を保存して、異なるリストからアイテムをドラッグできるようになりました。

javascript:

let connected = '.soratble';
let fixed = '.static';
let newParentContainer;

//wrap the code suggested by @sarunast and @DarthJDG into the function
//code was modified a little
function sortingAroundFixedPositions(container) {
  let sortable = $(container);
  let statics = $(fixed, container).detach();
  let tagName = statics.prop('tagName');
  let helper = $('<' + tagName + '/>').prependTo(container);
  statics.each(function() {
    let target = this.dataset.pos;
    let targetPosition = $(tagName, sortable).eq(target);
    if (targetPosition.length === 0) {
      targetPosition = $(tagName, sortable).eq(target - 1)
    }
    $(this).insertAfter(targetPosition);
  });
  helper.remove();
}

$('ul').sortable({
  connectWith: connected,
  cancel: fixed,
  start: function() {
    $(fixed, connected).each(function() {
      this.dataset.pos = $(this).index();
    });
  },
  change: function(e, ui) {
    sortingAroundFixedPositions(this);
    if (ui.sender) {
      newParentContainer = this;
    }
    if (newParentContainer) {
      sortingAroundFixedPositions(newParentContainer);
    }
  },
  update: function(e, ui) {
    newParentContainer = undefined;
  }
});

デモ: http://plnkr.co/edit/blmv4ZjaWJFcjvO2zQH0

1
Ilya Shashilov

多分これは誰かを助けるでしょう:「無効」と「有効」のメソッドを使用してください。 HTMLの例:

<ul class="sortable">
  <li>You can move me</li>
  <li data-state="lifeless">You can't move me.</li>
</ul>

脚本:

$('#sortable').sortable();
$('#sortable').mousedown(function() {
  if($(this).data('state')=='lifeless') $('#sortable').sortable('disable');
  else $('#sortable').sortable('enable');
});

ここにライブの例: https://jsfiddle.net/ozsvar/0ggqtva5/2/

0
Ozsvar Istvan

大野!要旨リンクが壊れています。これは https://Gist.github.com/peterh-capella/4234752 からのコードダンプです

2016年1月6日にアクセスしたコード

//this code is created to fix this problem: http://stackoverflow.com/questions/4299241/

(function( $, undefined ) {

$.widget("ui.fixedsortable", $.ui.sortable, {

    options: $.extend({},$.ui.sortable.prototype.options,{fixed:[]}),

    _create: function() {
      var o = this.options;
      this.containerCache = {};
      this.element.addClass("ui-sortable");

      //Get the items
      $.ui.sortable.prototype.refresh.apply(this,arguments);

      if( typeof this.options.fixed == "number") {
        var num = this.options.fixed
        this.options.fixed = [num];
      }
      else if( typeof this.options.fixed == "string" || typeof this.options.fixed == "object") {
        if(this.options.fixed.constructor != Array) {
          var selec = this.options.fixed;
          var temparr = [];
          var temp = $(this.element[0]).find(selec);
          var x = this;


          temp.each(function() {
            var i;
            for(i=0;i<x.items.length && x.items[i].item.get(0) != this;++i) {}
            if(i<x.items.length) temparr.Push(i);
          });
          this.options.fixed = temparr;
        }
      }   


      //Let's determine if the items are being displayed horizontally
      this.floating = this.items.length ? o.axis === 'x' || (/left|right/).test(this.items[0].item.css('float')) || (/inline|table-cell/).test(this.items[0].item.css('display')) : false;

      //Let's determine the parent's offset
      this.offset = this.element.offset();

      //Initialize mouse events for interaction
      $.ui.sortable.prototype._mouseInit.apply(this,arguments);
    },

    _mouseCapture: function( event ) { 

      this._fixPrev = this._returnItems();
      return $.ui.sortable.prototype._mouseCapture.apply(this,arguments);
    },

    _mouseStart: function( event ) { 

      for(var i=0;i<this.options.fixed.length;++i) {
        var num = this.options.fixed[i];
        var elem = this.items[num];
        if(event.target == elem.item.get(0)) return false;
      }

      return $.ui.sortable.prototype._mouseStart.apply(this,arguments);
    },

    _rearrange: function(event, i, a, hardRefresh) {

      a ? a[0].appendChild(this.placeholder[0]) : 
      i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction == 'down' ? i.item[0] : i.item[0].nextSibling));

      this._refix(i);



      //Various things done here to improve the performance:
      // 1. we create a setTimeout, that calls refreshPositions
      // 2. on the instance, we have a counter variable, that get's higher after every append
      // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
      // 4. this lets only the last addition to the timeout stack through



      this.counter = this.counter ? ++this.counter : 1;
      var self = this, counter = this.counter;


      window.setTimeout(function() {
        if(counter == self.counter) self.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
      },0);

    },

    _refix: function(a) {
      var prev = this._fixPrev;
      var curr = this._returnItems();

      var Fixcodes = this.options.fixed;

      var NoFixed = [];
      var Fixed = [];
      var Mixed = []
      var post = [];


      for(var i=0;i<Fixcodes.length;++i) {
        var fix_index = Fixcodes[i];
        var fix_item  = prev[fix_index];
        var j = 0;

        for(j=0;j<curr.length && curr[j].item.get(0) != fix_item.item.get(0);++j) {}

        curr.splice(j,1);

        Fixed.Push(fix_item);
      }

      for(var i=0;i<curr.length;++i) {
        if(curr[i].item.get(0) != this.currentItem.get(0)) {
          NoFixed.Push(curr[i]);
        }
      }

      var fix_count = 0;
      var nofix_count = 0;

      for(var i=0;i<Fixed.length + NoFixed.length;++i) {
        if(Fixcodes.indexOf(i) >= 0) {
          Mixed.Push(Fixed[fix_count++]);
        }
        else {
          Mixed.Push(NoFixed[nofix_count++]);
        }
      }

      var parent = this.currentItem.get(0).parentNode;    
      var allchild = parent.children;

      for(var i=0;i<Mixed.length;++i) {
        parent.removeChild(Mixed[i].item.get(0));
        parent.appendChild(Mixed[i].item.get(0));
      }
    },

    _returnItems: function(event) {

      this.containers = [this];
      var items = [];
      var self = this;
      var queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]];
      var connectWith = $.ui.sortable.prototype._connectWith.apply;

      if(connectWith) {
        for (var i = connectWith.length - 1; i >= 0; i--){
          var cur = $(connectWith[i]);
          for (var j = cur.length - 1; j >= 0; j--){
            var inst = $.data(cur[j], 'sortable');
            if(inst && inst != this && !inst.options.disabled) {
              queries.Push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
              this.containers.Push(inst);
            }
          };
        };
      }

      for (var i = queries.length - 1; i >= 0; i--) {
        var targetData = queries[i][1];
        var _queries = queries[i][0];

        for (var j=0, queriesLength = _queries.length; j < queriesLength; j++) {
          var item = $(_queries[j]);

          item.data('sortable-item', targetData); // Data for target checking (mouse manager)

          items.Push({
            item: item,
            instance: targetData,
            width: 0, height: 0,
            left: 0, top: 0
          });
        };
      };

      return items;
    },


    value: function(input) {
        //console.log("test");
        $.ui.sortable.prototype.value.apply(this,arguments);
    }
});

})(jQuery);

そして念のために彼の答えの残りを捨てる

依存関係

https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.jshttps://ajax.googleapis.com/ajax/libs/ jqueryui/1.8.13/jquery-ui.min.js

脚本

function randomColor() { //for a little fun ;)
   var r = (Math.floor(Math.random()*256));
   var g = (Math.floor(Math.random()*256));
   var b = (Math.floor(Math.random()*256));

   return "#" + r.toString(16) + g.toString(16) + b.toString(16)
}

$(function() {
    $("#sortable1").fixedsortable({
        fixed: "> .static", //you can use css selector
        sort: function() {  //you can add events as well, without getting confused. for example:
            $(".static").css("background",randomColor())  //change the fixed items background
        },
        change: function(event,ui) {
            $(ui.item[0]).css("border","2px solid "+randomColor())  //change the captured border color
        },
        stop: function(event,ui) {
            $(ui.item[0]).css("border","2px solid #777"); //change the back the css modifications
            $("#sortable1 > li.static").css("background","#aaa");
        }
    });

    $("#sortable2").fixedsortable({  //you can use jQuery object as selector
        fixed: $("li[foo]").css("background","red")
    });

    $("#sortable3").fixedsortable({
        fixed: [2,4], //you can use array of zero base indexes as selector
        update: function(event, ui) {
            alert($(this).fixedsortable('toArray'))   //the fixedsortable('toArray') also works
        }
    })

    $("#sortable4").fixedsortable({
        fixed: 5  //you can fix a single item with a simple integer
    })
});

HTML

 <body>
    <div style="width:120px;float:left;">
    <ul id="sortable1">
        <li><a href="#">oranges</a></li>
        <li class="static"><a href="#">apples</a></li>
        <li><a href="#">bananas</a></li>
        <li><a href="#">pineapples</a></li>
        <li><a href="#">grapes</a></li>
        <li class="static"><a href="#">pears</a></li>
        <li><a href="#">mango</a></li>
    </ul>

    <ul id="sortable2">
        <li>bananas</li>
        <li foo="asd">oranges</li>
        <li foo="dsa">apples</li>
        <li>pineapples</li>
        <li>grapes</li>
        <li>pears</li>
        <li>mango</li>
    </ul>
    </div>
    <div style="width:120px;float:left;">
    <ul id="sortable3">
        <li id="fru_1">bananas</li>
        <li id="fru_2">oranges</li>
        <li id="fru_3" style="background:#f4f">apples</li>
        <li id="fru_4">pineapples</li>
        <li id="fru_5" style="background:#faaba9">grapes</li>
        <li id="fru_6">pears</li>
        <li id="fru_7">mango</li>
    </ul>


    <ul id="sortable4">
        <li>bananas</li>
        <li>oranges</li>
        <li>apples</li>
        <li>pineapples</li>
        <li>grapes</li>
        <li style="background:#dada00">pears</li>
        <li>mango</li>
    </ul>
   </div>
</body>

CSS

ul {margin:10px;}
ul#sortable1 > li, ul#sortable2 > li, ul#sortable3 > li, ul#sortable4 > li {
    display:block;
    width:100px;
    height:15px;
    padding: 3px;
    background: #aaa;
    border: 2px solid #777;
    margin: 1px;
}
ul#sortable1 > li.static {
    opacity:0.5;
}
0
user1778606