JQuery listes sortables et articles fixes / verrouillés
est-il possible de verrouiller des éléments de liste dans la liste sortable JQuery d'une manière que ces éléments resteront à cet endroit particulier dans la liste.
par exemple,
considérez cette pseudo liste avec des articles verrouillés...
item A
item B(locked)
item C(locked)
item D
item E
item F
item G(locked)
donc, je voudrais que les éléments B,C et G soient fixés d'une manière que si l'utilisateur glisser et déposer l'élément D au début de la liste, L'élément A "saute" sur les éléments B et c fixes/verrouillés avec la suivante résultat...
item D
item B(locked)
item C(locked)
item A
item E
item F
item G(locked)
j'ai cherché quelque chose comme ça sans succès. Est-il possible..?
8 réponses
j'ai étendu la jQuery.Ui.sortable
:
vue d'ensemble
jQuery.Ui.sortable
extension du widget avec la fonctionnalité fixed
. Cette fonctionnalité permet à l'utilisateur de fixer des éléments dans la liste.
Avec le constructeur .fixedsortable()
vous construisez une classe .sortable()
qui s'est étendue avec les caractéristiques. Vous pouvez utiliser les méthodes original et le étendu comme bien.
Code
https://gist.github.com/3758329#file_fixedsortable.js > fixedsortable.js
exemple
http://jsfiddle.net/omnosis/jQkdb /
Utilisation
général:
à utiliser, ajouter la propriété fixed
à la liste sortable optios:
$("#list").fixedsortable({
fixed: (value)
})
la valeur peut être:
- entier exemple:
3
- array de nombres entiers exemple:
[1,2,5]
- a élément html ou une liste d'éléments html
- un sélecteur css
- jquery objet
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
})
});
Notes:
si vous insistez pour utiliser le .sortable
au lieu de .fixedsortable
vous pouvez utiliser ce https://gist.github.com/3758329#file_sortable.js au lieu du jquery.bibliothèque d'interface utilisateur. Il s'agit d'un remplacement complet du jQuery.ui
, mais je ne recommande pas de l'utiliser en raison de mises à jour ultérieures.
j'ai travaillé plus de 12 heures :( je suis fou..
Voici une version avec un peu de chance sans bug, mise à jour au fur et à mesure que vous faites glisser. Il génère les positions désirées actuelles des éléments lors du tri commence, ce qui signifie que vous devriez être en mesure de changer les classes chaque fois que vous avez besoin, rafraîchir la liste des éléments du widget et vous êtes bon pour aller.
il utilise également la propriété intégrée items
de sortable pour empêcher le déplacement des articles fixes et pour régler tout problème de tri en haut et en bas de la liste.
j'ai essayé de déplacer les éléments fixes autour, mais cela a entraîné un comportement horriblement buggy, surtout quand il ya plusieurs éléments fixes dans les groupes. La solution finale détache tous les éléments fixes de la liste, ajoute un élément helper à l'avant, puis ré-insère les éléments fixes à leur position désirée, ce qui semble corriger tous les bugs.
essayez la démo ici: 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();
}
});
Check this out: Forçant un élément de rester en place dans un jQuery UI liste Triable
aussi, j'ai mis en œuvre la solution ci-dessus avec plusieurs éléments fixes ici: http://jsfiddle.net/enBnH/12 / (obsolète, voir ci-dessous)) C'est plutôt l'auto-explicatif, je pense.
EDIT:
j'ai aussi automatisé le processus pour générer les valeurs de lockto comme ajouter des ID à ces li
s avec la classe "fixe" (notez que je dois ajouter un ID pour que nous puissions le référencer)
voir la solution complète ici: http://jsfiddle.net/enBnH/44 /
EDIT
OK, après un million d'erreurs avec ce qui précède, j'ai juste réécrit la chose dang moi-même: http://jsfiddle.net/thomas4g/GPMZZ/15 /
NOTE: ce qui précède ne fonctionne pas, mais la réponse de @DarthJDG me semble bien plus gentille. Je laisse les miennes sur le offchance quelqu'un pourrait préférer comment les miennes se comportent (j'ai appris à ne pas supprimer des trucs juste parce qu'il y a une meilleure version :P)
en utilisant le paramètre items vous pouvez obtenir ce que vous voulez comme ceci:
$("#mytable tbody").sortable({items: 'tr.sortable'});
seules les lignes avec une classe CSS .sortable
peuvent être triées maintenant.
si vous ne voulez verrouiller que la première rangée, vous pouvez le faire:
$("#mytable tbody").sortable({items: 'tr:not(:first)'});
Les possibilités sont infinies...
basé sur le code @DarthJDG. Cependant, il ne récupérait pas toutes les pièces d'identité et le tri ne fonctionnait pas avec la table. J'ai donc réussi à mettre à jour sa solution qui fonctionne à la fois avec list et tables et garde l'id dans le tableau.
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();
}
});
articles durables et fixes connectés
j'ai rencontré le problème quand nous avons plusieurs sortables connectés. Le code suggéré par @sarunast et @DarthJDG a un comportement erroné lors du déplacement d'éléments d'une liste à une autre. Par conséquent, je l'ai modifié un peu, et maintenant vous pouvez faire glisser des articles de différentes listes avec des positions de sauvegarde dans les deux.
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;
}
});
oh non! gist lien est rompu. voici le code dump de https://gist.github.com/peterh-capella/4234752
code Accédé le 6 janvier 2016
//this code is created to fix this problem: /q/jquery-sortable-lists-and-fixed-locked-items-25398/"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);
et de dumping reste de sa réponse, juste au cas
dépendances
https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js
Script
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;
}
peut-être cela aidera quelqu'un: utilisez les méthodes" disable "et"enable". Exemple HTML:
<ul class="sortable">
<li>You can move me</li>
<li data-state="lifeless">You can't move me.</li>
</ul>
Script:
$('#sortable').sortable();
$('#sortable').mousedown(function() {
if($(this).data('state')=='lifeless') $('#sortable').sortable('disable');
else $('#sortable').sortable('enable');
});
Live exemple ici: https://jsfiddle.net/ozsvar/0ggqtva5/2/