[ Index ]
 

Code source de Drupal 5.3

Accédez au Source d'autres logiciels libres

Classes | Fonctions | Variables | Constantes | Tables

title

Body

[fermer]

/modules/forum/ -> forum.module (source)

   1  <?php
   2  // $Id: forum.module,v 1.375.2.6 2007/08/08 06:27:22 drumm Exp $
   3  
   4  /**
   5   * @file
   6   * Enable threaded discussions about general topics.
   7   */
   8  
   9  /**
  10   * Implementation of hook_help().
  11   */
  12  function forum_help($section) {
  13    switch ($section) {
  14      case 'admin/help#forum':
  15        $output = '<p>'. t('The forum module lets you create threaded discussion forums for a particular topic on your site. This is similar to a message board system such as phpBB. Forums are very useful because they allow community members to discuss topics with one another, and they are archived for future reference.') .'</p>';
  16        $output .= '<p>'. t('Forums can be organized under what are called <em>containers</em>. 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. Forum topics can be moved by selecting a different forum and can be left in the existing forum by selecting <em>leave a shadow copy</em>. Forum topics can also have their own URL.') .'</p>';
  17        $output .= '<p>'. t('Forums module <strong>requires Taxonomy and Comments module</strong> be enabled.') .'</p>';
  18        $output .= '<p>'. t('For more information please read the configuration and customization handbook <a href="@forum">Forum page</a>.', array('@forum' => 'http://drupal.org/handbook/modules/forum/')) .'</p>';
  19        return $output;
  20      case 'admin/content/forum':
  21        return '<p>'. t('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>';
  22      case 'admin/content/forum/add/container':
  23        return '<p>'. t('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>';
  24      case 'admin/content/forum/add/forum':
  25        return '<p>'. t('A forum holds discussion topics that are related. For example, a forum named "Fruit" might contain topics titled "Apples" and "Bananas".') .'</p>';
  26      case 'admin/content/forum/settings':
  27        return '<p>'. t('These settings provide the ability to fine tune the display of your forum topics.') .'</p>';
  28    }
  29  }
  30  
  31  /**
  32   * Implementation of hook_menu().
  33   */
  34  function forum_menu($may_cache) {
  35    $items = array();
  36  
  37    if ($may_cache) {
  38      $items[] = array('path' => 'forum',
  39        'title' => t('Forums'),
  40        'callback' => 'forum_page',
  41        'access' => user_access('access content'),
  42        'type' => MENU_SUGGESTED_ITEM);
  43      $items[] = array('path' => 'admin/content/forum',
  44        'title' => t('Forums'),
  45        'description' => t('Control forums and their hierarchy and change forum settings.'),
  46        'callback' => 'forum_overview',
  47        'access' => user_access('administer forums'),
  48        'type' => MENU_NORMAL_ITEM);
  49      $items[] = array('path' => 'admin/content/forum/list',
  50        'title' => t('List'),
  51        'access' => user_access('administer forums'),
  52        'type' => MENU_DEFAULT_LOCAL_TASK,
  53        'weight' => -10);
  54      $items[] = array('path' => 'admin/content/forum/add/container',
  55        'title' => t('Add container'),
  56        'callback' => 'forum_form_main',
  57        'callback arguments' => array('container'),
  58        'access' => user_access('administer forums'),
  59        'type' => MENU_LOCAL_TASK);
  60      $items[] = array('path' => 'admin/content/forum/add/forum',
  61        'title' => t('Add forum'),
  62        'callback' => 'forum_form_main',
  63        'callback arguments' => array('forum'),
  64        'access' => user_access('administer forums'),
  65        'type' => MENU_LOCAL_TASK);
  66      $items[] = array('path' => 'admin/content/forum/settings',
  67        'title' => t('Settings'),
  68        'callback' => 'drupal_get_form',
  69        'callback arguments' => array('forum_admin_settings'),
  70        'weight' => 5,
  71        'access' => user_access('administer forums'),
  72        'type' => MENU_LOCAL_TASK);
  73    }
  74    elseif (is_numeric(arg(5))) {
  75      $term = taxonomy_get_term(arg(5));
  76      // Check if this is a valid term.
  77      if ($term) {
  78        $items[] = array('path' => 'admin/content/forum/edit/container',
  79          'title' => t('Edit container'),
  80          'callback' => 'forum_form_main',
  81          'callback arguments' => array('container', (array)$term),
  82          'access' => user_access('administer forums'),
  83          'type' => MENU_CALLBACK);
  84        $items[] = array('path' => 'admin/content/forum/edit/forum',
  85          'title' => t('Edit forum'),
  86          'callback' => 'forum_form_main',
  87          'callback arguments' => array('forum', (array)$term),
  88          'access' => user_access('administer forums'),
  89          'type' => MENU_CALLBACK);
  90      }
  91    }
  92  
  93    return $items;
  94  }
  95  
  96  /**
  97   * Implementation of hook_node_info().
  98   */
  99  function forum_node_info() {
 100    return array(
 101      'forum' => array(
 102        'name' => t('Forum topic'),
 103        'module' => 'forum',
 104        'description' => t('Create a new topic for discussion in the forums.'),
 105        'title_label' => t('Subject'),
 106      )
 107    );
 108  }
 109  
 110  /**
 111   * Implementation of hook_access().
 112   */
 113  function forum_access($op, $node) {
 114    global $user;
 115  
 116    if ($op == 'create') {
 117      return user_access('create forum topics');
 118    }
 119  
 120    if ($op == 'update' || $op == 'delete') {
 121      if (user_access('edit own forum topics') && ($user->uid == $node->uid)) {
 122        return TRUE;
 123      }
 124    }
 125  }
 126  
 127  /**
 128   * Implementation of hook_perm().
 129   */
 130  function forum_perm() {
 131    return array('create forum topics', 'edit own forum topics', 'administer forums');
 132  }
 133  
 134  /**
 135   * Implementation of hook_nodeapi().
 136   */
 137  function forum_nodeapi(&$node, $op, $teaser, $page) {
 138    switch ($op) {
 139      case 'delete revision':
 140        db_query('DELETE FROM {forum} WHERE vid = %d', $node->vid);
 141        break;
 142    }
 143  }
 144  
 145  /**
 146   * Implementation of hook_taxonomy().
 147   */
 148  function forum_taxonomy($op, $type, $term = NULL) {
 149    if ($op == 'delete' && $term['vid'] == _forum_get_vid()) {
 150      switch ($type) {
 151        case 'term':
 152          $results = db_query('SELECT f.nid FROM {forum} f WHERE f.tid = %d', $term['tid']);
 153          while ($node = db_fetch_object($results)) {
 154            // node_delete will also remove any association with non-forum vocabularies.
 155            node_delete($node->nid);
 156          }
 157  
 158          // For containers, remove the tid from the forum_containers variable.
 159          $containers = variable_get('forum_containers', array());
 160          $key = array_search($term['tid'], $containers);
 161          if ($key !== FALSE) {
 162            unset($containers[$key]);
 163          }
 164          variable_set('forum_containers', $containers);
 165          break;
 166        case 'vocabulary':
 167          variable_del('forum_nav_vocabulary');
 168      }
 169    }
 170  }
 171  
 172  function forum_admin_settings() {
 173    $form = array();
 174    $number = drupal_map_assoc(array(5, 10, 15, 20, 25, 30, 35, 40, 50, 60, 80, 100, 150, 200, 250, 300, 350, 400, 500));
 175    $form['forum_hot_topic'] = array('#type' => 'select',
 176      '#title' => t('Hot topic threshold'),
 177      '#default_value' => variable_get('forum_hot_topic', 15),
 178      '#options' => $number,
 179      '#description' => t('The number of posts a topic must have to be considered hot.'),
 180    );
 181    $number = drupal_map_assoc(array(10, 25, 50, 75, 100));
 182    $form['forum_per_page'] = array('#type' => 'select',
 183      '#title' => t('Topics per page'),
 184      '#default_value' => variable_get('forum_per_page', 25),
 185      '#options' => $number,
 186      '#description' => t('The default number of topics displayed per page; links to browse older messages are automatically being displayed.'),
 187    );
 188    $forder = array(1 => t('Date - newest first'), 2 => t('Date - oldest first'), 3 => t('Posts - most active first'), 4=> t('Posts - least active first'));
 189    $form['forum_order'] = array('#type' => 'radios',
 190      '#title' => t('Default order'),
 191      '#default_value' => variable_get('forum_order', '1'),
 192      '#options' => $forder,
 193      '#description' => t('The default display order for topics.'),
 194    );
 195    return system_settings_form($form);
 196  }
 197  
 198  /**
 199   * Implementation of hook_form_alter().
 200   */
 201  function forum_form_alter($form_id, &$form) {
 202    // hide critical options from forum vocabulary
 203    if ($form_id == 'taxonomy_form_vocabulary') {
 204      if ($form['vid']['#value'] == _forum_get_vid()) {
 205        $form['help_forum_vocab'] = array(
 206          '#value' => t('This is the designated forum vocabulary. Some of the normal vocabulary options have been removed.'),
 207          '#weight' => -1,
 208        );
 209        $form['nodes']['forum'] = array('#type' => 'checkbox', '#value' => 1, '#title' => t('forum topic'), '#attributes' => array('disabled' => '' ), '#description' => t('forum topic is affixed to the forum vocabulary.'));
 210        $form['hierarchy'] = array('#type' => 'value', '#value' => 1);
 211        unset($form['relations']);
 212        unset($form['tags']);
 213        unset($form['multiple']);
 214        $form['required'] = array('#type' => 'value', '#value' => 1);
 215      }
 216      else {
 217        unset($form['nodes']['forum']);
 218      }
 219    }
 220  }
 221  
 222  /**
 223   * Implementation of hook_load().
 224   */
 225  function forum_load($node) {
 226    $forum = db_fetch_object(db_query('SELECT * FROM {forum} WHERE vid = %d', $node->vid));
 227  
 228    return $forum;
 229  }
 230  
 231  /**
 232   * Implementation of hook_block().
 233   *
 234   * Generates a block containing the currently active forum topics and the
 235   * most recently added forum topics.
 236   */
 237  function forum_block($op = 'list', $delta = 0, $edit = array()) {
 238    switch ($op) {
 239      case 'list':
 240        $blocks[0]['info'] = t('Active forum topics');
 241        $blocks[1]['info'] = t('New forum topics');
 242        return $blocks;
 243  
 244      case 'configure':
 245        $form['forum_block_num_'. $delta] = array('#type' => 'select', '#title' => t('Number of topics'), '#default_value' => variable_get('forum_block_num_'. $delta, '5'), '#options' => drupal_map_assoc(array(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)));
 246        return $form;
 247  
 248      case 'save':
 249        variable_set('forum_block_num_'. $delta, $edit['forum_block_num_'. $delta]);
 250        break;
 251  
 252      case 'view':
 253        if (user_access('access content')) {
 254          switch ($delta) {
 255            case 0:
 256              $title = t('Active forum topics');
 257              $sql = db_rewrite_sql("SELECT n.nid, n.title, l.comment_count, l.last_comment_timestamp 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");
 258              $result = db_query_range($sql, 0, variable_get('forum_block_num_0', '5'));
 259              if (db_num_rows($result)) {
 260                $content = node_title_list($result);
 261              }
 262              break;
 263  
 264            case 1:
 265              $title = t('New forum topics');
 266              $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");
 267              $result = db_query_range($sql, 0, variable_get('forum_block_num_1', '5'));
 268              if (db_num_rows($result)) {
 269                $content = node_title_list($result);
 270              }
 271              break;
 272          }
 273  
 274          if ($content) {
 275            $content .= '<div class="more-link">'. l(t('more'), 'forum', array('title' => t('Read the latest forum topics.'))) .'</div>';
 276          }
 277  
 278          $block['subject'] = $title;
 279          $block['content'] = $content;
 280  
 281          return $block;
 282        }
 283    }
 284  }
 285  
 286  /**
 287   * Implementation of hook_view().
 288   */
 289  function forum_view(&$node, $teaser = FALSE, $page = FALSE) {
 290    drupal_add_css(drupal_get_path('module', 'forum') .'/forum.css');
 291    if ($page) {
 292      $vocabulary = taxonomy_get_vocabulary(variable_get('forum_nav_vocabulary', ''));
 293      // Breadcrumb navigation
 294      $breadcrumb = array();
 295      $breadcrumb[] = array('path' => 'forum', 'title' => $vocabulary->name);
 296      if ($parents = taxonomy_get_parents_all($node->tid)) {
 297        $parents = array_reverse($parents);
 298        foreach ($parents as $p) {
 299          $breadcrumb[] = array('path' => 'forum/'. $p->tid, 'title' => $p->name);
 300        }
 301      }
 302      $breadcrumb[] = array('path' => 'node/'. $node->nid);
 303      menu_set_location($breadcrumb);
 304    }
 305  
 306    $node = node_prepare($node, $teaser);
 307    if (!$teaser) {
 308      $node->content['forum_navigation'] = array(
 309        '#value' => theme('forum_topic_navigation', $node),
 310        '#weight' => 100,
 311      );
 312    }
 313    return $node;
 314  }
 315  
 316  /**
 317   * Implementation of hook_submit().
 318   *
 319   * Check in particular that only a "leaf" term in the associated taxonomy
 320   * vocabulary is selected, not a "container" term.
 321   */
 322  function forum_submit(&$node) {
 323    // Make sure all fields are set properly:
 324    $node->icon = !empty($node->icon) ? $node->icon : '';
 325  
 326    if ($node->taxonomy) {
 327      // Get the forum terms from the (cached) tree
 328      $tree = taxonomy_get_tree(_forum_get_vid());
 329      if ($tree) {
 330        foreach ($tree as $term) {
 331          $forum_terms[] = $term->tid;
 332        }
 333      }
 334      foreach ($node->taxonomy as $term) {
 335        if (in_array($term, $forum_terms)) {
 336          $node->tid = $term;
 337        }
 338      }
 339      $old_tid = db_result(db_query_range("SELECT tid FROM {forum} WHERE nid = %d ORDER BY vid DESC", $node->nid, 0,1));
 340      if ($old_tid) {
 341        if (($node->tid != $old_tid) && $node->shadow) {
 342          // A shadow copy needs to be created. Retain new term and add old term.
 343          $node->taxonomy[] = $old_tid;
 344        }
 345      }
 346    }
 347  }
 348  
 349  /**
 350   * Implementation of hook_validate().
 351   *
 352   * Check in particular that only a "leaf" term in the associated taxonomy
 353   * vocabulary is selected, not a "container" term.
 354   */
 355  function forum_validate($node) {
 356    if ($node->taxonomy) {
 357      // Extract the node's proper topic ID.
 358      $vocabulary = variable_get('forum_nav_vocabulary', '');
 359      $containers = variable_get('forum_containers', array());
 360      foreach ($node->taxonomy as $term) {
 361        if (db_result(db_query('SELECT COUNT(*) FROM {term_data} WHERE tid = %d AND vid = %d', $term, $vocabulary))) {
 362          if (in_array($term, $containers)) {
 363            $term = taxonomy_get_term($term);
 364            form_set_error('taxonomy', t('The item %forum is only a container for forums. Please select one of the forums below it.', array('%forum' => $term->name)));
 365          }
 366        }
 367      }
 368    }
 369  }
 370  
 371  /**
 372   * Implementation of hook_update().
 373   */
 374  function forum_update($node) {
 375    if ($node->revision) {
 376      db_query("INSERT INTO {forum} (nid, vid, tid) VALUES (%d, %d, %d)", $node->nid, $node->vid, $node->tid);
 377    }
 378    else {
 379      db_query('UPDATE {forum} SET tid = %d WHERE vid = %d', $node->tid, $node->vid);
 380    }
 381  }
 382  
 383  /**
 384   * Implementation of hook_form().
 385   */
 386  function forum_form(&$node) {
 387    $type = node_get_types('type', $node);
 388    $form['title'] = array('#type' => 'textfield', '#title' => check_plain($type->title_label), '#default_value' => $node->title, '#required' => TRUE, '#weight' => -5);
 389  
 390    if ($node->nid) {
 391      $forum_terms = taxonomy_node_get_terms_by_vocabulary(_forum_get_vid(), $node->nid);
 392      // if editing, give option to leave shadows
 393      $shadow = (count($forum_terms) > 1);
 394      $form['shadow'] = array('#type' => 'checkbox', '#title' => t('Leave shadow copy'), '#default_value' => $shadow, '#description' => t('If you move this topic, you can leave a link in the old forum to the new forum.'));
 395    }
 396  
 397    $form['body_filter']['body'] = array('#type' => 'textarea', '#title' => check_plain($type->body_label), '#default_value' => $node->body, '#rows' => 20, '#required' => TRUE);
 398    $form['body_filter']['format'] = filter_form($node->format);
 399  
 400    return $form;
 401  }
 402  
 403  /**
 404   * Implementation of hook_prepare; assign forum taxonomy when adding a topic from within a forum.
 405   */
 406  function forum_prepare(&$node) {
 407    if (!$node->nid) {
 408      // new topic
 409      $node->taxonomy[arg(3)]->vid = _forum_get_vid();
 410      $node->taxonomy[arg(3)]->tid = arg(3);
 411    }
 412  }
 413  
 414  /**
 415   * Implementation of hook_insert().
 416   */
 417  function forum_insert($node) {
 418    db_query('INSERT INTO {forum} (nid, vid, tid) VALUES (%d, %d, %d)', $node->nid, $node->vid, $node->tid);
 419  }
 420  
 421  /**
 422   * Implementation of hook_delete().
 423   */
 424  function forum_delete(&$node) {
 425    db_query('DELETE FROM {forum} WHERE nid = %d', $node->nid);
 426  }
 427  
 428  /**
 429   * Returns a form for adding a container to the forum vocabulary
 430   *
 431   * @param $edit Associative array containing a container term to be added or edited.
 432   */
 433  function forum_form_container($edit = array()) {
 434    // Handle a delete operation.
 435    $form['name'] = array(
 436      '#title' => t('Container name'),
 437      '#type' => 'textfield',
 438      '#default_value' => $edit['name'],
 439      '#maxlength' =>  64,
 440      '#description' => t('The container name is used to identify related forums.'),
 441      '#required' => TRUE
 442    );
 443  
 444    $form['description'] = array(
 445      '#type' => 'textarea',
 446      '#title' => t('Description'),
 447      '#default_value' => $edit['description'],
 448      '#description' => t('The container description can give users more information about the forums it contains.')
 449    );
 450    $form['parent']['#tree'] = TRUE;
 451    $form['parent'][0] = _forum_parent_select($edit['tid'], t('Parent'), 'container');
 452    $form['weight'] = array('#type' => 'weight',
 453      '#title' => t('Weight'),
 454      '#default_value' => $edit['weight'],
 455      '#description' => 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.')
 456    );
 457  
 458    $form['vid'] = array('#type' => 'hidden',
 459      '#value' => _forum_get_vid());
 460    $form['submit'] = array(
 461      '#type' => 'submit',
 462      '#value' => t('Submit')
 463    );
 464    if ($edit['tid']) {
 465      $form['delete'] = array('#type' => 'submit', '#value' => t('Delete'));
 466      $form['tid'] = array('#type' => 'value', '#value' => $edit['tid']);
 467    }
 468    $form['#base'] = 'forum_form';
 469  
 470    return $form;
 471  }
 472  
 473  function forum_form_main($type, $edit = array()) {
 474    if ($_POST['op'] == t('Delete') || $_POST['confirm']) {
 475      return drupal_get_form('forum_confirm_delete', $edit['tid']);
 476    }
 477    switch ($type) {
 478      case 'forum':
 479        return drupal_get_form('forum_form_forum', $edit);
 480        break;
 481      case 'container':
 482        return drupal_get_form('forum_form_container', $edit);
 483        break;
 484    }
 485  }
 486  
 487  /**
 488   * Returns a form for adding a forum to the forum vocabulary
 489   *
 490   * @param $edit Associative array containing a forum term to be added or edited.
 491   */
 492  function forum_form_forum($edit = array()) {
 493    $form['name'] = array('#type' => 'textfield',
 494      '#title' => t('Forum name'),
 495      '#default_value' => $edit['name'],
 496      '#maxlength' =>  64,
 497      '#description' => t('The forum name is used to identify related discussions.'),
 498      '#required' => TRUE,
 499    );
 500    $form['description'] = array('#type' => 'textarea',
 501      '#title' => t('Description'),
 502      '#default_value' => $edit['description'],
 503      '#description' => t('The forum description can give users more information about the discussion topics it contains.'),
 504    );
 505    $form['parent']['#tree'] = TRUE;
 506    $form['parent'][0] = _forum_parent_select($edit['tid'], t('Parent'), 'forum');
 507    $form['weight'] = array('#type' => 'weight',
 508      '#title' => t('Weight'),
 509      '#default_value' => $edit['weight'],
 510      '#description' => t('When listing forums, those with lighter (smaller) weights get listed before containers with heavier (larger) weights. Forums with equal weights are sorted alphabetically.'),
 511    );
 512  
 513    $form['vid'] = array('#type' => 'hidden', '#value' => _forum_get_vid());
 514    $form['submit' ] = array('#type' => 'submit', '#value' => t('Submit'));
 515    if ($edit['tid']) {
 516      $form['delete'] = array('#type' => 'submit', '#value' => t('Delete'));
 517      $form['tid'] = array('#type' => 'hidden', '#value' => $edit['tid']);
 518    }
 519    $form['#base'] = 'forum_form';
 520  
 521    return $form;
 522  }
 523  
 524  /**
 525   * Process forum form and container form submissions.
 526   */
 527  function forum_form_submit($form_id, $form_values) {
 528    if ($form_id == 'forum_form_container') {
 529      $container = TRUE;
 530      $type = t('forum container');
 531    }
 532    else {
 533      $container = FALSE;
 534      $type = t('forum');
 535    }
 536  
 537    $status = taxonomy_save_term($form_values);
 538    switch ($status) {
 539      case SAVED_NEW:
 540        if ($container) {
 541          $containers = variable_get('forum_containers', array());
 542          $containers[] = $form_values['tid'];
 543          variable_set('forum_containers', $containers);
 544        }
 545        drupal_set_message(t('Created new @type %term.', array('%term' => $form_values['name'], '@type' => $type)));
 546        break;
 547      case SAVED_UPDATED:
 548        drupal_set_message(t('The @type %term has been updated.', array('%term' => $form_values['name'], '@type' => $type)));
 549        break;
 550    }
 551    return 'admin/content/forum';
 552  }
 553  
 554  /**
 555   * Returns a confirmation page for deleting a forum taxonomy term.
 556   *
 557   * @param $tid ID of the term to be deleted
 558   */
 559  function forum_confirm_delete($tid) {
 560    $term = taxonomy_get_term($tid);
 561  
 562    $form['tid'] = array('#type' => 'value', '#value' => $tid);
 563    $form['name'] = array('#type' => 'value', '#value' => $term->name);
 564  
 565    return confirm_form($form, t('Are you sure you want to delete the forum %name?', array('%name' => $term->name)), 'admin/content/forum', t('Deleting a forum or container will delete all sub-forums and associated posts as well. This action cannot be undone.'), t('Delete'), t('Cancel'));
 566  }
 567  
 568  /**
 569   * Implementation of forms api _submit call. Deletes a forum after confirmation.
 570   */
 571  function forum_confirm_delete_submit($form_id, $form_values) {
 572    taxonomy_del_term($form_values['tid']);
 573    drupal_set_message(t('The forum %term and all sub-forums and associated posts have been deleted.', array('%term' => $form_values['name'])));
 574    watchdog('content', t('forum: deleted %term and all its sub-forums and associated posts.', array('%term' => $form_values['name'])));
 575  
 576    return 'admin/content/forum';
 577  }
 578  
 579  /**
 580   * Returns an overview list of existing forums and containers
 581   */
 582  function forum_overview() {
 583    $header = array(t('Name'), t('Operations'));
 584  
 585    $tree = taxonomy_get_tree(_forum_get_vid());
 586    if ($tree) {
 587      foreach ($tree as $term) {
 588        if (in_array($term->tid, variable_get('forum_containers', array()))) {
 589          $rows[] = array(str_repeat(' -- ', $term->depth) .' '. l($term->name, 'forum/'. $term->tid), l(t('edit container'), 'admin/content/forum/edit/container/'. $term->tid));
 590        }
 591        else {
 592          $rows[] = array(str_repeat(' -- ', $term->depth) .' '. l($term->name, 'forum/'. $term->tid), l(t('edit forum'), 'admin/content/forum/edit/forum/'. $term->tid));
 593         }
 594  
 595      }
 596    }
 597    else {
 598      $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/content/forum/add/container'), '@forum' => url('admin/content/forum/add/forum'))) . '</em>', 'colspan' => 2));
 599    }
 600    return theme('table', $header, $rows);
 601  }
 602  
 603  /**
 604   * Returns a select box for available parent terms
 605   *
 606   * @param $tid ID of the term which is being added or edited
 607   * @param $title Title to display the select box with
 608   * @param $child_type Whether the child is forum or container
 609   */
 610  function _forum_parent_select($tid, $title, $child_type) {
 611  
 612    $parents = taxonomy_get_parents($tid);
 613    if ($parents) {
 614      $parent = array_shift($parents);
 615      $parent = $parent->tid;
 616    }
 617    else {
 618      $parent = 0;
 619    }
 620  
 621    $children = taxonomy_get_tree(_forum_get_vid(), $tid);
 622  
 623    // A term can't be the child of itself, nor of its children.
 624    foreach ($children as $child) {
 625      $exclude[] = $child->tid;
 626    }
 627    $exclude[] = $tid;
 628  
 629    $tree = taxonomy_get_tree(_forum_get_vid());
 630    $options[0] = '<'. t('root') .'>';
 631    if ($tree) {
 632      foreach ($tree as $term) {
 633        if (!in_array($term->tid, $exclude)) {
 634          $options[$term->tid] = str_repeat(' -- ', $term->depth) . $term->name;
 635        }
 636      }
 637    }
 638    if ($child_type == 'container') {
 639      $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.');
 640    }
 641    else if ($child_type == 'forum') {
 642      $description = t('You may place your forum inside a parent container or forum, or at the top (root) level of your forum.');
 643    }
 644  
 645    return array('#type' => 'select', '#title' => $title, '#default_value' => $parent, '#options' => $options, '#description' => $description, '#required' => TRUE);
 646  }
 647  
 648  function forum_link_alter(&$node, &$links) {
 649    foreach ($links as $module => $link) {
 650      if (strstr($module, 'taxonomy_term')) {
 651        // Link back to the forum and not the taxonomy term page. We'll only
 652        // do this if the taxonomy term in question belongs to forums.
 653        $tid = str_replace('taxonomy/term/', '', $link['href']);
 654        $term = taxonomy_get_term($tid);
 655        if ($term->vid == _forum_get_vid()) {
 656          $links[$module]['href'] = str_replace('taxonomy/term', 'forum', $link['href']);
 657        }
 658      }
 659    }
 660  }
 661  
 662  /**
 663   * Returns the vocabulary id for forum navigation.
 664   */
 665  function _forum_get_vid() {
 666    $vid = variable_get('forum_nav_vocabulary', '');
 667    if (empty($vid)) {
 668      // Check to see if a forum vocabulary exists
 669      $vid = db_result(db_query("SELECT vid FROM {vocabulary} WHERE module = '%s'", 'forum'));
 670      if (!$vid) {
 671        // Create the forum vocabulary. Assign the vocabulary a low weight so
 672        // it will appear first in forum topic create and edit forms.
 673        $edit = array('name' => t('Forums'), 'multiple' => 0, 'required' => 1, 'hierarchy' => 1, 'relations' => 0, 'module' => 'forum', 'weight' => -10, 'nodes' => array('forum' => 1));
 674        taxonomy_save_vocabulary($edit);
 675        $vid = $edit['vid'];
 676      }
 677      variable_set('forum_nav_vocabulary', $vid);
 678    }
 679  
 680    return $vid;
 681  }
 682  
 683  /**
 684   * Formats a topic for display
 685   *
 686   * @TODO Give a better description. Not sure where this function is used yet.
 687   */
 688  function _forum_format($topic) {
 689    if ($topic && $topic->timestamp) {
 690      return t('@time ago<br />by !author', array('@time' => format_interval(time() - $topic->timestamp), '!author' => theme('username', $topic)));
 691    }
 692    else {
 693      return t('n/a');
 694    }
 695  }
 696  
 697  /**
 698   * Returns a list of all forums for a given taxonomy id
 699   *
 700   * Forum objects contain the following fields
 701   * -num_topics Number of topics in the forum
 702   * -num_posts Total number of posts in all topics
 703   * -last_post Most recent post for the forum
 704   *
 705   * @param $tid
 706   *   Taxonomy ID of the vocabulary that holds the forum list.
 707   * @return
 708   *   Array of object containing the forum information.
 709   */
 710  function forum_get_forums($tid = 0) {
 711  
 712    $forums = array();
 713    $_forums = taxonomy_get_tree(variable_get('forum_nav_vocabulary', ''), $tid);
 714  
 715    if (count($_forums)) {
 716  
 717      $counts = array();
 718  
 719      $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";
 720      $sql = db_rewrite_sql($sql);
 721      $_counts = db_query($sql, $forum->tid);
 722      while ($count = db_fetch_object($_counts)) {
 723        $counts[$count->tid] = $count;
 724      }
 725    }
 726  
 727    foreach ($_forums as $forum) {
 728      if (in_array($forum->tid, variable_get('forum_containers', array()))) {
 729        $forum->container = 1;
 730      }
 731  
 732      if ($counts[$forum->tid]) {
 733        $forum->num_topics = $counts[$forum->tid]->topic_count;
 734        $forum->num_posts = $counts[$forum->tid]->topic_count + $counts[$forum->tid]->comment_count;
 735      }
 736      else {
 737        $forum->num_topics = 0;
 738        $forum->num_posts = 0;
 739      }
 740  
 741      // This query does not use full ANSI syntax since MySQL 3.x does not support
 742      // table1 INNER JOIN table2 INNER JOIN table3 ON table2_criteria ON table3_criteria
 743      // used to join node_comment_statistics to users.
 744      $sql = "SELECT ncs.last_comment_timestamp, IF (ncs.last_comment_uid != 0, u2.name, ncs.last_comment_name) AS last_comment_name, ncs.last_comment_uid FROM {node} n INNER JOIN {users} u1 ON n.uid = u1.uid INNER JOIN {term_node} tn ON n.nid = tn.nid INNER JOIN {node_comment_statistics} ncs ON n.nid = ncs.nid INNER JOIN {users} u2 ON ncs.last_comment_uid=u2.uid WHERE n.status = 1 AND n.type='forum' AND tn.tid = %d ORDER BY ncs.last_comment_timestamp DESC";
 745      $sql = db_rewrite_sql($sql);
 746      $topic = db_fetch_object(db_query_range($sql, $forum->tid, 0, 1));
 747  
 748      $last_post = new stdClass();
 749      $last_post->timestamp = $topic->last_comment_timestamp;
 750      $last_post->name = $topic->last_comment_name;
 751      $last_post->uid = $topic->last_comment_uid;
 752      $forum->last_post = $last_post;
 753  
 754      $forums[$forum->tid] = $forum;
 755    }
 756  
 757    return $forums;
 758  }
 759  
 760  /**
 761   * Calculate the number of nodes the user has not yet read and are newer
 762   * than NODE_NEW_LIMIT.
 763   */
 764  function _forum_topics_unread($term, $uid) {
 765    $sql = "SELECT COUNT(n.nid) FROM {node} n INNER JOIN {term_node} tn ON n.nid = tn.nid AND tn.tid = %d LEFT JOIN {history} h ON n.nid = h.nid AND h.uid = %d WHERE n.status = 1 AND n.type = 'forum' AND n.created > %d AND h.nid IS NULL";
 766    $sql = db_rewrite_sql($sql);
 767    return db_result(db_query($sql, $term, $uid, NODE_NEW_LIMIT));
 768  }
 769  
 770  function forum_get_topics($tid, $sortby, $forum_per_page) {
 771    global $user, $forum_topic_list_header;
 772  
 773    $forum_topic_list_header = array(
 774      array('data' => '&nbsp;', 'field' => NULL),
 775      array('data' => t('Topic'), 'field' => 'n.title'),
 776      array('data' => t('Replies'), 'field' => 'l.comment_count'),
 777      array('data' => t('Created'), 'field' => 'n.created'),
 778      array('data' => t('Last reply'), 'field' => 'l.last_comment_timestamp'),
 779    );
 780  
 781    $order = _forum_get_topic_order($sortby);
 782    for ($i = 0; $i < count($forum_topic_list_header); $i++) {
 783      if ($forum_topic_list_header[$i]['field'] == $order['field']) {
 784        $forum_topic_list_header[$i]['sort'] = $order['sort'];
 785      }
 786    }
 787  
 788    $term = taxonomy_get_term($tid);
 789  
 790    $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 != 0, cu.name, l.last_comment_name) AS last_comment_name, l.last_comment_uid, l.comment_count AS num_comments FROM {node_comment_statistics} l, {users} cu, {term_node} r, {users} u, {forum} f, {node} n 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.vid = f.vid");
 791    $sql .= tablesort_sql($forum_topic_list_header, 'n.sticky DESC,');
 792    $sql .= ', n.created DESC';  // Always add a secondary sort order so that the news forum topics are on top.
 793  
 794    $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'");
 795  
 796    $result = pager_query($sql, $forum_per_page, 0, $sql_count, $tid);
 797    $topics = array();
 798    while ($topic = db_fetch_object($result)) {
 799      if ($user->uid) {
 800        // folder is new if topic is new or there are new comments since last visit
 801        if ($topic->tid != $tid) {
 802          $topic->new = 0;
 803        }
 804        else {
 805          $history = _forum_user_last_visit($topic->nid);
 806          $topic->new_replies = comment_num_new($topic->nid, $history);
 807          $topic->new = $topic->new_replies || ($topic->timestamp > $history);
 808        }
 809      }
 810      else {
 811        // Do not track "new replies" status for topics if the user is anonymous.
 812        $topic->new_replies = 0;
 813        $topic->new = 0;
 814      }
 815  
 816      if ($topic->num_comments > 0) {
 817        $last_reply = new stdClass();
 818        $last_reply->timestamp = $topic->last_comment_timestamp;
 819        $last_reply->name = $topic->last_comment_name;
 820        $last_reply->uid = $topic->last_comment_uid;
 821        $topic->last_reply = $last_reply;
 822      }
 823      $topics[] = $topic;
 824    }
 825  
 826    return $topics;
 827  }
 828  
 829  /**
 830   * Finds the first unread node for a given forum.
 831   */
 832  function _forum_new($tid) {
 833    global $user;
 834  
 835    $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";
 836    $sql = db_rewrite_sql($sql);
 837    $nid = db_result(db_query_range($sql, $user->uid, $tid, NODE_NEW_LIMIT, 0, 1));
 838  
 839    return $nid ? $nid : 0;
 840  }
 841  
 842  /**
 843   * Menu callback; prints a forum listing.
 844   */
 845  function forum_page($tid = 0) {
 846    drupal_add_css(drupal_get_path('module', 'forum') .'/forum.css');
 847    $forum_per_page = variable_get('forum_per_page', 25);
 848    $sortby = variable_get('forum_order', 1);
 849  
 850    $forums = forum_get_forums($tid);
 851    $parents = taxonomy_get_parents_all($tid);
 852    if ($tid && !in_array($tid, variable_get('forum_containers', array()))) {
 853      $topics = forum_get_topics($tid, $sortby, $forum_per_page);
 854    }
 855  
 856    return theme('forum_display', $forums, $topics, $parents, $tid, $sortby, $forum_per_page);
 857  }
 858  
 859  /**
 860   * Format the forum body.
 861   *
 862   * @ingroup themeable
 863   */
 864  function theme_forum_display($forums, $topics, $parents, $tid, $sortby, $forum_per_page) {
 865    global $user;
 866    // forum list, topics list, topic browser and 'add new topic' link
 867  
 868    $vocabulary = taxonomy_get_vocabulary(variable_get('forum_nav_vocabulary', ''));
 869    $title = $vocabulary->name;
 870  
 871    // Breadcrumb navigation:
 872    $breadcrumb = array();
 873    if ($tid) {
 874      $breadcrumb[] = array('path' => 'forum', 'title' => $title);
 875    }
 876  
 877    if ($parents) {
 878      $parents = array_reverse($parents);
 879      foreach ($parents as $p) {
 880        if ($p->tid == $tid) {
 881          $title = $p->name;
 882        }
 883        else {
 884          $breadcrumb[] = array('path' => 'forum/'. $p->tid, 'title' => $p->name);
 885        }
 886      }
 887    }
 888  
 889    drupal_set_title(check_plain($title));
 890  
 891    $breadcrumb[] = array('path' => $_GET['q']);
 892    menu_set_location($breadcrumb);
 893  
 894    if (count($forums) || count($parents)) {
 895      $output  = '<div id="forum">';
 896      $output .= '<ul>';
 897  
 898      if (user_access('create forum topics')) {
 899        $output .= '<li>'. l(t('Post new forum topic.'), "node/add/forum/$tid") .'</li>';
 900      }
 901      else if ($user->uid) {
 902        $output .= '<li>'. t('You are not allowed to post a new forum topic.') .'</li>';
 903      }
 904      else {
 905        $output .= '<li>'. t('<a href="@login">Login</a> to post a new forum topic.', array('@login' => url('user/login', drupal_get_destination()))) .'</li>';
 906      }
 907      $output .= '</ul>';
 908  
 909      $output .= theme('forum_list', $forums, $parents, $tid);
 910  
 911      if ($tid && !in_array($tid, variable_get('forum_containers', array()))) {
 912        $output .= theme('forum_topic_list', $tid, $topics, $sortby, $forum_per_page);
 913        drupal_add_feed(url('taxonomy/term/'. $tid .'/0/feed'), 'RSS - '. $title);
 914      }
 915      $output .= '</div>';
 916    }
 917    else {
 918      drupal_set_title(t('No forums defined'));
 919      $output = '';
 920    }
 921  
 922    return $output;
 923  }
 924  
 925  /**
 926   * Format the forum listing.
 927   *
 928   * @ingroup themeable
 929   */
 930  function theme_forum_list($forums, $parents, $tid) {
 931    global $user;
 932  
 933    if ($forums) {
 934  
 935      $header = array(t('Forum'), t('Topics'), t('Posts'), t('Last post'));
 936  
 937      foreach ($forums as $forum) {
 938        if ($forum->container) {
 939          $description  = '<div style="margin-left: '. ($forum->depth * 30) ."px;\">\n";
 940          $description .= ' <div class="name">'. l($forum->name, "forum/$forum->tid") ."</div>\n";
 941  
 942          if ($forum->description) {
 943            $description .= ' <div class="description">'. filter_xss_admin($forum->description) ."</div>\n";
 944          }
 945          $description .= "</div>\n";
 946  
 947          $rows[] = array(array('data' => $description, 'class' => 'container', 'colspan' => '4'));
 948        }
 949        else {
 950          $new_topics = _forum_topics_unread($forum->tid, $user->uid);
 951          $forum->old_topics = $forum->num_topics - $new_topics;
 952          if (!$user->uid) {
 953            $new_topics = 0;
 954          }
 955  
 956          $description  = '<div style="margin-left: '. ($forum->depth * 30) ."px;\">\n";
 957          $description .= ' <div class="name">'. l($forum->name, "forum/$forum->tid") ."</div>\n";
 958  
 959          if ($forum->description) {
 960            $description .= ' <div class="description">'. filter_xss_admin($forum->description) ."</div>\n";
 961          }
 962          $description .= "</div>\n";
 963  
 964          $rows[] = array(
 965            array('data' => $description, 'class' => 'forum'),
 966            array('data' => $forum->num_topics . ($new_topics ? '<br />'. l(format_plural($new_topics, '1 new', '@count new'), "forum/$forum->tid", NULL, NULL, 'new') : ''), 'class' => 'topics'),
 967            array('data' => $forum->num_posts, 'class' => 'posts'),
 968            array('data' => _forum_format($forum->last_post), 'class' => 'last-reply'));
 969        }
 970      }
 971  
 972      return theme('table', $header, $rows);
 973  
 974    }
 975  
 976  }
 977  
 978  /**
 979   * Format the topic listing.
 980   *
 981   * @ingroup themeable
 982   */
 983  function theme_forum_topic_list($tid, $topics, $sortby, $forum_per_page) {
 984    global $forum_topic_list_header;
 985    $rows = array();
 986    if ($topics) {
 987  
 988      foreach ($topics as $topic) {
 989        // folder is new if topic is new or there are new comments since last visit
 990        if ($topic->tid != $tid) {
 991          $rows[] = array(
 992            array('data' => theme('forum_icon', $topic->new, $topic->num_comments, $topic->comment_mode, $topic->sticky), 'class' => 'icon'),
 993            array('data' => check_plain($topic->title), 'class' => 'title'),
 994            array('data' => l(t('This topic has been moved'), "forum/$topic->tid"), 'colspan' => '3')
 995          );
 996        }
 997        else {
 998          $rows[] = array(
 999            array('data' => theme('forum_icon', $topic->new, $topic->num_comments, $topic->comment_mode, $topic->sticky), 'class' => 'icon'),
1000            array('data' => l($topic->title, "node/$topic->nid"), 'class' => 'topic'),
1001            array('data' => $topic->num_comments . ($topic->new_replies ? '<br />'. l(format_plural($topic->new_replies, '1 new', '@count new'), "node/$topic->nid", NULL, NULL, 'new') : ''), 'class' => 'replies'),
1002            array('data' => _forum_format($topic), 'class' => 'created'),
1003            array('data' => _forum_format(isset($topic->last_reply) ? $topic->last_reply : NULL), 'class' => 'last-reply')
1004          );
1005        }
1006      }
1007    }
1008  
1009    $output = theme('table', $forum_topic_list_header, $rows);
1010    $output .= theme('pager', NULL, $forum_per_page, 0);
1011  
1012    return $output;
1013  }
1014  
1015  /**
1016   * Format the icon for each individual topic.
1017   *
1018   * @ingroup themeable
1019   */
1020  function theme_forum_icon($new_posts, $num_posts = 0, $comment_mode = 0, $sticky = 0) {
1021  
1022    if ($num_posts > variable_get('forum_hot_topic', 15)) {
1023      $icon = $new_posts ? 'hot-new' : 'hot';
1024    }
1025    else {
1026      $icon = $new_posts ? 'new' : 'default';
1027    }
1028  
1029    if ($comment_mode == COMMENT_NODE_READ_ONLY || $comment_mode == COMMENT_NODE_DISABLED) {
1030      $icon = 'closed';
1031    }
1032  
1033    if ($sticky == 1) {
1034      $icon = 'sticky';
1035    }
1036  
1037    $output = theme('image', "misc/forum-$icon.png");
1038  
1039    if ($new_posts) {
1040      $output = "<a name=\"new\">$output</a>";
1041    }
1042  
1043    return $output;
1044  }
1045  
1046  /**
1047   * Format the next/previous forum topic navigation links.
1048   *
1049   * @ingroup themeable
1050   */
1051  function theme_forum_topic_navigation($node) {
1052    $output = '';
1053  
1054    // get previous and next topic
1055    $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));
1056    $result = db_query(db_rewrite_sql($sql), $node->tid);
1057  
1058    $stop = 0;
1059    while ($topic = db_fetch_object($result)) {
1060      if ($stop == 1) {
1061        $next = new stdClass();
1062        $next->nid = $topic->nid;
1063        $next->title = $topic->title;
1064        break;
1065      }
1066      if ($topic->nid == $node->nid) {
1067        $stop = 1;
1068      }
1069      else {
1070        $prev = new stdClass();
1071        $prev->nid = $topic->nid;
1072        $prev->title = $topic->title;
1073      }
1074    }
1075  
1076    if ($prev || $next) {
1077      $output .= '<div class="forum-topic-navigation clear-block">';
1078  
1079      if ($prev) {
1080        $output .= l(t('‹ ') . $prev->title, 'node/'. $prev->nid, array('class' => 'topic-previous', 'title' => t('Go to previous forum topic')));
1081      }
1082      if ($prev && $next) {
1083        // Word break (a is an inline element)
1084        $output .= ' ';
1085      }
1086      if (!empty($next)) {
1087        $output .= l($next->title . t(' ›'), 'node/'. $next->nid, array('class' => 'topic-next', 'title' => t('Go to next forum topic')));
1088      }
1089  
1090      $output .= '</div>';
1091    }
1092  
1093    return $output;
1094  }
1095  
1096  function _forum_user_last_visit($nid) {
1097    global $user;
1098    static $history = array();
1099  
1100    if (empty($history)) {
1101      $result = db_query('SELECT nid, timestamp FROM {history} WHERE uid = %d', $user->uid);
1102      while ($t = db_fetch_object($result)) {
1103        $history[$t->nid] = $t->timestamp > NODE_NEW_LIMIT ? $t->timestamp : NODE_NEW_LIMIT;
1104      }
1105    }
1106    return isset($history[$nid]) ? $history[$nid] : NODE_NEW_LIMIT;
1107  }
1108  
1109  function _forum_get_topic_order($sortby) {
1110    switch ($sortby) {
1111      case 1:
1112        return array('field' => 'l.last_comment_timestamp', 'sort' => 'desc');
1113        break;
1114      case 2:
1115        return array('field' => 'l.last_comment_timestamp', 'sort' => 'asc');
1116        break;
1117      case 3:
1118        return array('field' => 'l.comment_count', 'sort' => 'desc');
1119        break;
1120      case 4:
1121        return array('field' => 'l.comment_count', 'sort' => 'asc');
1122        break;
1123    }
1124  }
1125  
1126  function _forum_get_topic_order_sql($sortby) {
1127    $order = _forum_get_topic_order($sortby);
1128    return $order['field'] .' '. $order['sort'];
1129  }
1130  
1131  


Généré le : Fri Nov 30 16:20:15 2007 par Balluche grâce à PHPXref 0.7
  Clicky Web Analytics