JQuery Sortable with fixed row - javascript

In fiddle
$("#sortable").sortable({
cancel: ".fixed"
});
$("#sortable").disableSelection();
this example the item 3,5 are fixed but when i moved Item 7 to above to Item 3 Item 3 Changes it position to 4, i want it to remain in 3rd position(Item 3 and Item 7) rest of Items can drag and drop by the user.
How can i achieve this functionality?

Half solution is http://jsfiddle.net/wa1grxrh/1/
$("#sortable").sortable({
cancel: ".fixed",
start: function(event, ui) {
var start_pos = ui.item.index();
ui.item.data('last_pos', start_pos);
},
change: function(event, ui) {
var last_pos = ui.item.data('last_pos'),
index = ui.placeholder.index(),
options = $(this).data().sortable.options;
if (last_pos > index) {
$(options.items, $(this)).slice(index, last_pos + 1).filter(options.cancel).each(function(ix) {
$(this).prevAll().not('.ui-sortable-placeholder').first().detach().insertAfter(this);
});
} else if (last_pos < index) {
$(options.items, $(this)).slice(last_pos, index + 1).filter(options.cancel).each(function(ix) {
$(this).nextAll().not('.ui-sortable-placeholder').first().detach().insertBefore(this);
});
}
ui.item.data('last_pos', ui.placeholder.index());
},
});
$("#sortable").disableSelection();
But it doesn't work if any fixed item is first or last or several fixed items are in a row.
I'm affraid full solution is required to modify sortable module. It's needed to prevent the placeholder putting between fixed items or in the edge of item list.

Related

Make draggable sortable with the droppable

I made a drag & drop system. The draggable items can be dropped in placeholders. Those placeholders are added dynamically based on the amount of draggable items.
But when I drag a draggable item between those placeholders, it doesn't get appended to it. I've tried many many things but I'm still stuck on it.
I'm afraid that I'll need to change a lot of the code, but maybe one of you has a genius idea on how to solve this.
Here's the jsfiddle
Is it possible to check wether it has been placed on a placeholder, or not?
This is my droppable function:
function dropping () {
$("li.placeholder").droppable({
accept: ".to-drag",
hoverClass: correct_placeholder,
activeClass: active_placeholder,
revert: false,
tolerance: "pointer",
drop: function (event, ui) {
var dragging = ui.draggable.clone().find("img").remove();
$(this).append(dragging).addClass("dropped");
$(this).droppable('disable');
var day = $(ui.draggable).attr('data-id');
var index = $(event.target).index();
$(this).attr("data-id", day);
$(this).attr("date-order", index);
$(this).addClass("drop-"+ index);
$(this).attr("data-content", "");
$(this).find("h1, p").remove();
var dropped = $(".dropped").length;
var original = $(".placeholder").length;
if (dropped === original) {
$("li.placeholder").removeClass(blank_placeholder);
$("#dropzone").append('<li class="placeholder ' + blank_placeholder +' " data-id="" data-order=""></li>');
init();
}
$(".remove").click(function() {
var removable = $(this).parent();
var modal = $(this).attr("data-modal");
$(".modal-"+modal).remove();
if (dropped > original) {
$(this).parent().droppable('enable')
removable.remove();
removable.removeClass("dropped");
removable.removeClass("ui-droppable-disabled");
} else {
$(this).parent().droppable('enable');
removable.empty();
removable.removeClass("dropped");
removable.removeClass("ui-droppable-disabled");
}
init();
});
}
});
$("li.dropped").droppable({
disabled: function (event, ui) {
disabled: true
}
});
}

How to sync jquery sortable lists that contain cloned elements?

