forum.module 34.4 KB
Newer Older
Dries's avatar
   
Dries committed
1
2
3
<?php
// $Id$

Dries's avatar
   
Dries committed
4
5
6
7
8
/**
 * @file
 * Enable threaded discussions about general topics.
 */

9
10
11
12
/**
 * Implementation of hook_help().
 */
function forum_help($section) {
Dries's avatar
   
Dries committed
13
  switch ($section) {
14
    case 'admin/forum':
15
      return t('<p>This is a list of existing containers and forums that you can edit. Containers hold forums and, in turn, forums hold threaded discussions. Both containers and forums can be placed inside other containers and forums. By planning the structure of your containers and forums well, you make it easier for users to find a topic area of interest to them.</p>');
16
    case 'admin/forum/add/container':
17
      return t('<p>Containers help you organize your forums. The job of a container is to hold, or contain, other forums that are related. For example, a container named "Food" might hold two forums named "Fruit" and "Vegetables".</p>');
18
    case 'admin/forum/add/forum':
19
      return t('<p>A forum holds discussion topics that are related. For example, a forum named "Fruit" might contain topics titled "Apples" and "Bananas".</p>');
Dries's avatar
   
Dries committed
20
    case 'admin/modules#description':
21
      return t('Enables threaded discussions about general topics.');
22
23
    case 'admin/forum/configure':
      return t('This is where you can configure system-wide options for how your forums act and display.');
Dries's avatar
   
Dries committed
24
    case 'node/add#forum':
25
      return t('Create a new topic for discussion in the forums.');
Dries's avatar
   
Dries committed
26
27
28
  }
}

29
30
31
/**
 * Implementation of hook_node_name().
 */
Dries's avatar
   
Dries committed
32
function forum_node_name($node) {
Dries's avatar
   
Dries committed
33
  return t('forum topic');
Dries's avatar
   
Dries committed
34
35
}

36
37
38
/**
 * Implementation of hook_access().
 */
Dries's avatar
   
Dries committed
39
function forum_access($op, $node) {
Dries's avatar
   
Dries committed
40
41
  global $user;

Dries's avatar
   
Dries committed
42
43
  if ($op == 'create') {
    return user_access('create forum topics');
Dries's avatar
   
Dries committed
44
  }
Dries's avatar
   
Dries committed
45
46
47
48
49
50

  if ($op == 'update' || $op == 'delete') {
    if (user_access('edit own forum topics') && ($user->uid == $node->uid)) {
      return TRUE;
    }
  }
Dries's avatar
   
Dries committed
51
52
}

53
54
55
/**
 * Implementation of hook_perm().
 */
Dries's avatar
   
Dries committed
56
function forum_perm() {
57
  return array('create forum topics', 'edit own forum topics', 'administer forums');
Dries's avatar
   
Dries committed
58
}
Dries's avatar
   
Dries committed
59

60
/**
61
 * Administration page which allows maintaining forums
62
 */
63
64
65
66
67
68
69
function forum_admin() {
  $op = $_POST['op'];
  $edit = $_POST['edit'];

  if (empty($op)) {
    $op = arg(2);
  }
Dries's avatar
   
Dries committed
70

71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
  switch ($op) {
    case 'add':
      if (arg(3) == 'forum') {
        $output = forum_form_forum();
      }
      else if (arg(3) == 'container') {
        $output = forum_form_container();
      }
      break;
    case 'edit':
      if (arg(3) == 'forum') {
        $output = forum_form_forum(object2array(taxonomy_get_term(arg(4))));
      }
      else if (arg(3) == 'container') {
         $output = forum_form_container(object2array(taxonomy_get_term(arg(4))));
      }
      break;
    case t('Delete'):
      if (!$edit['confirm']) {
90
        $output = _forum_confirm_delete($edit['tid']);
91
92
93
94
95
96
        break;
      }
      else {
        $edit['name'] = 0;
      }
    case t('Submit'):
97
      list($status, $object) = array_values(taxonomy_save_term($edit));
98
99
100
101
      if (arg(3) == 'container') {
        $containers = variable_get('forum_containers', array());
        $containers[] = $edit['tid'];
        variable_set('forum_containers', $containers);
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
        if ($status == SAVED_NEW) {
          drupal_set_message(t('Created new forum container %term.', array('%term' => theme('placeholder', $edit['name']))));
        }
        else {
          drupal_set_message(t('The forum container %term has been updated.', array('%term' => theme('placeholder', $edit['name']))));
        }
      }
      else {
        if ($status == SAVED_NEW) {
          drupal_set_message(t('Created new forum %term.', array('%term' => theme('placeholder', $edit['name']))));
        }
        else {
          drupal_set_message(t('The forum %term has been updated.', array('%term' => theme('placeholder', $edit['name']))));
        }
      }
117
118
119
120
121
      drupal_goto('admin/forum');
    default:
      $output = forum_overview();
  }

Dries's avatar
   
Dries committed
122
  return $output;
123
124
125
126
127
128
129
}

/**
 * Implementation of hook_taxonomy().
 */
function forum_taxonomy($op, $type, $object) {
  if ($op == 'delete' && $type == 'term' && $object->vid == _forum_get_vid())  {
Dries's avatar
Dries committed
130
    $results = db_query('SELECT f.nid FROM {forum} f WHERE f.tid = %d', $object->tid);
131
132
133
134
    while ($node = db_fetch_object($results)) {
      $edit['nid'] = $node->nid;
      $edit['confirm'] = TRUE;
      node_delete($edit);
Dries's avatar
   
Dries committed
135
    }
136
137
  }
}
Dries's avatar
   
Dries committed
138

139
140
141
142
143
/**
 * Returns a confirmation page for deleting a forum taxonomy term
 *
 * @param $tid ID of the term to be deleted
 */
144
function _forum_confirm_delete($tid) {
145
146
147
148
  $term = taxonomy_get_term($tid);

  $extra = form_hidden('tid', $tid);
  $output = theme('confirm',
Steven Wittens's avatar
Steven Wittens committed
149
                  t('Are you sure you want to delete the forum %name?', array('%name' => theme('placeholder', $term->name))),
150
151
152
153
154
                  'admin/forums',
                  t('Deleting a forum or container will delete all sub-forums as well. This action cannot be undone.'),
                  t('Delete'),
                  t('Cancel'),
                  $extra);
155
  return $output;
156
157
158
159
160
161
162
163
}

/**
 * Returns a form for adding a container to the forum vocabulary
 *
 * @param $edit Associative array containing a container term to be added or edited.
 */
