My favorites | Sign in
Project Logo
                
Search
for
Updated Oct 17, 2007 by berpasan
NestedSortableDocumentation  
Documentation for the NestedSortable jQuery/Interface plugin

Introduction

The NestedSortable jQuery Plugin is built on top of the popular Interface plugin. jQuery is a "no-nonsense", fast, small, and extremelly easy to use JavaScript framework that is taking the world by storm. NestedSortable provides you with a way to easily build lists of elements that can be vertically sorted and nested (eg. one element can be made son of another) at the same time, using "Drag and Drop". It is based on Interface's Sortables and works on top of it. So, a NestedSortable will also have all the configuration options which are present in a regular Sortable in Interface. Some examples of possible usages:

  • Organizing a table of contents
  • Organizing a list of hierarchical pages (it was originally created with this goal, for WordPress)
  • Organizing categories
  • Organizing files and folders

Perhaps the easier way to get what it does it by looking at the demo. This plugin was designed as part of a Google Summer of Code project for WordPress, in 2007.

Change Log

1.0

  • Initial Release

1.0.1

  • Added noNestingClass option, to prevent nesting in some elements.

Download

I have compiled a compressed version which has only 5kB:

NestedSortable 1.0.1 (You will also need to download the dependencies)

You can also get the whole code, as well as the test code used in the demo:

NestedSortables Source 1.0.1

Dependencies

It was built on the latest versions of both jQuery and Interface.

  • jQuery 1.1.4 (currently with jQuery 1.2 there is an IE-specific problem caused by Interface incompatibility - thanks to n3dst4 for reporting it, so I recomend sticking to 1.1)
  • Interface 1.2 or above (only needs the components bellow, in that order)
    • iutil.js
    • idrag.js
    • idrop.js
    • isortables.js

Those dependencies have to be loaded in your HTML file in that order and before the NestedSortable plugin itself.

Usage

Basic Usage

Include the dependencies and the plugin itself in your HTML file.

<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="interface.js"></script>
<script type="text/javascript" src="inestedsortable.js"></script>

Include the HTML that represents your nested list. I recommend you to use an UL with LIs to represent the list, but you can actually use any pair of HTML elements that can be nested. The elements that are being sorted (the ones with the "accept" class) should have an ID, so the list can be serialized and sent back to the server.

Be aware than when a new nesting is created (eg. you make an element a child of a childless element), the plugin will create a new HTML element of the same type of the container element (in this example an UL) with all CSS classes this element has, inside the parent element (in this example an LI).

<ul id="list-container">
  <li class="sortable-element-class" id="ele-1">
    Element 1
  </li>
  <li class="sortable-element-class" id="ele-2">
    Element 2
  </li>
  <li class="sortable-element-class" id="ele-3">
    Element 3
    <ul>
      <li class="sortable-element-class" id="ele-4">
        Element 4
        <ul>
          <li class="sortable-element-class" id="ele-5">
            Element 5
          </li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

Add the JavaScript code that will set up your NestedSortable list. The minimum configuration options are used bellow, but you probably should want to add more parameters, such as an onChange callback (read the next section).

jQuery( function($) {
$('#list-container').NestedSortable(
  {
    accept: 'sortable-element-class',
  }
);
});

Configuration Parameters

The NestedSortable plugin will add two functions to the jQuery object: NestedSortable and NestedSortableDestroy. The first will configure the nested sortable and takes a object of configuration parameters, the second will undo such configuration and takes no parameters.

NestedSortable needs to be called on a jQuery object after selecting the elements that will be the list containers. If you have only one list you should probably use $.NestedSortable("#element_id") to select it.

The table bellow shows all the parameters that can be passed to the NestedSortable. These parameters are passed as a JS object. Use the {} notation to create such object. Many of those options are inherited from of the original Interface's Sortable.

Native options are exclusive to the NestedSortable plugin. Inherited options came from Interface's Sortable. Not all options from the original Sortable are listed here, the ones missing might work, but are not supported or useful.

