Changeset 1088

Show
Ignore:
Timestamp:
08/06/06 11:36:35 (2 years ago)
Author:
Blackhex
Message:

DiscussionPlugin:

  • Groups, forums and topics ordering by their fields in lists.
  • Display of new topics and messages since last visit.
  • Ability to change between tree and flat message list display.
Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • discussionplugin/0.9/tracdiscussion/api.py

    r1077 r1088  
    136136                elif action == 'delete': 
    137137                    return ['message-delete', 'message-list'] 
     138                elif action == 'set-display': 
     139                    return ['message-set-display', 'message-list'] 
    138140                else: 
    139141                    return ['message-list'] 
     
    157159                elif action == 'delete': 
    158160                    return ['message-delete', 'message-list'] 
     161                elif action == 'set-display': 
     162                    return ['message-set-display', 'message-list'] 
    159163                else: 
    160164                    return ['message-list'] 
     
    182186                    self.req.hdf['discussion.no_display'] = True 
    183187                    return ['topic-delete', 'message-list'] 
     188                elif action == 'set-display': 
     189                    return ['message-set-display', 'message-list'] 
    184190                else: 
    185191                    return ['message-list'] 
     
    207213                elif action == 'post-move': 
    208214                    return ['topic-post-move', 'topic-list'] 
     215                elif action == 'set-display': 
     216                    return ['message-set-display', 'message-list'] 
    209217                else: 
    210218                    return ['message-list'] 
     
    279287                self.req.perm.assert_permission('DISCUSSION_ADMIN') 
    280288 
     289                # Get form values 
     290                order = self.req.args.get('order') or 'id' 
     291                desc = self.req.args.get('desc') 
     292 
     293                # Prepare ORDER BY statement 
     294                order_by = 'ORDER BY ' + order 
     295                if desc: 
     296                    order_by = order_by + ' DESC' 
     297                else: 
     298                    order_by = order_by + ' ASC' 
     299 
    281300                # Display groups. 
     301                self.req.hdf['discussion.order'] = order 
     302                self.req.hdf['discussion.desc'] = desc 
    282303                if group: 
    283304                    self.req.hdf['discussion.name'] = group['name'] 
    284305                    self.req.hdf['discussion.description'] = group['description'] 
    285                 self.req.hdf['discussion.groups'] = self.get_groups(
     306                self.req.hdf['discussion.groups'] = self.get_groups(order_by
    286307 
    287308            elif mode == 'group-add': 
     
    322343                # Delete selected groups. 
    323344                if selection: 
    324                     for group in selection: 
    325                         self.delete_group(group
     345                    for group_id in selection: 
     346                        self.delete_group(group_id
    326347 
    327348            elif mode == 'forum-list': 
    328349                self.req.perm.assert_permission('DISCUSSION_VIEW') 
    329350 
     351                # Get form values 
     352                order = self.req.args.get('order') or 'id' 
     353                desc = self.req.args.get('desc') 
     354 
     355                # Prepare ORDER BY statement 
     356                order_by = 'ORDER BY ' + order 
     357                if desc: 
     358                    order_by = order_by + ' DESC' 
     359                else: 
     360                    order_by = order_by + ' ASC' 
     361 
    330362                # Display forums. 
     363                self.req.hdf['discussion.order'] = order 
     364                self.req.hdf['discussion.desc'] = desc 
    331365                self.req.hdf['discussion.groups'] = self.get_groups() 
    332                 self.req.hdf['discussion.forums'] = self.get_forums(
     366                self.req.hdf['discussion.forums'] = self.get_forums(order_by
    333367 
    334368            elif mode == 'admin-forum-list': 
    335369                self.req.perm.assert_permission('DISCUSSION_ADMIN') 
    336370 
     371                # Get form values 
     372                order = self.req.args.get('order') or 'id' 
     373                desc = self.req.args.get('desc') 
     374 
     375                # Prepare ORDER BY statement 
     376                order_by = 'ORDER BY ' + order 
     377                if desc: 
     378                    order_by = order_by + ' DESC' 
     379                else: 
     380                    order_by = order_by + ' ASC' 
     381 
    337382                # Display forums. 
     383                self.req.hdf['discussion.order'] = order 
     384                self.req.hdf['discussion.desc'] = desc 
     385                self.log.debug(forum) 
    338386                if forum: 
    339387                    self.req.hdf['discussion.name'] = forum['name'] 
     
    344392                self.req.hdf['discussion.users'] = self.get_users() 
    345393                self.req.hdf['discussion.groups'] = self.get_groups() 
    346                 self.req.hdf['discussion.forums'] = self.get_forums(
     394                self.req.hdf['discussion.forums'] = self.get_forums(order_by
    347395 
    348396            elif mode == 'forum-add': 
     
    407455                # Delete selected forums. 
    408456                if selection: 
    409                     for forum in selection: 
    410                         self.delete_forum(forum
     457                    for forum_id in selection: 
     458                        self.delete_forum(forum_id
    411459 
    412460            elif mode == 'topic-list': 
    413461                self.req.perm.assert_permission('DISCUSSION_VIEW') 
    414462 
     463                # Get form values 
     464                order = self.req.args.get('order') or 'id' 
     465                desc = self.req.args.get('desc') 
     466 
     467                # Prepare ORDER BY statement 
     468                order_by = 'ORDER BY ' + order 
     469                if desc: 
     470                    order_by = order_by + ' DESC' 
     471                else: 
     472                    order_by = order_by + ' ASC' 
     473 
    415474                # Display topics. 
    416                 self.req.hdf['discussion.topics'] = self.get_topics(forum['id']) 
     475                self.req.hdf['discussion.order'] = order 
     476                self.req.hdf['discussion.desc'] = desc 
     477                self.req.hdf['discussion.topics'] = self.get_topics(forum['id'], 
     478                  order_by) 
    417479 
    418480            elif mode == 'topic-add': 
     
    513575                new_body = Markup(self.req.args.get('body')) 
    514576 
    515                 # Display message list. 
     577                # Get time when topic was visited from session. 
     578                visited = eval(self.req.session.get('visited-topics') or '{}') 
     579                self.log.debug(visited) 
     580                if visited.has_key(topic['id']): 
     581                    visit_time = int(visited[topic['id']]) 
     582                else: 
     583                    visit_time = 0 
     584 
     585                # Update this topic visit time and save to session. 
     586                visited[topic['id']] = int(time.time()) 
     587                self.req.session['visited-topics'] = str(visited) 
     588 
     589                # Mark new topic. 
     590                if int(topic['time']) > visit_time: 
     591                    topic['new'] = True 
     592 
     593                # Prepare display of topic 
    516594                if new_author: 
    517595                    self.req.hdf['discussion.author'] = wiki_to_oneliner( 
     
    523601                    self.req.hdf['discussion.body'] = wiki_to_html(new_body, 
    524602                      self.env, self.req) 
    525                 self.req.hdf['discussion.messages'] = self.get_messages(topic['id']) 
     603 
     604                # Prepare display of messages 
     605                display = self.req.session.get('message-list-display') 
     606                self.req.hdf['discussion.display'] = display 
     607                if display == 'flat-asc': 
     608                    self.req.hdf['discussion.messages'] = self.get_flat_messages( 
     609                      topic['id'], visit_time) 
     610                elif display == 'flat-desc': 
     611                    self.req.hdf['discussion.messages'] = self.get_flat_messages( 
     612                      topic['id'], visit_time, 'ORDER BY time DESC') 
     613                else: 
     614                    self.req.hdf['discussion.messages'] = self.get_messages( 
     615                      topic['id'], visit_time) 
    526616 
    527617            elif mode == 'message-quote': 
     
    546636                      new_author, new_body) 
    547637                else: 
    548                     self.add_message(forum['id'], topic['id'], '-1', new_author, new_body) 
     638                    self.add_message(forum['id'], topic['id'], '-1', new_author, 
     639                      new_body) 
    549640 
    550641            elif mode == 'message-edit': 
     
    576667                # Delete message. 
    577668                self.delete_message(message['id']) 
     669 
     670            elif mode == 'message-set-display': 
     671                self.req.perm.assert_permission('DISCUSSION_VIEW') 
     672 
     673                # Get form values 
     674                display = self.req.args.get('display') 
     675 
     676                # Set message list display mode to session 
     677                self.req.session['message-list-display'] = display 
    578678 
    579679    # Get one item functions 
     
    686786    # Get list functions 
    687787 
    688     def get_groups(self): 
     788    def get_groups(self, order_by = 'ORDER BY id ASC'): 
    689789        # Get count of forums without group 
    690790        sql = "SELECT COUNT(id) FROM forum WHERE forum_group = 0" 
     
    700800        columns = ('id', 'name', 'description', 'forums') 
    701801        sql = "SELECT id, name, description, (SELECT COUNT(id) FROM forum f" \ 
    702           " WHERE f.forum_group = forum_group.id) FROM forum_group" 
     802          " WHERE f.forum_group = forum_group.id) FROM forum_group " + order_by 
    703803        self.log.debug(sql) 
    704804        self.cursor.execute(sql) 
     
    710810        return groups 
    711811 
    712     def get_forums(self): 
     812    def get_forums(self, order_by = 'ORDER BY subject ASC'): 
    713813        columns = ('id', 'name', 'author', 'time', 'moderators', 'group', 
    714814          'subject', 'description', 'topics', 'replies', 'lastreply', 
     
    716816        sql = "SELECT id, name, author, time, moderators, forum_group," \ 
    717817          " subject, description, (SELECT COUNT(id) FROM topic t WHERE" \ 
    718           " t.forum = forum.id), (SELECT COUNT(id) FROM message m WHERE" \ 
    719           " m.forum = forum.id), (SELECT MAX(time) FROM message m WHERE" \ 
    720           " m.forum = forum.id), (SELECT MAX(time) FROM topic t WHERE" \ 
    721           " t.forum = forum.id) FROM forum ORDER BY subject" 
     818          " t.forum = forum.id) AS topics, (SELECT COUNT(id) FROM message m" \ 
     819          " WHERE m.forum = forum.id) AS replies, (SELECT MAX(time) FROM" \ 
     820          " message m WHERE m.forum = forum.id) AS lasttopic, (SELECT" \ 
     821          " MAX(time) FROM topic t WHERE t.forum = forum.id) AS lastreply" \ 
     822          " FROM forum " + order_by 
    722823        self.log.debug(sql) 
    723824        self.cursor.execute(sql) 
     
    739840        return forums 
    740841 
    741     def get_topics(self, forum): 
     842    def get_topics(self, forum, order_by = 'ORDER BY time ASC'): 
    742843        columns = ('id', 'forum', 'time', 'subject', 'body', 'author', 
    743844          'replies', 'lastreply') 
    744845        sql = "SELECT id, forum, time, subject, body, author, (SELECT" \ 
    745           " COUNT(id) FROM message m WHERE m.topic = topic.id), (SELECT" \ 
    746           " MAX(time) FROM message m WHERE m.topic = topic.id) FROM topic" \ 
    747           " WHERE forum = %s ORDER BY time" 
     846          " COUNT(id) FROM message m WHERE m.topic = topic.id) AS replies," \ 
     847          " (SELECT MAX(time) FROM message m WHERE m.topic = topic.id) AS" \ 
     848          " lastreply FROM topic WHERE forum = %s " + order_by 
    748849        self.log.debug(sql % (forum,)) 
    749850        self.cursor.execute(sql, (forum,)) 
     
    761862        return topics 
    762863 
    763     def get_messages(self, topic): 
     864    def get_messages(self, topic, time, order_by = 'ORDER BY time ASC'): 
    764865        columns = ('id', 'replyto', 'time', 'author', 'body') 
    765866        sql = "SELECT id, replyto, time, author, body FROM message WHERE" \ 
    766           " topic = %s ORDER BY time" 
     867          " topic = %s " + order_by 
    767868        self.log.debug(sql % (topic,)) 
    768869        self.cursor.execute(sql, (topic,)) 
    769  
    770870        messagemap = {} 
    771871        messages = [] 
    772  
    773872        for row in self.cursor: 
    774873            row = dict(zip(columns, row)) 
    775874            row['author'] = wiki_to_oneliner(row['author'], self.env) 
    776875            row['body'] = wiki_to_html(row['body'], self.env, self.req) 
     876            if int(row['time']) > time: 
     877                row['new'] = True 
    777878            row['time'] = format_datetime(row['time']) 
    778879            messagemap[row['id']] = row 
     
    791892                    parent['replies'] = [message] 
    792893        return messages; 
     894 
     895    def get_flat_messages(self, topic, time, order_by = 'ORDER BY time ASC'): 
     896        columns = ('id', 'replyto', 'time', 'author', 'body') 
     897        sql = "SELECT id, replyto, time, author, body FROM message WHERE" \ 
     898          " topic = %s " + order_by 
     899        self.log.debug(sql % (topic,)) 
     900        self.cursor.execute(sql, (topic,)) 
     901        messages = [] 
     902        for row in self.cursor: 
     903            row = dict(zip(columns, row)) 
     904            row['author'] = wiki_to_oneliner(row['author'], self.env) 
     905            row['body'] = wiki_to_html(row['body'], self.env, self.req) 
     906            if int(row['time']) > time: 
     907                row['new'] = True 
     908            row['time'] = format_datetime(row['time']) 
     909            messages.append(row) 
     910        return messages 
    793911 
    794912    def get_users(self): 
  • discussionplugin/0.9/tracdiscussion/htdocs/css/admin.css

    r1072 r1088  
    2121} 
    2222 
    23 .listing td.id, .listing td.moderators, .listing td.group 
     23.listing td.id, .listing td.moderators, .listing td.forum_group 
    2424{ 
    2525  text-align: center; 
  • discussionplugin/0.9/tracdiscussion/htdocs/css/discussion.css

    r1077 r1088  
    2323 
    2424.forum-list td.id, .forum-list td.moderators, .forum-list td.lasttopic, 
    25 .forum-list td.lastreply, .forum-list td.founded, .forum-list td.topics, 
     25.forum-list td.lastreply, .forum-list td.time, .forum-list td.topics, 
    2626.forum-list td.replies 
    2727{ 
     
    5353/* Topic list */ 
    5454.topic-list td.id, .topic-list td.author, .topic-list td.lastreply, 
    55 .topic-list td.founded, .topic-list td.replies 
     55.topic-list td.time, .topic-list td.replies 
    5656{ 
    5757  text-align: center; 
     
    6363} 
    6464 
     65.topic-add form.add_form 
     66{ 
     67  margin: 1em; 
     68} 
     69 
    6570/* Message list */ 
    6671.message-list div.topic 
     
    6974  margin-bottom: 0em; 
    7075  border: 1px solid #d7d7d7; 
     76} 
     77 
     78.message-list div.topic.new 
     79{ 
     80  border: 2px solid #b00; 
    7181} 
    7282 
     
    105115  border-left: 1px solid #d7d7d7; 
    106116  border-bottom: 1px solid #d7d7d7; 
     117} 
     118 
     119.message-list div.replies.new 
     120{ 
     121  border-right: 2px solid #b00; 
     122  border-left: 2px solid #b00; 
     123  border-bottom: 2px solid #b00; 
    107124} 
    108125 
     
    162179  border: 1px dashed #b00; 
    163180} 
     181 
     182.message-list div.replies li.new div.body 
     183{ 
     184  border: 2px solid #b00; 
     185} 
     186 
     187.message-list div.set-display 
     188{ 
     189  text-align: center; 
     190  margin-top: 2em; 
     191} 
     192 
     193.message-list div.set-display a 
     194{ 
     195  margin: 0.5em; 
     196} 
  • discussionplugin/0.9/tracdiscussion/templates/admin-forum-list.cs

    r1072 r1088  
    121121        <tr> 
    122122          <th class="sel">&nbsp;</th> 
    123           <th class="id">ID</th
    124           <th class="name">Name</th
    125           <th class="subject">Subject</th
    126           <th class="description">Description</th
    127           <th class="moderators">Moderators</th
     123          <?cs call:sortable_th(discussion.order, discussion.desc, 'id', 'ID', discussion.href + '/forum' + '?') ?
     124          <?cs call:sortable_th(discussion.order, discussion.desc, 'name', 'Name', discussion.href + '/forum' + '?') ?
     125          <?cs call:sortable_th(discussion.order, discussion.desc, 'subject', 'Subject', discussion.href + '/forum' + '?') ?
     126          <?cs call:sortable_th(discussion.order, discussion.desc, 'description', 'Description', discussion.href + '/forum' + '?') ?
     127          <?cs call:sortable_th(discussion.order, discussion.desc, 'moderators', 'Moderators', discussion.href + '/forum' + '?') ?
    128128          <?cs if:discussion.groups.1.id ?> 
    129             <th class="group">Group</th
     129            <?cs call:sortable_th(discussion.order, discussion.desc, 'forum_group', 'Group', discussion.href + '/forum' + '?') ?
    130130          <?cs /if ?> 
    131131        </tr> 
  • discussionplugin/0.9/tracdiscussion/templates/admin-group-list.cs

    r1072 r1088  
    5151        <tr> 
    5252          <th class="sel">&nbsp;</th> 
    53           <th class="id">ID</th
    54           <th class="name">Name</th
    55           <th class="description">Description</th
     53          <?cs call:sortable_th(discussion.order, discussion.desc, 'id', 'ID', discussion.href + '/group' + '?') ?
     54          <?cs call:sortable_th(discussion.order, discussion.desc, 'name', 'Name', discussion.href + '/group' + '?') ?
     55          <?cs call:sortable_th(discussion.order, discussion.desc, 'description', 'Description', discussion.href + '/group' + '?') ?
    5656        </tr> 
    5757      </thead> 
  • discussionplugin/0.9/tracdiscussion/templates/discussion-header.cs

    r1066 r1088  
    11<?cs include "header.cs" ?> 
    2 <?cs include "macros.cs" ?> 
    32 
    43<div id="ctxtnav" class="nav"> 
  • discussionplugin/0.9/tracdiscussion/templates/forum-list.cs

    r1071 r1088  
     1<?cs include "macros.cs" ?> 
     2 
    13<?cs def:display_group(group, forums) ?> 
    24  <table class="listing"> 
     
    1113      <?cs /if ?> 
    1214      <tr> 
    13         <th class="id">ID</th
    14         <th class="subject">Forum</th
    15         <th class="moderators">Moderators</th
    16         <th class="lasttopic">Last Topic</th
    17         <th class="lastreply">Last Reply</th
    18         <th class="founded">Founded</th
    19         <th class="topics">Topics</th
    20         <th class="replies">Replies</th
     15        <?cs call:sortable_th(discussion.order, discussion.desc, 'id', 'ID', discussion.href + '?') ?
     16        <?cs call:sortable_th(discussion.order, discussion.desc, 'subject', 'Forum', discussion.href + '?') ?
     17        <?cs call:sortable_th(discussion.order, discussion.desc, 'moderators', 'Moderators', discussion.href + '?') ?
     18        <?cs call:sortable_th(discussion.order, discussion.desc, 'lasttopic', 'Last Topic', discussion.href + '?') ?
     19        <?cs call:sortable_th(discussion.order, discussion.desc, 'lastreply', 'Last Reply', discussion.href + '?') ?
     20        <?cs call:sortable_th(discussion.order, discussion.desc, 'time', 'Founded', discussion.href + '?') ?
     21        <?cs call:sortable_th(discussion.order, discussion.desc, 'topics', 'Topics', discussion.href + '?') ?
     22        <?cs call:sortable_th(discussion.order, discussion.desc, 'replies', 'Replies', discussion.href + '?') ?
    2123      </tr> 
    2224    </thead> 
  • discussionplugin/0.9/tracdiscussion/templates/message-list.cs

    r1077 r1088  
    8383<?cs /def ?> 
    8484 
     85<?cs def:display_set_display() ?> 
     86  <div class="set-display"> 
     87    <a href="<?cs var:discussion.href ?>?discussion_action=set-display;display=tree">Tree View</a> 
     88    <a href="<?cs var:discussion.href ?>?discussion_action=set-display;display=flat-desc">Flat View (newer first)</a> 
     89    <a href="<?cs var:discussion.href ?>?discussion_action=set-display;display=flat-asc">Flat View (older first)</a> 
     90  </div> 
     91<?cs /def ?> 
     92 
    8593<?cs def:display_topic(messages) ?> 
    8694  <?cs each:message = messages ?> 
    87     <li
     95    <li <?cs if:message.new ?>class="new"<?cs /if ?>
    8896      <a name="<?cs var:message.id ?>"></a> 
    8997      <div class="id"> 
     
    121129      <?cs /if ?> 
    122130    </li> 
    123     <?cs if:message.replies.0.id || args.discussion_action && (args.discussion_action != 'delete') && (args.discussion_action != 'edit') && (args.discussion_action != 'post-edit') ?> 
     131    <?cs if:message.replies.0.id || args.discussion_action && ((args.discussion_action == 'add') || (args.discussion_action == 'quote') || (args.discussion_action == 'post-add')) ?> 
    124132      <ul> 
    125133        <?cs if:message.replies.0.id ?> 
    126134          <?cs call:display_topic(message.replies) ?> 
    127135        <?cs /if ?> 
    128         <?cs if:(args.message == message.id) && !args.submit && args.discussion_action && (args.discussion_action != "delete") && (args.discussion_action != 'edit') && (args.discussion_action != 'post-edit') ?> 
     136        <?cs if:(args.message == message.id) && !args.submit && (args.discussion_action && (args.discussion_action == 'add') || (args.discussion_action == 'quote') || (args.discussion_action == 'post-add')) ?> 
    129137          <?cs if:args.preview ?> 
    130138            <?cs call:display_preview() ?> 
     
    150158 
    151159<?cs if:trac.acl.DISCUSSION_VIEW ?> 
    152   <a name="-1"></a> 
    153160  <?cs if:!discussion.no_display && discussion.topic.id ?> 
    154     <div class="topic"> 
     161    <?cs call:display_set_display() ?> 
     162    <a name="-1"></a> 
     163    <div class="topic <?cs if:discussion.topic.new ?>new<?cs /if ?>"> 
    155164      <div class="header"> 
    156165        <div class="subject"> 
     
    190199      <?cs /if ?> 
    191200    </div> 
    192     <?cs if:discussion.messages.0.id || args.discussion_action && (args.discussion_action != "delete") && (args.discussion_action != 'edit') && (args.discussion_action != 'post-edit') ?> 
    193       <div class="replies"> 
     201    <?cs if:discussion.messages.0.id || args.discussion_action && ((args.discussion_action == 'add') || (args.discussion_action == 'quote') || (args.discussion_action == 'post-add')) ?> 
     202      <div class="replies <?cs if:discussion.topic.new ?>new<?cs /if ?>"> 
    194203        <ul> 
    195204          <?cs if:discussion.messages.0.id ?> 
    196205            <?cs call:display_topic(discussion.messages) ?> 
    197206          <?cs /if ?> 
    198           <?cs if:!args.message && !args.submit && args.discussion_action && (args.discussion_action != "delete") && (args.discussion_action != 'edit') && (args.discussion_action != 'post-edit') ?> 
     207          <?cs if:!args.message && !args.submit && args.discussion_action && ((args.discussion_action == 'add') || (args.discussion_action == 'quote') || (args.discussion_action == 'post-add')) ?> 
    199208            <?cs if:args.preview ?> 
    200209              <?cs call:display_preview() ?> 
     
    205214      </div> 
    206215    <?cs /if ?> 
     216    <?cs call:display_set_display() ?> 
    207217  <?cs else?> 
    208218    <span>No discussion for this page created.</span> 
  • discussionplugin/0.9/tracdiscussion/templates/topic-list.cs

    r1071 r1088  
     1<?cs include "macros.cs" ?> 
    12<?cs include "discussion-header.cs" ?> 
    23 
     
    1213    <thead> 
    1314      <tr> 
    14         <th class="id">ID</th
    15         <th class="subject">Subject</th
    16         <th class="author">Author</th
    17         <th class="lastreply">Last Reply</th
    18         <th class="founded">Founded</th
    19         <th class="replies">Replies</th
     15        <?cs call:sortable_th(discussion.order, discussion.desc, 'id', 'ID', discussion.href + '/' + discussion.forum.id + '?') ?
     16        <?cs call:sortable_th(discussion.order, discussion.desc, 'subject', 'Subject', discussion.href + '/' + discussion.forum.id + '?') ?
     17        <?cs call:sortable_th(discussion.order, discussion.desc, 'author', 'Author', discussion.href + '/' + discussion.forum.id + '?') ?
     18        <?cs call:sortable_th(discussion.order, discussion.desc, 'lastreply', 'Last Reply', discussion.href + '/' + discussion.forum.id + '?') ?
     19        <?cs call:sortable_th(discussion.order, discussion.desc, 'time', 'Founded', discussion.href + '/' + discussion.forum.id + '?') ?
     20        <?cs call:sortable_th(discussion.order, discussion.desc, 'replies', 'Replies', discussion.href + '/' + discussion.forum.id + '?') ?
    2021      </tr> 
    2122    </thead>