function forum_form_container($edit = array()) {
164
  $form = form_textfield(t('Container name'), 'name', $edit['name'], 60, 64, t('The container name is used to identify related forums.'), NULL, TRUE);
165
  $form .= form_textarea(t('Description'), 'description', $edit['description'], 60, 5, t('The container description can give users more information about the forums it contains.'));
166

167
168
  $form .= _forum_parent_select($edit['tid'], t('Parent'), 'parent][', 'container');
  $form .= form_weight(t('Weight'), 'weight', $edit['weight'], 10, t('When listing containers, those with with light (small) weights get listed before containers with heavier (larger) weights. Containers with equal weights are sorted alphabetically.'));
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185

  $form .= form_hidden('vid', _forum_get_vid());
  $form .= form_submit(t('Submit'));
  if ($edit['tid']) {
    $form .= form_submit(t('Delete'));
    $form .= form_hidden('tid', $edit['tid']);
  }

  return form($form);
}

/**
 * Returns a form for adding a forum to the forum vocabulary
 *
 * @param $edit Associative array containing a forum term to be added or edited.
 */
function forum_form_forum($edit = array()) {
186
  $form = form_textfield(t('Forum name'), 'name', $edit['name'], 60, 64, t('The forum name is used to identify related topic discussions.'), NULL, TRUE);
187
  $form .= form_textarea(t('Description'), 'description', $edit['description'], 60, 5, t('The forum description can give users more information about the discussion topics it contains.'));
188

189
190
  $form .= _forum_parent_select($edit['tid'], t('Parent'), 'parent][', 'forum');
  $form .= form_weight(t('Weight'), 'weight', $edit['weight'], 10, t('When listing forums, those with light (small) weights get listed before forums with heavier (larger) weights. Forums with equal weights are sorted alphabetically.'));
191
192
193
194
195
196
197

  $form .= form_hidden('vid', _forum_get_vid());
  $form .= form_submit(t('Submit'));
  if ($edit['tid']) {
    $form .= form_submit(t('Delete'));
    $form .= form_hidden('tid', $edit['tid']);
  }
198

199
200
201
202
203
204
205
206
207
208
  return form($form);
}

/**
 * Returns a select box for available parent terms
 *
 * @param $tid ID of the term which is being added or edited
 * @param $title Title to display the select box with
 * @param $name Name to use in the forum
 */
209
function _forum_parent_select($tid, $title, $name, $child_type) {
210
211

  $parents = taxonomy_get_parents($tid);
212
213
214
215
216
217
218
219
  if ($parents) {
    $parent = array_shift($parents);
    $parent = $parent->tid;
  }
  else {
    $parent = 0;
  }

220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
  $children = taxonomy_get_tree(_forum_get_vid, $tid);

  // A term can't be the child of itself, nor of its children.
  foreach ($children as $child) {
    $exclude[] = $child->tid;
  }
  $exclude[] = $tid;

  $tree = taxonomy_get_tree(_forum_get_vid());
  $options[0] = '<'. t('root') .'>';
  if ($tree) {
    foreach ($tree as $term) {
      if (!in_array($term->tid, $exclude)) {
        $options[$term->tid] = _forum_depth($term->depth).$term->name;
      }
Dries's avatar
   
Dries committed
235
236
    }
  }
237
238
239
240
241
242
  if ($child_type == 'container') {
    $description = t('Containers are usually placed at the top (root) level of your forum but you can also place a container inside a parent container or forum.');
  }
  else if ($child_type == 'forum') {
    $description = t('You may place your forum inside a parent container or forum, or at the top (root) level of your forum.');
  }
Dries's avatar
   
Dries committed
243

244
  return form_select($title, $name, $parent, $options, $description, 0, FALSE, TRUE);
Dries's avatar
   
Dries committed
245
246
}

247
/**
248
 * Returns an overview list of existing forums and containers
249
 */
250
251
252
253
254
255
256
function forum_overview() {
  $header = array(t('Name'), t('Operations'));

  $tree = taxonomy_get_tree(_forum_get_vid());
  if ($tree) {
    foreach ($tree as $term) {
      if (in_array($term->tid, variable_get('forum_containers', array()))) {
257
        $rows[] = array(_forum_depth($term->depth) .' '. check_plain($term->name), l(t('edit container'), "admin/forum/edit/container/$term->tid"));
258
259
      }
      else {
260
        $rows[] = array(_forum_depth($term->depth) .' '. check_plain($term->name), l(t('edit forum'), "admin/forum/edit/forum/$term->tid"));
261
262
       }

Dries's avatar
Dries committed
263
264
    }
  }
265
  else {
266
    $rows[] = array(array('data' => '<em>' . t('There are no existing containers or forums. You may add some on the <a href="%container">add container</a> or <a href="%forum">add forum</a> pages.', array('%container' => url('admin/forum/add/container'), '%forum' => url('admin/forum/add/forum'))) . '</em>', 'colspan' => 2));
267
268
  }
  return theme('table', $header, $rows);
Dries's avatar
Dries committed
269
270
}

271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
/**
 * Helper function used to generate indentation for forum list
 *
 * @param $depth Depth of the indentation
 * @param $graphic HTML text to be repeated for each stage of depth
 */
function _forum_depth($depth, $graphic = '--') {
  for ($n = 0; $n < $depth; $n++) {
    $result .= $graphic;
  }
  return $result;
}

/**
 * Returns the vocabulary id for forum navigation.
 */
function _forum_get_vid() {
  $vid = variable_get('forum_nav_vocabulary', '');
  if (empty($vid)) {
    // Check to see if a forum vocabulary exists
    $vid = db_result(db_query("SELECT vid FROM {vocabulary} WHERE module='%s'", 'forum'));
    if (!$vid) {
293
294
      list($status, $object) = array_values(taxonomy_save_vocabulary(array('name' => 'Forums', 'multiple' => 0, 'required' => 1, 'hierarchy' => 1, 'relations' => 0, 'module' => 'forum', 'nodes' => array('forum'))));
      $vid = $object['vid'];
295
296
297
298
299
300
301
302
303
304
    }
    variable_set('forum_nav_vocabulary', $vid);
  }

  return $vid;
}

/**
 * Implementation of hook_settings
 */