Parameter Name Value Type Type / Default Description
accept String mandatory Css class name of the elements that are going to the sorted. They have to be inside the selected list container.
rightToLeft Boolean native / false If you set this options, the indentation will be applied from right to left. Useful for right-to-left reading languages.
nestingPxSpace Integer native / 30 The indentation of the nested elements, in pixels. An "margin" css style will be applied to the nested list containers.
autoScroll Boolean native / true By default, when you are dragging an element and reach the top or bottom edge of the screen, your browser window scroll automatically to reveal the NestedSortable elements that are not being displayed.
scrollSensitivity Integer native / 20 How close to the edge you need to be in order for the autoScroll to happen. Only applied when is autoScroll is on.
scrollSpeed Integer native / 20 How fast will the window be scrolled by autoScroll. Only applied when is autoScroll is on.
serializeRegExp RegExp native / /[^\-]*$/ Regular expression that will be used to select only a part of the element id, when using serialization. The default will select only what comes after the last -, so if you have elements with ids such as my-sortable-element-NUMBER, only NUMBER will appear in the serialization, to identify the element that is in a certain position. You usually want to use that to filter only the element DB id. Refer to serialization in the docs.
currentNestingClass String native / "" Css class that will be applied, only when dragging, to the nesting where the dragged element is currently in. Provides the user with some visual aid to help identify who is going to be the parent of the element being dragged.
noNestingClass String native / "" Elements that have this CSS class, in addition to the accept class, won't receive elements as children (eg.: will only be nodes in the tree).
activeclass String inherited When an acceptable draggable is moved the droppable (the list container for the NestedSortable) gets this class
hoverclass String inherited When an acceptable draggable is inside the droppable (the list container for the NestedSortable), the droppable gets this class.
helperclass String inherited The Helper is used to point the place where the item will be positioned. This is the css class the will be applied to the helper.
opacity Float ( < 1) inherited Opacity of the item while it is dragged.
ghosting Boolean inherited / false When true the sorthelper will contain a copy of the dragged element, while dragging.
fx Integer inherited When set, this dictates the duration of a special effect (a fade in) applied to the dragged element, once it is released.
revert Boolean inherited When set, makes the dragged element fly from its current position to the place it will be moved to. Fx needs to be set for this to work.
handle String inherited When this is set to the CSS class name of an HTML element that is inside the draggable items, this element will be used as the drag handle, instead of the whole item itself.
cursorAt Object inherited The dragged element is moved to the cursor position with the offset specified. It is an object with properties for top, left, right and bottom offset.
onChange Function inherited This will be called after a drag and drop operation changed the disposition of the list. An array with the serialized representation of all altered NestedSortables is provided as the first parameter (more than one Nested Sortable might be changed in only one operation, if you move one item from a list to another.). this refers to the NestedSortable DOMElement. Refer to the Serialization section in the docs.
onStart Function inherited Callback function triggered when the dragging starts. this refers to the NestedSortable DOMElement.
onStop Function inherited Callback function triggered when the dragging stops. this refers to the NestedSortable DOMElement.
onHover Function inherited Called when an accepted draggble is hovering a NestedSortable. Gets as parameter the draggable DOMElement. this refers to the NestedSortable DOMElement.
onOut Function inherited Called when an accepted draggable is leaving a NestedSortable. Gets as parameter the draggable DOMElement. this refers to the NestedSortable DOMElement.

Serialization

The support for serialization was built into the NestedSortable in order to be similar in its usage to the original Sortable from Interface. It is not very well documented there, so I will try to explain in briefly here.

The way to do it is to define an onChange callback, that will get called whenever the list is modified. This onChange will receive a parameter, with an array with the serialized representation of all altered NestedSortables since its last call. More than one NestedSortable list might be changed in only one operation, if you move one item from a list to another.

You define the callback using something such as:

jQuery( function($) {
$('#list-container').NestedSortable(
  {
    accept: 'sortable-element-class',
    onChange : function(serialized) {
      // Do something with serialized here
      // such as sending it to the server via an AJAX call
      // or storing it in a JS variable that you can
      // send to the server once the user presses a button.
    },
  }
);
});

The serialized argument is an array of JS objects, one for each NestedSortable that was modified, each with the following format, exactly as in the original Sortable:

{
  id: "list-container", //id of the modified NestedSortable
  hash: "list-container[0][id]=2&list-container[1][id]=1(...)", 
            //String representation of the all the elements that
            //belong to this NestedSortable. It is format
            //is compatible with GET or POST requests, so you
            //should probably want to send this to the server.
  o: [Object id=2, Object id=1, (...)] 
            //Exactly the same contents of `hash`, but represented
            // in a JS array. Use that if you need to manipulate the
            // the list before sending it to the server.   
}

Due to the nature of the NestedSortable, the contents of o and hash are a little more complex. In the original Sortables, it is basically a flat array with the ids of the elements in the order they are positioned.

The first difference is that, instead of the whole element id, exactly as in the HTML id, the NestedSortable will only write a portion of that id, filtered by a regular expression, thanks to the serializeRegExp. If you don't want to mess with this option, simply name your elements with ids in the format some_pretty-funky-name-LASTNAMEORNUMBER, where LASTNAMEORNUMBER should identify the element in your database, for saving purposes. I added this option because it simplifies a little the job you will have on the server side implementation.

The biggest difference is that, instead of a simple list, we need to represent a tree-like list. To do that, I use a combination of arrays and objects. o is an array where each element in an object which may contain the following properties:

  • id - the proper id of the element, after being filtered by the RegExp.
  • children - an array just like the parent one, containing all the children of this element.

hash is basically the same thing in URL query string format. If you pass it to a GET request, your server should be smart enough to generate an "array of objects" (or equivalent) in your server side language.

Instead of being boring and wasteful by providing a formal grammar representing the hash format, I will just provide a simple example, which should make it obvious.

serialized[0] = {
 o:[
      {
        id:1, 
      },
      {
        id:2, 
        children: 
          [
            {
            id:3, 
            children: [
              {
              id:4, 
              },
              {
              id:5, 
              }
            ]
            }
          ]
      }
    ],
//ignore the white space in the hash property
hash:   "list-container[0][id]=1&
        list-container[1][id]=2
        &list-container[1][children][0][id]=3
        &list-container[1][children][0][children][0][id]=4
        &list-container[1][children][0][children][1][id]=5"
}

Known Bugs

Currently this plugin has no know bugs of its own. Interface 1.2, however, was built for jQuery 1.1 and does have a few issues, specially with animations, when you use it with jQuery 1.2. You might encounter issues with the animation options in the NestedSortables, which are inherited from Interface. jQuery 1.2 was just released, lets hope Interface is updated to support it. The combination used in the demo is using jQuery 1.2 and Interface 1.2, and at least in those examples, doesn't generate any errors.

TODO for next versions

  • Provide an option to limit the levels of nesting that can be used


Comment by daniel.s.fields, Sep 28, 2007

Provide the parent element and child element to the onchange event.

Comment by berpasan, Oct 01, 2007

Daniel: I will log that as a suggestion for the upcoming versions.

Comment by nickkwest, Nov 14, 2007

An option to keep depth static and not allow dragging out of a certain depth into another. Example: option to now allow dragging of a file outside the folder that it is currently in, only sort within the folder that the item is. Parent's would sort at their own depth as well etc.

Comment by issac.kelly, Nov 15, 2007

is there a way to get the serialized order outside of onChange (like onSumbit of a form)? i modified the serialize function to also send the class of the item (since that can change too, but if somebody changes the class but not the order, none of the information is sent

Comment by berpasan, Nov 19, 2007

nickkwest: I get what you mean. It is a pretty specific need. Perhaps you could provide that to your users by simply using regular Sortables (eg.: you would have one Sortable for each hierarchy you wanted to sort).

issac.kelly: The recommended way to do this is to implement the onChange and make it save the serialized order in a global variable somewhere. You can latter on access that variable, when you submit a form, for instance. I don't recommend you to use the plugin's internal variable that stores the serialized representation, as that may change in the future (if you do what I told you your app will be more decoupled from my plugin's internals).

Comment by playairguitar, Nov 23, 2007

I'm in a similiar boat as nickkwest. I need to restrict an list item's nest depth depending on whether or not it has any children. I tried using onStart and then set the class "no-nesting" to the appropriate items. It seems however, that when I did this, the class was ignored and the item was allowed to be nested.

Comment by mauricederegt, Nov 25, 2007

Hi,

I am a total noob and have several questions:

1) How to get the hash output into a form? 2) How to use the hash output the serialize the list?

See my demo/test page for examples and more questions: http://www.sourceskins.com/index.html