I've a peculiar situation. I have two lists. 1 list contains all items, and 2 contains top list. Obviously items overlap, and items in the second list are marked with class clone-23 clone-25 according to which element from list 1 are they cloned from.
Example:
List 1
1 run
2 eat
3 drink
4 play
List 2 (TOP)
1 run (class clone)
2 eat (class clone)
When re-arranged data is saved to DB.
I would like to avoid refresh and re-pulling of data from DB. So I would like to sync position of elements in two lists.
So whenever user drags around item in list 1, list 2 automatically shows changed positions and vice versa.
I initiate my sortable:
// Initiate jquery ui sortable
$(".word-list").sortable({
tolerance: 'pointer',
cursor: 'move',
forcePlaceholderSize: true,
dropOnEmpty: true,
connectWith: 'ol.word-list',
//containment: "body",
//
start: function(event, ui) {
// Starting position of the word element
//ui.item.startPos = ui.item.index();
//console.dir(ui.item.startPos);
},
//
stop: function(event, ui) {
//
},
update: function(event, ui) {
//
save_word_order(this);
//
},
out: function(event, ui) {
//
},
over: function(event, ui) {
//
},
placeholder: "ui-state-highlight"
});
Clone element html:
<li data-con-id="94" data-order-id="1" data-note="" class="ui-state-default clone-94"</li>
Lists are simply:
<ol id="tabs-1" class="word-list"></ol>
<ol id="tabs-2" class="word-list"></ol>
Any thoughts?
See this fiddle for code which syncs the order of items common to both lists:
http://jsfiddle.net/Fresh/22jc2/
Note that in my example I have simplified list two's li elements by not including the clone attributes; instead I am comparing items in both list by the list item's innerText value. It should be fairly easy for you to refactor my solution to use the clone item attributes if you really need to use them.
The script which I've used to achieve the synchronisation of the order of the common list items is:
var reorderLists = function (list1, list2) {
$('#' + list1 + ' li').each(function (index) {
var sortableItemWithText = $('#' + list2 + ' li:contains(' + this.textContent + ')');
if (sortableItemWithText.length === 1) {
sortableItemWithText.appendTo('#' + list2);
return;
}
});
};
$("#sortable1, #sortable2").sortable({
update: function (event, ui) {
var parentNodeId = ui.item[0].parentNode.id;
if (parentNodeId == "sortable1") {
reorderLists("sortable1", "sortable2");
}
if (parentNodeId == "sortable2") {
reorderLists("sortable2", "sortable1");
}
}
});
$("#tabs").tabs();
Note that the syncing of the order of common list items works if you change the position of items in either list 1 or list 2.
Also note that by commenting out:
$("#tabs").tabs();
You'll be able to see the lists updating automatically when you move the list items; this makes it easier to confirm that the re-order routine is work as expected.
perhaps this can help :
See this fiddle for code which syncs the order of items common to both
lists:
http://jsfiddle.net/penjepitkertasku/6bk7B/1/
$(function() {
var dragElementID = "";
var dropElementID = "";
var dragElementItemName = "";
var allElementItemName = "";
$(".word-list").sortable({
tolerance: 'pointer',
cursor: 'move',
helper: 'clone',
//revert: 'invalid',
forcePlaceholderSize: true,
dropOnEmpty: true,
connectWith: 'ol.word-list',
start: function(e, ui){
var id = $('ol.word-list').children().index($(ui.item[0]));
var name = $('ol.word-list').children(':eq(' + id + ')').text();
dragElementItemName = name;
dragElementID = this.id;
},
stop: function(event, ui) {
var id = $('ol.word-list').children().index($(ui.item[0]));
//validate
if(dragElementID == dropElementID) { return; }
if(id == -1)return;
if(dragElementID == "tabs-1")
{
if(allElementItemName.indexOf(dragElementItemName,1) > 0) { $(this).sortable('cancel'); return; }
var elm = $(ui.item[0]).clone(true).removeClass('box ui-draggable ui-draggable-dragging').addClass('box-clone');
$('ol.word-list').children(':eq(' + id + ')').after(elm);
$(this).sortable('cancel');
}else{
ui.item.remove();
}
},
update: function(event, ui) {
//
//save_word_order(this);
//
},
out: function(event, ui) {
//
},
over: function(event, ui) {
//
dropElementID = this.id;
allElementItemName = '|' + $('#' + dropElementID + ' li').text() + '|';
},
placeholder: "ui-state-highlight"
});
});

How to prevent child sortables from cloning