305
306
307
function forum_admin_configure() {
  system_settings_save();

308
309
310
311
312
313
314
315
  $output .= form_textfield(t('Forum icon path'), 'forum_icon_path', variable_get('forum_icon_path', ''), 30, 255, t('The path to the forum icons.  Leave blank to disable icons. Don\'t add a trailing slash.  Default icons are available in the "misc" directory. You may use images of whatever size you wish, but it is recommended to use 15x15 or 16x16. '));
  $number = drupal_map_assoc(array(5, 10, 15, 20, 25, 30, 35, 40, 50, 60, 80, 100, 10000));
  $output .= form_select(t('Hot topic threshold'), 'forum_hot_topic', variable_get('forum_hot_topic', 15), $number, t('The number of posts a topic must have to be considered hot.'));
  $number = drupal_map_assoc(array(10, 25, 50, 75, 100));
  $output .= form_select(t('Topics per page'), 'forum_per_page', variable_get('forum_per_page', 25), $number, t('The default number of topics displayed per page; links to browse older messages are automatically being displayed.'));
  $forder = array(1 => t('Date - newest first'), 2 => t('Date - oldest first'), 3 => t('Posts - most active first'), 4=> t('Posts - least active first'));
  $output .= form_radios(t('Default order'), 'forum_order', variable_get('forum_order', '1'), $forder, t('The default display order for topics.'));

Dries's avatar
   
Dries committed
316
  return system_settings_form($output);
317
318
}

319
320
321
/**
 * Implementation of hook_load().
 */
Dries's avatar
   
Dries committed
322
function forum_load($node) {
Dries's avatar
   
Dries committed
323
  $forum = db_fetch_object(db_query('SELECT * FROM {forum} WHERE nid = %d', $node->nid));
Dries's avatar
   
Dries committed
324
325
326
327

  return $forum;
}

328
329
330
331
332
333
/**
 * Implementation of hook_block().
 *
 * Generates a block containing the currently active forum topics and the
 * most recently added forum topics.
 */
334
335
336
function forum_block($op = 'list', $delta = 0, $edit = array()) {
  switch ($op) {
    case 'list':
Dries's avatar
   
Dries committed
337
338
      $blocks[0]['info'] = t('Active forum topics');
      $blocks[1]['info'] = t('New forum topics');
339
      return $blocks;
Dries's avatar
   
Dries committed
340

341
    case 'configure':
342
      $output = form_select(t('Number of topics'), 'forum_block_num_'. $delta, variable_get('forum_block_num_'. $delta, '5'), drupal_map_assoc(array(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)));
343
      return $output;
Dries's avatar
   
Dries committed
344

345
    case 'save':
346
      variable_set('forum_block_num_'. $delta, $edit['forum_block_num_'. $delta]);
347
      break;
Dries's avatar
   
Dries committed
348

349
350
    case 'view':
      if (user_access('access content')) {
Dries's avatar
   
Dries committed
351
352
        switch ($delta) {
          case 0:
353
            $title = t('Active forum topics');
354
            $sql = db_rewrite_sql("SELECT n.nid, n.title, l.last_comment_timestamp, l.comment_count FROM {node} n INNER JOIN {node_comment_statistics} l ON n.nid = l.nid WHERE n.status = 1 AND n.type = 'forum' ORDER BY l.last_comment_timestamp DESC");
355
356
357
358
            $result = db_query_range($sql, 0, variable_get('forum_block_num_0', '5'));
            if (db_num_rows($result)) {
              $content = node_title_list($result);
            }
359
            break;
Dries's avatar
   
Dries committed
360
361

          case 1:
362
363
            $title = t('New forum topics');
            $sql = db_rewrite_sql("SELECT n.nid, n.title, l.comment_count FROM {node} n INNER JOIN {node_comment_statistics} l ON n.nid = l.nid WHERE n.type = 'forum' AND n.status = 1 ORDER BY n.nid DESC");
364
365
366
367
            $result = db_query_range($sql, 0, variable_get('forum_block_num_1', '5'));
            if (db_num_rows($result)) {
              $content = node_title_list($result);
            }
368
            break;
Dries's avatar
   
Dries committed
369
        }
Dries's avatar
   
Dries committed
370

371
372
373
374
        if ($content) {
          $content .= '<div class="more-link">'. l(t('more'), 'forum', array('title' => t('Read the latest forum topics.'))) .'</div>';
        }

Dries's avatar
   
Dries committed
375
        $block['subject'] = $title;
376
377
378
379
380
        $block['content'] = $content;

        return $block;
      }
  }
Dries's avatar
   
Dries committed
381
382
}

Dries's avatar
   
Dries committed
383
384
385
/**
 * Implementation of hook_link().
 */
386
function forum_link($type, $node = 0, $main = 0) {
Dries's avatar
Dries committed
387
  global $user;
Dries's avatar
   
Dries committed
388

Dries's avatar
   
Dries committed
389
390
  $links = array();

Dries's avatar
   
Dries committed
391
  if (!$main && $type == 'node' && $node->type == 'forum') {
Dries's avatar
   
Dries committed
392
393
    // get previous and next topic

Steven Wittens's avatar
Steven Wittens committed
394
    $sql = "SELECT n.nid, n.title, n.sticky, l.comment_count, l.last_comment_timestamp FROM {node} n INNER JOIN {node_comment_statistics} l ON n.nid = l.nid INNER JOIN {term_node} r ON n.nid = r.nid AND r.tid = %d WHERE n.status = 1 AND n.type = 'forum' ORDER BY n.sticky DESC, ". _forum_get_topic_order_sql(variable_get('forum_order', 1));
395
    $sql = db_rewrite_sql($sql);
Dries's avatar
   
Dries committed
396
    $result = db_query($sql, $node->tid);
Dries's avatar
   
Dries committed
397
398
399

    while ($topic = db_fetch_object($result)) {
      if ($stop == 1) {
400
        $next = new StdClass();
Dries's avatar
   
Dries committed
401
402
403
404
405
406
407
408
        $next->nid = $topic->nid;
        $next->title = $topic->title;
        break;
      }
      if ($topic->nid == $node->nid) {
        $stop = 1;
      }
      else {
409
        $prev = new StdClass();
Dries's avatar
   
Dries committed
410
411
412
413
414
415
        $prev->nid = $topic->nid;
        $prev->title = $topic->title;
      }
    }

    if ($prev) {
416
      $links[] = l(t('previous forum topic'), "node/$prev->nid", array('title' => check_plain($prev->title)));
Dries's avatar
   
Dries committed
417
418
419
    }

    if ($next) {
420
      $links[] = l(t('next forum topic'), "node/$next->nid", array('title' => check_plain($next->title)));
Dries's avatar
   
Dries committed
421
    }
Dries's avatar
   
Dries committed
422
423
  }

Dries's avatar
   
Dries committed
424
  return $links;
Dries's avatar
   
Dries committed
425
426
}

Dries's avatar
   
Dries committed
427
428
429
/**
 * Implementation of hook_menu().
 */
Dries's avatar
   