Thank you for your time!

Comment by astrokid, Dec 03, 2007

Is anyone know approximately when can we expecting the next version which can limit the nesting level coming out? Thanks,

Comment by farerock, Jan 29, 2008

Thanks

Comment by shelbyh, Feb 19, 2008

One bug I noticed when looking at the demos linked above, is that the onchange function isn't called for the 'spans-divs' example when items are moved within the same tree-level. Note this does work properly for the 'left-to-right' example. I determined this is because the 'spans-divs' is using div-tags where as the working example is using ul/li tags. So there appears to be an error with onchange when using divs... or is there something i'm missing?

Comment by shelbyh, Feb 19, 2008

In regards to my earlier post, I figured out what the problem 'really' was. There are no 'IDs' in the spans-divs example, and without them the onchange won't get called when elements change on the same tree-level... ooops. my bad.

Comment by vanderlow, Mar 18, 2008

Hi! Great code. I was just wondering if you were still planning on adding nesting depth limits to the code?

Comment by aleksandras.smirnovas, Mar 20, 2008

Hi! I need depth limit too. Thanks

Comment by roblong, Mar 27, 2008

Hi, In IE6, the font of the item while it is dragged becomes strangely bolded. I am guessing this is a wierd IE problem but this doesn't seem to occur with your nested sortable widget demo. Any recommendations for a fix so the text stays constant? This also applies to elements after they are dropped if the revert effect is turned on.

Comment by berpasan, Apr 02, 2008

Hi guys,

Sorry, but I can't make any promises on dates for any new features or bug fixes, since I am pretty busy with some other projects. Besides, the first priority should be moving this to use JQuery UI instead of Interface (which was deprecated). I will gladly apply any pathes you provide, though.

