<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Nobody Listens Anyway &#187; trees</title>
	<atom:link href="http://www.justinball.com/tag/trees/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.justinball.com</link>
	<description>Life is an optimization issue</description>
	<lastBuildDate>Fri, 03 Sep 2010 20:44:38 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1-alpha</generator>
		<item>
		<title>Hierarchies, trees, jQuery, Prototype, script.aculo.us and acts_as_nested_set</title>
		<link>http://www.justinball.com/2009/01/18/heirarchies-trees-jquery-prototype-scriptaculous-and-acts_as_nested_set/</link>
		<comments>http://www.justinball.com/2009/01/18/heirarchies-trees-jquery-prototype-scriptaculous-and-acts_as_nested_set/#comments</comments>
		<pubDate>Sun, 18 Jan 2009 21:09:04 +0000</pubDate>
		<dc:creator>Justin Ball</dc:creator>
				<category><![CDATA[Ruby On Rails]]></category>
		<category><![CDATA[acts_as_nested_set]]></category>
		<category><![CDATA[heirachy]]></category>
		<category><![CDATA[Heirarchies]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[ordered tree]]></category>
		<category><![CDATA[prototype]]></category>
		<category><![CDATA[script.aculo.us]]></category>
		<category><![CDATA[trees]]></category>

		<guid isPermaLink="false">http://www.justinball.com/?p=881</guid>
		<description><![CDATA[I've rarely worked on a web project that didn't require some type of hierarchical display of of data.  You see a tree like organization of data all over - in navigation, in forums, in threaded comments, etc.  I've done it three times and three different ways in three different Ruby on Rails projects [...]]]></description>
			<content:encoded><![CDATA[<p>I've rarely worked on a web project that didn't require some type of hierarchical display of of data.  You see a tree like organization of data all over - in navigation, in forums, in threaded comments, etc.  I've done it three times and three different ways in three different Ruby on Rails projects lately so I thought I would share some of what I have found.</p>
<p>In two of the projects I used the '<a href="http://github.com/collectiveidea/awesome_nested_set/tree/master">awesome_nested_set</a>' plugin from <a href="http://collectiveidea.com/">collectiveidea</a>.  I should have used it in the other project as well.  It is very powerful and handles all the complicated details for you.  Not only does it create a tree it creates an ordered tree which is typically what you want when you are trying to put nodes in very specific locations.  All you need to do to get the functionality of awesome_nested_set is to add acts_as_nested_set to your model and then include a couple of migrations:</p>
<h2>The Data and plugins and stuff</h2>
<p>Here's the model:</p>
<pre class="ruby">&nbsp;
<span style="color:#9966CC; font-weight:bold;">class</span> Message &lt; <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Base</span>
  acts_as_nested_set
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;</pre>
<p>Here's the migrations:</p>
<pre class="ruby">&nbsp;
<span style="color:#9966CC; font-weight:bold;">class</span> CreateMessages &lt; <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Migration</span>
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">up</span>
    create_table <span style="color:#ff3333; font-weight:bold;">:messages</span> <span style="color:#9966CC; font-weight:bold;">do</span> |t|
      t.<span style="color:#9900CC;">text</span>     <span style="color:#ff3333; font-weight:bold;">:text</span>
      t.<span style="color:#CC0066; font-weight:bold;">integer</span> <span style="color:#ff3333; font-weight:bold;">:user_id</span>
      t.<span style="color:#CC0066; font-weight:bold;">integer</span>  <span style="color:#ff3333; font-weight:bold;">:parent_id</span>
      t.<span style="color:#CC0066; font-weight:bold;">integer</span>  <span style="color:#ff3333; font-weight:bold;">:lft</span>
      t.<span style="color:#CC0066; font-weight:bold;">integer</span>  <span style="color:#ff3333; font-weight:bold;">:rgt</span>
      t.<span style="color:#9900CC;">timestamps</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">down</span>
    drop_table <span style="color:#ff3333; font-weight:bold;">:messages</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;</pre>
<p>Then you can do things like this:</p>
<pre class="ruby">&nbsp;
node = Message.<span style="color:#9900CC;">find</span><span style="color:#006600; font-weight:bold;">&#40;</span>params<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:id</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
parent = Message.<span style="color:#9900CC;">find</span><span style="color:#006600; font-weight:bold;">&#40;</span>params<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:parent_id</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
&nbsp;
<span style="color:#008000; font-style:italic;"># move the node to the first child of the parent node</span>
node.<span style="color:#9900CC;">move_to_child_of</span><span style="color:#006600; font-weight:bold;">&#40;</span>parent_node<span style="color:#006600; font-weight:bold;">&#41;</span>
&nbsp;
<span style="color:#008000; font-style:italic;"># move the node to the left of the sibling node</span>
sibling = Message.<span style="color:#9900CC;">find</span><span style="color:#006600; font-weight:bold;">&#40;</span>params<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:sibling_id</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
node.<span style="color:#9900CC;">move_to_right_of</span><span style="color:#006600; font-weight:bold;">&#40;</span>sibling<span style="color:#006600; font-weight:bold;">&#41;</span>
&nbsp;</pre>
<p>More about why this is important later.</p>
<h2>The HTML and rendering and stuff</h2>
<p>You'll need to generate html for your tree structure.  There are a couple of ways of doing this.</p>
<p>If you have a root message you can get all of its descendants very easily.  This will only make one sql call which improves performance.  You don't want to be hitting the database every time you need the children of a given node.<br />
You can do something like this in your view</p>
<pre class="ruby">&nbsp;
&lt;% <span style="color:#9966CC; font-weight:bold;">if</span> <span style="color:#0066ff; font-weight:bold;">@message</span>.<span style="color:#9900CC;">descendants</span>.<span style="color:#9900CC;">length</span> &gt; <span style="color:#006666;">0</span> -%&gt;
  &lt;%= render <span style="color:#ff3333; font-weight:bold;">:partial</span> =&gt; <span style="color:#996600;">'/messages/message'</span>, <span style="color:#ff3333; font-weight:bold;">:collection</span> =&gt; <span style="color:#0066ff; font-weight:bold;">@message</span>.<span style="color:#9900CC;">descendants</span> %&gt;
&lt;% <span style="color:#9966CC; font-weight:bold;">end</span> -%&gt;
&nbsp;</pre>
<p>The message partial will look like this.  I do make a few assumptions about methods that are available on the model - dom_id for example.  However 'level' is provided by the awesome_nested_set plugin and gives you the level of the given object in the tree.  Thus you can render something that looks like a hierarchy by simply iterating over a list.</p>
<pre class="ruby">&nbsp;
&lt;div id=<span style="color:#996600;">&quot;&lt;%= message.dom_id %&gt;&quot;</span> style=<span style="color:#996600;">&quot;margin-left:&lt;%= (20 * (message.level-1)) %&gt;px&quot;</span>&gt;
  &lt;%= message.<span style="color:#9900CC;">text</span> %&gt;
&lt;/div&gt;
&nbsp;</pre>
<p>If you need to calculate a level to indent the message without hitting the database you can add this as a helper:</p>
<pre class="ruby">&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> get_level<span style="color:#006600; font-weight:bold;">&#40;</span>message, single_message<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#0000FF; font-weight:bold;">return</span> <span style="color:#006600; font-weight:bold;">&#40;</span>message.<span style="color:#9900CC;">level</span> - <span style="color:#006666;">1</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">if</span> single_message
    <span style="color:#0066ff; font-weight:bold;">@levels</span> = <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#9966CC; font-weight:bold;">if</span> !<span style="color:#9966CC; font-weight:bold;">defined</span>?<span style="color:#006600; font-weight:bold;">&#40;</span>@levels<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">if</span> level = <span style="color:#0066ff; font-weight:bold;">@levels</span>.<span style="color:#9900CC;">index</span><span style="color:#006600; font-weight:bold;">&#40;</span>message.<span style="color:#9900CC;">parent_id</span><span style="color:#006600; font-weight:bold;">&#41;</span>
      <span style="color:#0066ff; font-weight:bold;">@levels</span>.<span style="color:#9900CC;">slice</span>!<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">&#40;</span>level + <span style="color:#006666;">1</span><span style="color:#006600; font-weight:bold;">&#41;</span>..<span style="color:#006666;">-1</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">else</span>
      <span style="color:#0066ff; font-weight:bold;">@levels</span> &lt;&lt; message.<span style="color:#9900CC;">parent_id</span>
      level = <span style="color:#0066ff; font-weight:bold;">@levels</span>.<span style="color:#9900CC;">size</span> - <span style="color:#006666;">1</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
    level
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;</pre>
<p>and then your code changes only slightly:</p>
<pre>&nbsp;
&lt;div id=&quot;&lt;%= message.dom_id %&gt;&quot; style=&quot;margin-left:&lt;%= (20 * get_level(message, single_message)) %&gt;px&quot;&gt;
  &lt;%= message.text %&gt;
&lt;/div&gt;
&nbsp;</pre>
<p>'single_message' should normally be set to false.  I added it in just in case I needed to render a single message for an ajax call.  If you aren't rendering an entire tree and thus have only one node then passing 'single_message = true' will force the method to call the database to get the level of the node in the tree.</p>
<p>If you want to render a true tree structure (not just indents) then you'll need to do a bit of recursion.  Assuming @message is a root level message you can do this:</p>
<pre class="ruby">&nbsp;
&lt;div id=<span style="color:#996600;">&quot;messageList&quot;</span>&gt;
&lt;ul id=<span style="color:#996600;">&quot;message_tree&quot;</span>&gt;
    &lt;% render_messages<span style="color:#006600; font-weight:bold;">&#40;</span>@message<span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">do</span> |message| -%&gt;
      &lt;%= message.<span style="color:#9900CC;">text</span> %&gt;
    &lt;% <span style="color:#9966CC; font-weight:bold;">end</span> -%&gt;
  &lt;/ul&gt;
&lt;/div&gt;
&nbsp;</pre>
<pre class="ruby">&nbsp;
<span style="color:#9966CC; font-weight:bold;">module</span> MessagesHelper
&nbsp;
<span style="color:#9966CC; font-weight:bold;">def</span> render_messages<span style="color:#006600; font-weight:bold;">&#40;</span>message, &amp;block<span style="color:#006600; font-weight:bold;">&#41;</span>
  concat<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'
&lt;li id=&quot;message_'</span> + message.<span style="color:#9900CC;">id</span>.<span style="color:#9900CC;">to_s</span> + <span style="color:#996600;">'&quot; class=&quot;messageContainer delete-container&quot;&gt;'</span>, block.<span style="color:#CC0066; font-weight:bold;">binding</span><span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">yield</span><span style="color:#006600; font-weight:bold;">&#40;</span>message<span style="color:#006600; font-weight:bold;">&#41;</span>
  concat<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'
&lt;ul style=&quot;display:none;&quot; id=&quot;ul_'</span> + message.<span style="color:#9900CC;">dom_id</span> + <span style="color:#996600;">'&quot;&gt;'</span>, block.<span style="color:#CC0066; font-weight:bold;">binding</span><span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">if</span> has_children?<span style="color:#006600; font-weight:bold;">&#40;</span>message.<span style="color:#9900CC;">id</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    children_of<span style="color:#006600; font-weight:bold;">&#40;</span>message.<span style="color:#9900CC;">id</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |child|
      render_messages<span style="color:#006600; font-weight:bold;">&#40;</span>child, &amp;block<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
  concat<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'&lt;/li&gt;
&lt;/ul&gt;
&nbsp;
'</span>, block.<span style="color:#CC0066; font-weight:bold;">binding</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#008000; font-style:italic;"># HACK these methods assume a variable named @messages is defined.</span>
<span style="color:#008000; font-style:italic;"># This hack prevents us from having to pass messages all over</span>
<span style="color:#9966CC; font-weight:bold;">def</span> has_children?<span style="color:#006600; font-weight:bold;">&#40;</span>message_id<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#0066ff; font-weight:bold;">@messages</span>.<span style="color:#9900CC;">any</span>?<span style="color:#006600; font-weight:bold;">&#123;</span>|message| message.<span style="color:#9900CC;">parent_id</span> == message_id<span style="color:#006600; font-weight:bold;">&#125;</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">def</span> children_of<span style="color:#006600; font-weight:bold;">&#40;</span>message_id<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#0066ff; font-weight:bold;">@messages</span>.<span style="color:#9900CC;">find_all</span><span style="color:#006600; font-weight:bold;">&#123;</span>|message| message.<span style="color:#9900CC;">parent_id</span> == message_id<span style="color:#006600; font-weight:bold;">&#125;</span>
<span style="color:#9966CC; font-weight:bold;">end</span>  
&nbsp;
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;</pre>
<p>(*Note that I've not fully tested the code above and I am betting it is not the most efficient.  At the very least you'll want to cache the resulting html.)</p>
<p>Next you'll need to add some script to get the drag and drop to work.  It will look something like this.  Honestly I can't remember if I got this code from somewhere online or if I wrote it.  I am sure someone could make it generic, but in this instance we use css class names to add drag and drop functionality to the various nodes:</p>
<pre class="javascript">&nbsp;
jQuery<span style="color: #66cc66;">&#40;</span>document<span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">ready</span><span style="color: #66cc66;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
&nbsp;
	jQuery<span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">&quot;.messageContainer&quot;</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">draggable</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#123;</span>
		zIndex : <span style="color: #CC0000;">1000000</span>,
		revert : <span style="color: #3366CC;">'invalid'</span>,
		opacity : <span style="color: #CC0000;">0.5</span>,
		<span style="color: #000066;">scroll</span> : <span style="color: #003366; font-weight: bold;">true</span>,
		helper : <span style="color: #3366CC;">'clone'</span>
	<span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
	jQuery<span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">&quot;#messageList&quot;</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">droppable</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#123;</span>
			accept: <span style="color: #3366CC;">&quot;.messageContainer&quot;</span>,
			drop: <span style="color: #003366; font-weight: bold;">function</span><span style="color: #66cc66;">&#40;</span>ev, ui<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
				<span style="color: #003366; font-weight: bold;">var</span> source_li = jQuery<span style="color: #66cc66;">&#40;</span>ui.<span style="color: #006600;">draggable</span><span style="color: #66cc66;">&#41;</span>;
				<span style="color: #003366; font-weight: bold;">var</span> child_ul = jQuery<span style="color: #66cc66;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">children</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'ul'</span><span style="color: #66cc66;">&#41;</span>;
				<span style="color: #003366; font-weight: bold;">var</span> message_id = source_li.<span style="color: #006600;">children</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'input'</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">val</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
				<span style="color: #003366; font-weight: bold;">var</span> parent_id = <span style="color: #CC0000;">0</span>;
				<span style="color: #000066; font-weight: bold;">if</span><span style="color: #66cc66;">&#40;</span>same_parent<span style="color: #66cc66;">&#40;</span>source_li, child_ul<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
					<span style="color: #000066; font-weight: bold;">return</span>;
				<span style="color: #66cc66;">&#125;</span>
				insert_alphabetic<span style="color: #66cc66;">&#40;</span>child_ul, source_li<span style="color: #66cc66;">&#41;</span>;
				update_parent<span style="color: #66cc66;">&#40;</span>message_id, parent_id<span style="color: #66cc66;">&#41;</span>;
	    <span style="color: #66cc66;">&#125;</span>
		<span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
	jQuery<span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">&quot;.messageContainer&quot;</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">droppable</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#123;</span>
	  accept: <span style="color: #3366CC;">&quot;.messageContainer&quot;</span>,
	  hoverClass: <span style="color: #3366CC;">'messageContainer-hover'</span>,
	  tolerance : <span style="color: #3366CC;">'pointer'</span>,
		greedy : <span style="color: #003366; font-weight: bold;">true</span>,
    drop: <span style="color: #003366; font-weight: bold;">function</span><span style="color: #66cc66;">&#40;</span>ev, ui<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
			<span style="color: #003366; font-weight: bold;">var</span> source_li = jQuery<span style="color: #66cc66;">&#40;</span>ui.<span style="color: #006600;">draggable</span><span style="color: #66cc66;">&#41;</span>;
			<span style="color: #003366; font-weight: bold;">var</span> target_li = jQuery<span style="color: #66cc66;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span><span style="color: #66cc66;">&#41;</span>;
			<span style="color: #003366; font-weight: bold;">var</span> message_id = source_li.<span style="color: #006600;">children</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'input'</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">val</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
			<span style="color: #003366; font-weight: bold;">var</span> parent_id = target_li.<span style="color: #006600;">children</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'input'</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">val</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
			<span style="color: #000066; font-weight: bold;">if</span><span style="color: #66cc66;">&#40;</span>target_li.<span style="color: #006600;">children</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'ul'</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">length</span> &lt;= <span style="color: #CC0000;">0</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
				target_li.<span style="color: #006600;">append</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'
&lt;ul&gt;&lt;/ul&gt;
&nbsp;
'</span><span style="color: #66cc66;">&#41;</span>;
			<span style="color: #66cc66;">&#125;</span>
			<span style="color: #003366; font-weight: bold;">var</span> child_ul = target_li.<span style="color: #006600;">children</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'ul'</span><span style="color: #66cc66;">&#41;</span>;
			<span style="color: #000066; font-weight: bold;">if</span><span style="color: #66cc66;">&#40;</span>same_parent<span style="color: #66cc66;">&#40;</span>source_li, child_ul<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
				<span style="color: #000066; font-weight: bold;">return</span>;
			<span style="color: #66cc66;">&#125;</span>
			jQuery<span style="color: #66cc66;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">children</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'ul:hidden'</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">slideDown</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
			insert_alphabetic<span style="color: #66cc66;">&#40;</span>child_ul, source_li<span style="color: #66cc66;">&#41;</span>;
			update_parent<span style="color: #66cc66;">&#40;</span>message_id, parent_id<span style="color: #66cc66;">&#41;</span>;
    <span style="color: #66cc66;">&#125;</span>
	<span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
	jQuery<span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">&quot;.submit-delete&quot;</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">click</span><span style="color: #66cc66;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
		<span style="color: #000066; font-weight: bold;">if</span><span style="color: #66cc66;">&#40;</span>jQuery<span style="color: #66cc66;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">parents</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'li:first'</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">siblings</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'li'</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">length</span> &lt;= <span style="color: #CC0000;">0</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
			jQuery<span style="color: #66cc66;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">parents</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'li:first'</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">parents</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'li:first'</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">children</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'.expander'</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">remove</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
		<span style="color: #66cc66;">&#125;</span>
		<span style="color: #000066; font-weight: bold;">return</span> <span style="color: #003366; font-weight: bold;">false</span>;
	<span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
	<span style="color: #003366; font-weight: bold;">function</span> insert_alphabetic<span style="color: #66cc66;">&#40;</span>child_ul, source_li<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
		<span style="color: #003366; font-weight: bold;">var</span> kids = child_ul.<span style="color: #006600;">children</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'li'</span><span style="color: #66cc66;">&#41;</span>;
		<span style="color: #003366; font-weight: bold;">var</span> source_text = source_li.<span style="color: #006600;">children</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'span.link'</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">children</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'a'</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">html</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">toLowerCase</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
		<span style="color: #000066; font-weight: bold;">for</span><span style="color: #66cc66;">&#40;</span>i=<span style="color: #CC0000;">0</span>; i&lt;kids.<span style="color: #006600;">length</span>; i++<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
			<span style="color: #003366; font-weight: bold;">var</span> current_text = jQuery<span style="color: #66cc66;">&#40;</span>kids<span style="color: #66cc66;">&#91;</span>i<span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">children</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'span.link'</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">children</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'a'</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">html</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">toLowerCase</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
			<span style="color: #000066; font-weight: bold;">if</span><span style="color: #66cc66;">&#40;</span>source_text &lt; current_text<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
				source_li.<span style="color: #006600;">insertBefore</span><span style="color: #66cc66;">&#40;</span>kids<span style="color: #66cc66;">&#91;</span>i<span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span>;
				<span style="color: #000066; font-weight: bold;">return</span>;
			<span style="color: #66cc66;">&#125;</span>
		<span style="color: #66cc66;">&#125;</span>
		source_li.<span style="color: #006600;">appendTo</span><span style="color: #66cc66;">&#40;</span>child_ul<span style="color: #66cc66;">&#41;</span>;
	<span style="color: #66cc66;">&#125;</span>
&nbsp;
	<span style="color: #003366; font-weight: bold;">function</span> same_parent<span style="color: #66cc66;">&#40;</span>source_li, child_ul<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
		<span style="color: #000066; font-weight: bold;">return</span> source_li.<span style="color: #006600;">parent</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> == child_ul;
	<span style="color: #66cc66;">&#125;</span>	
&nbsp;
	<span style="color: #003366; font-weight: bold;">function</span> update_parent<span style="color: #66cc66;">&#40;</span>message_id, parent_id<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
		<span style="color: #003366; font-weight: bold;">var</span> path = jQuery<span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'#updatePath'</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">val</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
		jQuery.<span style="color: #006600;">post</span><span style="color: #66cc66;">&#40;</span>path + <span style="color: #3366CC;">'/'</span> + message_id + <span style="color: #3366CC;">'.js'</span>, <span style="color: #66cc66;">&#123;</span>parent_id: parent_id, action: <span style="color: #3366CC;">'update'</span>, _method: <span style="color: #3366CC;">'put'</span>, only_parent: <span style="color: #3366CC;">'true'</span> <span style="color: #66cc66;">&#125;</span>,
		  <span style="color: #003366; font-weight: bold;">function</span><span style="color: #66cc66;">&#40;</span>data<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
				apply_expander<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
				<span style="color: #000066; font-weight: bold;">if</span><span style="color: #66cc66;">&#40;</span>data.<span style="color: #006600;">length</span> &gt; <span style="color: #CC0000;">0</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
					<span style="color: #003366; font-weight: bold;">var</span> result = <span style="color: #000066; font-weight: bold;">eval</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'('</span> + data + <span style="color: #3366CC;">')'</span><span style="color: #66cc66;">&#41;</span>;
					<span style="color: #000066; font-weight: bold;">if</span><span style="color: #66cc66;">&#40;</span>!result.<span style="color: #006600;">success</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
						jQuery.<span style="color: #006600;">jGrowl</span>.<span style="color: #006600;">error</span><span style="color: #66cc66;">&#40;</span>result.<span style="color: #006600;">message</span><span style="color: #66cc66;">&#41;</span>;
					<span style="color: #66cc66;">&#125;</span>
				<span style="color: #66cc66;">&#125;</span>
		  <span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span>;
		<span style="color: #000066; font-weight: bold;">return</span> <span style="color: #003366; font-weight: bold;">false</span>;
	<span style="color: #66cc66;">&#125;</span>
&nbsp;
	apply_expander<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
	<span style="color: #003366; font-weight: bold;">function</span> apply_expander<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
		jQuery<span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">&quot;.expander&quot;</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">remove</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
		jQuery<span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">&quot;.messageContainer ul:hidden li:first-child&quot;</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">parent</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">parent</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">prepend</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'&lt;a class=&quot;expander&quot; href=&quot;#&quot;&gt;&lt;img src=&quot;/images/expand.png&quot; /&gt;&lt;/a&gt;'</span><span style="color: #66cc66;">&#41;</span>;
		jQuery<span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">&quot;.messageContainer ul:visible li:first-child&quot;</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">parent</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">parent</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">prepend</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'&lt;a class=&quot;expander&quot; href=&quot;#&quot;&gt;&lt;img src=&quot;/images/collapse.png&quot; /&gt;&lt;/a&gt;'</span><span style="color: #66cc66;">&#41;</span>;
		jQuery<span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">&quot;.expander&quot;</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">click</span><span style="color: #66cc66;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
			<span style="color: #003366; font-weight: bold;">var</span> img = jQuery<span style="color: #66cc66;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">children</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'img'</span><span style="color: #66cc66;">&#41;</span>;
			<span style="color: #003366; font-weight: bold;">var</span> target_ul = jQuery<span style="color: #66cc66;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">siblings</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'ul'</span><span style="color: #66cc66;">&#41;</span>;
			<span style="color: #000066; font-weight: bold;">if</span><span style="color: #66cc66;">&#40;</span>img.<span style="color: #006600;">attr</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'src'</span><span style="color: #66cc66;">&#41;</span> == <span style="color: #3366CC;">'/images/expand.png'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
				img.<span style="color: #006600;">attr</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'src'</span>, <span style="color: #3366CC;">'/images/collapse.png'</span><span style="color: #66cc66;">&#41;</span>;
				target_ul.<span style="color: #006600;">slideDown</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
			<span style="color: #66cc66;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #66cc66;">&#123;</span>
				img.<span style="color: #006600;">attr</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'src'</span>, <span style="color: #3366CC;">'/images/expand.png'</span><span style="color: #66cc66;">&#41;</span>;
				target_ul.<span style="color: #006600;">slideUp</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
			<span style="color: #66cc66;">&#125;</span>
			<span style="color: #000066; font-weight: bold;">return</span> <span style="color: #003366; font-weight: bold;">false</span>;
		<span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span>;
	<span style="color: #66cc66;">&#125;</span>
&nbsp;
<span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;</pre>
<p>In two of the projects I have removed prototype and script.aculo.us in favor of jQuery.  Personally I prefer jQuery and the <a href="http://ennerchi.com/projects/jrails">jRails plugin</a> makes the transition simple.  However, there are probably more people using the default libraries.  Prototype actually comes with the ability to create a nice drag and drop ordered tree built in.  However, I don't love the fact that their 'onUpdate' callback doesn't give the node that was dropped.  Instead you are supposed to serialize the entire tree.  awesome_nested_set makes it very easy to move just one node and that seems more efficient so you'll see a hack in the code below that constantly records the dropped node into a hash table on the 'onChange' event.  That data is then sent to the server on the 'onUpdate' event.</p>
<pre class="javascript">&nbsp;
window._token = <span style="color: #3366CC;">'#{form_authenticity_token}'</span>; <span style="color: #009900; font-style: italic;">// Rails requires this token to validate forms so we'll need to pass it in the ajax request</span>
window._message_updates = <span style="color: #003366; font-weight: bold;">new</span> Hash;
Sortable.<span style="color: #006600;">create</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'message_tree'</span>, <span style="color: #66cc66;">&#123;</span>tree:<span style="color: #003366; font-weight: bold;">true</span>,
                                    dropOnEmpty:<span style="color: #003366; font-weight: bold;">true</span>,
                                    <span style="color: #000066;">scroll</span>:window,
                                    constraint:<span style="color: #003366; font-weight: bold;">false</span>,
                                    onChange:<span style="color: #003366; font-weight: bold;">function</span><span style="color: #66cc66;">&#40;</span>element<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
                                      <span style="color: #009900; font-style: italic;">// this is a bit of a hack, but basically we just pull the message id from the id of the html element</span>
                                      <span style="color: #003366; font-weight: bold;">var</span> child_id = element.<span style="color: #006600;">id</span>.<span style="color: #006600;">replace</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'message_'</span>, <span style="color: #3366CC;">''</span><span style="color: #66cc66;">&#41;</span>;
                                      <span style="color: #003366; font-weight: bold;">var</span> parent_id = element.<span style="color: #006600;">up</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">id</span>.<span style="color: #006600;">replace</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'ul_message_'</span>, <span style="color: #3366CC;">''</span><span style="color: #66cc66;">&#41;</span>;
                                      <span style="color: #003366; font-weight: bold;">var</span> previous = element.<span style="color: #006600;">previous</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
                                      <span style="color: #003366; font-weight: bold;">var</span> sibling_id = <span style="color: #3366CC;">''</span>;
                                      <span style="color: #000066; font-weight: bold;">if</span><span style="color: #66cc66;">&#40;</span>previous<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
                                        <span style="color: #003366; font-weight: bold;">var</span> sibling_id = previous.<span style="color: #006600;">id</span>.<span style="color: #006600;">replace</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'message_'</span>, <span style="color: #3366CC;">''</span><span style="color: #66cc66;">&#41;</span>;
                                      <span style="color: #66cc66;">&#125;</span>
                                      window._message_updates.<span style="color: #006600;">set</span><span style="color: #66cc66;">&#40;</span>child_id, <span style="color: #66cc66;">&#91;</span>parent_id, sibling_id<span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span>;
                                    <span style="color: #66cc66;">&#125;</span>,
                                    onUpdate:<span style="color: #003366; font-weight: bold;">function</span><span style="color: #66cc66;">&#40;</span>element<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
                                      window._message_updates.<span style="color: #006600;">each</span><span style="color: #66cc66;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #66cc66;">&#40;</span>pair<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
                                        <span style="color: #003366; font-weight: bold;">var</span> child_id = pair.<span style="color: #006600;">key</span>;
                                        <span style="color: #003366; font-weight: bold;">var</span> parent_id = pair.<span style="color: #006600;">value</span><span style="color: #66cc66;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #66cc66;">&#93;</span>;
                                        <span style="color: #003366; font-weight: bold;">var</span> sibling_id = pair.<span style="color: #006600;">value</span><span style="color: #66cc66;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #66cc66;">&#93;</span>;
                                        window._message_updates.<span style="color: #006600;">unset</span><span style="color: #66cc66;">&#40;</span>child_id<span style="color: #66cc66;">&#41;</span>;
                                        <span style="color: #003366; font-weight: bold;">var</span> url = <span style="color: #3366CC;">'/messages/'</span> + child_id + <span style="color: #3366CC;">'.js?parent_id='</span> + parent_id + <span style="color: #3366CC;">'&amp;sibling_id='</span> + sibling_id;
                                        <span style="color: #003366; font-weight: bold;">new</span> Ajax.<span style="color: #006600;">Request</span><span style="color: #66cc66;">&#40;</span>url, <span style="color: #66cc66;">&#123;</span>
                                          method: <span style="color: #3366CC;">'PUT'</span>,
                                          parameters: <span style="color: #66cc66;">&#123;</span>
                                            authenticity_token: window._token
                                          <span style="color: #66cc66;">&#125;</span>
                                        <span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span>;
                                      <span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span>;
                                    <span style="color: #66cc66;">&#125;</span>
                                    <span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;</pre>
<p>Here is a link to the default script.aculo.us tree example<br />
<a href="http://script.aculo.us/playground/test/functional/sortable_tree_test.html">http://script.aculo.us/playground/test/functional/sortable_tree_test.html</a></p>
<p>I borrowed many of the ideas from there.  I'm sure there are a few bugs in this so if anyone tries out the code and has problems let me know and I'll make changes as needed.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.justinball.com/2009/01/18/heirarchies-trees-jquery-prototype-scriptaculous-and-acts_as_nested_set/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
	</channel>
</rss>