I have three sortable list boxes, one grey and two yellow. I can drag and clone child sortable li's into the bottom yellow lists no problem.
The problem is that once the child clone li's from the grey list box are placed into the yellow list boxes, you can no longer drag/shift them within the containing yellow list box or to the adjacent yellow list box. They just clone continuously when you attempt to drag them elsewhere.
I would like to drag and clone sortables from the grey list box into the yellow boxes and have the cloned child li's be able to drag and move within the yellow lists boxes without cloning.
How can I prevent the child li's from cloning. Any help would be much appreciated. Thanks.
http://jsfiddle.net/equiroga/96hJj/
$(function() {
$(".sortable").sortable(
{
helper : "clone",
connectWith : ".sortable",
start : function(event,ui)
{
$(ui.item).show();
clone = $(ui.item).clone();
before = $(ui.item).prev();
position = $(ui.item).index();
},
beforeStop : function(event, ui)
{
if($(ui.item).closest('ul#sortable1').length>0)
$(this).sortable('cancel');
},
stop : function(event, ui)
{
if (position == 0) $("#sortable1").prepend(clone);
else before.after(clone);
}
});
$(".sortable").sortable();
});
You can set a particular behavior for the first list and a different for the others, the others can't interact with the first using a coonectWith selector with :not selector.
Code:
$(function () {
$("#sortable1").sortable({
helper: "clone",
connectWith: ".sortable",
start: function (event, ui) {
$(ui.item).show();
clone = $(ui.item).clone();
before = $(ui.item).prev();
position = $(ui.item).index();
},
beforeStop: function (event, ui) {
if ($(ui.item).closest('ul#sortable1').length > 0) $(this).sortable('cancel');
},
stop: function (event, ui) {
if (position == 0) $("#sortable1").prepend(clone);
else before.after(clone);
}
});
$(".sortable").sortable({connectWith: ".sortable:not('#sortable1')"});
});
Demo: http://jsfiddle.net/IrvinDominin/923VG/

revert manual changes to 2 connected jquery ui sortable lsts