mauricederegt: Use the onChange callback to do anything you want with the serialized output (including sending it on a form, and so on). You can easily use the jQuery for that (look up the jQuery docs, it's been quite a while since I last used it). If you use the hash output in a get request (such as http://url?HASH_OUTPUT) your server side language (such as PHP or Ruby on Rails) should interpret that and create a hash/array in the corresponding language automatically. Refer to the NestedSortableWidget? code to see a better way to do that.

Comment by dritterman, Apr 04, 2008

Thanks heaps for this great code, you couldn't have made it any simpler or robust. Great work!

One question though, sort of relating to nickkwest's question above: Is it possible to call the serialize function other than onchange? I have added the ability to 'remove' and 'add' items to the list dynamically and would like those actions to trigger the onChange or serialize call so that I can save the added values.

Any ideas?

Comment by skabet, Apr 04, 2008

I could might help out converting it to JQuery UI if desirable.. ?

Comment by Mail.BlackRay, Apr 07, 2008

How do I handle onClick event? For example I must know which one of folders is choosen

Comment by sc...@boyzoid.com, Apr 29, 2008

I am adding and removing items dynamically from a sortable. When I delete an item, I need to be able to grab the serialezed data. Is there a way to get this data, or to mimic a change so that the onChnage event will fire?

Comment by randy.ponce, May 06, 2008

I experienced a problem whereby the dragged elements would disappear while dragging. I determined that this was due to a z-index issue. When dragging, the z-index reverts to 0 (??). My first thought was to modify the class used in the helper parameter, but that didn't work. I wound up having to override #dragHelper in the CSS and put a z-index in there. Since #dragHelper isn't documented, I'm wondering if there is a better way to accomplish the same goal?

Comment by randy.ponce, May 06, 2008

Hi,

I have a problem with my code and would be very grateful if somebody would put me on the right track.

I have a mysql table structured like this: cid = autoincrement primary key ord = order parent title

My php generated list ordered by ord could look sth. like this:

<ul id="left-to-right" class="page-list">
  <li id="ele-1" class="clear-element page-item left">
    <div class='sort-handle'><img src="img/handle.gif" align="left"/></div>
    Lorem ipsum 1</li>
  <li id="ele-2" class="clear-element page-item left">
    <div class='sort-handle'><img src="img/handle.gif" align="left"/></div>
    Lorem ipsum 2
    <ul class="page-list">
      <li id="ele-3" class="clear-element page-item left">
        <div class='sort-handle'><img src="img/handle.gif" align="left"/></div>
        Lorem ipsum 21</li>
      <li id="ele-4" class="clear-element page-item left">
        <div class='sort-handle'><img src="img/handle.gif" align="left"/></div>
        Lorem ipsum 22 </li>
    </ul>
  </li>
  <li id="ele-5" class="clear-element page-item left">
    <div class='sort-handle'><img src="img/handle.gif" align="left"/></div>
    Lorem ipsum 3</li>
</ul>

The id of each list element contains cid from my table.

Now my code:

<script type="text/javascript">
jQuery( function($) {
$('#left-to-right').NestedSortable(
	{
		accept: 'page-item',
		noNestingClass: "no-nesting",
		opacity: 0.8,
		helperclass: 'helper',
		onChange: function(serialized) {	
			$.post("saveMenu.php", 'm='+serialized[0].hash);		
		},
		autoScroll: true,
		handle: '.sort-handle'
	}
);
});
</script>

And saveMenu.php:

<?php
$aMenu = $_POST['left-to-right'];
function saveMenu($parent, $children) {
	$parent = (int) $parent;
	$i = 1;
	foreach ($children as $k => $v) {
		$id = (int) $children[$k]['id'];
		$upd = mysql_query("UPDATE `news` SET `parent` = ".$parent.", `ord` = ".$i." WHERE `cid` = ".$id) or die(mysql_error());
		if (isset  ( $children[$k]['children'][0]  )) {
		saveMenu($id, $children[$k]['children']);
		}
		$i++;
	}
}

saveMenu(0, $aMenu);
?>

OK. With this code I can reorder (and mysql is updated) all elements except the first one. I can place it anywhere, put other elements in front of it but mysql table is not updated. What am I missing?

Thanks in advance

Comment by Fall.iNTo.DozE, May 27, 2008

To skriptek:

change

$aMenu = $POST'left-to-right'?;

to

$aMenu = $POST'm'?;

hope it's useful :]

Comment by baolin1389, Jun 02, 2008

hi, I like the perfect plusin,so i want to use it to effect a tree.how can i get it with the tree-view plusin or by other method ? just effect the expandable and collapsable ,can you help me? thanks a lot.

Comment by r.allens...@gmx.net, Jun 16, 2008

I would like to add and remove items dynamic. Is there any documentation for it?

The problem is, if i delete the root element of a nested list like 1 1.1 1.1.1 1.1.2 1.1.3

all items disappear. For example i only want to delete the item 1.1 and all children should be moved to the root item 1 - how to i do that? :)

Greets!

Comment by r.allens...@gmx.net, Jun 16, 2008

Here is my example again: # Item 1 ## Item 1.1 ### Item 1.1.1 ### Item 1.1.2 ### Item 1.1.3

If Item 1.1 is deleted, the childrens should go to Item 1 like this: # Item 1 ## Item 1.1.1 ## Item 1.1.2 ## Item 1.1.3

Comment by r.allens...@gmx.net, Jun 16, 2008

I'm sorry, the Wiki-List-Function doesn't work correctly?

Comment by civeson, Jul 18, 2008

Hi,

Great code! Just what I'm looking for.

A small problem I've got is an "input type=text" element in one of my LI elements - in IE it's not possible to select any text within the element using either the mouse or keyboard. I'm guessing it's something to do with the iDraggable object applied to a parent element, but not sure how to disable it so that text in the control can be selected normally.

Is there any quick fix for this?

Thanks in advance for any help.

Comment by bubblesn...@nerdshack.com, Aug 27, 2008

I've been trying to get this working properly and I just can't make it work. It nearly works, but after being moved once, certain items can't be selected anymore. Here's my page, I basically copied it all from the demo page. It uses the exact same js files as the demo page.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    <title>Untitled Page</title>
    <style type="text/css">
        div.wrap {
			border:1px solid #BBBBBB;
			padding: 1em 1em 1em 1em;
		}
		
		.page-list {
			list-style: none;
			margin: 0;
			padding: 0;
			display: block;
		}
		
		.clear-element {
			clear: both;
		}
		
		.page-item1 > div,
		.page-item2 > div,
		.page-item3 > div,
		.page-item4 > div {
			background: #f8f8f8;
			margin: 0.25em 0 0 0;
		}

		.left {
			text-align: left;
		}
		
		.right {
			text-align: right;
		}

		.sort-handle {
			cursor:move;
		}
		
		.helper {
		border:2px dashed #777777;
		}
		
		.current-nesting {
			background-color: yellow;
		}
		
		.bold {
			color: red;
			font-weight: bold;
		}
    </style>
    <script type="text/Javascript" src="../js/jquery.js"></script>
    <script type="text/Javascript" src="../js/interface.js"></script>
    <script type="text/Javascript" src="../js/inestedsortable.js"></script>
    