Dries committed
430
function forum_menu($may_cache) {
Dries's avatar
   
Dries committed
431
432
  $items = array();

Dries's avatar
   
Dries committed
433
434
435
  if ($may_cache) {
    $items[] = array('path' => 'node/add/forum', 'title' => t('forum topic'),
      'access' => user_access('create forum topics'));
436

Dries's avatar
   
Dries committed
437
438
439
    $items[] = array('path' => 'forum', 'title' => t('forums'),
      'callback' => 'forum_page',
      'access' => user_access('access content'),
440
      'type' => MENU_SUGGESTED_ITEM);
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455

    $items[] = array('path' => 'admin/forum', 'title' => t('forums'),
      'callback' => 'forum_admin',
      'access' => user_access('administer forums'),
      'type' => MENU_NORMAL_ITEM);

    $items[] = array('path' => 'admin/forum/list', 'title' => t('list'),
      'access' => user_access('administer forums'),
      'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);
    $items[] = array('path' => 'admin/forum/add/container', 'title' => t('add container'),
      'access' => user_access('administer forums'),
      'type' => MENU_LOCAL_TASK);
    $items[] = array('path' => 'admin/forum/add/forum', 'title' => t('add forum'),
      'access' => user_access('administer forums'),
      'type' => MENU_LOCAL_TASK);
456
457
458
459
    $items[] = array('path' => 'admin/forum/configure', 'title' => t('configure'),
      'callback' => 'forum_admin_configure',
      'access' => user_access('administer forums'),
      'type' => MENU_LOCAL_TASK);
460
461
462
463
464
465
466

    $items[] = array('path' => 'admin/forum/edit/container', 'title' => t('edit container'),
      'access' => user_access('administer forums'),
      'type' => MENU_CALLBACK);
    $items[] = array('path' => 'admin/forum/edit/forum', 'title' => t('edit forum'),
      'access' => user_access('administer forums'),
      'type' => MENU_CALLBACK);
Dries's avatar
   
Dries committed
467
  }
Dries's avatar
   
Dries committed
468
469
470
471

  return $items;
}

472
473
474
/**
 * Implementation of hook_view().
 */
Dries's avatar
   
Dries committed
475
function forum_view(&$node, $teaser = FALSE, $page = FALSE) {
Dries's avatar
   
Dries committed
476

Dries's avatar
   
Dries committed
477
  if ($page) {
Dries's avatar
   
Dries committed
478
    $vocabulary = taxonomy_get_vocabulary(variable_get('forum_nav_vocabulary', ''));
Dries's avatar
   
Dries committed
479
    // Breadcrumb navigation
Dries's avatar
   
Dries committed
480
481
    $breadcrumb = array();
    $breadcrumb[] = array('path' => 'forum', 'title' => $vocabulary->name);
Dries's avatar
   
Dries committed
482
    if ($parents = taxonomy_get_parents_all($node->tid)) {
Dries's avatar
   
Dries committed
483
484
      $parents = array_reverse($parents);
      foreach ($parents as $p) {
Dries's avatar
   
Dries committed
485
        $breadcrumb[] = array('path' => 'forum/'. $p->tid, 'title' => $p->name);
Dries's avatar
   
Dries committed
486
487
      }
    }
Dries's avatar
   
Dries committed
488
489
    $breadcrumb[] = array('path' => 'node/'. $node->nid);
    menu_set_location($breadcrumb);
490
  }
Dries's avatar
   
Dries committed
491

492
  $node = node_prepare($node, $teaser);
Dries's avatar
   
Dries committed
493
494
}

495
496
497
498
499
500
/**
 * Implementation of hook_validate().
 *
 * Check in particular that only a "leaf" term in the associated taxonomy
 * vocabulary is selected, not a "container" term.
 */
501
502
function forum_validate(&$node) {
  // Make sure all fields are set properly:
Dries's avatar
   
Dries committed
503
  $node->icon = $node->icon ? $node->icon : '';
Dries's avatar
   
Dries committed
504
505
506

  if ($node->taxonomy) {
    // Extract the node's proper topic ID.
Dries's avatar
   
Dries committed
507
    $vocabulary = variable_get('forum_nav_vocabulary', '');
508
    $containers = variable_get('forum_containers', array());
Dries's avatar
   
Dries committed
509
    foreach ($node->taxonomy as $term) {
Dries's avatar
   
Dries committed
510
      if (db_result(db_query('SELECT COUNT(*) FROM {term_data} WHERE tid = %d AND vid = %d', $term, $vocabulary))) {
511
512
        if (in_array($term, $containers)) {
          $term = taxonomy_get_term($term);
513
          form_set_error('taxonomy', t('The item %forum is only a container for forums. Please select one of the forums below it.', array('%forum' => theme('placeholder', $term->name))));
514
515
516
517
        }
        else {
          $node->tid = $term;
        }
Dries's avatar
   
Dries committed
518
      }
519
    }
Dries's avatar
   
Dries committed
520
521
522
523
524
525
526
    if ($node->tid && $node->shadow) {
      $terms = array_keys(taxonomy_node_get_terms($node->nid));
      if (!in_array($node->tid, $terms)) {
        $terms[] = $node->tid;
      }
      $node->taxonomy = $terms;
    }
Dries's avatar
Dries committed
527
528
529
  }
}

Dries's avatar
   
Dries committed
530
531
532
533
534
535
536
/**
 * Implementation of hook_update().
 */
function forum_update($node) {
  db_query('UPDATE {forum} SET tid = %d WHERE nid = %d', $node->tid, $node->nid);
}

537
538
539
/**
 * Implementation of hook_form().
 */
Dries's avatar
   
Dries committed
540
function forum_form(&$node) {
Dries's avatar
   
Dries committed
541
  if (!$node->nid) {
Dries's avatar
Dries committed
542
    // new topic
Dries's avatar
   
Dries committed
543
    $node->taxonomy[] = arg(3);
544
  }
Dries's avatar
   
Dries committed
545
546
547
  else {
    $node->taxonomy = array($node->tid);
  }
548

Dries's avatar
   
Dries committed
549
  $output = implode('', taxonomy_node_form('forum', $node));
Dries's avatar
Dries committed
550
551
552

  if ($node->nid) {
    // if editing, give option to leave shadows
Dries's avatar
   
Dries committed
553
554
    $shadow = (count(taxonomy_node_get_terms($node->nid)) > 1);
    $output .= form_checkbox(t('Leave shadow copy'), 'shadow', 1, $shadow, t('If you move this topic, you can leave a link in the old forum to the new forum.'));
Dries's avatar
Dries committed
555
  }
Dries's avatar
   
Dries committed
556

557
  $output .= form_textarea(t('Body'), 'body', $node->body, 60, 20, '');
558
  $output .= filter_form('format', $node->format);
Dries's avatar
   
Dries committed
559
560
561
562

  return $output;
}

563
564
565
/**
 * Implementation of hook_insert().
 */
Dries's avatar
   
Dries committed
566
function forum_insert($node) {
Dries's avatar
   
Dries committed
567
  db_query('INSERT INTO {forum} (nid, tid) VALUES (%d, %d)', $node->nid, $node->tid);
Dries's avatar
   
Dries committed
568
569
}

570
571
572
/**
 * Implementation of hook_delete().
 */
Dries's avatar
   
Dries committed
573
function forum_delete(&$node) {
Dries's avatar
   
Dries committed
574
  db_query('DELETE FROM {forum} WHERE nid = %d', $node->nid);
Dries's avatar
   
Dries committed
575
}
Dries's avatar
   
Dries committed
576

Dries's avatar
   
Dries committed
577
578
579
/**
 * Formats a topic for display
 *
580
 * @TODO Give a better description. Not sure where this function is used yet.
Dries's avatar
   
Dries committed
581
 */
Dries's avatar
   
Dries committed
582
function _forum_format($topic) {
583
  if ($topic && $topic->timestamp) {
584
    return t('%time ago<br />by %author', array('%time' => format_interval(time() - $topic->timestamp), '%author' => theme('username', $topic)));
Dries's avatar
   
Dries committed
585
586
587
588
589
590
  }
  else {
    return message_na();
  }
}

Dries's avatar
   
Dries committed
591
592
593
/**
 * Returns a list of all forums for a given taxonomy id
 *
594
 * Forum objects contain the following fields
Dries's avatar
   
Dries committed
595
596
597
598
599
600
601
602
603
 * -num_topics Number of topics in the forum
 * -num_posts Total number of posts in all topics
 * -last_post Most recent post for the forum
 *
 * @param $tid
 *   Taxonomy ID of the vocabulary that holds the forum list.
 * @return
 *   Array of object containing the forum information.
 */
Dries's avatar
   
Dries committed
604
function forum_get_forums($tid = 0) {
605

Dries's avatar
   
Dries committed
606
607
608
609
  if (!$tid) {
    $tid = 0;
  }

Dries's avatar
   
Dries committed
610
611
  $forums = array();
  $_forums = taxonomy_get_tree(variable_get('forum_nav_vocabulary', ''), $tid);
Dries's avatar
   
Dries committed
612

Dries's avatar
   
Dries committed
613
  if (count($_forums)) {
Dries's avatar
   
Dries committed
614

Dries's avatar
   
Dries committed
615
616
    $counts = array();

Dries's avatar
   
Dries committed
617
    $sql = "SELECT r.tid, COUNT(n.nid) AS topic_count, SUM(l.comment_count) AS comment_count FROM {node} n INNER JOIN {node_comment_statistics} l ON n.nid = l.nid INNER JOIN {term_node} r ON n.nid = r.nid WHERE n.status = 1 AND n.type = 'forum' GROUP BY r.tid";
618
    $sql = db_rewrite_sql($sql);
Dries's avatar
   
Dries committed
619
    $_counts = db_query($sql, $forum->tid);
Dries's avatar
   
Dries committed
620
621
622
    while ($count = db_fetch_object($_counts)) {
      $counts[$count->tid] = $count;
    }
Dries's avatar
   
Dries committed
623
  }
Dries's avatar
   
Dries committed
624

Dries's avatar
   
Dries committed
625
626
627
628
  foreach ($_forums as $forum) {
    if (in_array($forum->tid, variable_get('forum_containers', array()))) {
      $forum->container = 1;
    }
Dries's avatar
   
Dries committed
629

Dries's avatar
   
Dries committed
630
631
632
633
634
635
636
637
638
639
640
    if ($counts[$forum->tid]) {
      $forum->num_topics = $counts[$forum->tid]->topic_count;
      $forum->num_posts = $counts[$forum->tid]->topic_count + $counts[$forum->tid]->comment_count;
    }
    else {
      $forum->num_topics = 0;
      $forum->num_posts = 0;
    }

    // This query does not use full ANSI syntax since MySQL 3.x does not support
    // table1 INNER JOIN table2 INNER JOIN table3 ON table2_criteria ON table3_criteria
Dries's avatar
   
Dries committed
641
    // used to join node_comment_statistics to users.
642
    $sql = "SELECT n.nid, l.last_comment_timestamp, IF(l.last_comment_uid, cu.name, l.last_comment_name) as last_comment_name, l.last_comment_uid FROM {node} n, {node_comment_statistics} l, {users} cu, {term_node} r WHERE  n.nid = r.nid AND r.tid = %d AND n.status = 1 AND n.type = 'forum' AND l.last_comment_uid = cu.uid AND n.nid = l.nid ORDER BY l.last_comment_timestamp DESC";
643
    $sql = db_rewrite_sql($sql);
Dries's avatar
   
Dries committed
644
    $topic = db_fetch_object(db_query_range($sql, $forum->tid, 0, 1));
645
646

    $last_post = new StdClass();
Dries's avatar
   
Dries committed
647
648
649
650
    $last_post->timestamp = $topic->last_comment_timestamp;
    $last_post->name = $topic->last_comment_name;
    $last_post->uid = $topic->last_comment_uid;
    $forum->last_post = $last_post;
Dries's avatar
   
Dries committed
651

Dries's avatar
   
Dries committed
652
653
654
655
    $forums[$forum->tid] = $forum;
  }

  return $forums;
Dries's avatar
   
Dries committed
656
657
}

658
659
660
661
function _forum_topics_read($term, $uid) {
  // Calculate the number of topics the user has read. Assume all entries older
  // than NODE_NEW_LIMIT are read, and include the recent posts that user has
  // read.
Dries's avatar
   
Dries committed
662
  $sql = "SELECT COUNT(n.nid) FROM {node} n INNER JOIN {term_node} r ON n.nid = r.nid AND r.tid = %d WHERE n.created <= %d AND n.status = 1 AND n.type = 'forum'";
663
  $sql = db_rewrite_sql($sql);
Dries's avatar
   
Dries committed
664
665
  $ancient = db_result(db_query($sql, $term, NODE_NEW_LIMIT));
  $sql = "SELECT COUNT(n.nid) FROM {node} n INNER JOIN {history} h ON n.nid = h.nid AND h.uid = %d INNER JOIN {term_node} r ON n.nid = r.nid AND r.tid = %d WHERE n.status = 1 AND n.type = 'forum' AND n.created > %d";
666
  $sql = db_rewrite_sql($sql);
Dries's avatar
   
Dries committed
667
  $recent = db_result(db_query($sql, $uid, $term, NODE_NEW_LIMIT));
Dries's avatar
   
Dries committed
668

669
  return $ancient + $recent;
Dries's avatar
   
Dries committed
670
671
}

Dries's avatar
Dries committed
672
function forum_get_topics($tid, $sortby, $forum_per_page) {
Dries's avatar
   
Dries committed
673
  global $user, $forum_topic_list_header;
Dries's avatar
   
Dries committed
674

Dries's avatar
   
Dries committed
675
  $forum_topic_list_header = array(
Dries's avatar
   
Dries committed
676
677
    array('data' => '&nbsp;'),
    array('data' => t('Topic'), 'field' => 'n.title'),
Dries's avatar
   
Dries committed
678
    array('data' => t('Replies'), 'field' => 'l.comment_count'),
Dries's avatar
   
Dries committed
679
    array('data' => t('Created'), 'field' => 'n.created'),
Dries's avatar
   
Dries committed
680
    array('data' => t('Last reply'), 'field' => 'l.last_comment_timestamp'),
Dries's avatar
   
Dries committed
681
  );
Dries's avatar
   
Dries committed
682

Dries's avatar
   
Dries committed
683
  $order = _forum_get_topic_order($sortby);
Dries's avatar
   
Dries committed
684
  for ($i = 0; $i < count($forum_topic_list_header); $i++) {
Dries's avatar
   
Dries committed
685
686
    if ($forum_topic_list_header[$i]['field'] == $order['field']) {
      $forum_topic_list_header[$i]['sort'] = $order['sort'];
Dries's avatar
   
Dries committed
687
688
689
690
    }
  }

  $term = taxonomy_get_term($tid);
Dries's avatar
   
Dries committed
691

692
  $sql = db_rewrite_sql("SELECT n.nid, f.tid, n.title, n.sticky, u.name, u.uid, n.created AS timestamp, n.comment AS comment_mode, l.last_comment_timestamp, IF(l.last_comment_uid, cu.name, l.last_comment_name) AS last_comment_name, l.last_comment_uid, l.comment_count AS num_comments FROM {node} n, {node_comment_statistics} l, {users} cu, {term_node} r, {users} u, {forum} f WHERE n.status = 1 AND l.last_comment_uid = cu.uid AND n.nid = l.nid AND n.nid = r.nid AND r.tid = %d AND n.uid = u.uid AND n.nid = f.nid");
Dries's avatar
   
Dries committed
693
  $sql .= tablesort_sql($forum_topic_list_header, 'n.sticky DESC,');
Dries's avatar
Dries committed
694

695
  $sql_count = db_rewrite_sql("SELECT COUNT(n.nid) FROM {node} n INNER JOIN {term_node} r ON n.nid = r.nid AND r.tid = %d WHERE n.status = 1 AND n.type = 'forum'");
Dries's avatar
   
Dries committed
696

Steven Wittens's avatar
Steven Wittens committed
697
  $result = pager_query($sql, $forum_per_page, 0, $sql_count, $tid);
Dries's avatar
   
Dries committed
698
699

  while ($topic = db_fetch_object($result)) {
Dries's avatar
Dries committed
700
701
    if ($user->uid) {
      // folder is new if topic is new or there are new comments since last visit
Dries's avatar
   
Dries committed
702
      if ($topic->tid != $tid) {
Dries's avatar
Dries committed
703
        $topic->new = 0;
Dries's avatar
   
Dries committed
704
705
      }
      else {
Dries's avatar
   
Dries committed
706
        $history = _forum_user_last_visit($topic->nid);
Dries's avatar
   
Dries committed
707
        $topic->new_replies = comment_num_new($topic->nid, $history);
708
        $topic->new = $topic->new_replies || ($topic->timestamp > $history);
Dries's avatar
   
Dries committed
709
      }
710
711
    }
    else {
712
      // Do not track "new replies" status for topics if the user is anonymous.
Dries's avatar
Dries committed
713
714
      $topic->new_replies = 0;
      $topic->new = 0;
715
    }
Dries's avatar
   
Dries committed
716

Dries's avatar
   
Dries committed
717
    if ($topic->num_comments > 0) {
718
      $last_reply = new StdClass();
Dries's avatar
   
Dries committed
719
720
721
722
723
      $last_reply->timestamp = $topic->last_comment_timestamp;
      $last_reply->name = $topic->last_comment_name;
      $last_reply->uid = $topic->last_comment_uid;
      $topic->last_reply = $last_reply;
    }
Dries's avatar
   
Dries committed
724
725
726
    $topics[] = $topic;
  }

Dries's avatar
Dries committed
727
  return $topics;
Dries's avatar
   
Dries committed
728
729
}

Dries's avatar
   
Dries committed
730
731
732
/**
 * Finds the first unread node for a given forum.
 */
Dries's avatar
Dries committed
733
function _forum_new($tid) {
Dries's avatar
   
Dries committed
734
735
  global $user;

Dries's avatar
   
Dries committed
736
  $sql = "SELECT n.nid FROM {node} n LEFT JOIN {history} h ON n.nid = h.nid AND h.uid = %d INNER JOIN {term_node} r ON n.nid = r.nid AND r.tid = %d WHERE n.status = 1 AND n.type = 'forum' AND h.nid IS NULL AND n.created > %d ORDER BY created";
737
  $sql = db_rewrite_sql($sql);
Dries's avatar
   
Dries committed
738
  $nid = db_result(db_query_range($sql, $user->uid, $tid, NODE_NEW_LIMIT, 0, 1));
Dries's avatar
   
Dries committed
739
740
741
742

  return $nid ? $nid : 0;
}

743
/**
Dries's avatar
Dries committed
744
 * Menu callback; prints a forum listing.
745
 */
Dries's avatar
Dries committed
746
function forum_page($tid = 0) {
Dries's avatar
   
Dries committed
747
  global $user;
Dries's avatar
   
Dries committed
748

Dries's avatar
   
Dries committed
749
  if (module_exist('taxonomy')) {
Dries's avatar
Dries committed
750
751
    $forum_per_page = variable_get('forum_per_page', 25);
    $sortby = variable_get('forum_order', 1);
Dries's avatar
   
Dries committed
752

Dries's avatar
Dries committed
753
754
755
756
    $forums = forum_get_forums($tid);
    $parents = taxonomy_get_parents_all($tid);
    if ($tid && !in_array($tid, variable_get('forum_containers', array()))) {
      $topics = forum_get_topics($tid, $sortby, $forum_per_page);
Dries's avatar
   
Dries committed
757
    }
Dries's avatar
Dries committed
758

Dries's avatar
   
Dries committed
759
    return theme('forum_display', $forums, $topics, $parents, $tid, $sortby, $forum_per_page);
Dries's avatar
   
Dries committed
760
761
  }
  else {
762
    drupal_set_title(t('Warning'));
Dries's avatar
   
Dries committed
763
    return forum_help('admin/settings/forum');
Dries's avatar
   
Dries committed
764
765
766
  }
}

Dries's avatar
   
Dries committed
767
/**
Dries's avatar
   
Dries committed
768
769
 * Format the forum body.
 *
Dries's avatar
   
Dries committed
770
 * @ingroup themeable
Dries's avatar
   
Dries committed
771
 */
Dries's avatar
   
Dries committed
772
function theme_forum_display($forums, $topics, $parents, $tid, $sortby, $forum_per_page) {
Dries's avatar
   
Dries committed
773
  global $user;
Dries's avatar
   
Dries committed
774
  // forum list, topics list, topic browser and 'add new topic' link
Dries's avatar
   
Dries committed
775

Dries's avatar
   
Dries committed
776
  $vocabulary = taxonomy_get_vocabulary(variable_get('forum_nav_vocabulary', ''));
777
  $title = $vocabulary->name;
Dries's avatar
   
Dries committed
778

Dries's avatar
   
Dries committed
779
780
  // Breadcrumb navigation:
  $breadcrumb = array();
Dries's avatar
   
Dries committed
781
  if ($tid) {
Dries's avatar
   
Dries committed
782
    $breadcrumb[] = array('path' => 'forum', 'title' => $title);
Dries's avatar
   
Dries committed
783
  }
Dries's avatar
   
Dries committed
784
785

  if ($parents) {
Dries's avatar
   
Dries committed
786
787
    $parents = array_reverse($parents);
    foreach ($parents as $p) {
788
789
      if ($p->tid == $tid) {
        $title = $p->name;
Dries's avatar
   
Dries committed
790
791
      }
      else {
Dries's avatar
   
Dries committed
792
        $breadcrumb[] = array('path' => 'forum/'. $p->tid, 'title' => $p->name);
Dries's avatar
   
Dries committed
793
794
795
      }
    }
  }
796
797
798

  drupal_set_title($title);

Dries's avatar
   
Dries committed
799
800
  $breadcrumb[] = array('path' => $_GET['q']);
  menu_set_location($breadcrumb);
Dries's avatar
   
Dries committed
801

Dries's avatar
   
Dries committed
802
  if (count($forums) || count($parents)) {
803
804
    $output  = '<div id="forum">';
    $output .= '<ul>';
Dries's avatar
   
Dries committed
805
806
807

    if (module_exist('tracker')) {
      if ($user->uid) {
Dries's avatar
   
Dries committed
808
        $output .= ' <li>'. l(t('My forum discussions.'), "tracker/$user->uid") .'</li>';
Dries's avatar
   
Dries committed
809
810
      }

Dries's avatar
   
Dries committed
811
      $output .= ' <li>'. l(t('Active forum discussions.'), 'tracker') .'</li>';
Dries's avatar
   
Dries committed
812
813
814
    }

    if (user_access('create forum topics')) {
815
      $output .= '<li>'. l(t('Post new forum topic.'), "node/add/forum/$tid") .'</li>';
Dries's avatar
   
Dries committed
816
817
    }
    else if ($user->uid) {
818
      $output .= '<li>'. t('You are not allowed to post a new forum topic.') .'</li>';
Dries's avatar
   
Dries committed
819
820
821
822
    }
    else {
      $output .= '<li>'. t('<a href="%login">Login</a> to post a new forum topic.', array('%login' => url('user/login'))) .'</li>';
    }
823
    $output .= '</ul>';
Dries's avatar
   
Dries committed
824

Dries's avatar
   
Dries committed
825
    $output .= theme('forum_list', $forums, $parents, $tid);
Dries's avatar
   
Dries committed
826

Dries's avatar
   
Dries committed
827
    if ($tid && !in_array($tid, variable_get('forum_containers', array()))) {
828
829
830
831
      drupal_add_link(array('rel' => 'alternate',
                            'type' => 'application/rss+xml',
                            'title' => 'RSS - '. $title,
                            'href' => url('taxonomy/term/'. $tid .'/0/feed')));
Dries's avatar
   
Dries committed
832

Dries's avatar
   
Dries committed
833
      $output .= theme('forum_topic_list', $tid, $topics, $sortby, $forum_per_page);
Dries's avatar
   
Dries committed
834
      $output .= theme('xml_icon', url("taxonomy/term/$tid/0/feed"));
Dries's avatar
   
Dries committed
835
    }
836
    $output .= '</div>';
Dries's avatar
   
Dries committed
837
838
  }
  else {
839
    drupal_set_title(t('No forums defined'));
Dries's avatar
   
Dries committed
840
    $output = '';
Dries's avatar
   
Dries committed
841
842
  }

843
  return $output;
Dries's avatar
   
Dries committed
844
845
}

Dries's avatar
   
Dries committed
846
/**
Dries's avatar
   
Dries committed
847
848
 * Format the forum listing.
 *
Dries's avatar
   
Dries committed
849
 * @ingroup themeable
Dries's avatar
   
Dries committed
850
 */
Dries's avatar
   
Dries committed
851
function theme_forum_list($forums, $parents, $tid) {
Dries's avatar
   
Dries committed
852
853
  global $user;

Dries's avatar
   
Dries committed
854
855
  if ($forums) {

Dries's avatar
   
Dries committed
856
    $header = array(t('Forum'), t('Topics'), t('Posts'), t('Last post'));
Dries's avatar
   
Dries committed
857
858

    foreach ($forums as $forum) {
Dries's avatar
   
Dries committed
859
      if ($forum->container) {
860
861
        $description  = '<div style="margin-left: '. ($forum->depth * 30) ."px;\">\n";
        $description .= ' <div class="name">'. l($forum->name, "forum/$forum->tid") ."</div>\n";
Dries's avatar
   
Dries committed
862
863

        if ($forum->description) {
864
          $description .= ' <div class="description">'. check_plain($forum->description) ."</div>\n";
Dries's avatar
   
Dries committed
865
866
867
        }
        $description .= "</div>\n";

Dries's avatar
   
Dries committed
868
        $rows[] = array(array('data' => $description, 'class' => 'container', 'colspan' => '4'));
869
      }
Dries's avatar
   
Dries committed
870
      else {
871
        $forum->old_topics = _forum_topics_read($forum->tid, $user->uid);
Dries's avatar
   
Dries committed
872
873
874
        if ($user->uid) {
          $new_topics = $forum->num_topics - $forum->old_topics;
        }
Dries's avatar
   
Dries committed
875
876
877
        else {
          $new_topics = 0;
        }
Dries's avatar
   
Dries committed
878

879
880
        $description  = '<div style="margin-left: '. ($forum->depth * 30) ."px;\">\n";
        $description .= ' <div class="name">'. l($forum->name, "forum/$forum->tid") ."</div>\n";
Dries's avatar
   
Dries committed
881

Dries's avatar
   
Dries committed
882
        if ($forum->description) {
883
          $description .= ' <div class="description">'. check_plain($forum->description) ."</div>\n";
Dries's avatar
   
Dries committed
884
885
        }
        $description .= "</div>\n";
Dries's avatar
   
Dries committed
886

Dries's avatar
   
Dries committed
887
        $rows[] = array(
Dries's avatar
   
Dries committed
888
          array('data' => $description, 'class' => 'forum'),
889
          array('data' => $forum->num_topics . ($new_topics ? '<br />'. l(t('%a new', array('%a' => $new_topics)), "forum/$forum->tid", NULL, NULL, 'new') : ''), 'class' => 'topics'),
Dries's avatar
   
Dries committed
890
891
          array('data' => $forum->num_posts, 'class' => 'posts'),
          array('data' => _forum_format($forum->last_post), 'class' => 'last-reply'));
Dries's avatar
   
Dries committed
892
      }
Dries's avatar
   
Dries committed
893
    }
Dries's avatar
   
Dries committed
894
895
896

    return theme('table', $header, $rows);

Dries's avatar
   
Dries committed
897
898
899
900
  }

}

Dries's avatar
   
Dries committed
901
/**
Dries's avatar
   
Dries committed
902
903
 * Format the topic listing.
 *
Dries's avatar
   
Dries committed
904
 * @ingroup themeable
Dries's avatar
   
Dries committed
905
 */
Dries's avatar
   
Dries committed
906
907
function theme_forum_topic_list($tid, $topics, $sortby, $forum_per_page) {
  global $forum_topic_list_header;
Dries's avatar
   
Dries committed
908
909

  if ($topics) {
Dries's avatar
   
Dries committed
910

Dries's avatar
   
Dries committed
911
912
    foreach ($topics as $topic) {
      // folder is new if topic is new or there are new comments since last visit
Dries's avatar
Dries committed
913
      if ($topic->tid != $tid) {
Dries's avatar
   
Dries committed
914
        $rows[] = array(
Dries's avatar
   
Dries committed
915
          array('data' => _forum_icon($topic->new, $topic->num_comments, $topic->comment_mode, $topic->sticky), 'class' => 'icon'),
916
          array('data' => check_plain($topic->title), 'class' => 'title'),
Dries's avatar
   
Dries committed
917
          array('data' => l(t('This topic has been moved'), "forum/$topic->tid"), 'colspan' => '3')
Dries's avatar
   
Dries committed
918
        );
Dries's avatar
   
Dries committed
919
920
      }
      else {
Dries's avatar
   
Dries committed
921
        $rows[] = array(
Dries's avatar
   
Dries committed
922
          array('data' => _forum_icon($topic->new, $topic->num_comments, $topic->comment_mode, $topic->sticky), 'class' => 'icon'),
Dries's avatar
   
Dries committed
923
924
          array('data' => l($topic->title, "node/$topic->nid"), 'class' => 'topic'),
          array('data' => $topic->num_comments . ($topic->new_replies ? '<br />'. l(t('%a new', array('%a' => $topic->new_replies)), "node/$topic->nid", NULL, NULL, 'new') : ''), 'class' => 'replies'),
Dries's avatar
   
Dries committed
925
926
          array('data' => _forum_format($topic), 'class' => 'created'),
          array('data' => _forum_format($topic->last_reply), 'class' => 'last-reply')
Dries's avatar
   
Dries committed
927
        );
Dries's avatar
   
Dries committed
928
929
930
      }
    }

Dries's avatar
   
Dries committed
931
932
    if ($pager = theme('pager', NULL, $forum_per_page, 0, tablesort_pager())) {
      $rows[] = array(array('data' => $pager, 'colspan' => '5', 'class' => 'pager'));
Dries's avatar
   
Dries committed
933
934
    }
  }
Dries's avatar
   
Dries committed
935

Dries's avatar
   
Dries committed
936
  $output .= theme('table', $forum_topic_list_header, $rows);
Dries's avatar
   
Dries committed
937

Dries's avatar
   
Dries committed
938
939
940
  return $output;
}

Dries's avatar
   
Dries committed
941
function _forum_icon($new_posts, $num_posts = 0, $comment_mode = 0, $sticky = 0) {
Dries's avatar
   
Dries committed
942

Dries's avatar
   
Dries committed
943
  $base_path = variable_get('forum_icon_path', '');
Dries's avatar
   
Dries committed
944
  if ($base_path) {
Dries's avatar
   
Dries committed
945
946
    if ($num_posts > variable_get('forum_hot_topic', 15)) {
      $icon = $new_posts ? 'hot-new' : 'hot';
Dries's avatar
   
Dries committed
947
948
    }
    else {
Dries's avatar
   
Dries committed
949
      $icon = $new_posts ? 'new' : 'default';
Dries's avatar
   
Dries committed
950
951
952
    }

    if ($comment_mode == 1) {
Dries's avatar
   
Dries committed
953
      $icon = 'closed';
Dries's avatar
   
Dries committed
954
955
    }

Dries's avatar
   
Dries committed
956
957
958
959
    if ($sticky == 1) {
      $icon = 'sticky';
    }

Dries's avatar
   
Dries committed
960
    // default
961
    $file = variable_get('forum_icon_path', 'misc') ."/forum-$icon.png";
Dries's avatar
   
Dries committed
962

Dries's avatar
   
Dries committed
963
    $output = theme('image', $file);
Dries's avatar
   
Dries committed
964
965
  }
  else {
Dries's avatar
   
Dries committed
966
    $output = '&nbsp;';
Dries's avatar
   
Dries committed
967
  }
Dries's avatar
   
Dries committed
968
969
970
971
972
973

  if ($new_posts) {
    $output = "<a name=\"new\">$output</a>";
  }

  return $output;
Dries's avatar
   
Dries committed
974
975
976
977
}

function _forum_user_last_visit($nid) {