And in the spirit of TIMTOWTDI: This is from UF's soon to be overhauled forum system.

That being said, this code is linear to the number of posts, and does not suffer from problems from extra deeply nested structures.

It also handles moderation and some other things. Please understand, it has some serious issues, and it is being re-vamped.

sub getThreads { # main code section for comment display # here's where all the deep magic happens. # The algorithm is simple, but has a speed issue. # 1. select all comments from the db # 2. store the comment contents in %text, keyed by ID # 3. Put the id of the parent posting of a given posting in %p +arent, keyed by ID # By nature of the way comments are entered, # we know that a given reply to a comment will always # have a larger ID than its parent, # 4. read %parent in reverse order # take the current posting and append it to the parent # since we're in reverse order, parent will always exist +. and the # text will appear after the parent, with the newest rep +lies first on the page # if parent is this post, leave alone -> is a top level +post # reply comments are thus added to the top level post # 5. read %text in reverse order as well # append the text to the output data # this will give a reverse order thread, but with the ra +ther # cool side effect of putting the latest thread at the t +op. # so the latest discussion comes first on the page. # so less scrolling for most posters. # my ($table,$id,$mode,$dirc,$type,$path,$modmode) = @_; if($id !~ /^\d{1,10}$/) { return &readfile("$doc_root/templates/badvar.html"); } my ($output,$comment,$thread, $indent, $full, $sort, $cursor); if($mode eq 'flat') { $indent = 0; $full = 1; } elsif($mode eq 'thread') { $indent = 1; $full = 0; } elsif($mode eq 'nested') { $indent = 1; $full = 1; } elsif($mode eq 'in-order') { $indent = 0; $full = 0; $sort = "ID $dirc"; } elsif($mode eq 'indexed' || $mode eq '') { $indent = 1; $full = 1; } # select all from the table my ($c) = &sqlSelectMany("$table.ID,$table.USERNAME,$table.SUB +JECT,$table.MESSAGE,$table.TIMESTAMP,$table.STATUS,$table.PARENT,$tab +le.SUB_PARENT,$table.LEVEL,USERS.EMAIL as EMAIL", "$table,USERS", "ITEM='$id' && STATUS != 'dead' && USERS.USERNAME=$tab +le.USERNAME", "order by ID"); my %parent; my %text; if($c->rows >= 1) { while($cursor=$c->fetchrow_hashref) { my $tid = $cursor->{'ID'}; my $username = $cursor->{'USERNAME'}; my $subject = $cursor->{'SUBJECT'}; my $message = $cursor->{'MESSAGE'}; $message =~ s/\n/<br>/g; my $timestamp = &post_date($cursor->{'TIMEST +AMP'}); my $status = $cursor->{'STATUS'}; my $parent = $cursor->{'PARENT'}; my $sub_parent = $cursor->{'SUB_PARENT'}; my $level = $cursor->{'LEVEL'}; my $email = $cursor->{'EMAIL'}; $parent{$tid}=$sub_parent; if($status eq "active" || ($modmode eq 'yes' & +& $status ne 'kthread')) { if($modmode eq 'yes' && $status ne 'ac +tive') { $subject .= " &lt;MODERATED& +gt;"; } if(length($email) <= 4) { $email=""; } # parent is hash containing the parent + of this posting } elsif ($status eq 'dthread') { $subject = "&lt;Deleted&gt;"; $message = "This message has been mode +rated down, score -1 :)"; $username = "&lt;Deleted&gt;"; $email = ""; } elsif($status eq 'inactive' || $status eq 'kth +read') { my ($leafchk) = &sqlSelectMany("PARENT +,ID", $table, "PARENT = $tid"); my $leafrows = $leafchk->rows; my $lfr = $leafchk->fetchrow_hashref; $leafchk->finish; if($leafrows > 1 || ($leafrows == 1 && $lfr->{'PARENT'} == $lfr->{'I +D'})) { $subject = "&lt;Deleted&gt;"; $message = "This message has b +een moderated down, score -1"; $username = "&lt;Deleted&gt;"; $email = ""; } else { next; } } else { $subject = "&lt;Error&gt;"; $message = "This is an Error and is be +ing looked into."; $username = "lt;Error&gt;"; $email = ""; } $text{$tid}=&posting($indent,$full,$level,$mod +e, $id,$tid,$level,$subject,$message,'Yes +', $email,$username,$timestamp,$type,$pat +h); # $message is the comment text of this posting } foreach $node (sort reverse_number (keys (%text)) ) { # for every posting numbered $node # start at the last posting # and go backwards if ( $node == $parent{$node}) { # this is parented by itself. # leave it alone, because its a top le +vel posting } else { $text{$parent{$node}}.=$text{$node}; $text{$node}=""; # attach this text to its parent's tex +t # delete it from the text hash # so that we can just run thru the has +h to display # the entire posting contents } } foreach $node ( sort reverse_number (keys %text )) { $output.=$text{$node}; # finally , add all the output reverse sequent +ially } } else { $output = qq| <tr bgcolor="#FFFFFF"> <td align=\"cente +r\"> <font face="Verdana, Arial, Helvetica, sans-se +rif"> <br><br> <b>No threads are currently available +.</b><br><br>|; } $c->finish; $output .= qq|</font></td></tr>|; return($output); }

--
Jay "Yohimbe" Thorne, alpha geek for UserFriendly

In reply to Re: Graphical Hierarchical Tree by Yohimbe
in thread Graphical Hierarchical Tree by yojimbo

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.