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 .= " <MODERATED&
+gt;";
}
if(length($email) <= 4) { $email=""; }
# parent is hash containing the parent
+ of this posting
}
elsif ($status eq 'dthread') {
$subject = "<Deleted>";
$message = "This message has been mode
+rated down, score -1 :)";
$username = "<Deleted>";
$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 = "<Deleted>";
$message = "This message has b
+een moderated down, score -1";
$username = "<Deleted>";
$email = "";
}
else {
next;
}
}
else {
$subject = "<Error>";
$message = "This is an Error and is be
+ing looked into.";
$username = "lt;Error>";
$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