</head>
<body>
    <div class="wrap">
        <ul id="left-to-right" class="page-list">

            <li id="ele-1" class="clear-element page-item1 left no-nesting">
                <div class='sort-handle'>File 1</div>
            </li>
            <li id="ele-2" class="clear-element page-item1 left no-nesting">
                <div class='sort-handle'>File 2</div>
            </li>
            <li id="ele-3" class="clear-element page-item1 left">
                <div class='sort-handle'>Folder 1</div>
            </li>
             <li id="ele-4" class="clear-element page-item1 left">
                <div class='sort-handle'>Folder 2</div>
                <ul class="page-list">
                    <li id="ele-5" class="clear-element page-item1 left">
 	                    <div class='sort-handle'>Folder 3</div>
	                    <ul  class="page-list" >
                            <li id="ele-6" class="clear-element page-item1 left no-nesting">
        	                    <div class='sort-handle'>File 3</div>
                            </li>
	                    </ul>
                    </li>
                </ul>
            </li>
        </ul>
    </div>
    <script type="text/Javascript">
        jQuery(function($){
	        $(''#left-to-right').NestedSortable({
		        accept: 'page-item1',
		        noNestingClass: "no-nesting",
		        opacity: .8,
		        helperclass: 'helper',
		        autoScroll: true,
		        handle: '.sort-handle'
	        });
        });
    </script>
</body>
</html>
Comment by bubblesn...@nerdshack.com, Aug 27, 2008

Just to verify, tested in Firefox it appears to work fine. But the problem occurs in IE7 (the demo page works fine in IE7).

Comment by bubblesn...@nerdshack.com, Aug 28, 2008

I've just seeb the issue here: http://code.google.com/p/nestedsortables/issues/detail?id=4

I've taken the workaround of using jquery 1.1.4, and it all seems good now :)

Comment by sea...@web.de, Sep 05, 2008

Hi,

for my implementation, I need only the id of the dragged element. How can I find out this id?

Best regards...

Comment by geordienz, Sep 10, 2008

Hiya,

I'm struggling to incorporate a linked image within the <li> element.

This causes problems: <li><a href="#"><img src="an_image.gif"/></a>Page Title</li>

In that it will either cause the image to drop off, or the entire list item to collapse entirely.

Am I missing something very obvious or is there a magic switch I need to use with CSS to control the relationship between the <li> element and the image & link nested within it?

Thanks

Comment by geordienz, Sep 11, 2008

Well, after too much head scratching I've opted for the <spans'n'divs> method. While not as clear cut as the unordered list, it is proving to be a little more robust in terms of nested elements (links / images etc) not dropping into oblivion.

Sweet.

Comment by angstsix, Sep 24, 2008

Hello, I'm trying to use the sortable list feature with mysql/php to save the list order, I've pretty much used the script that skriptek posted above.

echo "<div id='list'>";
$db->Query("SELECT * FROM Contacts ORDER BY DisplayOrder ASC");
$result = $db->result;
while ($row = mysql_fetch_array($result)){
	echo "<div class='line' id='ele-" . $row['ContactsID'] . "'>
			<div class='line_icon'>
			<a href='Contacts_Modify.php?ContactsID=" . $row['ContactsID'] . "'><img src='images/icon_edit.gif' alt='View Contacts Details' class='noborder'></a>
			<a href='Contacts_Main.php?action=delete&ContactsID=" . $row['ContactsID'] . "' onclick=\"return confirm('Are you sure you want to remove this Contacts?');\"><img src='images/icon_del.gif' alt='Delete Contacts\' class='noborder'></a>
			</div>
			<div class='line_text'><a href='Contacts_Modify.php?action=edit&ContactsID=" . $row['ContactsID'] . "'>" . $row["ContactName"] . "</a></div>
            <div class='clear'>&nbsp;</div>
			</div>";
			
}
echo "</div>";


