jquery-sortable-lists
Advanced tools
Comparing version 1.4.0 to 2.0.0
<h1><a href="http://camohub.github.io/jquery-sortable-lists/index.html">jquery-sortable-lists</a></h1> | ||
<h2 style="font-size:17px">Changelog</h2> | ||
<h3>v2.0.0</h3> | ||
<p>Max levels number has been implemented | ||
and opener background-image has been removed</p> | ||
<h3>v1.4.0</h3> | ||
@@ -27,3 +31,1 @@ <p>Support for mobile devices in jquery-sortable-lists-mobile.js</p> | ||
<p>Fixed bug with empty ignoreClass value (as default). If condition checked target.hasClass( setting.ignoreClass ) and ignoreClass was "" it returned always true. This blocked startDragg() call.</p> | ||
@@ -56,2 +56,3 @@ /** | ||
}, | ||
maxLevels: false, | ||
listSelector: 'ul', | ||
@@ -72,25 +73,25 @@ listsClass: '', // Used for hintWrapper and baseElement | ||
// base element from which is counted position of draged element | ||
// base element from which is counted position of draged element | ||
base = $( '<' + setting.listSelector + ' />' ) | ||
.prependTo( jQBody ) | ||
.attr( 'id', 'sortableListsBase' ) | ||
.attr( 'id', 's-l-base' ) | ||
.css( setting.baseCss ) | ||
.addClass( setting.listsClass + ' ' + setting.baseClass ), | ||
// placeholder != state.placeholderNode | ||
// placeholder is document fragment and state.placeholderNode is document node | ||
// placeholder != state.placeholderNode | ||
// placeholder is document fragment and state.placeholderNode is document node | ||
placeholder = $( '<li />' ) | ||
.attr( 'id', 'sortableListsPlaceholder' ) | ||
.attr( 'id', 's-l-placeholder' ) | ||
.css( setting.placeholderCss ) | ||
.addClass( setting.placeholderClass ), | ||
// hint is document fragment | ||
// hint is document fragment | ||
hint = $( '<li />' ) | ||
.attr( 'id', 'sortableListsHint' ) | ||
.attr( 'id', 's-l-hint' ) | ||
.css( setting.hintCss ) | ||
.addClass( setting.hintClass ), | ||
// Is document fragment used as wrapper if hint is inserted to the empty li | ||
// Is document fragment used as wrapper if hint is inserted to the empty li | ||
hintWrapper = $( '<' + setting.listSelector + ' />' ) | ||
.attr( 'id', 'sortableListsHintWrapper' ) | ||
.attr( 'id', 's-l-hint-wrapper' ) | ||
.addClass( setting.listsClass + ' ' + setting.hintWrapperClass ) | ||
@@ -100,5 +101,5 @@ .css( setting.listsCss ) | ||
// Is +/- ikon to open/close nested lists | ||
// Is +/- ikon to open/close nested lists | ||
opener = $( '<span />' ) | ||
.addClass( 'sortableListsOpener ' + setting.opener.openerClass ) | ||
.addClass( 's-l-opener ' + setting.opener.openerClass ) | ||
.css( setting.opener.openerCss ) | ||
@@ -109,3 +110,3 @@ .on( 'mousedown', function( e ) | ||
if ( li.hasClass( 'sortableListsClosed' ) ) | ||
if ( li.hasClass( 's-l-closed' ) ) | ||
{ | ||
@@ -132,4 +133,3 @@ open( li ); | ||
{ | ||
opener.css( 'background-image', 'url(' + setting.opener.close + ')' ); | ||
console.error( 'jQuerySortableLists opener as background image is deprecated. In version 2.0.0 it will be removed. Use html instead please.' ); | ||
console.error( 'jQuerySortableLists opener as background image has been removed with release 2.0.0. Use html instead please.' ); | ||
} | ||
@@ -142,4 +142,9 @@ | ||
oEl: null, // overElement is element which returns elementFromPoint() method | ||
rootEl: null, | ||
rootEl: { | ||
el: $( this ), | ||
offset: null, | ||
rootElClass: $( this ).attr( 'class' ) | ||
}, | ||
cEl: null, // currentElement is currently dragged element | ||
placeholderParentLi: null, | ||
upScroll: false, | ||
@@ -170,3 +175,3 @@ downScroll: false, | ||
if ( ! li.hasClass( 'sortableListsOpen' ) ) | ||
if ( ! li.hasClass( 's-l-open' ) ) | ||
{ | ||
@@ -183,2 +188,15 @@ close( li ); | ||
if( setting.maxLevels !== false ) | ||
{ | ||
if( isNaN( setting.maxLevels ) ) throw 'JQuery-sortable-lists maxLevels values is not a number'; | ||
$( this ).find( 'li' ).each( function() | ||
{ | ||
var insideLevs = getInsideLevels( $(this) ); | ||
var upperLevs = getUpperLevels( $(this) ); | ||
setInsideLevels( $(this), insideLevs ); | ||
setUpperLevels( $(this), upperLevs ); | ||
}); | ||
} | ||
// Return this ensures chaining | ||
@@ -199,3 +217,3 @@ return this.on( 'mousedown', function( e ) | ||
// Check if el is not empty | ||
if ( el[ 0 ] ) | ||
if ( el[0] ) | ||
{ | ||
@@ -238,7 +256,7 @@ setting.onDragStart( e, el ); | ||
state.cEl.xyOffsetDiff = { X: e.pageX - state.cEl.offset.left, Y: e.pageY - state.cEl.offset.top }; | ||
state.cEl.el.addClass( 'sortableListsCurrent' + ' ' + setting.currElClass ); | ||
state.cEl.el.addClass( 's-l-current ' + setting.currElClass ); | ||
el.before( placeholder ); // Now document has node placeholder | ||
var placeholderNode = state.placeholderNode = $( '#sortableListsPlaceholder' ); // jQuery object && document node | ||
var placeholderNode = state.placeholderNode = $( '#s-l-placeholder' ); // jQuery object && document node | ||
@@ -262,3 +280,2 @@ el.css( { | ||
.on( 'mouseup', endDrag ); | ||
} | ||
@@ -326,5 +343,5 @@ | ||
cEl.el[ 0 ].style.visibility = 'hidden'; // This is important for the next row | ||
cEl.el[0].style.visibility = 'hidden'; // This is important for the next row | ||
state.oEl = oEl = elFromPoint( e.pageX, e.pageY ); | ||
cEl.el[ 0 ].style.visibility = 'visible'; | ||
cEl.el[0].style.visibility = 'visible'; | ||
@@ -334,3 +351,2 @@ showHint( e, state ); | ||
setCElPos( e, state ); | ||
} | ||
@@ -346,7 +362,7 @@ } | ||
var cEl = state.cEl, | ||
hintNode = $( '#sortableListsHint', state.rootEl.el ), | ||
hintStyle = hint[ 0 ].style, | ||
hintNode = $( '#s-l-hint', state.rootEl.el ), | ||
hintStyle = hint[0].style, | ||
targetEl = null, // hintNode/placeholderNode | ||
isHintTarget = false, // if cEl will be placed to the hintNode | ||
hintWrapperNode = $( '#sortableListsHintWrapper' ); | ||
hintWrapperNode = $( '#s-l-hint-wrapper' ); | ||
@@ -371,6 +387,6 @@ if ( hintStyle.display == 'block' && hintNode.length && state.isAllowed ) | ||
targetEl.after( cEl.el[ 0 ] ); | ||
targetEl[ 0 ].style.display = 'none'; | ||
targetEl.after( cEl.el[0] ); | ||
targetEl[0].style.display = 'none'; | ||
hintStyle.display = 'none'; | ||
// This have to be document node, not hint as a part of documentFragment. | ||
// This has to be document node, not hint as a part of documentFragment. | ||
hintNode.remove(); | ||
@@ -390,10 +406,20 @@ | ||
{ | ||
// !!! Do not use local var cause it seems it creates a closure variables lakes in Chrome !!! | ||
state.placeholderNode.slideUp( 150, function() | ||
{ | ||
state.placeholderParentLi = ( ! state.placeholderNode.parent().is( state.rootEl.el ) ) ? state.placeholderNode.parent().closest( 'li' ) : null; | ||
state.placeholderNode.remove(); | ||
tidyEmptyLists(); | ||
setting.onChange( cEl.el ); | ||
setting.complete( cEl.el ); // Have to be here cause is necessary to remove placeholder before complete call. | ||
state.isDragged = false; | ||
} ); | ||
if( setting.maxLevels !== false ) // Has to be after placeholder remove. | ||
{ | ||
recountLevels( cEl.el ); | ||
if( state.placeholderParentLi ) recountLevels( state.placeholderParentLi ); | ||
} | ||
}); | ||
} | ||
@@ -415,4 +441,2 @@ else | ||
.unbind( "mouseup", endDrag ); | ||
} | ||
@@ -439,3 +463,2 @@ | ||
}, 50 ); | ||
} | ||
@@ -456,3 +479,2 @@ | ||
}, 50 ); | ||
} | ||
@@ -484,2 +506,3 @@ | ||
e.clientX = state.cX; | ||
} | ||
@@ -501,2 +524,3 @@ | ||
/////// End of Scroll handlers ////////////////////////////////////////////////////////////// | ||
/////// Current element handlers ////////////////////////////////////////////////////////////// | ||
@@ -516,4 +540,3 @@ /** | ||
'left': e.pageX - cEl.xyOffsetDiff.X - cEl.mL | ||
} ) | ||
} ); | ||
} | ||
@@ -564,3 +587,3 @@ | ||
} | ||
else if ( el.is( '#sortableListsPlaceholder' ) || el.is( '#sortableListsHint' ) ) // el is #placeholder/#hint | ||
else if ( el.is( '#s-l-placeholder' ) || el.is( '#s-l-hint' ) ) // el is #placeholder/#hint | ||
{ | ||
@@ -572,3 +595,3 @@ return null; | ||
el = el.closest( 'li' ); | ||
return el[ 0 ] ? el : null; | ||
return el[0] ? el : null; | ||
} | ||
@@ -579,5 +602,5 @@ else if ( el.is( 'li' ) ) // el is most wanted li | ||
} | ||
} | ||
//////// End of current element handlers ////////////////////////////////////////////////////// | ||
//////// Show hint handlers ////////////////////////////////////////////////////// | ||
@@ -633,5 +656,5 @@ | ||
{ | ||
if ( $( '#sortableListsHintWrapper', state.rootEl.el ).length ) | ||
if ( $( '#s-l-hint-wrapper', state.rootEl.el ).length ) | ||
{ | ||
hint.unwrap(); // If hint is wrapped by ul/ol #sortableListsHintWrapper | ||
hint.unwrap(); // If hint is wrapped by ul/ol #s-l-hint-wrapper | ||
} | ||
@@ -643,3 +666,3 @@ | ||
// Ensure display:none if hint will be next to the placeholder | ||
if ( oEl.prev( '#sortableListsPlaceholder' ).length ) | ||
if ( (oEl.prev( '#s-l-placeholder' ).length) || (setting.maxLevels !== false && ! checkMaxLevels( false )) ) | ||
{ | ||
@@ -657,3 +680,3 @@ hint.css( 'display', 'none' ); | ||
if ( list.children().first().is( '#sortableListsPlaceholder' ) ) | ||
if ( (list.children().first().is( '#s-l-placeholder' )) || ( setting.maxLevels !== false && ! checkMaxLevels( true )) ) | ||
{ | ||
@@ -697,5 +720,5 @@ hint.css( 'display', 'none' ); | ||
{ | ||
if ( $( '#sortableListsHintWrapper', state.rootEl.el ).length ) | ||
if ( $( '#s-l-hint-wrapper', state.rootEl.el ).length ) | ||
{ | ||
hint.unwrap(); // If hint is wrapped by ul/ol #sortableListsHintWrapper | ||
hint.unwrap(); // If hint is wrapped by ul/ol #s-l-hint-wrapper | ||
} | ||
@@ -709,3 +732,3 @@ | ||
if ( list.children().first().is( '#sortableListsPlaceholder' ) ) | ||
if ( (list.children().first().is( '#s-l-placeholder' )) || (setting.maxLevels !== false && ! checkMaxLevels( true )) ) | ||
{ | ||
@@ -736,3 +759,3 @@ hint.css( 'display', 'none' ); | ||
// Ensure display:none if hint will be next to the placeholder | ||
if ( oEl.prev( '#sortableListsPlaceholder' ).length ) | ||
if ( (oEl.prev( '#s-l-placeholder' ).length) || (setting.maxLevels !== false && ! checkMaxLevels( false )) ) | ||
{ | ||
@@ -760,5 +783,5 @@ hint.css( 'display', 'none' ); | ||
{ | ||
if ( $( '#sortableListsHintWrapper', state.rootEl.el ).length ) | ||
if ( $( '#s-l-hint-wrapper', state.rootEl.el ).length ) | ||
{ | ||
hint.unwrap(); // If hint is wrapped by ul/ol sortableListsHintWrapper | ||
hint.unwrap(); // If hint is wrapped by ul/ol s-l-hint-wrapper | ||
} | ||
@@ -770,3 +793,3 @@ | ||
// Ensure display:none if hint will be next to the placeholder | ||
if ( oEl.next( '#sortableListsPlaceholder' ).length ) | ||
if ( (oEl.next( '#s-l-placeholder' ).length) || (setting.maxLevels !== false && ! checkMaxLevels( false )) ) | ||
{ | ||
@@ -784,3 +807,3 @@ hint.css( 'display', 'none' ); | ||
if ( list.children().last().is( '#sortableListsPlaceholder' ) ) | ||
if ( (list.children().last().is( '#s-l-placeholder' )) || (setting.maxLevels !== false && ! checkMaxLevels( true )) ) | ||
{ | ||
@@ -824,5 +847,5 @@ hint.css( 'display', 'none' ); | ||
{ | ||
if ( $( '#sortableListsHintWrapper', state.rootEl.el ).length ) | ||
if ( $( '#s-l-hint-wrapper', state.rootEl.el ).length ) | ||
{ | ||
hint.unwrap(); // If hint is wrapped by ul/ol sortableListsHintWrapper | ||
hint.unwrap(); // If hint is wrapped by ul/ol s-l-hint-wrapper | ||
} | ||
@@ -836,3 +859,3 @@ | ||
if ( list.children().last().is( '#sortableListsPlaceholder' ) ) | ||
if ( (list.children().last().is( '#s-l-placeholder' )) || (setting.maxLevels !== false && ! checkMaxLevels( true )) ) | ||
{ | ||
@@ -864,3 +887,3 @@ hint.css( 'display', 'none' ); | ||
// Ensure display:none if hint will be next to the placeholder | ||
if ( oEl.next( '#sortableListsPlaceholder' ).length ) | ||
if ( (oEl.next( '#s-l-placeholder' ).length) || (setting.maxLevels !== false && ! checkMaxLevels( false )) ) | ||
{ | ||
@@ -889,6 +912,6 @@ hint.css( 'display', 'none' ); | ||
{ | ||
li.removeClass( 'sortableListsClosed' ).addClass( 'sortableListsOpen' ); | ||
li.removeClass( 's-l-closed' ).addClass( 's-l-open' ); | ||
li.children( setting.listSelector ).css( 'display', 'block' ); | ||
var opener = li.children( 'div' ).children( '.sortableListsOpener' ).first(); | ||
var opener = li.children( 'div' ).children( '.s-l-opener' ).first(); | ||
@@ -903,6 +926,2 @@ if ( setting.opener.as == 'html' ) | ||
} | ||
else | ||
{ | ||
opener.css( 'background-image', 'url(' + setting.opener.close + ')' ); | ||
} | ||
} | ||
@@ -916,6 +935,6 @@ | ||
{ | ||
li.removeClass( 'sortableListsOpen' ).addClass( 'sortableListsClosed' ); | ||
li.removeClass( 's-l-open' ).addClass( 's-l-closed' ); | ||
li.children( setting.listSelector ).css( 'display', 'none' ); | ||
var opener = li.children( 'div' ).children( '.sortableListsOpener' ).first(); | ||
var opener = li.children( 'div' ).children( '.s-l-opener' ).first(); | ||
@@ -930,11 +949,92 @@ if ( setting.opener.as == 'html' ) | ||
} | ||
else | ||
} | ||
/////// Enf of open/close handlers ////////////////////////////////////////////// | ||
/////// Levels handlers ///////////////////////////////////////////////////////// | ||
function getInsideLevels( li ) | ||
{ | ||
var levs = 0; | ||
var list = li.children( setting.listSelector ); | ||
if( list.length ) | ||
{ | ||
opener.css( 'background-image', 'url(' + setting.opener.open + ')' ); | ||
levs++; | ||
var maxNestedLevs = 0; | ||
var currLiLevs = 0; | ||
list.find( 'li' ).each( function( i ) | ||
{ | ||
currLiLevs = getInsideLevels($(this)); | ||
if( maxNestedLevs < currLiLevs ) maxNestedLevs = currLiLevs; | ||
}); | ||
if( maxNestedLevs ) levs = levs + maxNestedLevs; | ||
} | ||
return levs; | ||
} | ||
/////// Enf of open/close handlers ////////////////////////////////////////////// | ||
function setInsideLevels( li, levs ) | ||
{ | ||
li.data('insideLevels', levs); | ||
} | ||
function getUpperLevels( li ) | ||
{ | ||
var levs = 0; | ||
var rootEl = state.rootEl.el; | ||
var parentList = li.closest( setting.listSelector ); | ||
while( ! parentList.is( rootEl ) ) | ||
{ | ||
levs++; | ||
parentList = parentList.parent().closest( setting.listSelector ); | ||
} | ||
return levs; | ||
} | ||
function setUpperLevels( li, levs ) | ||
{ | ||
li.data('upperLevels', levs); | ||
} | ||
function checkMaxLevels( inside ) | ||
{ | ||
var insideLevs = state.cEl.el.data( 'insideLevels' ); | ||
var upperLevs = state.oEl.data( 'upperLevels' ); | ||
return setting.maxLevels > upperLevs + insideLevs + (inside ? 1 : 0); | ||
} | ||
function recountLevels( li ) | ||
{ | ||
var rootEl = state.rootEl.el; | ||
var parentList = li.parent( setting.listSelector ); | ||
setInsideLevels( li, getInsideLevels( li ) ); | ||
setUpperLevels( li, getUpperLevels( li ) ); | ||
var i = 0; | ||
li.find( 'li' ).each( function() | ||
{ | ||
var li = $(this); | ||
setInsideLevels( li, getInsideLevels( li ) ); | ||
setUpperLevels( li, getUpperLevels( li ) ); | ||
}); | ||
while( ! parentList.is( rootEl ) && i < 50 ) | ||
{ | ||
var li = parentList.parent( 'li' ); | ||
setInsideLevels( li, getInsideLevels( li ) ); // No need to set upper levels | ||
parentList = li.parent( setting.listSelector ); | ||
i++; | ||
} | ||
} | ||
/////// End of levels handlers ////////////////////////////////////////////////// | ||
/////// Tidy handlers /////////////////////////////////////////////////////////// | ||
/** | ||
@@ -946,5 +1046,5 @@ * @desc Places the currEl to the target place | ||
{ | ||
var cElStyle = cEl.el[ 0 ].style; | ||
var cElStyle = cEl.el[0].style; | ||
cEl.el.removeClass( setting.currElClass + ' ' + 'sortableListsCurrent' ); | ||
cEl.el.removeClass( setting.currElClass + ' s-l-current' ); | ||
cElStyle.top = '0'; | ||
@@ -962,3 +1062,3 @@ cElStyle.left = '0'; | ||
{ | ||
// Remove every empty ul/ol from root and also with .sortableListsOpener | ||
// Remove every empty ul/ol from root and also with .s-l-opener | ||
// hintWrapper can not be removed before the hint | ||
@@ -969,3 +1069,3 @@ $( setting.listSelector, state.rootEl.el ).each( function( i ) | ||
{ | ||
$( this ).prev( 'div' ).children( '.sortableListsOpener' ).first().remove(); | ||
$( this ).prev( 'div' ).children( '.s-l-opener' ).first().remove(); | ||
$( this ).remove(); | ||
@@ -1070,4 +1170,4 @@ } | ||
arr.push( matches[ 1 ] + '[' + matches[ 2 ] + ']=' + parentId ); | ||
$( this ).children( 'ul,ol' ).sortableListsToString( arr, matches[ 2 ] ); | ||
arr.push( matches[1] + '[' + matches[2] + ']=' + parentId ); | ||
$( this ).children( 'ul,ol' ).sortableListsToString( arr, matches[2] ); | ||
@@ -1080,4 +1180,2 @@ } ); | ||
}( jQuery )); | ||
}( jQuery )); |
@@ -1,23 +0,1 @@ | ||
/* | ||
MIT | ||
*/ | ||
(function(g){g.fn.sortableLists=function(k){function n(a){if(b.isDragged){var f=b.cEl,d=b.doc,u=b.win;a.pageX||A(a);d.scrollTop()>b.rootEl.offset.top-10&&50>a.clientY?b.upScroll?(a.pageY-=c.scroll,g("html, body").each(function(a){g(this).scrollTop(g(this).scrollTop()-c.scroll)}),r(a)):e(a):d.scrollTop()+u.height()<b.rootEl.offset.top+b.rootEl.el.outerHeight(!1)+10&&50>u.height()-a.clientY?b.downScroll?(a.pageY+=c.scroll,g("html, body").each(function(a){g(this).scrollTop(g(this).scrollTop()+c.scroll)}), | ||
r(a)):l(a):x(b);b.oElOld=b.oEl;f.el[0].style.visibility="hidden";b.oEl=oEl=B(a.pageX,a.pageY);f.el[0].style.visibility="visible";C(a,b);D(a,b)}}function m(a){var q=b.cEl,d=g("#sortableListsHint",b.rootEl.el),u=f[0].style,h=null,e=!1,k=g("#sortableListsHintWrapper");"block"==u.display&&d.length&&b.isAllowed?(h=d,e=!0):(h=b.placeholderNode,e=!1);offset=h.offset();q.el.animate({left:offset.left-b.cEl.mL,top:offset.top-b.cEl.mT},250,function(){E(q);h.after(q.el[0]);h[0].style.display="none";u.display= | ||
"none";d.remove();k.removeAttr("id").removeClass(c.hintWrapperClass);k.length&&k.prev("div").append(t.clone(!0));e?b.placeholderNode.slideUp(150,function(){b.placeholderNode.remove();y();c.onChange(q.el);c.complete(q.el);b.isDragged=!1}):(b.placeholderNode.remove(),y(),c.complete(q.el),b.isDragged=!1)});x(b);b.doc.unbind("mousemove",n).unbind("mouseup",m)}function e(a){b.upScroll||(b.upScroll=setInterval(function(){b.doc.trigger("mousemove")},50))}function l(a){b.downScroll||(b.downScroll=setInterval(function(){b.doc.trigger("mousemove")}, | ||
50))}function r(a){b.pY=a.pageY;b.pX=a.pageX;b.cY=a.clientY;b.cX=a.clientX}function A(a){a.pageY=b.pY;a.pageX=b.pX;a.clientY=b.cY;a.clientX=b.cX}function x(a){clearInterval(a.upScroll);clearInterval(a.downScroll);a.upScroll=a.downScroll=!1}function D(a,b){var c=b.cEl;c.el.css({top:a.pageY-c.xyOffsetDiff.Y-c.mT,left:a.pageX-c.xyOffsetDiff.X-c.mL})}function B(a,c){if(!document.elementFromPoint)return null;var d=b.isRelEFP;if(null===d){var f,h;0<(f=b.doc.scrollTop())&&(d=null==(h=document.elementFromPoint(0, | ||
f+g(window).height()-1))||"HTML"==h.tagName.toUpperCase());0<(f=b.doc.scrollLeft())&&(d=null==(h=document.elementFromPoint(f+g(window).width()-1,0))||"HTML"==h.tagName.toUpperCase())}d&&(a-=b.doc.scrollLeft(),c-=b.doc.scrollTop());d=g(document.elementFromPoint(a,c));if(b.rootEl.el.find(d).length){if(d.is("#sortableListsPlaceholder")||d.is("#sortableListsHint"))return null;if(!d.is("li"))return d=d.closest("li"),d[0]?d:null;if(d.is("li"))return d}else return null}function C(a,q){var d=q.oEl;if(d&& | ||
q.oElOld){var e=d.outerHeight(!1),h=a.pageY-d.offset().top;if(c.insertZonePlus)if(14>h)a:{e=7>h;g("#sortableListsHintWrapper",b.rootEl.el).length&&f.unwrap();if(!e&&a.pageX-d.offset().left>c.insertZone){e=d.children();h=d.children(c.listSelector).first();if(h.children().first().is("#sortableListsPlaceholder")){f.css("display","none");break a}h.length?h.prepend(f):(e.first().after(f),f.wrap(v));b.oEl&&p(d)}else{if(d.prev("#sortableListsPlaceholder").length){f.css("display","none");break a}d.before(f)}f.css("display", | ||
"block");b.isAllowed=c.isAllowed(b.cEl.el,f,f.parents("li").first())}else{if(e-14<h)a:{e=e-7<h;g("#sortableListsHintWrapper",b.rootEl.el).length&&f.unwrap();if(!e&&a.pageX-d.offset().left>c.insertZone){e=d.children();h=d.children(c.listSelector).last();if(h.children().last().is("#sortableListsPlaceholder")){f.css("display","none");break a}h.length?e.last().append(f):(d.append(f),f.wrap(v));b.oEl&&p(d)}else{if(d.next("#sortableListsPlaceholder").length){f.css("display","none");break a}d.after(f)}f.css("display", | ||
"block");b.isAllowed=c.isAllowed(b.cEl.el,f,f.parents("li").first())}}else if(5>h)a:{g("#sortableListsHintWrapper",b.rootEl.el).length&&f.unwrap();if(a.pageX-d.offset().left<c.insertZone){if(d.prev("#sortableListsPlaceholder").length){f.css("display","none");break a}d.before(f)}else{e=d.children();h=d.children(c.listSelector).first();if(h.children().first().is("#sortableListsPlaceholder")){f.css("display","none");break a}h.length?h.prepend(f):(e.first().after(f),f.wrap(v));b.oEl&&p(d)}f.css("display", | ||
"block");b.isAllowed=c.isAllowed(b.cEl.el,f,f.parents("li").first())}else if(e-5<h)a:{g("#sortableListsHintWrapper",b.rootEl.el).length&&f.unwrap();if(a.pageX-d.offset().left<c.insertZone){if(d.next("#sortableListsPlaceholder").length){f.css("display","none");break a}d.after(f)}else{e=d.children();h=d.children(c.listSelector).last();if(h.children().last().is("#sortableListsPlaceholder")){f.css("display","none");break a}h.length?e.last().append(f):(d.append(f),f.wrap(v));b.oEl&&p(d)}f.css("display", | ||
"block");b.isAllowed=c.isAllowed(b.cEl.el,f,f.parents("li").first())}}}function p(a){a.removeClass("sortableListsClosed").addClass("sortableListsOpen");a.children(c.listSelector).css("display","block");a=a.children("div").children(".sortableListsOpener").first();"html"==c.opener.as?a.html(c.opener.close):"class"==c.opener.as?a.addClass(c.opener.close).removeClass(c.opener.open):a.css("background-image","url("+c.opener.close+")")}function z(a){a.removeClass("sortableListsOpen").addClass("sortableListsClosed"); | ||
a.children(c.listSelector).css("display","none");a=a.children("div").children(".sortableListsOpener").first();"html"==c.opener.as?a.html(c.opener.open):"class"==c.opener.as?a.addClass(c.opener.open).removeClass(c.opener.close):a.css("background-image","url("+c.opener.open+")")}function E(a){var b=a.el[0].style;a.el.removeClass(c.currElClass+" sortableListsCurrent");b.top="0";b.left="0";b.position="relative";b.width="auto"}function y(){g(c.listSelector,b.rootEl.el).each(function(a){g(this).children().length|| | ||
(g(this).prev("div").children(".sortableListsOpener").first().remove(),g(this).remove())})}var w=g("body").css("position","relative"),F={currElClass:"",placeholderClass:"",placeholderCss:{position:"relative",padding:0},hintClass:"",hintCss:{display:"none",position:"relative",padding:0},hintWrapperClass:"",hintWrapperCss:{},baseClass:"",baseCss:{position:"absolute",top:0-parseInt(w.css("margin-top")),left:0-parseInt(w.css("margin-left")),margin:0,padding:0,"z-index":2500},opener:{active:!1,open:"", | ||
close:"",openerCss:{"float":"left",display:"inline-block","background-position":"center center","background-repeat":"no-repeat"},openerClass:""},listSelector:"ul",listsClass:"",listsCss:{},insertZone:50,insertZonePlus:!1,scroll:20,ignoreClass:"",isAllowed:function(a,b,c){return!0},onDragStart:function(a,b){return!0},onChange:function(a){return!0},complete:function(a){return!0}},c=g.extend(!0,{},F,k),G=g("<"+c.listSelector+" />").prependTo(w).attr("id","sortableListsBase").css(c.baseCss).addClass(c.listsClass+ | ||
" "+c.baseClass),H=g("<li />").attr("id","sortableListsPlaceholder").css(c.placeholderCss).addClass(c.placeholderClass),f=g("<li />").attr("id","sortableListsHint").css(c.hintCss).addClass(c.hintClass),v=g("<"+c.listSelector+" />").attr("id","sortableListsHintWrapper").addClass(c.listsClass+" "+c.hintWrapperClass).css(c.listsCss).css(c.hintWrapperCss),t=g("<span />").addClass("sortableListsOpener "+c.opener.openerClass).css(c.opener.openerCss).on("mousedown",function(a){a=g(this).closest("li");a.hasClass("sortableListsClosed")? | ||
p(a):z(a);return!1});"class"==c.opener.as?t.addClass(c.opener.close):"html"==c.opener.as?t.html(c.opener.close):(t.css("background-image","url("+c.opener.close+")"),console.error("jQuerySortableLists opener as background image is deprecated. In version 2.0.0 it will be removed. Use html instead please."));var b={isDragged:!1,isRelEFP:null,oEl:null,rootEl:null,cEl:null,upScroll:!1,downScroll:!1,pX:0,pY:0,cX:0,cY:0,isAllowed:!0,e:{pageX:0,pageY:0,clientX:0,clientY:0},doc:g(document),win:g(window)}; | ||
if(c.opener.active){if(!c.opener.open)throw"Opener.open value is not defined. It should be valid url, html or css class.";if(!c.opener.close)throw"Opener.close value is not defined. It should be valid url, html or css class.";g(this).find("li").each(function(){var a=g(this);a.children(c.listSelector).length&&(t.clone(!0).prependTo(a.children("div").first()),a.hasClass("sortableListsOpen")?p(a):z(a))})}return this.on("mousedown",function(a){var e=g(a.target);if(!(!1!==b.isDragged||c.ignoreClass&&e.hasClass(c.ignoreClass))){a.preventDefault(); | ||
var e=e.closest("li"),d=g(this);if(e[0]){c.onDragStart(a,e);b.isDragged=!0;var k=parseInt(e.css("margin-top")),h=parseInt(e.css("margin-bottom")),l=parseInt(e.css("margin-left")),r=parseInt(e.css("margin-right")),p=e.offset(),t=e.innerHeight();b.rootEl={el:d,offset:d.offset(),rootElClass:d.attr("class")};b.cEl={el:e,mT:k,mL:l,mB:h,mR:r,offset:p};b.cEl.xyOffsetDiff={X:a.pageX-b.cEl.offset.left,Y:a.pageY-b.cEl.offset.top};b.cEl.el.addClass("sortableListsCurrent "+c.currElClass);e.before(H);a=b.placeholderNode= | ||
g("#sortableListsPlaceholder");e.css({width:e.width(),position:"absolute",top:p.top-k,left:p.left-l}).prependTo(G);a.css({display:"block",height:t});f.css("height",t);b.doc.on("mousemove",n).on("mouseup",m)}}})};g.fn.sortableListsToArray=function(k,n){k=k||[];var m=0;this.children("li").each(function(){var e=g(this),l={},r=e.attr("id");if(!r)throw console.log(e),"Previous item in console.log has no id. It is necessary to create the array.";l.id=r;l.parentId=n;l.value=e.data("value");l.order=m;k.push(l); | ||
e.children("ul,ol").sortableListsToArray(k,r);m++});return k};g.fn.sortableListsToHierarchy=function(){var k=[],n=0;g(this).children("li").each(function(){var m=g(this),e={},l=m.attr("id");if(!l)throw console.log(m),"Previous item in console.log has no id. It is necessary to create the array.";e.id=l;e.value=m.data("value");e.order=n;k.push(e);e.children=m.children("ul,ol").sortableListsToHierarchy();n++});return k};g.fn.sortableListsToString=function(k,n){k=k||[];n=n||"no-parent";g(this).children("li").each(function(){var m= | ||
g(this),e=m.attr("id"),e=e?e.match(/(.+)[-=_](.+)/):null;if(!e)throw console.log(m),"Previous item in console.log has no id or id is not in required format xx_yy, xx-yy or xx=yy. It is necessary to create valid string.";k.push(e[1]+"["+e[2]+"]="+n);g(this).children("ul,ol").sortableListsToString(k,e[2])});return k.join("&")}})(jQuery); | ||
(function(a){a.fn.sortableLists=function(m){var F=a("body").css("position","relative"),u={currElClass:"",placeholderClass:"",placeholderCss:{position:"relative",padding:0},hintClass:"",hintCss:{display:"none",position:"relative",padding:0},hintWrapperClass:"",hintWrapperCss:{},baseClass:"",baseCss:{position:"absolute",top:0-parseInt(F.css("margin-top")),left:0-parseInt(F.css("margin-left")),margin:0,padding:0,"z-index":2500},opener:{active:false,open:"",close:"",openerCss:{"float":"left",display:"inline-block","background-position":"center center","background-repeat":"no-repeat"},openerClass:""},maxLevels:false,listSelector:"ul",listsClass:"",listsCss:{},insertZone:50,insertZonePlus:false,scroll:20,ignoreClass:"",isAllowed:function(K,M,L){return true},onDragStart:function(L,K){return true},onChange:function(K){return true},complete:function(K){return true}},D=a.extend(true,{},u,m),p=a("<"+D.listSelector+" />").prependTo(F).attr("id","s-l-base").css(D.baseCss).addClass(D.listsClass+" "+D.baseClass),r=a("<li />").attr("id","s-l-placeholder").css(D.placeholderCss).addClass(D.placeholderClass),x=a("<li />").attr("id","s-l-hint").css(D.hintCss).addClass(D.hintClass),k=a("<"+D.listSelector+" />").attr("id","s-l-hint-wrapper").addClass(D.listsClass+" "+D.hintWrapperClass).css(D.listsCss).css(D.hintWrapperCss),A=a("<span />").addClass("s-l-opener "+D.opener.openerClass).css(D.opener.openerCss).on("mousedown",function(L){var K=a(this).closest("li");if(K.hasClass("s-l-closed")){v(K)}else{z(K)}return false});if(D.opener.as=="class"){A.addClass(D.opener.close)}else{if(D.opener.as=="html"){A.html(D.opener.close)}else{console.error("jQuerySortableLists opener as background image has been removed with release 2.0.0. Use html instead please.")}}var o={isDragged:false,isRelEFP:null,oEl:null,rootEl:{el:a(this),offset:null,rootElClass:a(this).attr("class")},cEl:null,placeholderParentLi:null,upScroll:false,downScroll:false,pX:0,pY:0,cX:0,cY:0,isAllowed:true,e:{pageX:0,pageY:0,clientX:0,clientY:0},doc:a(document),win:a(window)};if(D.opener.active){if(!D.opener.open){throw"Opener.open value is not defined. It should be valid url, html or css class."}if(!D.opener.close){throw"Opener.close value is not defined. It should be valid url, html or css class."}a(this).find("li").each(function(){var K=a(this);if(K.children(D.listSelector).length){A.clone(true).prependTo(K.children("div").first());if(!K.hasClass("s-l-open")){z(K)}else{v(K)}}})}if(D.maxLevels!==false){if(isNaN(D.maxLevels)){throw"JQuery-sortable-lists maxLevels values is not a number"}a(this).find("li").each(function(){var L=q(a(this));var K=w(a(this));c(a(this),L);i(a(this),K)})}return this.on("mousedown",function(N){var M=a(N.target);if(o.isDragged!==false||(D.ignoreClass&&M.hasClass(D.ignoreClass))){return}N.preventDefault();var L=M.closest("li"),K=a(this);if(L[0]){D.onDragStart(N,L);f(N,L,K)}});function f(Q,M,L){o.isDragged=true;var S=parseInt(M.css("margin-top")),O=parseInt(M.css("margin-bottom")),K=parseInt(M.css("margin-left")),T=parseInt(M.css("margin-right")),R=M.offset(),P=M.innerHeight();o.rootEl={el:L,offset:L.offset(),rootElClass:L.attr("class")};o.cEl={el:M,mT:S,mL:K,mB:O,mR:T,offset:R};o.cEl.xyOffsetDiff={X:Q.pageX-o.cEl.offset.left,Y:Q.pageY-o.cEl.offset.top};o.cEl.el.addClass("s-l-current "+D.currElClass);M.before(r);var N=o.placeholderNode=a("#s-l-placeholder");M.css({width:M.width(),position:"absolute",top:R.top-S,left:R.left-K}).prependTo(p);N.css({display:"block",height:P});x.css("height",P);o.doc.on("mousemove",E).on("mouseup",G)}function E(N){if(o.isDragged){var K=o.cEl,M=o.doc,L=o.win;if(!N.pageX){g(N)}if(M.scrollTop()>o.rootEl.offset.top-10&&N.clientY<50){if(!o.upScroll){B(N)}else{N.pageY=N.pageY-D.scroll;a("html, body").each(function(O){a(this).scrollTop(a(this).scrollTop()-D.scroll)});j(N)}}else{if(M.scrollTop()+L.height()<o.rootEl.offset.top+o.rootEl.el.outerHeight(false)+10&&L.height()-N.clientY<50){if(!o.downScroll){s(N)}else{N.pageY=N.pageY+D.scroll;a("html, body").each(function(O){a(this).scrollTop(a(this).scrollTop()+D.scroll)});j(N)}}else{n(o)}}o.oElOld=o.oEl;K.el[0].style.visibility="hidden";o.oEl=oEl=t(N.pageX,N.pageY);K.el[0].style.visibility="visible";h(N,o);d(N,o)}}function G(O){var N=o.cEl,K=a("#s-l-hint",o.rootEl.el),Q=x[0].style,P=null,M=false,L=a("#s-l-hint-wrapper");if(Q.display=="block"&&K.length&&o.isAllowed){P=K;M=true}else{P=o.placeholderNode;M=false}offset=P.offset();N.el.animate({left:offset.left-o.cEl.mL,top:offset.top-o.cEl.mT},250,function(){b(N);P.after(N.el[0]);P[0].style.display="none";Q.display="none";K.remove();L.removeAttr("id").removeClass(D.hintWrapperClass);if(L.length){L.prev("div").append(A.clone(true))}if(M){o.placeholderNode.slideUp(150,function(){o.placeholderParentLi=(!o.placeholderNode.parent().is(o.rootEl.el))?o.placeholderNode.parent().closest("li"):null;o.placeholderNode.remove();H();D.onChange(N.el);D.complete(N.el);o.isDragged=false;if(D.maxLevels!==false){y(N.el);if(o.placeholderParentLi){y(o.placeholderParentLi)}}})}else{o.placeholderNode.remove();H();D.complete(N.el);o.isDragged=false}});n(o);o.doc.unbind("mousemove",E).unbind("mouseup",G)}function B(K){if(o.upScroll){return}o.upScroll=setInterval(function(){o.doc.trigger("mousemove")},50)}function s(K){if(o.downScroll){return}o.downScroll=setInterval(function(){o.doc.trigger("mousemove")},50)}function j(K){o.pY=K.pageY;o.pX=K.pageX;o.cY=K.clientY;o.cX=K.clientX}function g(K){K.pageY=o.pY;K.pageX=o.pX;K.clientY=o.cY;K.clientX=o.cX}function n(K){clearInterval(K.upScroll);clearInterval(K.downScroll);K.upScroll=K.downScroll=false}function d(M,L){var K=L.cEl;K.el.css({top:M.pageY-K.xyOffsetDiff.Y-K.mT,left:M.pageX-K.xyOffsetDiff.X-K.mL})}function t(K,P){if(!document.elementFromPoint){return null}var O=o.isRelEFP;if(O===null){var N,L;if((N=o.doc.scrollTop())>0){O=((L=document.elementFromPoint(0,N+a(window).height()-1))==null||L.tagName.toUpperCase()=="HTML")}if((N=o.doc.scrollLeft())>0){O=((L=document.elementFromPoint(N+a(window).width()-1,0))==null||L.tagName.toUpperCase()=="HTML")}}if(O){K-=o.doc.scrollLeft();P-=o.doc.scrollTop()}var M=a(document.elementFromPoint(K,P));if(!o.rootEl.el.find(M).length){return null}else{if(M.is("#s-l-placeholder")||M.is("#s-l-hint")){return null}else{if(!M.is("li")){M=M.closest("li");return M[0]?M:null}else{if(M.is("li")){return M}}}}}function h(O,N){var K=N.oEl;if(!K||!N.oElOld){return}var M=K.outerHeight(false),L=O.pageY-K.offset().top;if(D.insertZonePlus){if(14>L){e(O,K,7>L)}else{if(M-14<L){C(O,K,M-7<L)}}}else{if(5>L){l(O,K)}else{if(M-5<L){J(O,K)}}}}function l(N,K){if(a("#s-l-hint-wrapper",o.rootEl.el).length){x.unwrap()}if(N.pageX-K.offset().left<D.insertZone){if((K.prev("#s-l-placeholder").length)||(D.maxLevels!==false&&!I(false))){x.css("display","none");return}K.before(x)}else{var L=K.children(),M=K.children(D.listSelector).first();if((M.children().first().is("#s-l-placeholder"))||(D.maxLevels!==false&&!I(true))){x.css("display","none");return}if(!M.length){L.first().after(x);x.wrap(k)}else{M.prepend(x)}if(o.oEl){v(K)}}x.css("display","block");o.isAllowed=D.isAllowed(o.cEl.el,x,x.parents("li").first())}function e(O,K,N){if(a("#s-l-hint-wrapper",o.rootEl.el).length){x.unwrap()}if(!N&&O.pageX-K.offset().left>D.insertZone){var L=K.children(),M=K.children(D.listSelector).first();if((M.children().first().is("#s-l-placeholder"))||(D.maxLevels!==false&&!I(true))){x.css("display","none");return}if(!M.length){L.first().after(x);x.wrap(k)}else{M.prepend(x)}if(o.oEl){v(K)}}else{if((K.prev("#s-l-placeholder").length)||(D.maxLevels!==false&&!I(false))){x.css("display","none");return}K.before(x)}x.css("display","block");o.isAllowed=D.isAllowed(o.cEl.el,x,x.parents("li").first())}function J(N,K){if(a("#s-l-hint-wrapper",o.rootEl.el).length){x.unwrap()}if(N.pageX-K.offset().left<D.insertZone){if((K.next("#s-l-placeholder").length)||(D.maxLevels!==false&&!I(false))){x.css("display","none");return}K.after(x)}else{var L=K.children(),M=K.children(D.listSelector).last();if((M.children().last().is("#s-l-placeholder"))||(D.maxLevels!==false&&!I(true))){x.css("display","none");return}if(M.length){L.last().append(x)}else{K.append(x);x.wrap(k)}if(o.oEl){v(K)}}x.css("display","block");o.isAllowed=D.isAllowed(o.cEl.el,x,x.parents("li").first())}function C(O,K,N){if(a("#s-l-hint-wrapper",o.rootEl.el).length){x.unwrap()}if(!N&&O.pageX-K.offset().left>D.insertZone){var L=K.children(),M=K.children(D.listSelector).last();if((M.children().last().is("#s-l-placeholder"))||(D.maxLevels!==false&&!I(true))){x.css("display","none");return}if(M.length){L.last().append(x)}else{K.append(x);x.wrap(k)}if(o.oEl){v(K)}}else{if((K.next("#s-l-placeholder").length)||(D.maxLevels!==false&&!I(false))){x.css("display","none");return}K.after(x)}x.css("display","block");o.isAllowed=D.isAllowed(o.cEl.el,x,x.parents("li").first())}function v(K){K.removeClass("s-l-closed").addClass("s-l-open");K.children(D.listSelector).css("display","block");var L=K.children("div").children(".s-l-opener").first();if(D.opener.as=="html"){L.html(D.opener.close)}else{if(D.opener.as=="class"){L.addClass(D.opener.close).removeClass(D.opener.open)}}}function z(K){K.removeClass("s-l-open").addClass("s-l-closed");K.children(D.listSelector).css("display","none");var L=K.children("div").children(".s-l-opener").first();if(D.opener.as=="html"){L.html(D.opener.open)}else{if(D.opener.as=="class"){L.addClass(D.opener.open).removeClass(D.opener.close)}}}function q(K){var O=0;var M=K.children(D.listSelector);if(M.length){O++;var N=0;var L=0;M.find("li").each(function(P){L=q(a(this));if(N<L){N=L}});if(N){O=O+N}}return O}function c(K,L){K.data("insideLevels",L)}function w(K){var N=0;var M=o.rootEl.el;var L=K.closest(D.listSelector);while(!L.is(M)){N++;L=L.parent().closest(D.listSelector)}return N}function i(K,L){K.data("upperLevels",L)}function I(K){var M=o.cEl.el.data("insideLevels");var L=o.oEl.data("upperLevels");return D.maxLevels>L+M+(K?1:0)}function y(K){var N=o.rootEl.el;var L=K.parent(D.listSelector);c(K,q(K));i(K,w(K));var M=0;K.find("li").each(function(){var O=a(this);c(O,q(O));i(O,w(O))});while(!L.is(N)&&M<50){var K=L.parent("li");c(K,q(K));L=K.parent(D.listSelector);M++}}function b(K){var L=K.el[0].style;K.el.removeClass(D.currElClass+" s-l-current");L.top="0";L.left="0";L.position="relative";L.width="auto"}function H(){a(D.listSelector,o.rootEl.el).each(function(K){if(!a(this).children().length){a(this).prev("div").children(".s-l-opener").first().remove();a(this).remove()}})}};a.fn.sortableListsToArray=function(c,d){c=c||[];var b=0;this.children("li").each(function(){var e=a(this),f={},g=e.attr("id");if(!g){console.log(e);throw"Previous item in console.log has no id. It is necessary to create the array."}f.id=g;f.parentId=d;f.value=e.data("value");f.order=b;c.push(f);e.children("ul,ol").sortableListsToArray(c,g);b++});return c};a.fn.sortableListsToHierarchy=function(){var c=[],b=0;a(this).children("li").each(function(){var d=a(this),e={},f=d.attr("id");if(!f){console.log(d);throw"Previous item in console.log has no id. It is necessary to create the array."}e.id=f;e.value=d.data("value");e.order=b;c.push(e);e.children=d.children("ul,ol").sortableListsToHierarchy();b++});return c};a.fn.sortableListsToString=function(b,c){b=b||[];c=c||"no-parent";a(this).children("li").each(function(){var d=a(this),f=d.attr("id"),e=f?f.match(/(.+)[-=_](.+)/):null;if(!e){console.log(d);throw"Previous item in console.log has no id or id is not in required format xx_yy, xx-yy or xx=yy. It is necessary to create valid string."}b.push(e[1]+"["+e[2]+"]="+c);a(this).children("ul,ol").sortableListsToString(b,e[2])});return b.join("&")}}(jQuery)); |
{ | ||
"name": "jquery-sortable-lists", | ||
"version": "1.4.0", | ||
"version": "2.0.0", | ||
"description": "jQuery plugin to sorting lists also the tree structures", | ||
@@ -5,0 +5,0 @@ "main": "jquery-sortable-lists.min.js", |
@@ -8,10 +8,14 @@ <h1><a href="http://camohub.github.io/jquery-sortable-lists/index.html">jquery-sortable-lists</a></h1> | ||
Format <strong>css</strong> of all active items however you want. | ||
You can define the <strong>isAllowed callback</strong> which determines if dragged item can be inserted into another. | ||
Set the <strong>insert zone</strong> like a distance which determines if item will be inserted inside or outside of the active area, | ||
<strong>speed of autoscroll</strong>. | ||
Available is <strong>onDragStart</strong>, <strong>onChange</strong> and <strong>complete callback</strong>.</p> | ||
You can define the | ||
<strong>isAllowed callback</strong> which determines | ||
if dragged item can be inserted into another. Set the | ||
<strong>insert zone</strong> like a distance which determines if item will | ||
be inserted inside or outside of the active area, also | ||
<strong class="c1">insert zone plus</strong> feature, | ||
<strong class="c1">speed of autoscroll</strong> function, | ||
<strong class="c1">max levels</strong> number... <strong class="c1">speed of autoscroll</strong> function, <strong class="c1">max levels</strong> number... | ||
Available is <strong>onDragStart</strong> and <strong>complete callback</strong>.</p> | ||
<p>Now plugin supports also mobile devices. Link jquery-sortable-lists-mobile.js instead of jquery-sortable-lists.js.</p> | ||
<p>Sortable lists also contains export functions <strong>toArray, toHierarchy, toString</strong>.</p> | ||
<p>For more info look at <a href="http://camohub.github.io/jquery-sortable-lists">the documentation</a>.</p> | ||
<p>For more info look at <a href="http://camohub.github.io/jquery-sortable-lists/index.html">the documentation</a>.</p> | ||
<p>Changelog is <a href="https://github.com/camohub/jquery-sortable-lists/blob/master/CHANGELOG.md">here</a>.</p> | ||
48685
968
21