[ Index ] |
|
Code source de Drupal 5.3 |
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' => ' ', '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
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Fri Nov 30 16:20:15 2007 | par Balluche grâce à PHPXref 0.7 |
![]() |