echo "</div>";
echo $page->AdminFooter();
?>
<script type="text/javascript">
jQuery( function($) {

	$('#list').Sortable(
		{
		accept: 'line',
		opacity: 0.8,
		helperclass: 'helper',
        onChange: function(serialized) {
            $.post("SaveOrder.php", 'm='+serialized[0].hash);
        }

		}
	);
	
});
</script>

and this is my SaveOrder?.php script

include '../functions/_settings.php';

$aMenu = $_POST['m'];

function saveOrder($children) {
    $i = 1;
    foreach ($children as $k => $v) {
        $id = (int) $children[$k]['id'];
        $upd = mysql_query("UPDATE Contacts SET DisplayOrder = '".$i."' WHERE ContactsID = ".$id);


        if (isset  ( $children[$k]['children'][0]  )) {
            saveOrder($id, $children[$k]['children']);
        }
    $i++;
    }
}

mysql_query("INSERT INTO Errors SET Msg = '" . mysql_errno() . ": " . mysql_error() . "'");

saveOrder($aMenu);

but this wont write anything to me data base, any ideas would be great!

Comment by stephen.d.francis, Oct 08, 2008

Several people above (e.g. dritterman) have mentioned dynamically adding and removing elements. Could somebody advise on the best way of achieving these activities?

Thanks.

Comment by bo...@getsupernova.com, Oct 30, 2008

does anyone know what code is being called that's responsible for allowing items to be draggable? I have the code dynamically appending new items to the list but they cannot be dragged.

It's not the cleanest but I'll post my code after its worked out.

Comment by obafg2km, Nov 05, 2008

How about a way to cancel a sort operation? Possibly a callback onstart? return false or similar?

Comment by kelly.dirk, Nov 09, 2008

@daniel: we needed the same thing, we're using this.

@author: I love the script, but I don't think it is necessary to return the entire list of data, only thing of interest is the elements that have been affected. Like I said though, this script is insanely helpful and I appreciate your hard work.

jQuery.iNestedSortable.check = function(dragged)
{
	jQuery.iNestedSortable.newCheck(dragged);
		
	$return = jQuery.iNestedSortable.oldCheck(dragged);
		
	$element = $(dragged);
	$parent = $element.parent().parent();
	$position = -1;
		
	jQuery.each($element.parent().children(), function(i)
	{
		if($(this).attr('id') == $element.attr('id'))
		{
			$position = i;
		}
	});
		
	console.log('element = ',$element.attr('id'));
	console.log('parent = ',$parent.attr('id'));
	console.log('position = ',$position);
		
	return $return;
};
Comment by remon.oldenbeuving, Nov 28, 2008

As mentioned is Issue 9, I have a slight problem. I need to limit the depth of the tree. So far this works pretty well, only one slight problem.

Its still possible to move menuitems with subitems into a subitem, when the nesting limit is reached.

When I look to the code I think the best way to stop this is to check in shouldNestItem if the item that is being dragged has subitems, and then check if including the nested items the limit is reached.

It looks like berpasan was trying to get this done, but his version doesnt work yet and it looks like this project is kinda dead.

			//for each leaf element inside the dragged element (that have no elements nested to it)
			jQuery(e.nestedSortCfg.nestingTag + "." + e.nestedSortCfg.nestingTagClass.split(" ").join(".") + " > ." + e.sortCfg.accept.split(" ").join(".") + ":first-child", jQuery.iDrag.dragged)
				.not("*["+e.nestedSortCfg.nestingTag + "." + e.nestedSortCfg.nestingTagClass.split(" ").join(".")+"]")
				.each( function(i) {
					var draggedIndex = 0;
					//finds out 
					var parentLength = jQuery(this).parents("." + e.sortCfg.accept.split(" ").join(".")).each(
						function(i) {
							draggedIndex = i;
							return this == jQuery.iDrag.dragged;
						}
						).length;
					//here dradraggedIndex holds the index 
					//of the dragged element in the ancestors array of the leaf element
					var thisLevel = parentLength - draggedIndex;
					if (thisLevel > nLevelDrag )
						nLevelDrag = thisLevel;
					}
				);