I have multiple jquery ui sortable lists that are connected and get balanced manually to N number of items whenever items are received by one list - just like in this answer: https://stackoverflow.com/a/13754827/27497
However, it appears that when you manually move items between lists (using jquery's .appendTo() or .prependTo()), these changes aren't detected by the jquery ui sortable library, and thus when you use the "cancel" command to revert the state, the manually moved items aren't placed back into their original list.
Is there a proper way to manually move an item from one list to another so that the sortable library is able to move the item back when you call $(".my-lists-selector").sortable("cancel");
Here is an example of how the items don't revert when you call .sortable("cancel") - just click the red cancel button after moving items from one list to another: http://jsfiddle.net/SUffL/3/
$(function() {
$( ".connectedSortable" ).sortable({
connectWith: ".connectedSortable",
update: function(event, ui) {
var ul1 = $("#ul1 li");
var ul2 = $("#ul2 li");
var ul3 = $("#ul3 li");
checkul1(ul1, ul2, ul3);
checkul2(ul1, ul2, ul3);
checkul3(ul1, ul2, ul3);
}
}).disableSelection();
$("#cancel-btn").click(function(){
$(".connectedSortable").sortable("cancel");
});
});
function checkul1(ul1, ul2, ul3) {
if (ul1.length > 5) {
ul1.last().prependTo(ul2.parent());
}
}
function checkul2(ul1, ul2, ul3) {
if (ul2.length > 5) {
if (ul1.length < 5) {
ul2.first().appendTo(ul1.parent());
} else {
ul2.last().prependTo(ul3.parent());
}
}
}
function checkul3(ul1, ul2, ul3) {
if (ul3.length > 5) {
ul3.first().appendTo(ul2.parent());
checkul2(ul1, ul2, ul3);
}
}
Here is a solution that stores the manually moved item along with list it started in and list it is moved to. Within the receive event handler the 2 lists are available as ui.sender and this. I created a simple balanceLists function to handle the manual move and the cancel of same
$(function () {
var listChange = {
startList: null,
item: null,
endList: null
}
$(".connectedSortable").sortable({
connectWith: ".connectedSortable",
receive: function (event, ui) {
listChange = {
startList: ui.sender,
item: ui.item,
endList: $(this)
}
balanceLists($(this), ui.sender)
}
}).disableSelection();
$("#cancel-btn").click(function () {
if (listChange.item) {
balanceLists(listChange.startList, listChange.endList)
$(".connectedSortable").sortable("cancel").sortable("refresh");
listChange.item=null;
}
});
});
function balanceLists($from, $to) {
$to.append($from.find('li').last())
}
DEMO: http://jsfiddle.net/SUffL/8/
This allows to undo one move with cancel button.

Sort multiple selected items in jQuery sortable?

I'm trying to select more than one item in a jQuery sortable set and then move the selected items around together.
Here's my weak beginning of an attempt to make it work. And here's the code:
HTML:
<div class="container">
<div>one</div>
<div>two</div>
<div>three</div>
<div>four</div>
<div>five</div>
</div>
JS:
$('.container div').draggable({
connectToSortable: '.container',
//How do I drag all selected items?
helper: function(e, ui) {
return $('.selected');
}
});
$('.container').sortable({
axis: 'y',
//How do I sort all selected items?
helper: function(e, ui) {
return $('.selected');
}
});
$('.container div').live('click', function(e) {
$(this).toggleClass('selected');
});
CSS:
body{background-color:#012;font-family:sans-serif;text-align:center;}
div{margin:5px 0;padding:1em;}
.container{width:52%;margin:1in auto;background-color:#555;border-radius:.5em;box-shadow:0 0 20px black;}
.container div{background-color:#333;color:#aaa;border:1px solid #777;background-color:#333;color:#aaa;border-radius:.25em;cursor:default;height:1em;}
.container div:hover{background-color:#383838;color:#ccc;}
.selected{background-color:#36a !important;border-color:#036 !important;color:#fff !important;font-weight:bolder;}
I don't know if I'm headed in the right direction or not. I can't find an example of this anywhere online. Just lots of related questions. Does anyone know how?
For example, if I've selected items 4 and 5 out of a list of 6. I want to be able to drag 4 and 5 to the top of the set to get this order - 4 5 1 2 3 6 - Or if I selected 5 and 1 and drag them to the bottom - 2 3 4 6 1 5
This seems to work with the multisortable plugin. Code below. Or see jsFiddle.
// ctrl + click to select multiple
$('.container').multisortable({
stop: function(e, ui) {
var $group = $('.ui-multisort-grouped').not(ui.item);
$group.clone().insertAfter($(ui.item));
$group.each(function() {
$(this).removeClass('ui-multisort-grouped');
});
$group.remove();
}
});
But what if multisortable breaks with future jQuery versions?
Modifying my answer here (according to your HTML and CSS) :
Select items to sort
Create a custom helper
Hide the selected items until sort is done
Resize the helper and placeholder according to the selection
Manually detach selected items from the current position and attach them to the new position after sort
Show the hidden items (undo step 3) after step5
$(function () {
$('.container').on('click', 'div', function () {
$(this).toggleClass('selected');
});
$(".container").sortable({
revert: true,
helper: function (e, item) {
if (!item.hasClass('selected')) item.addClass('selected');
var elements = $('.selected').not('.ui-sortable-placeholder').clone();
var helper = $('<div/>');
item.siblings('.selected').addClass('hidden');
return helper.append(elements);
},
start: function (e, ui) {
var elements = ui.item.siblings('.selected.hidden').not('.ui-sortable-placeholder');
ui.item.data('items', elements);
var len = ui.helper.children().length;
var currentHeight = ui.helper.height()
var itemHeight = ui.item.height() + 32; // 32 = 16x2 padding
ui.helper.height(currentHeight + (len * itemHeight))
ui.placeholder.height((len * itemHeight))
},
receive: function (e, ui) {
ui.item.before(ui.item.data('items'));
},
stop: function (e, ui) {
ui.item.siblings('.selected').removeClass('hidden');
$('.selected').removeClass('selected');
}
});
});
Updated Fiddle

Categories