The inside of this function is never reached, it looks like it that this is where you are trying to check if the item has subitems, and then check if including the subitems the nestingLimit is reached

			if (nLevelPrec + nLevelDrag > e.nestedSortCfg.nestingLimit) return false;

But now I cant see why this wont work. I tried some stuff myself, which isnt as pretty, but easy, because I only want to accept a nestingLimit of 1. I tried to check if there is a subitem nested, but this function always returns null...

Is there anybody with a fix for this?

Comment by remon.oldenbeuving, Nov 28, 2008

Basicly the only thing I need is to know inside shouldNestItem if the item that is being dragged has subItems. If someone could help me with that, it would be muchly apreciated. When I find a fix for this problem I will post it here, because I can see there are many people waiting on this:)

Comment by randyphi, Dec 14, 2008

I'm trying kelly.dirk's idea from Nov. 9 above to return the element id, parent id and position when an item is dropped. I'm not real clear on how or where to implement it though. I placed a version in the iNestedSortable check: function like this...

check : function(dragged)

{
jQuery.iNestedSortable.newCheck(dragged);
$return = jQuery.iNestedSortable.oldCheck(dragged);
$element = $(dragged); $parent = $element.parent().parent(); $position = 1;
jQuery.each($element.parent().children(), function(i) {
if($(this).attr('id') == $element.attr('id')) {
$position = i;
}
});
console.log('parent = ',$parent.attr('id')); console.log('element = ',$element.attr('id')); console.log('position = ',$position);

return $return;

}

And while that does return what I am looking for to the console, as cool as that is, it would be more useful to access that info from onChange directly on the page where iNestedSortable is called.

Comment by nicolas.perussel, Feb 18, 2009

Hi, very pretty script ! I'm love it !

I'have a probleme with my server side version, I don't have probleme to serialize data (when i write in a div, I have my answer) but when I want make a $post request I receive only the first item information

My javascript script:

	jQuery( function($) {
		$('#list-container').NestedSortable({
			accept: 'sortable',
            opacity: 0.8,
            autoScroll: true,

			onChange: function(serialized) {
				serial = serialized[0].hash;
				$("#serialize").html(serial)
				$.post("menu.php", 'menu= '+ serial);
			}
		});
	});

My very simply PHP script:

$valeur = isset($_POST['menu']) ? $_POST['menu'] : '';
echo '<pre>';var_dump($valeur); echo '</pre>';

Can you help me ?

Nico

Comment by nicolas.perussel, Feb 24, 2009

I have a answer of my previous post

I have changed this :

onChange: function(serialized) {
                                serial = serialized[0].hash;
                                $("#serialize").html(serial)
                                $.post("menu.php", 'menu= '+ serial);
                        }

by that :

onChange: function(serialized) {
     $.post("menu.php", serialized[0].hash);
}
Comment by irek.surma, Apr 05, 2009

look at this. http://skolman.kei.pl/inestedsortable.js

function send(event) {
	var current = event[0].my.current;
	var parent = event[0].my.parent;
	var prev_sibling = event[0].my.prev_sibling;

	$.ajax({
		type: "POST",
		async: false,
		url: "/ajax-move-node",
		data: "parent="+parent+"&current="+current+"&prev_sibling="+prev_sibling
	});
}

$('#list-container').NestedSortable({
    accept: 'sortable-element-class',
    onChange: send,
    helperclass: 'highlight'
    
});
Comment by toastkid.williams, Apr 06, 2009

Hi - thanks for this plugin, i've been using it for a while now with no problems. However, i've been asked to make a change and can't work out how to do it.

Currently. when you drag an element down the tree, if you drag it over a closed branch, the branch will open automatically to show where the element would sit within it. I want to STOP it doing that - ie, so that a branch only ever opens when you tell it to (by clicking on it's plus sign). Is that possible with the current options?

thanks again max

Comment by raju.rachana, May 18, 2009

I want to have some restrictions in the drag and drop. Like i have categories and articles inside respective categories. So there should not be possible to put the main categories under another (main) category but still every categories should be possible to sort/order.

How can i achieve this?

Thank you in advance.


Sign in to add a comment
Hosted by Google Code