annotate modules/comment/comment.module @ 1:c1f4ac30525a 6.0

Drupal 6.0
author Franck Deroche <webmaster@defr.org>
date Tue, 23 Dec 2008 14:28:28 +0100
parents
children 2427550111ae
rev   line source
webmaster@1 1 <?php
webmaster@1 2 // $Id: comment.module,v 1.617 2008/01/25 16:19:12 goba Exp $
webmaster@1 3
webmaster@1 4 /**
webmaster@1 5 * @file
webmaster@1 6 * Enables users to comment on published content.
webmaster@1 7 *
webmaster@1 8 * When enabled, the Drupal comment module creates a discussion
webmaster@1 9 * board for each Drupal node. Users can post comments to discuss
webmaster@1 10 * a forum topic, weblog post, story, collaborative book page, etc.
webmaster@1 11 */
webmaster@1 12
webmaster@1 13 /**
webmaster@1 14 * Comment is published.
webmaster@1 15 */
webmaster@1 16 define('COMMENT_PUBLISHED', 0);
webmaster@1 17
webmaster@1 18 /**
webmaster@1 19 * Comment is awaiting approval.
webmaster@1 20 */
webmaster@1 21 define('COMMENT_NOT_PUBLISHED', 1);
webmaster@1 22
webmaster@1 23 /**
webmaster@1 24 * Comments are displayed in a flat list - collapsed.
webmaster@1 25 */
webmaster@1 26 define('COMMENT_MODE_FLAT_COLLAPSED', 1);
webmaster@1 27
webmaster@1 28 /**
webmaster@1 29 * Comments are displayed in a flat list - expanded.
webmaster@1 30 */
webmaster@1 31 define('COMMENT_MODE_FLAT_EXPANDED', 2);
webmaster@1 32
webmaster@1 33 /**
webmaster@1 34 * Comments are displayed as a threaded list - collapsed.
webmaster@1 35 */
webmaster@1 36 define('COMMENT_MODE_THREADED_COLLAPSED', 3);
webmaster@1 37
webmaster@1 38 /**
webmaster@1 39 * Comments are displayed as a threaded list - expanded.
webmaster@1 40 */
webmaster@1 41 define('COMMENT_MODE_THREADED_EXPANDED', 4);
webmaster@1 42
webmaster@1 43 /**
webmaster@1 44 * Comments are ordered by date - newest first.
webmaster@1 45 */
webmaster@1 46 define('COMMENT_ORDER_NEWEST_FIRST', 1);
webmaster@1 47
webmaster@1 48 /**
webmaster@1 49 * Comments are ordered by date - oldest first.
webmaster@1 50 */
webmaster@1 51 define('COMMENT_ORDER_OLDEST_FIRST', 2);
webmaster@1 52
webmaster@1 53 /**
webmaster@1 54 * Comment controls should be shown above the comment list.
webmaster@1 55 */
webmaster@1 56 define('COMMENT_CONTROLS_ABOVE', 0);
webmaster@1 57
webmaster@1 58 /**
webmaster@1 59 * Comment controls should be shown below the comment list.
webmaster@1 60 */
webmaster@1 61 define('COMMENT_CONTROLS_BELOW', 1);
webmaster@1 62
webmaster@1 63 /**
webmaster@1 64 * Comment controls should be shown both above and below the comment list.
webmaster@1 65 */
webmaster@1 66 define('COMMENT_CONTROLS_ABOVE_BELOW', 2);
webmaster@1 67
webmaster@1 68 /**
webmaster@1 69 * Comment controls are hidden.
webmaster@1 70 */
webmaster@1 71 define('COMMENT_CONTROLS_HIDDEN', 3);
webmaster@1 72
webmaster@1 73 /**
webmaster@1 74 * Anonymous posters may not enter their contact information.
webmaster@1 75 */
webmaster@1 76 define('COMMENT_ANONYMOUS_MAYNOT_CONTACT', 0);
webmaster@1 77
webmaster@1 78 /**
webmaster@1 79 * Anonymous posters may leave their contact information.
webmaster@1 80 */
webmaster@1 81 define('COMMENT_ANONYMOUS_MAY_CONTACT', 1);
webmaster@1 82
webmaster@1 83 /**
webmaster@1 84 * Anonymous posters must leave their contact information.
webmaster@1 85 */
webmaster@1 86 define('COMMENT_ANONYMOUS_MUST_CONTACT', 2);
webmaster@1 87
webmaster@1 88 /**
webmaster@1 89 * Comment form should be displayed on a separate page.
webmaster@1 90 */
webmaster@1 91 define('COMMENT_FORM_SEPARATE_PAGE', 0);
webmaster@1 92
webmaster@1 93 /**
webmaster@1 94 * Comment form should be shown below post or list of comments.
webmaster@1 95 */
webmaster@1 96 define('COMMENT_FORM_BELOW', 1);
webmaster@1 97
webmaster@1 98 /**
webmaster@1 99 * Comments for this node are disabled.
webmaster@1 100 */
webmaster@1 101 define('COMMENT_NODE_DISABLED', 0);
webmaster@1 102
webmaster@1 103 /**
webmaster@1 104 * Comments for this node are locked.
webmaster@1 105 */
webmaster@1 106 define('COMMENT_NODE_READ_ONLY', 1);
webmaster@1 107
webmaster@1 108 /**
webmaster@1 109 * Comments are enabled on this node.
webmaster@1 110 */
webmaster@1 111 define('COMMENT_NODE_READ_WRITE', 2);
webmaster@1 112
webmaster@1 113 /**
webmaster@1 114 * Comment preview is optional.
webmaster@1 115 */
webmaster@1 116 define('COMMENT_PREVIEW_OPTIONAL', 0);
webmaster@1 117
webmaster@1 118 /**
webmaster@1 119 * Comment preview is required.
webmaster@1 120 */
webmaster@1 121 define('COMMENT_PREVIEW_REQUIRED', 1);
webmaster@1 122
webmaster@1 123 /**
webmaster@1 124 * Implementation of hook_help().
webmaster@1 125 */
webmaster@1 126 function comment_help($path, $arg) {
webmaster@1 127 switch ($path) {
webmaster@1 128 case 'admin/help#comment':
webmaster@1 129 $output = '<p>'. t('The comment module allows visitors to comment on your posts, creating ad hoc discussion boards. Any <a href="@content-type">content type</a> may have its <em>Default comment setting</em> set to <em>Read/Write</em> to allow comments, or <em>Disabled</em>, to prevent comments. Comment display settings and other controls may also be customized for each content type (some display settings are customizable by individual users).', array('@content-type' => url('admin/content/types'))) .'</p>';
webmaster@1 130 $output .= '<p>'. t('Comment permissions are assigned to user roles, and are used to determine whether anonymous users (or other roles) are allowed to comment on posts. If anonymous users are allowed to comment, their individual contact information may be retained in cookies stored on their local computer for use in later comment submissions. When a comment has no replies, it may be (optionally) edited by its author. The comment module uses the same input formats and HTML tags available when creating other forms of content.') .'</p>';
webmaster@1 131 $output .= '<p>'. t('For more information, see the online handbook entry for <a href="@comment">Comment module</a>.', array('@comment' => 'http://drupal.org/handbook/modules/comment/')) .'</p>';
webmaster@1 132 return $output;
webmaster@1 133 case 'admin/content/comment':
webmaster@1 134 return '<p>'. t("Below is a list of the latest comments posted to your site. Click on a subject to see the comment, the author's name to edit the author's user information, 'edit' to modify the text, and 'delete' to remove their submission.") .'</p>';
webmaster@1 135 case 'admin/content/comment/approval':
webmaster@1 136 return '<p>'. t("Below is a list of the comments posted to your site that need approval. To approve a comment, click on 'edit' and then change its 'moderation status' to Approved. Click on a subject to see the comment, the author's name to edit the author's user information, 'edit' to modify the text, and 'delete' to remove their submission.") .'</p>';
webmaster@1 137 }
webmaster@1 138 }
webmaster@1 139
webmaster@1 140 /**
webmaster@1 141 * Implementation of hook_theme().
webmaster@1 142 */
webmaster@1 143 function comment_theme() {
webmaster@1 144 return array(
webmaster@1 145 'comment_block' => array(
webmaster@1 146 'arguments' => array(),
webmaster@1 147 ),
webmaster@1 148 'comment_admin_overview' => array(
webmaster@1 149 'arguments' => array('form' => NULL),
webmaster@1 150 ),
webmaster@1 151 'comment_preview' => array(
webmaster@1 152 'arguments' => array('comment' => NULL, 'node' => NULL, 'links' => array(), 'visible' => 1),
webmaster@1 153 ),
webmaster@1 154 'comment_view' => array(
webmaster@1 155 'arguments' => array('comment' => NULL, 'node' => NULL, 'links' => array(), 'visible' => 1),
webmaster@1 156 ),
webmaster@1 157 'comment_controls' => array(
webmaster@1 158 'arguments' => array('form' => NULL),
webmaster@1 159 ),
webmaster@1 160 'comment' => array(
webmaster@1 161 'template' => 'comment',
webmaster@1 162 'arguments' => array('comment' => NULL, 'node' => NULL, 'links' => array()),
webmaster@1 163 ),
webmaster@1 164 'comment_folded' => array(
webmaster@1 165 'template' => 'comment-folded',
webmaster@1 166 'arguments' => array('comment' => NULL),
webmaster@1 167 ),
webmaster@1 168 'comment_flat_collapsed' => array(
webmaster@1 169 'arguments' => array('comment' => NULL, 'node' => NULL),
webmaster@1 170 ),
webmaster@1 171 'comment_flat_expanded' => array(
webmaster@1 172 'arguments' => array('comment' => NULL, 'node' => NULL),
webmaster@1 173 ),
webmaster@1 174 'comment_thread_collapsed' => array(
webmaster@1 175 'arguments' => array('comment' => NULL, 'node' => NULL),
webmaster@1 176 ),
webmaster@1 177 'comment_thread_expanded' => array(
webmaster@1 178 'arguments' => array('comment' => NULL, 'node' => NULL),
webmaster@1 179 ),
webmaster@1 180 'comment_post_forbidden' => array(
webmaster@1 181 'arguments' => array('nid' => NULL),
webmaster@1 182 ),
webmaster@1 183 'comment_wrapper' => array(
webmaster@1 184 'template' => 'comment-wrapper',
webmaster@1 185 'arguments' => array('content' => NULL, 'node' => NULL),
webmaster@1 186 ),
webmaster@1 187 'comment_submitted' => array(
webmaster@1 188 'arguments' => array('comment' => NULL),
webmaster@1 189 ),
webmaster@1 190 );
webmaster@1 191 }
webmaster@1 192
webmaster@1 193 /**
webmaster@1 194 * Implementation of hook_menu().
webmaster@1 195 */
webmaster@1 196 function comment_menu() {
webmaster@1 197 $items['admin/content/comment'] = array(
webmaster@1 198 'title' => 'Comments',
webmaster@1 199 'description' => 'List and edit site comments and the comment moderation queue.',
webmaster@1 200 'page callback' => 'comment_admin',
webmaster@1 201 'access arguments' => array('administer comments'),
webmaster@1 202 'file' => 'comment.admin.inc',
webmaster@1 203 );
webmaster@1 204
webmaster@1 205 // Tabs:
webmaster@1 206 $items['admin/content/comment/new'] = array(
webmaster@1 207 'title' => 'Published comments',
webmaster@1 208 'type' => MENU_DEFAULT_LOCAL_TASK,
webmaster@1 209 'weight' => -10,
webmaster@1 210 );
webmaster@1 211 $items['admin/content/comment/approval'] = array(
webmaster@1 212 'title' => 'Approval queue',
webmaster@1 213 'page arguments' => array('approval'),
webmaster@1 214 'type' => MENU_LOCAL_TASK,
webmaster@1 215 'file' => 'comment.admin.inc',
webmaster@1 216 );
webmaster@1 217
webmaster@1 218 $items['comment/delete'] = array(
webmaster@1 219 'title' => 'Delete comment',
webmaster@1 220 'page callback' => 'comment_delete',
webmaster@1 221 'access arguments' => array('administer comments'),
webmaster@1 222 'type' => MENU_CALLBACK,
webmaster@1 223 'file' => 'comment.admin.inc',
webmaster@1 224 );
webmaster@1 225
webmaster@1 226 $items['comment/edit'] = array(
webmaster@1 227 'title' => 'Edit comment',
webmaster@1 228 'page callback' => 'comment_edit',
webmaster@1 229 'access arguments' => array('post comments'),
webmaster@1 230 'type' => MENU_CALLBACK,
webmaster@1 231 'file' => 'comment.pages.inc',
webmaster@1 232 );
webmaster@1 233 $items['comment/reply/%node'] = array(
webmaster@1 234 'title' => 'Reply to comment',
webmaster@1 235 'page callback' => 'comment_reply',
webmaster@1 236 'page arguments' => array(2),
webmaster@1 237 'access callback' => 'node_access',
webmaster@1 238 'access arguments' => array('view', 2),
webmaster@1 239 'type' => MENU_CALLBACK,
webmaster@1 240 'file' => 'comment.pages.inc',
webmaster@1 241 );
webmaster@1 242
webmaster@1 243 return $items;
webmaster@1 244 }
webmaster@1 245
webmaster@1 246 /**
webmaster@1 247 * Implementation of hook_node_type().
webmaster@1 248 */
webmaster@1 249 function comment_node_type($op, $info) {
webmaster@1 250 $settings = array(
webmaster@1 251 'comment',
webmaster@1 252 'comment_default_mode',
webmaster@1 253 'comment_default_order',
webmaster@1 254 'comment_default_per_page',
webmaster@1 255 'comment_controls',
webmaster@1 256 'comment_anonymous',
webmaster@1 257 'comment_subject_field',
webmaster@1 258 'comment_preview',
webmaster@1 259 'comment_form_location',
webmaster@1 260 );
webmaster@1 261 switch ($op) {
webmaster@1 262 case 'delete':
webmaster@1 263 foreach ($settings as $setting) {
webmaster@1 264 variable_del($setting .'_'. $info->type);
webmaster@1 265 }
webmaster@1 266 break;
webmaster@1 267 }
webmaster@1 268 }
webmaster@1 269
webmaster@1 270 /**
webmaster@1 271 * Implementation of hook_perm().
webmaster@1 272 */
webmaster@1 273 function comment_perm() {
webmaster@1 274 return array('access comments', 'post comments', 'administer comments', 'post comments without approval');
webmaster@1 275 }
webmaster@1 276
webmaster@1 277 /**
webmaster@1 278 * Implementation of hook_block().
webmaster@1 279 *
webmaster@1 280 * Generates a block with the most recent comments.
webmaster@1 281 */
webmaster@1 282 function comment_block($op = 'list', $delta = 0) {
webmaster@1 283 if ($op == 'list') {
webmaster@1 284 $blocks[0]['info'] = t('Recent comments');
webmaster@1 285 return $blocks;
webmaster@1 286 }
webmaster@1 287 else if ($op == 'view' && user_access('access comments')) {
webmaster@1 288 $block['subject'] = t('Recent comments');
webmaster@1 289 $block['content'] = theme('comment_block');
webmaster@1 290 return $block;
webmaster@1 291 }
webmaster@1 292 }
webmaster@1 293
webmaster@1 294 /**
webmaster@1 295 * Find a number of recent comments. This is done in two steps.
webmaster@1 296 * 1. Find the n (specified by $number) nodes that have the most recent
webmaster@1 297 * comments. This is done by querying node_comment_statistics which has
webmaster@1 298 * an index on last_comment_timestamp, and is thus a fast query.
webmaster@1 299 * 2. Loading the information from the comments table based on the nids found
webmaster@1 300 * in step 1.
webmaster@1 301 *
webmaster@1 302 * @param $number
webmaster@1 303 * (optional) The maximum number of comments to find.
webmaster@1 304 * @return
webmaster@1 305 * An array of comment objects each containing a nid,
webmaster@1 306 * subject, cid, and timestamp, or an empty array if there are no recent
webmaster@1 307 * comments visible to the current user.
webmaster@1 308 */
webmaster@1 309 function comment_get_recent($number = 10) {
webmaster@1 310 // Select the $number nodes (visible to the current user) with the most
webmaster@1 311 // recent comments. This is efficient due to the index on
webmaster@1 312 // last_comment_timestamp.
webmaster@1 313 $result = db_query_range(db_rewrite_sql("SELECT nc.nid FROM {node_comment_statistics} nc WHERE nc.comment_count > 0 ORDER BY nc.last_comment_timestamp DESC", 'nc'), 0, $number);
webmaster@1 314
webmaster@1 315 $nids = array();
webmaster@1 316 while ($row = db_fetch_object($result)) {
webmaster@1 317 $nids[] = $row->nid;
webmaster@1 318 }
webmaster@1 319
webmaster@1 320 $comments = array();
webmaster@1 321 if (!empty($nids)) {
webmaster@1 322 // From among the comments on the nodes selected in the first query,
webmaster@1 323 // find the $number most recent comments.
webmaster@1 324 $result = db_query_range('SELECT c.nid, c.subject, c.cid, c.timestamp FROM {comments} c INNER JOIN {node} n ON n.nid = c.nid WHERE c.nid IN ('. implode(',', $nids) .') AND n.status = 1 AND c.status = %d ORDER BY c.cid DESC', COMMENT_PUBLISHED, 0, $number);
webmaster@1 325 while ($comment = db_fetch_object($result)) {
webmaster@1 326 $comments[] = $comment;
webmaster@1 327 }
webmaster@1 328 }
webmaster@1 329
webmaster@1 330 return $comments;
webmaster@1 331 }
webmaster@1 332
webmaster@1 333 /**
webmaster@1 334 * Calculate page number for first new comment.
webmaster@1 335 *
webmaster@1 336 * @param $num_comments
webmaster@1 337 * Number of comments.
webmaster@1 338 * @param $new_replies
webmaster@1 339 * Number of new replies.
webmaster@1 340 * @param $node
webmaster@1 341 * The first new comment node.
webmaster@1 342 * @return
webmaster@1 343 * "page=X" if the page number is greater than zero; empty string otherwise.
webmaster@1 344 */
webmaster@1 345 function comment_new_page_count($num_comments, $new_replies, $node) {
webmaster@1 346 $comments_per_page = _comment_get_display_setting('comments_per_page', $node);
webmaster@1 347 $mode = _comment_get_display_setting('mode', $node);
webmaster@1 348 $order = _comment_get_display_setting('sort', $node);
webmaster@1 349 $pagenum = NULL;
webmaster@1 350 $flat = in_array($mode, array(COMMENT_MODE_FLAT_COLLAPSED, COMMENT_MODE_FLAT_EXPANDED));
webmaster@1 351 if ($num_comments <= $comments_per_page || ($flat && $order == COMMENT_ORDER_NEWEST_FIRST)) {
webmaster@1 352 // Only one page of comments or flat forum and newest first.
webmaster@1 353 // First new comment will always be on first page.
webmaster@1 354 $pageno = 0;
webmaster@1 355 }
webmaster@1 356 else {
webmaster@1 357 if ($flat) {
webmaster@1 358 // Flat comments and oldest first.
webmaster@1 359 $count = $num_comments - $new_replies;
webmaster@1 360 }
webmaster@1 361 else {
webmaster@1 362 // Threaded comments. See the documentation for comment_render().
webmaster@1 363 if ($order == COMMENT_ORDER_NEWEST_FIRST) {
webmaster@1 364 // Newest first: find the last thread with new comment
webmaster@1 365 $result = db_query('(SELECT thread FROM {comments} WHERE nid = %d AND status = 0 ORDER BY timestamp DESC LIMIT %d) ORDER BY thread DESC LIMIT 1', $node->nid, $new_replies);
webmaster@1 366 $thread = db_result($result);
webmaster@1 367 $result_count = db_query("SELECT COUNT(*) FROM {comments} WHERE nid = %d AND status = 0 AND thread > '". $thread ."'", $node->nid);
webmaster@1 368 }
webmaster@1 369 else {
webmaster@1 370 // Oldest first: find the first thread with new comment
webmaster@1 371 $result = db_query('(SELECT thread FROM {comments} WHERE nid = %d AND status = 0 ORDER BY timestamp DESC LIMIT %d) ORDER BY SUBSTRING(thread, 1, (LENGTH(thread) - 1)) LIMIT 1', $node->nid, $new_replies);
webmaster@1 372 $thread = substr(db_result($result), 0, -1);
webmaster@1 373 $result_count = db_query("SELECT COUNT(*) FROM {comments} WHERE nid = %d AND status = 0 AND SUBSTRING(thread, 1, (LENGTH(thread) - 1)) < '". $thread ."'", $node->nid);
webmaster@1 374 }
webmaster@1 375 $count = db_result($result_count);
webmaster@1 376 }
webmaster@1 377 $pageno = $count / $comments_per_page;
webmaster@1 378 }
webmaster@1 379 if ($pageno >= 1) {
webmaster@1 380 $pagenum = "page=". intval($pageno);
webmaster@1 381 }
webmaster@1 382 return $pagenum;
webmaster@1 383 }
webmaster@1 384
webmaster@1 385 /**
webmaster@1 386 * Returns a formatted list of recent comments to be displayed in the comment block.
webmaster@1 387 *
webmaster@1 388 * @return
webmaster@1 389 * The comment list HTML.
webmaster@1 390 * @ingroup themeable
webmaster@1 391 */
webmaster@1 392 function theme_comment_block() {
webmaster@1 393 $items = array();
webmaster@1 394 foreach (comment_get_recent() as $comment) {
webmaster@1 395 $items[] = l($comment->subject, 'node/'. $comment->nid, array('fragment' => 'comment-'. $comment->cid)) .'<br />'. t('@time ago', array('@time' => format_interval(time() - $comment->timestamp)));
webmaster@1 396 }
webmaster@1 397 if ($items) {
webmaster@1 398 return theme('item_list', $items);
webmaster@1 399 }
webmaster@1 400 }
webmaster@1 401
webmaster@1 402 /**
webmaster@1 403 * Implementation of hook_link().
webmaster@1 404 */
webmaster@1 405 function comment_link($type, $node = NULL, $teaser = FALSE) {
webmaster@1 406 $links = array();
webmaster@1 407
webmaster@1 408 if ($type == 'node' && $node->comment) {
webmaster@1 409
webmaster@1 410 if ($teaser) {
webmaster@1 411 // Main page: display the number of comments that have been posted.
webmaster@1 412
webmaster@1 413 if (user_access('access comments')) {
webmaster@1 414 $all = comment_num_all($node->nid);
webmaster@1 415
webmaster@1 416 if ($all) {
webmaster@1 417 $links['comment_comments'] = array(
webmaster@1 418 'title' => format_plural($all, '1 comment', '@count comments'),
webmaster@1 419 'href' => "node/$node->nid",
webmaster@1 420 'attributes' => array('title' => t('Jump to the first comment of this posting.')),
webmaster@1 421 'fragment' => 'comments'
webmaster@1 422 );
webmaster@1 423
webmaster@1 424 $new = comment_num_new($node->nid);
webmaster@1 425
webmaster@1 426 if ($new) {
webmaster@1 427 $links['comment_new_comments'] = array(
webmaster@1 428 'title' => format_plural($new, '1 new comment', '@count new comments'),
webmaster@1 429 'href' => "node/$node->nid",
webmaster@1 430 'query' => comment_new_page_count($all, $new, $node),
webmaster@1 431 'attributes' => array('title' => t('Jump to the first new comment of this posting.')),
webmaster@1 432 'fragment' => 'new'
webmaster@1 433 );
webmaster@1 434 }
webmaster@1 435 }
webmaster@1 436 else {
webmaster@1 437 if ($node->comment == COMMENT_NODE_READ_WRITE) {
webmaster@1 438 if (user_access('post comments')) {
webmaster@1 439 $links['comment_add'] = array(
webmaster@1 440 'title' => t('Add new comment'),
webmaster@1 441 'href' => "comment/reply/$node->nid",
webmaster@1 442 'attributes' => array('title' => t('Add a new comment to this page.')),
webmaster@1 443 'fragment' => 'comment-form'
webmaster@1 444 );
webmaster@1 445 }
webmaster@1 446 else {
webmaster@1 447 $links['comment_forbidden']['title'] = theme('comment_post_forbidden', $node);
webmaster@1 448 }
webmaster@1 449 }
webmaster@1 450 }
webmaster@1 451 }
webmaster@1 452 }
webmaster@1 453 else {
webmaster@1 454 // Node page: add a "post comment" link if the user is allowed to
webmaster@1 455 // post comments, if this node is not read-only, and if the comment form isn't already shown
webmaster@1 456
webmaster@1 457 if ($node->comment == COMMENT_NODE_READ_WRITE) {
webmaster@1 458 if (user_access('post comments')) {
webmaster@1 459 if (variable_get('comment_form_location_'. $node->type, COMMENT_FORM_SEPARATE_PAGE) == COMMENT_FORM_SEPARATE_PAGE) {
webmaster@1 460 $links['comment_add'] = array(
webmaster@1 461 'title' => t('Add new comment'),
webmaster@1 462 'href' => "comment/reply/$node->nid",
webmaster@1 463 'attributes' => array('title' => t('Share your thoughts and opinions related to this posting.')),
webmaster@1 464 'fragment' => 'comment-form'
webmaster@1 465 );
webmaster@1 466 }
webmaster@1 467 }
webmaster@1 468 else {
webmaster@1 469 $links['comment_forbidden']['title'] = theme('comment_post_forbidden', $node);
webmaster@1 470 }
webmaster@1 471 }
webmaster@1 472 }
webmaster@1 473 }
webmaster@1 474
webmaster@1 475 if ($type == 'comment') {
webmaster@1 476 $links = comment_links($node, $teaser);
webmaster@1 477 }
webmaster@1 478 if (isset($links['comment_forbidden'])) {
webmaster@1 479 $links['comment_forbidden']['html'] = TRUE;
webmaster@1 480 }
webmaster@1 481
webmaster@1 482 return $links;
webmaster@1 483 }
webmaster@1 484
webmaster@1 485 /**
webmaster@1 486 * Implementation of hook_form_alter().
webmaster@1 487 */
webmaster@1 488 function comment_form_alter(&$form, $form_state, $form_id) {
webmaster@1 489 if ($form_id == 'node_type_form' && isset($form['identity']['type'])) {
webmaster@1 490 $form['comment'] = array(
webmaster@1 491 '#type' => 'fieldset',
webmaster@1 492 '#title' => t('Comment settings'),
webmaster@1 493 '#collapsible' => TRUE,
webmaster@1 494 '#collapsed' => TRUE,
webmaster@1 495 );
webmaster@1 496 $form['comment']['comment'] = array(
webmaster@1 497 '#type' => 'radios',
webmaster@1 498 '#title' => t('Default comment setting'),
webmaster@1 499 '#default_value' => variable_get('comment_'. $form['#node_type']->type, COMMENT_NODE_READ_WRITE),
webmaster@1 500 '#options' => array(t('Disabled'), t('Read only'), t('Read/Write')),
webmaster@1 501 '#description' => t('Users with the <em>administer comments</em> permission will be able to override this setting.'),
webmaster@1 502 );
webmaster@1 503 $form['comment']['comment_default_mode'] = array(
webmaster@1 504 '#type' => 'radios',
webmaster@1 505 '#title' => t('Default display mode'),
webmaster@1 506 '#default_value' => variable_get('comment_default_mode_'. $form['#node_type']->type, COMMENT_MODE_THREADED_EXPANDED),
webmaster@1 507 '#options' => _comment_get_modes(),
webmaster@1 508 '#description' => t('The default view for comments. Expanded views display the body of the comment. Threaded views keep replies together.'),
webmaster@1 509 );
webmaster@1 510 $form['comment']['comment_default_order'] = array(
webmaster@1 511 '#type' => 'radios',
webmaster@1 512 '#title' => t('Default display order'),
webmaster@1 513 '#default_value' => variable_get('comment_default_order_'. $form['#node_type']->type, COMMENT_ORDER_NEWEST_FIRST),
webmaster@1 514 '#options' => _comment_get_orders(),
webmaster@1 515 '#description' => t('The default sorting for new users and anonymous users while viewing comments. These users may change their view using the comment control panel. For registered users, this change is remembered as a persistent user preference.'),
webmaster@1 516 );
webmaster@1 517 $form['comment']['comment_default_per_page'] = array(
webmaster@1 518 '#type' => 'select',
webmaster@1 519 '#title' => t('Default comments per page'),
webmaster@1 520 '#default_value' => variable_get('comment_default_per_page_'. $form['#node_type']->type, 50),
webmaster@1 521 '#options' => _comment_per_page(),
webmaster@1 522 '#description' => t('Default number of comments for each page: more comments are distributed in several pages.'),
webmaster@1 523 );
webmaster@1 524 $form['comment']['comment_controls'] = array(
webmaster@1 525 '#type' => 'radios',
webmaster@1 526 '#title' => t('Comment controls'),
webmaster@1 527 '#default_value' => variable_get('comment_controls_'. $form['#node_type']->type, COMMENT_CONTROLS_HIDDEN),
webmaster@1 528 '#options' => array(
webmaster@1 529 t('Display above the comments'),
webmaster@1 530 t('Display below the comments'),
webmaster@1 531 t('Display above and below the comments'),
webmaster@1 532 t('Do not display')),
webmaster@1 533 '#description' => t('Position of the comment controls box. The comment controls let the user change the default display mode and display order of comments.'),
webmaster@1 534 );
webmaster@1 535 $form['comment']['comment_anonymous'] = array(
webmaster@1 536 '#type' => 'radios',
webmaster@1 537 '#title' => t('Anonymous commenting'),
webmaster@1 538 '#default_value' => variable_get('comment_anonymous_'. $form['#node_type']->type, COMMENT_ANONYMOUS_MAYNOT_CONTACT),
webmaster@1 539 '#options' => array(
webmaster@1 540 COMMENT_ANONYMOUS_MAYNOT_CONTACT => t('Anonymous posters may not enter their contact information'),
webmaster@1 541 COMMENT_ANONYMOUS_MAY_CONTACT => t('Anonymous posters may leave their contact information'),
webmaster@1 542 COMMENT_ANONYMOUS_MUST_CONTACT => t('Anonymous posters must leave their contact information')),
webmaster@1 543 '#description' => t('This option is enabled when anonymous users have permission to post comments on the <a href="@url">permissions page</a>.', array('@url' => url('admin/user/permissions', array('fragment' => 'module-comment')))),
webmaster@1 544 );
webmaster@1 545 if (!user_access('post comments', drupal_anonymous_user())) {
webmaster@1 546 $form['comment']['comment_anonymous']['#disabled'] = TRUE;
webmaster@1 547 }
webmaster@1 548 $form['comment']['comment_subject_field'] = array(
webmaster@1 549 '#type' => 'radios',
webmaster@1 550 '#title' => t('Comment subject field'),
webmaster@1 551 '#default_value' => variable_get('comment_subject_field_'. $form['#node_type']->type, 1),
webmaster@1 552 '#options' => array(t('Disabled'), t('Enabled')),
webmaster@1 553 '#description' => t('Can users provide a unique subject for their comments?'),
webmaster@1 554 );
webmaster@1 555 $form['comment']['comment_preview'] = array(
webmaster@1 556 '#type' => 'radios',
webmaster@1 557 '#title' => t('Preview comment'),
webmaster@1 558 '#default_value' => variable_get('comment_preview_'. $form['#node_type']->type, COMMENT_PREVIEW_REQUIRED),
webmaster@1 559 '#options' => array(t('Optional'), t('Required')),
webmaster@1 560 '#description' => t("Forces a user to look at their comment by clicking on a 'Preview' button before they can actually add the comment"),
webmaster@1 561 );
webmaster@1 562 $form['comment']['comment_form_location'] = array(
webmaster@1 563 '#type' => 'radios',
webmaster@1 564 '#title' => t('Location of comment submission form'),
webmaster@1 565 '#default_value' => variable_get('comment_form_location_'. $form['#node_type']->type, COMMENT_FORM_SEPARATE_PAGE),
webmaster@1 566 '#options' => array(t('Display on separate page'), t('Display below post or comments')),
webmaster@1 567 );
webmaster@1 568 }
webmaster@1 569 elseif (isset($form['type']) && isset($form['#node'])) {
webmaster@1 570 if ($form['type']['#value'] .'_node_form' == $form_id) {
webmaster@1 571 $node = $form['#node'];
webmaster@1 572 $form['comment_settings'] = array(
webmaster@1 573 '#type' => 'fieldset',
webmaster@1 574 '#access' => user_access('administer comments'),
webmaster@1 575 '#title' => t('Comment settings'),
webmaster@1 576 '#collapsible' => TRUE,
webmaster@1 577 '#collapsed' => TRUE,
webmaster@1 578 '#weight' => 30,
webmaster@1 579 );
webmaster@1 580 $form['comment_settings']['comment'] = array(
webmaster@1 581 '#type' => 'radios',
webmaster@1 582 '#parents' => array('comment'),
webmaster@1 583 '#default_value' => $node->comment,
webmaster@1 584 '#options' => array(t('Disabled'), t('Read only'), t('Read/Write')),
webmaster@1 585 );
webmaster@1 586 }
webmaster@1 587 }
webmaster@1 588 }
webmaster@1 589
webmaster@1 590 /**
webmaster@1 591 * Implementation of hook_nodeapi().
webmaster@1 592 */
webmaster@1 593 function comment_nodeapi(&$node, $op, $arg = 0) {
webmaster@1 594 switch ($op) {
webmaster@1 595 case 'load':
webmaster@1 596 return db_fetch_array(db_query("SELECT last_comment_timestamp, last_comment_name, comment_count FROM {node_comment_statistics} WHERE nid = %d", $node->nid));
webmaster@1 597 break;
webmaster@1 598
webmaster@1 599 case 'prepare':
webmaster@1 600 if (!isset($node->comment)) {
webmaster@1 601 $node->comment = variable_get("comment_$node->type", COMMENT_NODE_READ_WRITE);
webmaster@1 602 }
webmaster@1 603 break;
webmaster@1 604
webmaster@1 605 case 'insert':
webmaster@1 606 db_query('INSERT INTO {node_comment_statistics} (nid, last_comment_timestamp, last_comment_name, last_comment_uid, comment_count) VALUES (%d, %d, NULL, %d, 0)', $node->nid, $node->changed, $node->uid);
webmaster@1 607 break;
webmaster@1 608
webmaster@1 609 case 'delete':
webmaster@1 610 db_query('DELETE FROM {comments} WHERE nid = %d', $node->nid);
webmaster@1 611 db_query('DELETE FROM {node_comment_statistics} WHERE nid = %d', $node->nid);
webmaster@1 612 break;
webmaster@1 613
webmaster@1 614 case 'update index':
webmaster@1 615 $text = '';
webmaster@1 616 $comments = db_query('SELECT subject, comment, format FROM {comments} WHERE nid = %d AND status = %d', $node->nid, COMMENT_PUBLISHED);
webmaster@1 617 while ($comment = db_fetch_object($comments)) {
webmaster@1 618 $text .= '<h2>'. check_plain($comment->subject) .'</h2>'. check_markup($comment->comment, $comment->format, FALSE);
webmaster@1 619 }
webmaster@1 620 return $text;
webmaster@1 621
webmaster@1 622 case 'search result':
webmaster@1 623 $comments = db_result(db_query('SELECT comment_count FROM {node_comment_statistics} WHERE nid = %d', $node->nid));
webmaster@1 624 return format_plural($comments, '1 comment', '@count comments');
webmaster@1 625
webmaster@1 626 case 'rss item':
webmaster@1 627 if ($node->comment != COMMENT_NODE_DISABLED) {
webmaster@1 628 return array(array('key' => 'comments', 'value' => url('node/'. $node->nid, array('fragment' => 'comments', 'absolute' => TRUE))));
webmaster@1 629 }
webmaster@1 630 else {
webmaster@1 631 return array();
webmaster@1 632 }
webmaster@1 633 }
webmaster@1 634 }
webmaster@1 635
webmaster@1 636 /**
webmaster@1 637 * Implementation of hook_user().
webmaster@1 638 */
webmaster@1 639 function comment_user($type, $edit, &$user, $category = NULL) {
webmaster@1 640 if ($type == 'delete') {
webmaster@1 641 db_query('UPDATE {comments} SET uid = 0 WHERE uid = %d', $user->uid);
webmaster@1 642 db_query('UPDATE {node_comment_statistics} SET last_comment_uid = 0 WHERE last_comment_uid = %d', $user->uid);
webmaster@1 643 }
webmaster@1 644 }
webmaster@1 645
webmaster@1 646 /**
webmaster@1 647 * This is *not* a hook_access() implementation. This function is called
webmaster@1 648 * to determine whether the current user has access to a particular comment.
webmaster@1 649 *
webmaster@1 650 * Authenticated users can edit their comments as long they have not been
webmaster@1 651 * replied to. This prevents people from changing or revising their
webmaster@1 652 * statements based on the replies to their posts.
webmaster@1 653 *
webmaster@1 654 * @param $op
webmaster@1 655 * The operation that is to be performed on the comment. Only 'edit' is recognized now.
webmaster@1 656 * @param $comment
webmaster@1 657 * The comment object.
webmaster@1 658 * @return
webmaster@1 659 * TRUE if the current user has acces to the comment, FALSE otherwise.
webmaster@1 660 */
webmaster@1 661 function comment_access($op, $comment) {
webmaster@1 662 global $user;
webmaster@1 663
webmaster@1 664 if ($op == 'edit') {
webmaster@1 665 return ($user->uid && $user->uid == $comment->uid && comment_num_replies($comment->cid) == 0) || user_access('administer comments');
webmaster@1 666 }
webmaster@1 667 }
webmaster@1 668
webmaster@1 669 /**
webmaster@1 670 * A simple helper function.
webmaster@1 671 *
webmaster@1 672 * @return
webmaster@1 673 * The 0th and the 1st path components joined by a slash.
webmaster@1 674 */
webmaster@1 675 function comment_node_url() {
webmaster@1 676 return arg(0) .'/'. arg(1);
webmaster@1 677 }
webmaster@1 678
webmaster@1 679 /**
webmaster@1 680 * Accepts a submission of new or changed comment content.
webmaster@1 681 *
webmaster@1 682 * @param $edit
webmaster@1 683 * A comment array.
webmaster@1 684 *
webmaster@1 685 * @return
webmaster@1 686 * If the comment is successfully saved the comment ID is returned. If the comment
webmaster@1 687 * is not saved, FALSE is returned.
webmaster@1 688 */
webmaster@1 689 function comment_save($edit) {
webmaster@1 690 global $user;
webmaster@1 691 if (user_access('post comments') && (user_access('administer comments') || node_comment_mode($edit['nid']) == COMMENT_NODE_READ_WRITE)) {
webmaster@1 692 if (!form_get_errors()) {
webmaster@1 693 $edit += array(
webmaster@1 694 'mail' => '',
webmaster@1 695 'homepage' => '',
webmaster@1 696 'name' => '',
webmaster@1 697 'status' => user_access('post comments without approval') ? COMMENT_PUBLISHED : COMMENT_NOT_PUBLISHED,
webmaster@1 698 );
webmaster@1 699 if ($edit['cid']) {
webmaster@1 700 // Update the comment in the database.
webmaster@1 701 db_query("UPDATE {comments} SET status = %d, timestamp = %d, subject = '%s', comment = '%s', format = %d, uid = %d, name = '%s', mail = '%s', homepage = '%s' WHERE cid = %d", $edit['status'], $edit['timestamp'], $edit['subject'], $edit['comment'], $edit['format'], $edit['uid'], $edit['name'], $edit['mail'], $edit['homepage'], $edit['cid']);
webmaster@1 702
webmaster@1 703 // Allow modules to respond to the updating of a comment.
webmaster@1 704 comment_invoke_comment($edit, 'update');
webmaster@1 705
webmaster@1 706 // Add an entry to the watchdog log.
webmaster@1 707 watchdog('content', 'Comment: updated %subject.', array('%subject' => $edit['subject']), WATCHDOG_NOTICE, l(t('view'), 'node/'. $edit['nid'], array('fragment' => 'comment-'. $edit['cid'])));
webmaster@1 708 }
webmaster@1 709 else {
webmaster@1 710 // Add the comment to database.
webmaster@1 711 // Here we are building the thread field. See the documentation for
webmaster@1 712 // comment_render().
webmaster@1 713 if ($edit['pid'] == 0) {
webmaster@1 714 // This is a comment with no parent comment (depth 0): we start
webmaster@1 715 // by retrieving the maximum thread level.
webmaster@1 716 $max = db_result(db_query('SELECT MAX(thread) FROM {comments} WHERE nid = %d', $edit['nid']));
webmaster@1 717
webmaster@1 718 // Strip the "/" from the end of the thread.
webmaster@1 719 $max = rtrim($max, '/');
webmaster@1 720
webmaster@1 721 // Finally, build the thread field for this new comment.
webmaster@1 722 $thread = int2vancode(vancode2int($max) + 1) .'/';
webmaster@1 723 }
webmaster@1 724 else {
webmaster@1 725 // This is comment with a parent comment: we increase
webmaster@1 726 // the part of the thread value at the proper depth.
webmaster@1 727
webmaster@1 728 // Get the parent comment:
webmaster@1 729 $parent = _comment_load($edit['pid']);
webmaster@1 730
webmaster@1 731 // Strip the "/" from the end of the parent thread.
webmaster@1 732 $parent->thread = (string) rtrim((string) $parent->thread, '/');
webmaster@1 733
webmaster@1 734 // Get the max value in _this_ thread.
webmaster@1 735 $max = db_result(db_query("SELECT MAX(thread) FROM {comments} WHERE thread LIKE '%s.%%' AND nid = %d", $parent->thread, $edit['nid']));
webmaster@1 736
webmaster@1 737 if ($max == '') {
webmaster@1 738 // First child of this parent.
webmaster@1 739 $thread = $parent->thread .'.'. int2vancode(0) .'/';
webmaster@1 740 }
webmaster@1 741 else {
webmaster@1 742 // Strip the "/" at the end of the thread.
webmaster@1 743 $max = rtrim($max, '/');
webmaster@1 744
webmaster@1 745 // We need to get the value at the correct depth.
webmaster@1 746 $parts = explode('.', $max);
webmaster@1 747 $parent_depth = count(explode('.', $parent->thread));
webmaster@1 748 $last = $parts[$parent_depth];
webmaster@1 749
webmaster@1 750 // Finally, build the thread field for this new comment.
webmaster@1 751 $thread = $parent->thread .'.'. int2vancode(vancode2int($last) + 1) .'/';
webmaster@1 752 }
webmaster@1 753 }
webmaster@1 754
webmaster@1 755 $edit['timestamp'] = time();
webmaster@1 756
webmaster@1 757 if ($edit['uid'] === $user->uid) { // '===' because we want to modify anonymous users too
webmaster@1 758 $edit['name'] = $user->name;
webmaster@1 759 }
webmaster@1 760
webmaster@1 761 db_query("INSERT INTO {comments} (nid, pid, uid, subject, comment, format, hostname, timestamp, status, thread, name, mail, homepage) VALUES (%d, %d, %d, '%s', '%s', %d, '%s', %d, %d, '%s', '%s', '%s', '%s')", $edit['nid'], $edit['pid'], $edit['uid'], $edit['subject'], $edit['comment'], $edit['format'], ip_address(), $edit['timestamp'], $edit['status'], $thread, $edit['name'], $edit['mail'], $edit['homepage']);
webmaster@1 762 $edit['cid'] = db_last_insert_id('comments', 'cid');
webmaster@1 763
webmaster@1 764 // Tell the other modules a new comment has been submitted.
webmaster@1 765 comment_invoke_comment($edit, 'insert');
webmaster@1 766
webmaster@1 767 // Add an entry to the watchdog log.
webmaster@1 768 watchdog('content', 'Comment: added %subject.', array('%subject' => $edit['subject']), WATCHDOG_NOTICE, l(t('view'), 'node/'. $edit['nid'], array('fragment' => 'comment-'. $edit['cid'])));
webmaster@1 769 }
webmaster@1 770 _comment_update_node_statistics($edit['nid']);
webmaster@1 771
webmaster@1 772 // Clear the cache so an anonymous user can see his comment being added.
webmaster@1 773 cache_clear_all();
webmaster@1 774
webmaster@1 775 // Explain the approval queue if necessary, and then
webmaster@1 776 // redirect the user to the node he's commenting on.
webmaster@1 777 if ($edit['status'] == COMMENT_NOT_PUBLISHED) {
webmaster@1 778 drupal_set_message(t('Your comment has been queued for moderation by site administrators and will be published after approval.'));
webmaster@1 779 }
webmaster@1 780 else {
webmaster@1 781 comment_invoke_comment($edit, 'publish');
webmaster@1 782 }
webmaster@1 783 return $edit['cid'];
webmaster@1 784 }
webmaster@1 785 else {
webmaster@1 786 return FALSE;
webmaster@1 787 }
webmaster@1 788 }
webmaster@1 789 else {
webmaster@1 790 watchdog('content', 'Comment: unauthorized comment submitted or comment submitted to a closed post %subject.', array('%subject' => $edit['subject']), WATCHDOG_WARNING);
webmaster@1 791 drupal_set_message(t('Comment: unauthorized comment submitted or comment submitted to a closed post %subject.', array('%subject' => $edit['subject'])), 'error');
webmaster@1 792 return FALSE;
webmaster@1 793 }
webmaster@1 794 }
webmaster@1 795
webmaster@1 796 /**
webmaster@1 797 * Build command links for a comment (e.g.\ edit, reply, delete) with respect to the current user's access permissions.
webmaster@1 798 *
webmaster@1 799 * @param $comment
webmaster@1 800 * The comment to which the links will be related.
webmaster@1 801 * @param $return
webmaster@1 802 * Not used.
webmaster@1 803 * @return
webmaster@1 804 * An associative array containing the links.
webmaster@1 805 */
webmaster@1 806 function comment_links($comment, $return = 1) {
webmaster@1 807 global $user;
webmaster@1 808
webmaster@1 809 $links = array();
webmaster@1 810
webmaster@1 811 // If we are viewing just this comment, we link back to the node.
webmaster@1 812 if ($return) {
webmaster@1 813 $links['comment_parent'] = array(
webmaster@1 814 'title' => t('parent'),
webmaster@1 815 'href' => comment_node_url(),
webmaster@1 816 'fragment' => "comment-$comment->cid"
webmaster@1 817 );
webmaster@1 818 }
webmaster@1 819
webmaster@1 820 if (node_comment_mode($comment->nid) == COMMENT_NODE_READ_WRITE) {
webmaster@1 821 if (user_access('administer comments') && user_access('post comments')) {
webmaster@1 822 $links['comment_delete'] = array(
webmaster@1 823 'title' => t('delete'),
webmaster@1 824 'href' => "comment/delete/$comment->cid"
webmaster@1 825 );
webmaster@1 826 $links['comment_edit'] = array(
webmaster@1 827 'title' => t('edit'),
webmaster@1 828 'href' => "comment/edit/$comment->cid"
webmaster@1 829 );
webmaster@1 830 $links['comment_reply'] = array(
webmaster@1 831 'title' => t('reply'),
webmaster@1 832 'href' => "comment/reply/$comment->nid/$comment->cid"
webmaster@1 833 );
webmaster@1 834 }
webmaster@1 835 else if (user_access('post comments')) {
webmaster@1 836 if (comment_access('edit', $comment)) {
webmaster@1 837 $links['comment_edit'] = array(
webmaster@1 838 'title' => t('edit'),
webmaster@1 839 'href' => "comment/edit/$comment->cid"
webmaster@1 840 );
webmaster@1 841 }
webmaster@1 842 $links['comment_reply'] = array(
webmaster@1 843 'title' => t('reply'),
webmaster@1 844 'href' => "comment/reply/$comment->nid/$comment->cid"
webmaster@1 845 );
webmaster@1 846 }
webmaster@1 847 else {
webmaster@1 848 $node = node_load($comment->nid);
webmaster@1 849 $links['comment_forbidden']['title'] = theme('comment_post_forbidden', $node);
webmaster@1 850 }
webmaster@1 851 }
webmaster@1 852
webmaster@1 853 return $links;
webmaster@1 854 }
webmaster@1 855
webmaster@1 856 /**
webmaster@1 857 * Renders comment(s).
webmaster@1 858 *
webmaster@1 859 * @param $node
webmaster@1 860 * The node which comment(s) needs rendering.
webmaster@1 861 * @param $cid
webmaster@1 862 * Optional, if given, only one comment is rendered.
webmaster@1 863 *
webmaster@1 864 * To display threaded comments in the correct order we keep a 'thread' field
webmaster@1 865 * and order by that value. This field keeps this data in
webmaster@1 866 * a way which is easy to update and convenient to use.
webmaster@1 867 *
webmaster@1 868 * A "thread" value starts at "1". If we add a child (A) to this comment,
webmaster@1 869 * we assign it a "thread" = "1.1". A child of (A) will have "1.1.1". Next
webmaster@1 870 * brother of (A) will get "1.2". Next brother of the parent of (A) will get
webmaster@1 871 * "2" and so on.
webmaster@1 872 *
webmaster@1 873 * First of all note that the thread field stores the depth of the comment:
webmaster@1 874 * depth 0 will be "X", depth 1 "X.X", depth 2 "X.X.X", etc.
webmaster@1 875 *
webmaster@1 876 * Now to get the ordering right, consider this example:
webmaster@1 877 *
webmaster@1 878 * 1
webmaster@1 879 * 1.1
webmaster@1 880 * 1.1.1
webmaster@1 881 * 1.2
webmaster@1 882 * 2
webmaster@1 883 *
webmaster@1 884 * If we "ORDER BY thread ASC" we get the above result, and this is the
webmaster@1 885 * natural order sorted by time. However, if we "ORDER BY thread DESC"
webmaster@1 886 * we get:
webmaster@1 887 *
webmaster@1 888 * 2
webmaster@1 889 * 1.2
webmaster@1 890 * 1.1.1
webmaster@1 891 * 1.1
webmaster@1 892 * 1
webmaster@1 893 *
webmaster@1 894 * Clearly, this is not a natural way to see a thread, and users will get
webmaster@1 895 * confused. The natural order to show a thread by time desc would be:
webmaster@1 896 *
webmaster@1 897 * 2
webmaster@1 898 * 1
webmaster@1 899 * 1.2
webmaster@1 900 * 1.1
webmaster@1 901 * 1.1.1
webmaster@1 902 *
webmaster@1 903 * which is what we already did before the standard pager patch. To achieve
webmaster@1 904 * this we simply add a "/" at the end of each "thread" value. This way out
webmaster@1 905 * thread fields will look like depicted below:
webmaster@1 906 *
webmaster@1 907 * 1/
webmaster@1 908 * 1.1/
webmaster@1 909 * 1.1.1/
webmaster@1 910 * 1.2/
webmaster@1 911 * 2/
webmaster@1 912 *
webmaster@1 913 * we add "/" since this char is, in ASCII, higher than every number, so if
webmaster@1 914 * now we "ORDER BY thread DESC" we get the correct order. However this would
webmaster@1 915 * spoil the reverse ordering, "ORDER BY thread ASC" -- here, we do not need
webmaster@1 916 * to consider the trailing "/" so we use a substring only.
webmaster@1 917 */
webmaster@1 918 function comment_render($node, $cid = 0) {
webmaster@1 919 global $user;
webmaster@1 920
webmaster@1 921 $output = '';
webmaster@1 922
webmaster@1 923 if (user_access('access comments')) {
webmaster@1 924 // Pre-process variables.
webmaster@1 925 $nid = $node->nid;
webmaster@1 926 if (empty($nid)) {
webmaster@1 927 $nid = 0;
webmaster@1 928 }
webmaster@1 929
webmaster@1 930 $mode = _comment_get_display_setting('mode', $node);
webmaster@1 931 $order = _comment_get_display_setting('sort', $node);
webmaster@1 932 $comments_per_page = _comment_get_display_setting('comments_per_page', $node);
webmaster@1 933
webmaster@1 934 if ($cid && is_numeric($cid)) {
webmaster@1 935 // Single comment view.
webmaster@1 936 $query = 'SELECT c.cid, c.pid, c.nid, c.subject, c.comment, c.format, c.timestamp, c.name, c.mail, c.homepage, u.uid, u.name AS registered_name, u.signature, u.picture, u.data, c.status FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d';
webmaster@1 937 $query_args = array($cid);
webmaster@1 938 if (!user_access('administer comments')) {
webmaster@1 939 $query .= ' AND c.status = %d';
webmaster@1 940 $query_args[] = COMMENT_PUBLISHED;
webmaster@1 941 }
webmaster@1 942
webmaster@1 943 $query = db_rewrite_sql($query, 'c', 'cid');
webmaster@1 944 $result = db_query($query, $query_args);
webmaster@1 945
webmaster@1 946 if ($comment = db_fetch_object($result)) {
webmaster@1 947 $comment->name = $comment->uid ? $comment->registered_name : $comment->name;
webmaster@1 948 $links = module_invoke_all('link', 'comment', $comment, 1);
webmaster@1 949 drupal_alter('link', $links, $node);
webmaster@1 950
webmaster@1 951 $output .= theme('comment_view', $comment, $node, $links);
webmaster@1 952 }
webmaster@1 953 }
webmaster@1 954 else {
webmaster@1 955 // Multiple comment view
webmaster@1 956 $query_count = 'SELECT COUNT(*) FROM {comments} WHERE nid = %d';
webmaster@1 957 $query = 'SELECT c.cid as cid, c.pid, c.nid, c.subject, c.comment, c.format, c.timestamp, c.name, c.mail, c.homepage, u.uid, u.name AS registered_name, u.signature, u.picture, u.data, c.thread, c.status FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.nid = %d';
webmaster@1 958
webmaster@1 959 $query_args = array($nid);
webmaster@1 960 if (!user_access('administer comments')) {
webmaster@1 961 $query .= ' AND c.status = %d';
webmaster@1 962 $query_count .= ' AND status = %d';
webmaster@1 963 $query_args[] = COMMENT_PUBLISHED;
webmaster@1 964 }
webmaster@1 965
webmaster@1 966 if ($order == COMMENT_ORDER_NEWEST_FIRST) {
webmaster@1 967 if ($mode == COMMENT_MODE_FLAT_COLLAPSED || $mode == COMMENT_MODE_FLAT_EXPANDED) {
webmaster@1 968 $query .= ' ORDER BY c.cid DESC';
webmaster@1 969 }
webmaster@1 970 else {
webmaster@1 971 $query .= ' ORDER BY c.thread DESC';
webmaster@1 972 }
webmaster@1 973 }
webmaster@1 974 else if ($order == COMMENT_ORDER_OLDEST_FIRST) {
webmaster@1 975 if ($mode == COMMENT_MODE_FLAT_COLLAPSED || $mode == COMMENT_MODE_FLAT_EXPANDED) {
webmaster@1 976 $query .= ' ORDER BY c.cid';
webmaster@1 977 }
webmaster@1 978 else {
webmaster@1 979 // See comment above. Analysis reveals that this doesn't cost too
webmaster@1 980 // much. It scales much much better than having the whole comment
webmaster@1 981 // structure.
webmaster@1 982 $query .= ' ORDER BY SUBSTRING(c.thread, 1, (LENGTH(c.thread) - 1))';
webmaster@1 983 }
webmaster@1 984 }
webmaster@1 985 $query = db_rewrite_sql($query, 'c', 'cid');
webmaster@1 986 $query_count = db_rewrite_sql($query_count, 'c', 'cid');
webmaster@1 987
webmaster@1 988 // Start a form, for use with comment control.
webmaster@1 989 $result = pager_query($query, $comments_per_page, 0, $query_count, $query_args);
webmaster@1 990
webmaster@1 991 $divs = 0;
webmaster@1 992 $num_rows = FALSE;
webmaster@1 993 $comments = '';
webmaster@1 994 drupal_add_css(drupal_get_path('module', 'comment') .'/comment.css');
webmaster@1 995 while ($comment = db_fetch_object($result)) {
webmaster@1 996 $comment = drupal_unpack($comment);
webmaster@1 997 $comment->name = $comment->uid ? $comment->registered_name : $comment->name;
webmaster@1 998 $comment->depth = count(explode('.', $comment->thread)) - 1;
webmaster@1 999
webmaster@1 1000 if ($mode == COMMENT_MODE_THREADED_COLLAPSED || $mode == COMMENT_MODE_THREADED_EXPANDED) {
webmaster@1 1001 if ($comment->depth > $divs) {
webmaster@1 1002 $divs++;
webmaster@1 1003 $comments .= '<div class="indented">';
webmaster@1 1004 }
webmaster@1 1005 else {
webmaster@1 1006 while ($comment->depth < $divs) {
webmaster@1 1007 $divs--;
webmaster@1 1008 $comments .= '</div>';
webmaster@1 1009 }
webmaster@1 1010 }
webmaster@1 1011 }
webmaster@1 1012
webmaster@1 1013 if ($mode == COMMENT_MODE_FLAT_COLLAPSED) {
webmaster@1 1014 $comments .= theme('comment_flat_collapsed', $comment, $node);
webmaster@1 1015 }
webmaster@1 1016 else if ($mode == COMMENT_MODE_FLAT_EXPANDED) {
webmaster@1 1017 $comments .= theme('comment_flat_expanded', $comment, $node);
webmaster@1 1018 }
webmaster@1 1019 else if ($mode == COMMENT_MODE_THREADED_COLLAPSED) {
webmaster@1 1020 $comments .= theme('comment_thread_collapsed', $comment, $node);
webmaster@1 1021 }
webmaster@1 1022 else if ($mode == COMMENT_MODE_THREADED_EXPANDED) {
webmaster@1 1023 $comments .= theme('comment_thread_expanded', $comment, $node);
webmaster@1 1024 }
webmaster@1 1025
webmaster@1 1026 $num_rows = TRUE;
webmaster@1 1027 }
webmaster@1 1028 while ($divs-- > 0) {
webmaster@1 1029 $comments .= '</div>';
webmaster@1 1030 }
webmaster@1 1031
webmaster@1 1032 $comment_controls = variable_get('comment_controls_'. $node->type, COMMENT_CONTROLS_HIDDEN);
webmaster@1 1033 if ($num_rows && ($comment_controls == COMMENT_CONTROLS_ABOVE || $comment_controls == COMMENT_CONTROLS_ABOVE_BELOW)) {
webmaster@1 1034 $output .= drupal_get_form('comment_controls', $mode, $order, $comments_per_page);
webmaster@1 1035 }
webmaster@1 1036
webmaster@1 1037 $output .= $comments;
webmaster@1 1038 $output .= theme('pager', NULL, $comments_per_page, 0);
webmaster@1 1039
webmaster@1 1040 if ($num_rows && ($comment_controls == COMMENT_CONTROLS_BELOW || $comment_controls == COMMENT_CONTROLS_ABOVE_BELOW)) {
webmaster@1 1041 $output .= drupal_get_form('comment_controls', $mode, $order, $comments_per_page);
webmaster@1 1042 }
webmaster@1 1043 }
webmaster@1 1044
webmaster@1 1045 // If enabled, show new comment form if it's not already being displayed.
webmaster@1 1046 $reply = arg(0) == 'comment' && arg(1) == 'reply';
webmaster@1 1047 if (user_access('post comments') && node_comment_mode($nid) == COMMENT_NODE_READ_WRITE && (variable_get('comment_form_location_'. $node->type, COMMENT_FORM_SEPARATE_PAGE) == COMMENT_FORM_BELOW) && !$reply) {
webmaster@1 1048 $output .= comment_form_box(array('nid' => $nid), t('Post new comment'));
webmaster@1 1049 }
webmaster@1 1050
webmaster@1 1051 $output = theme('comment_wrapper', $output, $node);
webmaster@1 1052 }
webmaster@1 1053
webmaster@1 1054 return $output;
webmaster@1 1055 }
webmaster@1 1056
webmaster@1 1057 /**
webmaster@1 1058 * Comment operations. We offer different update operations depending on
webmaster@1 1059 * which comment administration page we're on.
webmaster@1 1060 *
webmaster@1 1061 * @param $action
webmaster@1 1062 * The comment administration page.
webmaster@1 1063 * @return
webmaster@1 1064 * An associative array containing the offered operations.
webmaster@1 1065 */
webmaster@1 1066 function comment_operations($action = NULL) {
webmaster@1 1067 if ($action == 'publish') {
webmaster@1 1068 $operations = array(
webmaster@1 1069 'publish' => array(t('Publish the selected comments'), 'UPDATE {comments} SET status = '. COMMENT_PUBLISHED .' WHERE cid = %d'),
webmaster@1 1070 'delete' => array(t('Delete the selected comments'), '')
webmaster@1 1071 );
webmaster@1 1072 }
webmaster@1 1073 else if ($action == 'unpublish') {
webmaster@1 1074 $operations = array(
webmaster@1 1075 'unpublish' => array(t('Unpublish the selected comments'), 'UPDATE {comments} SET status = '. COMMENT_NOT_PUBLISHED .' WHERE cid = %d'),
webmaster@1 1076 'delete' => array(t('Delete the selected comments'), '')
webmaster@1 1077 );
webmaster@1 1078 }
webmaster@1 1079 else {
webmaster@1 1080 $operations = array(
webmaster@1 1081 'publish' => array(t('Publish the selected comments'), 'UPDATE {comments} SET status = '. COMMENT_PUBLISHED .' WHERE cid = %d'),
webmaster@1 1082 'unpublish' => array(t('Unpublish the selected comments'), 'UPDATE {comments} SET status = '. COMMENT_NOT_PUBLISHED .' WHERE cid = %d'),
webmaster@1 1083 'delete' => array(t('Delete the selected comments'), '')
webmaster@1 1084 );
webmaster@1 1085 }
webmaster@1 1086 return $operations;
webmaster@1 1087 }
webmaster@1 1088
webmaster@1 1089 /**
webmaster@1 1090 * Misc functions: helpers, privates, history
webmaster@1 1091 */
webmaster@1 1092
webmaster@1 1093 /**
webmaster@1 1094 * Load the entire comment by cid.
webmaster@1 1095 *
webmaster@1 1096 * @param $cid
webmaster@1 1097 * The identifying comment id.
webmaster@1 1098 * @return
webmaster@1 1099 * The comment object.
webmaster@1 1100 */
webmaster@1 1101 function _comment_load($cid) {
webmaster@1 1102 return db_fetch_object(db_query('SELECT * FROM {comments} WHERE cid = %d', $cid));
webmaster@1 1103 }
webmaster@1 1104
webmaster@1 1105 /**
webmaster@1 1106 * Get comment count for a node.
webmaster@1 1107 *
webmaster@1 1108 * @param $nid
webmaster@1 1109 * The node id.
webmaster@1 1110 * @return
webmaster@1 1111 * The comment count.
webmaster@1 1112 */
webmaster@1 1113 function comment_num_all($nid) {
webmaster@1 1114 static $cache;
webmaster@1 1115
webmaster@1 1116 if (!isset($cache[$nid])) {
webmaster@1 1117 $cache[$nid] = db_result(db_query('SELECT comment_count FROM {node_comment_statistics} WHERE nid = %d', $nid));
webmaster@1 1118 }
webmaster@1 1119 return $cache[$nid];
webmaster@1 1120 }
webmaster@1 1121
webmaster@1 1122 /**
webmaster@1 1123 * Get replies count for a comment.
webmaster@1 1124 *
webmaster@1 1125 * @param $pid
webmaster@1 1126 * The comment id.
webmaster@1 1127 * @return
webmaster@1 1128 * The replies count.
webmaster@1 1129 */
webmaster@1 1130 function comment_num_replies($pid) {
webmaster@1 1131 static $cache;
webmaster@1 1132
webmaster@1 1133 if (!isset($cache[$pid])) {
webmaster@1 1134 $cache[$pid] = db_result(db_query('SELECT COUNT(cid) FROM {comments} WHERE pid = %d AND status = %d', $pid, COMMENT_PUBLISHED));
webmaster@1 1135 }
webmaster@1 1136
webmaster@1 1137 return $cache[$pid];
webmaster@1 1138 }
webmaster@1 1139
webmaster@1 1140 /**
webmaster@1 1141 * Get number of new comments for current user and specified node.
webmaster@1 1142 *
webmaster@1 1143 * @param $nid
webmaster@1 1144 * node-id to count comments for
webmaster@1 1145 * @param $timestamp
webmaster@1 1146 * time to count from (defaults to time of last user access
webmaster@1 1147 * to node)
webmaster@1 1148 */
webmaster@1 1149 function comment_num_new($nid, $timestamp = 0) {
webmaster@1 1150 global $user;
webmaster@1 1151
webmaster@1 1152 if ($user->uid) {
webmaster@1 1153 // Retrieve the timestamp at which the current user last viewed the
webmaster@1 1154 // specified node.
webmaster@1 1155 if (!$timestamp) {
webmaster@1 1156 $timestamp = node_last_viewed($nid);
webmaster@1 1157 }
webmaster@1 1158 $timestamp = ($timestamp > NODE_NEW_LIMIT ? $timestamp : NODE_NEW_LIMIT);
webmaster@1 1159
webmaster@1 1160 // Use the timestamp to retrieve the number of new comments.
webmaster@1 1161 $result = db_result(db_query('SELECT COUNT(c.cid) FROM {node} n INNER JOIN {comments} c ON n.nid = c.nid WHERE n.nid = %d AND timestamp > %d AND c.status = %d', $nid, $timestamp, COMMENT_PUBLISHED));
webmaster@1 1162
webmaster@1 1163 return $result;
webmaster@1 1164 }
webmaster@1 1165 else {
webmaster@1 1166 return 0;
webmaster@1 1167 }
webmaster@1 1168
webmaster@1 1169 }
webmaster@1 1170
webmaster@1 1171 /**
webmaster@1 1172 * Validate comment data.
webmaster@1 1173 *
webmaster@1 1174 * @param $edit
webmaster@1 1175 * An associative array containig the comment data.
webmaster@1 1176 * @return
webmaster@1 1177 * The original $edit.
webmaster@1 1178 */
webmaster@1 1179 function comment_validate($edit) {
webmaster@1 1180 global $user;
webmaster@1 1181
webmaster@1 1182 // Invoke other validation handlers
webmaster@1 1183 comment_invoke_comment($edit, 'validate');
webmaster@1 1184
webmaster@1 1185 if (isset($edit['date'])) {
webmaster@1 1186 // As of PHP 5.1.0, strtotime returns FALSE upon failure instead of -1.
webmaster@1 1187 if (strtotime($edit['date']) <= 0) {
webmaster@1 1188 form_set_error('date', t('You have to specify a valid date.'));
webmaster@1 1189 }
webmaster@1 1190 }
webmaster@1 1191 if (isset($edit['author']) && !$account = user_load(array('name' => $edit['author']))) {
webmaster@1 1192 form_set_error('author', t('You have to specify a valid author.'));
webmaster@1 1193 }
webmaster@1 1194
webmaster@1 1195 // Check validity of name, mail and homepage (if given)
webmaster@1 1196 if (!$user->uid || isset($edit['is_anonymous'])) {
webmaster@1 1197 $node = node_load($edit['nid']);
webmaster@1 1198 if (variable_get('comment_anonymous_'. $node->type, COMMENT_ANONYMOUS_MAYNOT_CONTACT) > COMMENT_ANONYMOUS_MAYNOT_CONTACT) {
webmaster@1 1199 if ($edit['name']) {
webmaster@1 1200 $taken = db_result(db_query("SELECT COUNT(uid) FROM {users} WHERE LOWER(name) = '%s'", $edit['name']));
webmaster@1 1201
webmaster@1 1202 if ($taken != 0) {
webmaster@1 1203 form_set_error('name', t('The name you used belongs to a registered user.'));
webmaster@1 1204 }
webmaster@1 1205
webmaster@1 1206 }
webmaster@1 1207 else if (variable_get('comment_anonymous_'. $node->type, COMMENT_ANONYMOUS_MAYNOT_CONTACT) == COMMENT_ANONYMOUS_MUST_CONTACT) {
webmaster@1 1208 form_set_error('name', t('You have to leave your name.'));
webmaster@1 1209 }
webmaster@1 1210
webmaster@1 1211 if ($edit['mail']) {
webmaster@1 1212 if (!valid_email_address($edit['mail'])) {
webmaster@1 1213 form_set_error('mail', t('The e-mail address you specified is not valid.'));
webmaster@1 1214 }
webmaster@1 1215 }
webmaster@1 1216 else if (variable_get('comment_anonymous_'. $node->type, COMMENT_ANONYMOUS_MAYNOT_CONTACT) == COMMENT_ANONYMOUS_MUST_CONTACT) {
webmaster@1 1217 form_set_error('mail', t('You have to leave an e-mail address.'));
webmaster@1 1218 }
webmaster@1 1219
webmaster@1 1220 if ($edit['homepage']) {
webmaster@1 1221 if (!valid_url($edit['homepage'], TRUE)) {
webmaster@1 1222 form_set_error('homepage', t('The URL of your homepage is not valid. Remember that it must be fully qualified, i.e. of the form <code>http://example.com/directory</code>.'));
webmaster@1 1223 }
webmaster@1 1224 }
webmaster@1 1225 }
webmaster@1 1226 }
webmaster@1 1227
webmaster@1 1228 return $edit;
webmaster@1 1229 }
webmaster@1 1230
webmaster@1 1231 /**
webmaster@1 1232 * Generate the basic commenting form, for appending to a node or display on a separate page.
webmaster@1 1233 *
webmaster@1 1234 * @param $title
webmaster@1 1235 * Not used.
webmaster@1 1236 * @ingroup forms
webmaster@1 1237 * @see comment_form_validate()
webmaster@1 1238 * @see comment_form_submit()
webmaster@1 1239 */
webmaster@1 1240 function comment_form(&$form_state, $edit, $title = NULL) {
webmaster@1 1241 global $user;
webmaster@1 1242
webmaster@1 1243 $op = isset($_POST['op']) ? $_POST['op'] : '';
webmaster@1 1244 $node = node_load($edit['nid']);
webmaster@1 1245
webmaster@1 1246 if (!$user->uid && variable_get('comment_anonymous_'. $node->type, COMMENT_ANONYMOUS_MAYNOT_CONTACT) != COMMENT_ANONYMOUS_MAYNOT_CONTACT) {
webmaster@1 1247 drupal_add_js(drupal_get_path('module', 'comment') .'/comment.js');
webmaster@1 1248 }
webmaster@1 1249 $edit += array('name' => '', 'mail' => '', 'homepage' => '');
webmaster@1 1250 if ($user->uid) {
webmaster@1 1251 if (!empty($edit['cid']) && user_access('administer comments')) {
webmaster@1 1252 if (!empty($edit['author'])) {
webmaster@1 1253 $author = $edit['author'];
webmaster@1 1254 }
webmaster@1 1255 elseif (!empty($edit['name'])) {
webmaster@1 1256 $author = $edit['name'];
webmaster@1 1257 }
webmaster@1 1258 else {
webmaster@1 1259 $author = $edit['registered_name'];
webmaster@1 1260 }
webmaster@1 1261
webmaster@1 1262 if (!empty($edit['status'])) {
webmaster@1 1263 $status = $edit['status'];
webmaster@1 1264 }
webmaster@1 1265 else {
webmaster@1 1266 $status = 0;
webmaster@1 1267 }
webmaster@1 1268
webmaster@1 1269 if (!empty($edit['date'])) {
webmaster@1 1270 $date = $edit['date'];
webmaster@1 1271 }
webmaster@1 1272 else {
webmaster@1 1273 $date = format_date($edit['timestamp'], 'custom', 'Y-m-d H:i O');
webmaster@1 1274 }
webmaster@1 1275
webmaster@1 1276 $form['admin'] = array(
webmaster@1 1277 '#type' => 'fieldset',
webmaster@1 1278 '#title' => t('Administration'),
webmaster@1 1279 '#collapsible' => TRUE,
webmaster@1 1280 '#collapsed' => TRUE,
webmaster@1 1281 '#weight' => -2,
webmaster@1 1282 );
webmaster@1 1283
webmaster@1 1284 if ($edit['registered_name'] != '') {
webmaster@1 1285 // The comment is by a registered user
webmaster@1 1286 $form['admin']['author'] = array(
webmaster@1 1287 '#type' => 'textfield',
webmaster@1 1288 '#title' => t('Authored by'),
webmaster@1 1289 '#size' => 30,
webmaster@1 1290 '#maxlength' => 60,
webmaster@1 1291 '#autocomplete_path' => 'user/autocomplete',
webmaster@1 1292 '#default_value' => $author,
webmaster@1 1293 '#weight' => -1,
webmaster@1 1294 );
webmaster@1 1295 }
webmaster@1 1296 else {
webmaster@1 1297 // The comment is by an anonymous user
webmaster@1 1298 $form['is_anonymous'] = array(
webmaster@1 1299 '#type' => 'value',
webmaster@1 1300 '#value' => TRUE,
webmaster@1 1301 );
webmaster@1 1302 $form['admin']['name'] = array(
webmaster@1 1303 '#type' => 'textfield',
webmaster@1 1304 '#title' => t('Authored by'),
webmaster@1 1305 '#size' => 30,
webmaster@1 1306 '#maxlength' => 60,
webmaster@1 1307 '#default_value' => $author,
webmaster@1 1308 '#weight' => -1,
webmaster@1 1309 );
webmaster@1 1310 $form['admin']['mail'] = array(
webmaster@1 1311 '#type' => 'textfield',
webmaster@1 1312 '#title' => t('E-mail'),
webmaster@1 1313 '#maxlength' => 64,
webmaster@1 1314 '#size' => 30,
webmaster@1 1315 '#default_value' => $edit['mail'],
webmaster@1 1316 '#description' => t('The content of this field is kept private and will not be shown publicly.'),
webmaster@1 1317 );
webmaster@1 1318
webmaster@1 1319 $form['admin']['homepage'] = array(
webmaster@1 1320 '#type' => 'textfield',
webmaster@1 1321 '#title' => t('Homepage'),
webmaster@1 1322 '#maxlength' => 255,
webmaster@1 1323 '#size' => 30,
webmaster@1 1324 '#default_value' => $edit['homepage'],
webmaster@1 1325 );
webmaster@1 1326 }
webmaster@1 1327
webmaster@1 1328 $form['admin']['date'] = array('#type' => 'textfield', '#parents' => array('date'), '#title' => t('Authored on'), '#size' => 20, '#maxlength' => 25, '#default_value' => $date, '#weight' => -1);
webmaster@1 1329
webmaster@1 1330 $form['admin']['status'] = array('#type' => 'radios', '#parents' => array('status'), '#title' => t('Status'), '#default_value' => $status, '#options' => array(t('Published'), t('Not published')), '#weight' => -1);
webmaster@1 1331
webmaster@1 1332 }
webmaster@1 1333 else {
webmaster@1 1334 $form['_author'] = array('#type' => 'item', '#title' => t('Your name'), '#value' => theme('username', $user)
webmaster@1 1335 );
webmaster@1 1336 $form['author'] = array('#type' => 'value', '#value' => $user->name);
webmaster@1 1337 }
webmaster@1 1338 }
webmaster@1 1339 else if (variable_get('comment_anonymous_'. $node->type, COMMENT_ANONYMOUS_MAYNOT_CONTACT) == COMMENT_ANONYMOUS_MAY_CONTACT) {
webmaster@1 1340 $form['name'] = array('#type' => 'textfield', '#title' => t('Your name'), '#maxlength' => 60, '#size' => 30, '#default_value' => $edit['name'] ? $edit['name'] : variable_get('anonymous', t('Anonymous'))
webmaster@1 1341 );
webmaster@1 1342
webmaster@1 1343 $form['mail'] = array('#type' => 'textfield', '#title' => t('E-mail'), '#maxlength' => 64, '#size' => 30, '#default_value' => $edit['mail'], '#description' => t('The content of this field is kept private and will not be shown publicly.')
webmaster@1 1344 );
webmaster@1 1345
webmaster@1 1346 $form['homepage'] = array('#type' => 'textfield', '#title' => t('Homepage'), '#maxlength' => 255, '#size' => 30, '#default_value' => $edit['homepage']);
webmaster@1 1347 }
webmaster@1 1348 else if (variable_get('comment_anonymous_'. $node->type, COMMENT_ANONYMOUS_MAYNOT_CONTACT) == COMMENT_ANONYMOUS_MUST_CONTACT) {
webmaster@1 1349 $form['name'] = array('#type' => 'textfield', '#title' => t('Your name'), '#maxlength' => 60, '#size' => 30, '#default_value' => $edit['name'] ? $edit['name'] : variable_get('anonymous', t('Anonymous')), '#required' => TRUE);
webmaster@1 1350
webmaster@1 1351 $form['mail'] = array('#type' => 'textfield', '#title' => t('E-mail'), '#maxlength' => 64, '#size' => 30, '#default_value' => $edit['mail'], '#description' => t('The content of this field is kept private and will not be shown publicly.'), '#required' => TRUE);
webmaster@1 1352
webmaster@1 1353 $form['homepage'] = array('#type' => 'textfield', '#title' => t('Homepage'), '#maxlength' => 255, '#size' => 30, '#default_value' => $edit['homepage']);
webmaster@1 1354 }
webmaster@1 1355
webmaster@1 1356 if (variable_get('comment_subject_field_'. $node->type, 1) == 1) {
webmaster@1 1357 $form['subject'] = array('#type' => 'textfield', '#title' => t('Subject'), '#maxlength' => 64, '#default_value' => !empty($edit['subject']) ? $edit['subject'] : '');
webmaster@1 1358 }
webmaster@1 1359
webmaster@1 1360 if (!empty($edit['comment'])) {
webmaster@1 1361 $default = $edit['comment'];
webmaster@1 1362 }
webmaster@1 1363 else {
webmaster@1 1364 $default = '';
webmaster@1 1365 }
webmaster@1 1366
webmaster@1 1367 $form['comment_filter']['comment'] = array(
webmaster@1 1368 '#type' => 'textarea',
webmaster@1 1369 '#title' => t('Comment'),
webmaster@1 1370 '#rows' => 15,
webmaster@1 1371 '#default_value' => $default,
webmaster@1 1372 '#required' => TRUE,
webmaster@1 1373 );
webmaster@1 1374 if (!isset($edit['format'])) {
webmaster@1 1375 $edit['format'] = FILTER_FORMAT_DEFAULT;
webmaster@1 1376 }
webmaster@1 1377 $form['comment_filter']['format'] = filter_form($edit['format']);
webmaster@1 1378
webmaster@1 1379 $form['cid'] = array('#type' => 'value', '#value' => !empty($edit['cid']) ? $edit['cid'] : NULL);
webmaster@1 1380 $form['pid'] = array('#type' => 'value', '#value' => !empty($edit['pid']) ? $edit['pid'] : NULL);
webmaster@1 1381 $form['nid'] = array('#type' => 'value', '#value' => $edit['nid']);
webmaster@1 1382 $form['uid'] = array('#type' => 'value', '#value' => !empty($edit['uid']) ? $edit['uid'] : NULL);
webmaster@1 1383
webmaster@1 1384 // Only show save button if preview is optional or if we are in preview mode.
webmaster@1 1385 // We show the save button in preview mode even if there are form errors so that
webmaster@1 1386 // optional form elements (e.g., captcha) can be updated in preview mode.
webmaster@1 1387 if (!form_get_errors() && ((variable_get('comment_preview_'. $node->type, COMMENT_PREVIEW_REQUIRED) == COMMENT_PREVIEW_OPTIONAL) || ($op == t('Preview')) || ($op == t('Save')))) {
webmaster@1 1388 $form['submit'] = array('#type' => 'submit', '#value' => t('Save'), '#weight' => 19);
webmaster@1 1389 }
webmaster@1 1390
webmaster@1 1391 $form['preview'] = array('#type' => 'button', '#value' => t('Preview'), '#weight' => 20);
webmaster@1 1392 $form['#token'] = 'comment'. $edit['nid'] . (isset($edit['pid']) ? $edit['pid'] : '');
webmaster@1 1393
webmaster@1 1394 if ($op == t('Preview')) {
webmaster@1 1395 $form['#after_build'] = array('comment_form_add_preview');
webmaster@1 1396 }
webmaster@1 1397
webmaster@1 1398 if (empty($edit['cid']) && empty($edit['pid'])) {
webmaster@1 1399 $form['#action'] = url('comment/reply/'. $edit['nid']);
webmaster@1 1400 }
webmaster@1 1401
webmaster@1 1402 return $form;
webmaster@1 1403 }
webmaster@1 1404
webmaster@1 1405 /**
webmaster@1 1406 * Theme the comment form box.
webmaster@1 1407 *
webmaster@1 1408 * @param $edit
webmaster@1 1409 * The form structure.
webmaster@1 1410 * @param $title
webmaster@1 1411 * The form title.
webmaster@1 1412 */
webmaster@1 1413 function comment_form_box($edit, $title = NULL) {
webmaster@1 1414 return theme('box', $title, drupal_get_form('comment_form', $edit, $title));
webmaster@1 1415 }
webmaster@1 1416
webmaster@1 1417 /**
webmaster@1 1418 * Form builder; Generate and validate a comment preview form.
webmaster@1 1419 *
webmaster@1 1420 * @ingroup forms
webmaster@1 1421 */
webmaster@1 1422 function comment_form_add_preview($form, &$form_state) {
webmaster@1 1423 global $user;
webmaster@1 1424 $edit = $form_state['values'];
webmaster@1 1425 drupal_set_title(t('Preview comment'));
webmaster@1 1426
webmaster@1 1427 $output = '';
webmaster@1 1428 $node = node_load($edit['nid']);
webmaster@1 1429
webmaster@1 1430 // Invoke full validation for the form, to protect against cross site
webmaster@1 1431 // request forgeries (CSRF) and setting arbitrary values for fields such as
webmaster@1 1432 // the input format. Preview the comment only when form validation does not
webmaster@1 1433 // set any errors.
webmaster@1 1434 drupal_validate_form($form['form_id']['#value'], $form, $form_state);
webmaster@1 1435 if (!form_get_errors()) {
webmaster@1 1436 _comment_form_submit($edit);
webmaster@1 1437 $comment = (object)$edit;
webmaster@1 1438
webmaster@1 1439 // Attach the user and time information.
webmaster@1 1440 if (!empty($edit['author'])) {
webmaster@1 1441 $account = user_load(array('name' => $edit['author']));
webmaster@1 1442 }
webmaster@1 1443 elseif ($user->uid && !isset($edit['is_anonymous'])) {
webmaster@1 1444 $account = $user;
webmaster@1 1445 }
webmaster@1 1446 if (!empty($account)) {
webmaster@1 1447 $comment->uid = $account->uid;
webmaster@1 1448 $comment->name = check_plain($account->name);
webmaster@1 1449 }
webmaster@1 1450 elseif (empty($comment->name)) {
webmaster@1 1451 $comment->name = variable_get('anonymous', t('Anonymous'));
webmaster@1 1452 }
webmaster@1 1453 $comment->timestamp = !empty($edit['timestamp']) ? $edit['timestamp'] : time();
webmaster@1 1454 $output .= theme('comment_view', $comment, $node);
webmaster@1 1455 }
webmaster@1 1456 $form['comment_preview'] = array(
webmaster@1 1457 '#value' => $output,
webmaster@1 1458 '#weight' => -100,
webmaster@1 1459 '#prefix' => '<div class="preview">',
webmaster@1 1460 '#suffix' => '</div>',
webmaster@1 1461 );
webmaster@1 1462
webmaster@1 1463 $output = '';
webmaster@1 1464
webmaster@1 1465 if ($edit['pid']) {
webmaster@1 1466 $comment = db_fetch_object(db_query('SELECT c.*, u.uid, u.name AS registered_name, u.signature, u.picture, u.data FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status = %d', $edit['pid'], COMMENT_PUBLISHED));
webmaster@1 1467 $comment = drupal_unpack($comment);
webmaster@1 1468 $comment->name = $comment->uid ? $comment->registered_name : $comment->name;
webmaster@1 1469 $output .= theme('comment_view', $comment, $node);
webmaster@1 1470 }
webmaster@1 1471 else {
webmaster@1 1472 $suffix = empty($form['#suffix']) ? '' : $form['#suffix'];
webmaster@1 1473 $form['#suffix'] = $suffix . node_view($node);
webmaster@1 1474 $edit['pid'] = 0;
webmaster@1 1475 }
webmaster@1 1476
webmaster@1 1477 $form['comment_preview_below'] = array('#value' => $output, '#weight' => 100);
webmaster@1 1478
webmaster@1 1479 return $form;
webmaster@1 1480 }
webmaster@1 1481
webmaster@1 1482 /**
webmaster@1 1483 * Validate comment form submissions.
webmaster@1 1484 */
webmaster@1 1485 function comment_form_validate($form, &$form_state) {
webmaster@1 1486 global $user;
webmaster@1 1487 if ($user->uid === 0) {
webmaster@1 1488 foreach (array('name', 'homepage', 'mail') as $field) {
webmaster@1 1489 // Set cookie for 365 days.
webmaster@1 1490 if (isset($form_state['values'][$field])) {
webmaster@1 1491 setcookie('comment_info_'. $field, $form_state['values'][$field], time() + 31536000, '/');
webmaster@1 1492 }
webmaster@1 1493 }
webmaster@1 1494 }
webmaster@1 1495 comment_validate($form_state['values']);
webmaster@1 1496 }
webmaster@1 1497
webmaster@1 1498 /**
webmaster@1 1499 * Prepare a comment for submission.
webmaster@1 1500 *
webmaster@1 1501 * @param $comment_values
webmaster@1 1502 * An associative array containing the comment data.
webmaster@1 1503 */
webmaster@1 1504 function _comment_form_submit(&$comment_values) {
webmaster@1 1505 $comment_values += array('subject' => '');
webmaster@1 1506 if (!isset($comment_values['date'])) {
webmaster@1 1507 $comment_values['date'] = 'now';
webmaster@1 1508 }
webmaster@1 1509 $comment_values['timestamp'] = strtotime($comment_values['date']);
webmaster@1 1510 if (isset($comment_values['author'])) {
webmaster@1 1511 $account = user_load(array('name' => $comment_values['author']));
webmaster@1 1512 $comment_values['uid'] = $account->uid;
webmaster@1 1513 $comment_values['name'] = $comment_values['author'];
webmaster@1 1514 }
webmaster@1 1515 // Validate the comment's subject. If not specified, extract
webmaster@1 1516 // one from the comment's body.
webmaster@1 1517 if (trim($comment_values['subject']) == '') {
webmaster@1 1518 // The body may be in any format, so we:
webmaster@1 1519 // 1) Filter it into HTML
webmaster@1 1520 // 2) Strip out all HTML tags
webmaster@1 1521 // 3) Convert entities back to plain-text.
webmaster@1 1522 // Note: format is checked by check_markup().
webmaster@1 1523 $comment_values['subject'] = trim(truncate_utf8(decode_entities(strip_tags(check_markup($comment_values['comment'], $comment_values['format']))), 29, TRUE));
webmaster@1 1524 // Edge cases where the comment body is populated only by HTML tags will
webmaster@1 1525 // require a default subject.
webmaster@1 1526 if ($comment_values['subject'] == '') {
webmaster@1 1527 $comment_values['subject'] = t('(No subject)');
webmaster@1 1528 }
webmaster@1 1529 }
webmaster@1 1530 }
webmaster@1 1531
webmaster@1 1532 /**
webmaster@1 1533 * Process comment form submissions; prepare the comment, store it, and set a redirection target.
webmaster@1 1534 */
webmaster@1 1535 function comment_form_submit($form, &$form_state) {
webmaster@1 1536 _comment_form_submit($form_state['values']);
webmaster@1 1537 if ($cid = comment_save($form_state['values'])) {
webmaster@1 1538 $node = node_load($form_state['values']['nid']);
webmaster@1 1539 $page = comment_new_page_count($node->comment_count, 1, $node);
webmaster@1 1540 $form_state['redirect'] = array('node/'. $node->nid, $page, "comment-$cid");
webmaster@1 1541 return;
webmaster@1 1542 }
webmaster@1 1543 }
webmaster@1 1544
webmaster@1 1545 /**
webmaster@1 1546 * Theme a single comment block.
webmaster@1 1547 *
webmaster@1 1548 * @param $comment
webmaster@1 1549 * The comment object.
webmaster@1 1550 * @param $node
webmaster@1 1551 * The comment node.
webmaster@1 1552 * @param $links
webmaster@1 1553 * An associative array containing control links.
webmaster@1 1554 * @param $visible
webmaster@1 1555 * Switches between folded/unfolded view.
webmaster@1 1556 * @ingroup themeable
webmaster@1 1557 */
webmaster@1 1558 function theme_comment_view($comment, $node, $links = array(), $visible = TRUE) {
webmaster@1 1559 static $first_new = TRUE;
webmaster@1 1560
webmaster@1 1561 $output = '';
webmaster@1 1562 $comment->new = node_mark($comment->nid, $comment->timestamp);
webmaster@1 1563 if ($first_new && $comment->new != MARK_READ) {
webmaster@1 1564 // Assign the anchor only for the first new comment. This avoids duplicate
webmaster@1 1565 // id attributes on a page.
webmaster@1 1566 $first_new = FALSE;
webmaster@1 1567 $output .= "<a id=\"new\"></a>\n";
webmaster@1 1568 }
webmaster@1 1569
webmaster@1 1570 $output .= "<a id=\"comment-$comment->cid\"></a>\n";
webmaster@1 1571
webmaster@1 1572 // Switch to folded/unfolded view of the comment
webmaster@1 1573 if ($visible) {
webmaster@1 1574 $comment->comment = check_markup($comment->comment, $comment->format, FALSE);
webmaster@1 1575
webmaster@1 1576 // Comment API hook
webmaster@1 1577 comment_invoke_comment($comment, 'view');
webmaster@1 1578
webmaster@1 1579 $output .= theme('comment', $comment, $node, $links);
webmaster@1 1580 }
webmaster@1 1581 else {
webmaster@1 1582 $output .= theme('comment_folded', $comment);
webmaster@1 1583 }
webmaster@1 1584
webmaster@1 1585 return $output;
webmaster@1 1586 }
webmaster@1 1587
webmaster@1 1588
webmaster@1 1589 /**
webmaster@1 1590 * Build a comment control form.
webmaster@1 1591 *
webmaster@1 1592 * @param $mode
webmaster@1 1593 * Comment display mode.
webmaster@1 1594 * @param $order
webmaster@1 1595 * Comment order mode.
webmaster@1 1596 * @param $comments_per_page
webmaster@1 1597 * Comments per page.
webmaster@1 1598 * @ingroup forms
webmaster@1 1599 */
webmaster@1 1600 function comment_controls($mode = COMMENT_MODE_THREADED_EXPANDED, $order = COMMENT_ORDER_NEWEST_FIRST, $comments_per_page = 50) {
webmaster@1 1601 $form['mode'] = array('#type' => 'select',
webmaster@1 1602 '#default_value' => $mode,
webmaster@1 1603 '#options' => _comment_get_modes(),
webmaster@1 1604 '#weight' => 1,
webmaster@1 1605 );
webmaster@1 1606 $form['order'] = array(
webmaster@1 1607 '#type' => 'select',
webmaster@1 1608 '#default_value' => $order,
webmaster@1 1609 '#options' => _comment_get_orders(),
webmaster@1 1610 '#weight' => 2,
webmaster@1 1611 );
webmaster@1 1612 foreach (_comment_per_page() as $i) {
webmaster@1 1613 $options[$i] = t('!a comments per page', array('!a' => $i));
webmaster@1 1614 }
webmaster@1 1615 $form['comments_per_page'] = array('#type' => 'select',
webmaster@1 1616 '#default_value' => $comments_per_page,
webmaster@1 1617 '#options' => $options,
webmaster@1 1618 '#weight' => 3,
webmaster@1 1619 );
webmaster@1 1620
webmaster@1 1621 $form['submit'] = array('#type' => 'submit',
webmaster@1 1622 '#value' => t('Save settings'),
webmaster@1 1623 '#weight' => 20,
webmaster@1 1624 );
webmaster@1 1625
webmaster@1 1626 return $form;
webmaster@1 1627 }
webmaster@1 1628
webmaster@1 1629 /**
webmaster@1 1630 * Theme comment controls box where the user can change the default display mode and display order of comments.
webmaster@1 1631 *
webmaster@1 1632 * @param $form
webmaster@1 1633 * The form structure.
webmaster@1 1634 * @ingroup themeable
webmaster@1 1635 */
webmaster@1 1636 function theme_comment_controls($form) {
webmaster@1 1637 $output = '<div class="container-inline">';
webmaster@1 1638 $output .= drupal_render($form);
webmaster@1 1639 $output .= '</div>';
webmaster@1 1640 $output .= '<div class="description">'. t('Select your preferred way to display the comments and click "Save settings" to activate your changes.') .'</div>';
webmaster@1 1641 return theme('box', t('Comment viewing options'), $output);
webmaster@1 1642 }
webmaster@1 1643
webmaster@1 1644 /**
webmaster@1 1645 * Process comment_controls form submissions.
webmaster@1 1646 */
webmaster@1 1647 function comment_controls_submit($form, &$form_state) {
webmaster@1 1648 global $user;
webmaster@1 1649
webmaster@1 1650 $mode = $form_state['values']['mode'];
webmaster@1 1651 $order = $form_state['values']['order'];
webmaster@1 1652 $comments_per_page = $form_state['values']['comments_per_page'];
webmaster@1 1653
webmaster@1 1654 if ($user->uid) {
webmaster@1 1655 $account = user_save($user, array('mode' => $mode, 'sort' => $order, 'comments_per_page' => $comments_per_page));
webmaster@1 1656 // Terminate if an error occured during user_save().
webmaster@1 1657 if (!$account) {
webmaster@1 1658 drupal_set_message(t("Error saving user account."), 'error');
webmaster@1 1659 return;
webmaster@1 1660 }
webmaster@1 1661 $user = $account;
webmaster@1 1662 }
webmaster@1 1663 else {
webmaster@1 1664 $_SESSION['comment_mode'] = $mode;
webmaster@1 1665 $_SESSION['comment_sort'] = $order;
webmaster@1 1666 $_SESSION['comment_comments_per_page'] = $comments_per_page;
webmaster@1 1667 }
webmaster@1 1668 }
webmaster@1 1669
webmaster@1 1670 /**
webmaster@1 1671 * Process variables for comment.tpl.php.
webmaster@1 1672 *
webmaster@1 1673 * @see comment.tpl.php
webmaster@1 1674 * @see theme_comment()
webmaster@1 1675 */
webmaster@1 1676 function template_preprocess_comment(&$variables) {
webmaster@1 1677 $comment = $variables['comment'];
webmaster@1 1678 $node = $variables['node'];
webmaster@1 1679 $variables['author'] = theme('username', $comment);
webmaster@1 1680 $variables['content'] = $comment->comment;
webmaster@1 1681 $variables['date'] = format_date($comment->timestamp);
webmaster@1 1682 $variables['links'] = isset($variables['links']) ? theme('links', $variables['links']) : '';
webmaster@1 1683 $variables['new'] = $comment->new ? t('new') : '';
webmaster@1 1684 $variables['picture'] = theme_get_setting('toggle_comment_user_picture') ? theme('user_picture', $comment) : '';
webmaster@1 1685 $variables['signature'] = $comment->signature;
webmaster@1 1686 $variables['submitted'] = theme('comment_submitted', $comment);
webmaster@1 1687 $variables['title'] = l($comment->subject, $_GET['q'], array('fragment' => "comment-$comment->cid"));
webmaster@1 1688 $variables['template_files'][] = 'comment-'. $node->type;
webmaster@1 1689 // set status to a string representation of comment->status.
webmaster@1 1690 if (isset($comment->preview)) {
webmaster@1 1691 $variables['status'] = 'comment-preview';
webmaster@1 1692 }
webmaster@1 1693 else {
webmaster@1 1694 $variables['status'] = ($comment->status == COMMENT_NOT_PUBLISHED) ? 'comment-unpublished' : 'comment-published';
webmaster@1 1695 }
webmaster@1 1696 }
webmaster@1 1697
webmaster@1 1698 /**
webmaster@1 1699 * Process variables for comment-folded.tpl.php.
webmaster@1 1700 *
webmaster@1 1701 * @see comment-folded.tpl.php
webmaster@1 1702 * @see theme_comment_folded()
webmaster@1 1703 */
webmaster@1 1704 function template_preprocess_comment_folded(&$variables) {
webmaster@1 1705 $comment = $variables['comment'];
webmaster@1 1706 $variables['author'] = theme('username', $comment);
webmaster@1 1707 $variables['date'] = format_date($comment->timestamp);
webmaster@1 1708 $variables['new'] = $comment->new ? t('new') : '';
webmaster@1 1709 $variables['title'] = l($comment->subject, comment_node_url() .'/'. $comment->cid, array('fragment' => "comment-$comment->cid"));
webmaster@1 1710 }
webmaster@1 1711
webmaster@1 1712 /**
webmaster@1 1713 * Theme comment flat collapsed view.
webmaster@1 1714 *
webmaster@1 1715 * @param $comment
webmaster@1 1716 * The comment to be themed.
webmaster@1 1717 * @param $node
webmaster@1 1718 * The comment node.
webmaster@1 1719 * @ingroup themeable
webmaster@1 1720 */
webmaster@1 1721 function theme_comment_flat_collapsed($comment, $node) {
webmaster@1 1722 return theme('comment_view', $comment, $node, '', 0);
webmaster@1 1723 }
webmaster@1 1724
webmaster@1 1725 /**
webmaster@1 1726 * Theme comment flat expanded view.
webmaster@1 1727 *
webmaster@1 1728 * @param $comment
webmaster@1 1729 * The comment to be themed.
webmaster@1 1730 * @param $node
webmaster@1 1731 * The comment node.
webmaster@1 1732 * @ingroup themeable
webmaster@1 1733 */
webmaster@1 1734 function theme_comment_flat_expanded($comment, $node) {
webmaster@1 1735 return theme('comment_view', $comment, $node, module_invoke_all('link', 'comment', $comment, 0));
webmaster@1 1736 }
webmaster@1 1737
webmaster@1 1738 /**
webmaster@1 1739 * Theme comment thread collapsed view.
webmaster@1 1740 *
webmaster@1 1741 * @param $comment
webmaster@1 1742 * The comment to be themed.
webmaster@1 1743 * @param $node
webmaster@1 1744 * The comment node.
webmaster@1 1745 * @ingroup themeable
webmaster@1 1746 */
webmaster@1 1747 function theme_comment_thread_collapsed($comment, $node) {
webmaster@1 1748 return theme('comment_view', $comment, $node, '', 0);
webmaster@1 1749 }
webmaster@1 1750
webmaster@1 1751 /**
webmaster@1 1752 * Theme comment thread expanded view.
webmaster@1 1753 *
webmaster@1 1754 * @param $comment
webmaster@1 1755 * The comment to be themed.
webmaster@1 1756 * @param $node
webmaster@1 1757 * The comment node.
webmaster@1 1758 * @ingroup themeable
webmaster@1 1759 */
webmaster@1 1760 function theme_comment_thread_expanded($comment, $node) {
webmaster@1 1761 return theme('comment_view', $comment, $node, module_invoke_all('link', 'comment', $comment, 0));
webmaster@1 1762 }
webmaster@1 1763
webmaster@1 1764 /**
webmaster@1 1765 * Theme a "you can't post comments" notice.
webmaster@1 1766 *
webmaster@1 1767 * @param $node
webmaster@1 1768 * The comment node.
webmaster@1 1769 * @ingroup themeable
webmaster@1 1770 */
webmaster@1 1771 function theme_comment_post_forbidden($node) {
webmaster@1 1772 global $user;
webmaster@1 1773 static $authenticated_post_comments;
webmaster@1 1774
webmaster@1 1775 if (!$user->uid) {
webmaster@1 1776 if (!isset($authenticated_post_comments)) {
webmaster@1 1777 // We only output any link if we are certain, that users get permission
webmaster@1 1778 // to post comments by logging in. We also locally cache this information.
webmaster@1 1779 $authenticated_post_comments = array_key_exists(DRUPAL_AUTHENTICATED_RID, user_roles(TRUE, 'post comments') + user_roles(TRUE, 'post comments without approval'));
webmaster@1 1780 }
webmaster@1 1781
webmaster@1 1782 if ($authenticated_post_comments) {
webmaster@1 1783 // We cannot use drupal_get_destination() because these links
webmaster@1 1784 // sometimes appear on /node and taxonomy listing pages.
webmaster@1 1785 if (variable_get('comment_form_location_'. $node->type, COMMENT_FORM_SEPARATE_PAGE) == COMMENT_FORM_SEPARATE_PAGE) {
webmaster@1 1786 $destination = 'destination='. drupal_urlencode("comment/reply/$node->nid#comment-form");
webmaster@1 1787 }
webmaster@1 1788 else {
webmaster@1 1789 $destination = 'destination='. drupal_urlencode("node/$node->nid#comment-form");
webmaster@1 1790 }
webmaster@1 1791
webmaster@1 1792 if (variable_get('user_register', 1)) {
webmaster@1 1793 // Users can register themselves.
webmaster@1 1794 return t('<a href="@login">Login</a> or <a href="@register">register</a> to post comments', array('@login' => url('user/login', array('query' => $destination)), '@register' => url('user/register', array('query' => $destination))));
webmaster@1 1795 }
webmaster@1 1796 else {
webmaster@1 1797 // Only admins can add new users, no public registration.
webmaster@1 1798 return t('<a href="@login">Login</a> to post comments', array('@login' => url('user/login', array('query' => $destination))));
webmaster@1 1799 }
webmaster@1 1800 }
webmaster@1 1801 }
webmaster@1 1802 }
webmaster@1 1803
webmaster@1 1804 /**
webmaster@1 1805 * Process variables for comment-wrapper.tpl.php.
webmaster@1 1806 *
webmaster@1 1807 * @see comment-wrapper.tpl.php
webmaster@1 1808 * @see theme_comment_wrapper()
webmaster@1 1809 */
webmaster@1 1810 function template_preprocess_comment_wrapper(&$variables) {
webmaster@1 1811 // Provide contextual information.
webmaster@1 1812 $variables['display_mode'] = _comment_get_display_setting('mode', $variables['node']);
webmaster@1 1813 $variables['display_order'] = _comment_get_display_setting('sort', $variables['node']);
webmaster@1 1814 $variables['comment_controls_state'] = variable_get('comment_controls_'. $variables['node']->type, COMMENT_CONTROLS_HIDDEN);
webmaster@1 1815 $variables['template_files'][] = 'comment-wrapper-'. $variables['node']->type;
webmaster@1 1816 }
webmaster@1 1817
webmaster@1 1818 /**
webmaster@1 1819 * Theme a "Submitted by ..." notice.
webmaster@1 1820 *
webmaster@1 1821 * @param $comment
webmaster@1 1822 * The comment.
webmaster@1 1823 * @ingroup themeable
webmaster@1 1824 */
webmaster@1 1825 function theme_comment_submitted($comment) {
webmaster@1 1826 return t('Submitted by !username on @datetime.',
webmaster@1 1827 array(
webmaster@1 1828 '!username' => theme('username', $comment),
webmaster@1 1829 '@datetime' => format_date($comment->timestamp)
webmaster@1 1830 ));
webmaster@1 1831 }
webmaster@1 1832
webmaster@1 1833 /**
webmaster@1 1834 * Return an array of viewing modes for comment listings.
webmaster@1 1835 *
webmaster@1 1836 * We can't use a global variable array because the locale system
webmaster@1 1837 * is not initialized yet when the comment module is loaded.
webmaster@1 1838 */
webmaster@1 1839 function _comment_get_modes() {
webmaster@1 1840 return array(
webmaster@1 1841 COMMENT_MODE_FLAT_COLLAPSED => t('Flat list - collapsed'),
webmaster@1 1842 COMMENT_MODE_FLAT_EXPANDED => t('Flat list - expanded'),
webmaster@1 1843 COMMENT_MODE_THREADED_COLLAPSED => t('Threaded list - collapsed'),
webmaster@1 1844 COMMENT_MODE_THREADED_EXPANDED => t('Threaded list - expanded')
webmaster@1 1845 );
webmaster@1 1846 }
webmaster@1 1847
webmaster@1 1848 /**
webmaster@1 1849 * Return an array of viewing orders for comment listings.
webmaster@1 1850 *
webmaster@1 1851 * We can't use a global variable array because the locale system
webmaster@1 1852 * is not initialized yet when the comment module is loaded.
webmaster@1 1853 */
webmaster@1 1854 function _comment_get_orders() {
webmaster@1 1855 return array(
webmaster@1 1856 COMMENT_ORDER_NEWEST_FIRST => t('Date - newest first'),
webmaster@1 1857 COMMENT_ORDER_OLDEST_FIRST => t('Date - oldest first')
webmaster@1 1858 );
webmaster@1 1859 }
webmaster@1 1860
webmaster@1 1861 /**
webmaster@1 1862 * Return an array of "comments per page" settings from which the user
webmaster@1 1863 * can choose.
webmaster@1 1864 */
webmaster@1 1865 function _comment_per_page() {
webmaster@1 1866 return drupal_map_assoc(array(10, 30, 50, 70, 90, 150, 200, 250, 300));
webmaster@1 1867 }
webmaster@1 1868
webmaster@1 1869 /**
webmaster@1 1870 * Return a current comment display setting
webmaster@1 1871 *
webmaster@1 1872 * @param $setting
webmaster@1 1873 * can be one of these: 'mode', 'sort', 'comments_per_page'
webmaster@1 1874 * @param $node
webmaster@1 1875 * The comment node in question.
webmaster@1 1876 */
webmaster@1 1877 function _comment_get_display_setting($setting, $node) {
webmaster@1 1878 global $user;
webmaster@1 1879
webmaster@1 1880 if (isset($_GET[$setting])) {
webmaster@1 1881 $value = $_GET[$setting];
webmaster@1 1882 }
webmaster@1 1883 else {
webmaster@1 1884 // get the setting's site default
webmaster@1 1885 switch ($setting) {
webmaster@1 1886 case 'mode':
webmaster@1 1887 $default = variable_get('comment_default_mode_'. $node->type, COMMENT_MODE_THREADED_EXPANDED);
webmaster@1 1888 break;
webmaster@1 1889 case 'sort':
webmaster@1 1890 $default = variable_get('comment_default_order_'. $node->type, COMMENT_ORDER_NEWEST_FIRST);
webmaster@1 1891 break;
webmaster@1 1892 case 'comments_per_page':
webmaster@1 1893 $default = variable_get('comment_default_per_page_'. $node->type, 50);
webmaster@1 1894 }
webmaster@1 1895 if (variable_get('comment_controls_'. $node->type, COMMENT_CONTROLS_HIDDEN) == COMMENT_CONTROLS_HIDDEN) {
webmaster@1 1896 // if comment controls are disabled use site default
webmaster@1 1897 $value = $default;
webmaster@1 1898 }
webmaster@1 1899 else {
webmaster@1 1900 // otherwise use the user's setting if set
webmaster@1 1901 if (isset($user->$setting) && $user->$setting) {
webmaster@1 1902 $value = $user->$setting;
webmaster@1 1903 }
webmaster@1 1904 else if (isset($_SESSION['comment_'. $setting]) && $_SESSION['comment_'. $setting]) {
webmaster@1 1905 $value = $_SESSION['comment_'. $setting];
webmaster@1 1906 }
webmaster@1 1907 else {
webmaster@1 1908 $value = $default;
webmaster@1 1909 }
webmaster@1 1910 }
webmaster@1 1911 }
webmaster@1 1912 return $value;
webmaster@1 1913 }
webmaster@1 1914
webmaster@1 1915 /**
webmaster@1 1916 * Updates the comment statistics for a given node. This should be called any
webmaster@1 1917 * time a comment is added, deleted, or updated.
webmaster@1 1918 *
webmaster@1 1919 * The following fields are contained in the node_comment_statistics table.
webmaster@1 1920 * - last_comment_timestamp: the timestamp of the last comment for this node or the node create stamp if no comments exist for the node.
webmaster@1 1921 * - last_comment_name: the name of the anonymous poster for the last comment
webmaster@1 1922 * - last_comment_uid: the uid of the poster for the last comment for this node or the node authors uid if no comments exists for the node.
webmaster@1 1923 * - comment_count: the total number of approved/published comments on this node.
webmaster@1 1924 */
webmaster@1 1925 function _comment_update_node_statistics($nid) {
webmaster@1 1926 $count = db_result(db_query('SELECT COUNT(cid) FROM {comments} WHERE nid = %d AND status = %d', $nid, COMMENT_PUBLISHED));
webmaster@1 1927
webmaster@1 1928 // comments exist
webmaster@1 1929 if ($count > 0) {
webmaster@1 1930 $last_reply = db_fetch_object(db_query_range('SELECT cid, name, timestamp, uid FROM {comments} WHERE nid = %d AND status = %d ORDER BY cid DESC', $nid, COMMENT_PUBLISHED, 0, 1));
webmaster@1 1931 db_query("UPDATE {node_comment_statistics} SET comment_count = %d, last_comment_timestamp = %d, last_comment_name = '%s', last_comment_uid = %d WHERE nid = %d", $count, $last_reply->timestamp, $last_reply->uid ? '' : $last_reply->name, $last_reply->uid, $nid);
webmaster@1 1932 }
webmaster@1 1933
webmaster@1 1934 // no comments
webmaster@1 1935 else {
webmaster@1 1936 $node = db_fetch_object(db_query("SELECT uid, created FROM {node} WHERE nid = %d", $nid));
webmaster@1 1937 db_query("UPDATE {node_comment_statistics} SET comment_count = 0, last_comment_timestamp = %d, last_comment_name = '', last_comment_uid = %d WHERE nid = %d", $node->created, $node->uid, $nid);
webmaster@1 1938 }
webmaster@1 1939 }
webmaster@1 1940
webmaster@1 1941 /**
webmaster@1 1942 * Invoke a hook_comment() operation in all modules.
webmaster@1 1943 *
webmaster@1 1944 * @param &$comment
webmaster@1 1945 * A comment object.
webmaster@1 1946 * @param $op
webmaster@1 1947 * A string containing the name of the comment operation.
webmaster@1 1948 * @return
webmaster@1 1949 * The returned value of the invoked hooks.
webmaster@1 1950 */
webmaster@1 1951 function comment_invoke_comment(&$comment, $op) {
webmaster@1 1952 $return = array();
webmaster@1 1953 foreach (module_implements('comment') as $name) {
webmaster@1 1954 $function = $name .'_comment';
webmaster@1 1955 $result = $function($comment, $op);
webmaster@1 1956 if (isset($result) && is_array($result)) {
webmaster@1 1957 $return = array_merge($return, $result);
webmaster@1 1958 }
webmaster@1 1959 else if (isset($result)) {
webmaster@1 1960 $return[] = $result;
webmaster@1 1961 }
webmaster@1 1962 }
webmaster@1 1963 return $return;
webmaster@1 1964 }
webmaster@1 1965
webmaster@1 1966 /**
webmaster@1 1967 * Generate vancode.
webmaster@1 1968 *
webmaster@1 1969 * Consists of a leading character indicating length, followed by N digits
webmaster@1 1970 * with a numerical value in base 36. Vancodes can be sorted as strings
webmaster@1 1971 * without messing up numerical order.
webmaster@1 1972 *
webmaster@1 1973 * It goes:
webmaster@1 1974 * 00, 01, 02, ..., 0y, 0z,
webmaster@1 1975 * 110, 111, ... , 1zy, 1zz,
webmaster@1 1976 * 2100, 2101, ..., 2zzy, 2zzz,
webmaster@1 1977 * 31000, 31001, ...
webmaster@1 1978 */
webmaster@1 1979 function int2vancode($i = 0) {
webmaster@1 1980 $num = base_convert((int)$i, 10, 36);
webmaster@1 1981 $length = strlen($num);
webmaster@1 1982 return chr($length + ord('0') - 1) . $num;
webmaster@1 1983 }
webmaster@1 1984
webmaster@1 1985 /**
webmaster@1 1986 * Decode vancode back to an integer.
webmaster@1 1987 */
webmaster@1 1988 function vancode2int($c = '00') {
webmaster@1 1989 return base_convert(substr($c, 1), 36, 10);
webmaster@1 1990 }
webmaster@1 1991
webmaster@1 1992 /**
webmaster@1 1993 * Implementation of hook_hook_info().
webmaster@1 1994 */
webmaster@1 1995 function comment_hook_info() {
webmaster@1 1996 return array(
webmaster@1 1997 'comment' => array(
webmaster@1 1998 'comment' => array(
webmaster@1 1999 'insert' => array(
webmaster@1 2000 'runs when' => t('After saving a new comment'),
webmaster@1 2001 ),
webmaster@1 2002 'update' => array(
webmaster@1 2003 'runs when' => t('After saving an updated comment'),
webmaster@1 2004 ),
webmaster@1 2005 'delete' => array(
webmaster@1 2006 'runs when' => t('After deleting a comment')
webmaster@1 2007 ),
webmaster@1 2008 'view' => array(
webmaster@1 2009 'runs when' => t('When a comment is being viewed by an authenticated user')
webmaster@1 2010 ),
webmaster@1 2011 ),
webmaster@1 2012 ),
webmaster@1 2013 );
webmaster@1 2014 }
webmaster@1 2015
webmaster@1 2016 /**
webmaster@1 2017 * Implementation of hook_action_info().
webmaster@1 2018 */
webmaster@1 2019 function comment_action_info() {
webmaster@1 2020 return array(
webmaster@1 2021 'comment_unpublish_action' => array(
webmaster@1 2022 'description' => t('Unpublish comment'),
webmaster@1 2023 'type' => 'comment',
webmaster@1 2024 'configurable' => FALSE,
webmaster@1 2025 'hooks' => array(
webmaster@1 2026 'comment' => array('insert', 'update'),
webmaster@1 2027 )
webmaster@1 2028 ),
webmaster@1 2029 'comment_unpublish_by_keyword_action' => array(
webmaster@1 2030 'description' => t('Unpublish comment containing keyword(s)'),
webmaster@1 2031 'type' => 'comment',
webmaster@1 2032 'configurable' => TRUE,
webmaster@1 2033 'hooks' => array(
webmaster@1 2034 'comment' => array('insert', 'update'),
webmaster@1 2035 )
webmaster@1 2036 )
webmaster@1 2037 );
webmaster@1 2038 }
webmaster@1 2039
webmaster@1 2040 /**
webmaster@1 2041 * Drupal action to unpublish a comment.
webmaster@1 2042 *
webmaster@1 2043 * @param $context
webmaster@1 2044 * Keyed array. Must contain the id of the comment if $comment is not passed.
webmaster@1 2045 * @param $comment
webmaster@1 2046 * An optional comment object.
webmaster@1 2047 */
webmaster@1 2048 function comment_unpublish_action($comment, $context = array()) {
webmaster@1 2049 if (isset($comment->cid)) {
webmaster@1 2050 $cid = $comment->cid;
webmaster@1 2051 $subject = $comment->subject;
webmaster@1 2052 }
webmaster@1 2053 else {
webmaster@1 2054 $cid = $context['cid'];
webmaster@1 2055 $subject = db_result(db_query("SELECT subject FROM {comments} WHERE cid = %d", $cid));
webmaster@1 2056 }
webmaster@1 2057 db_query('UPDATE {comments} SET status = %d WHERE cid = %d', COMMENT_NOT_PUBLISHED, $cid);
webmaster@1 2058 watchdog('action', 'Unpublished comment %subject.', array('%subject' => $subject));
webmaster@1 2059 }
webmaster@1 2060
webmaster@1 2061 /**
webmaster@1 2062 * Form builder; Prepare a form for blacklisted keywords.
webmaster@1 2063 *
webmaster@1 2064 * @ingroup forms
webmaster@1 2065 */
webmaster@1 2066 function comment_unpublish_by_keyword_action_form($context) {
webmaster@1 2067 $form['keywords'] = array(
webmaster@1 2068 '#title' => t('Keywords'),
webmaster@1 2069 '#type' => 'textarea',
webmaster@1 2070 '#description' => t('The comment will be unpublished if it contains any of the character sequences above. Use a comma-separated list of character sequences. Example: funny, bungee jumping, "Company, Inc.". Character sequences are case-sensitive.'),
webmaster@1 2071 '#default_value' => isset($context['keywords']) ? drupal_implode_tags($context['keywords']) : '',
webmaster@1 2072 );
webmaster@1 2073 return $form;
webmaster@1 2074 }
webmaster@1 2075
webmaster@1 2076 /**
webmaster@1 2077 * Process comment_unpublish_by_keyword_action_form form submissions.
webmaster@1 2078 */
webmaster@1 2079 function comment_unpublish_by_keyword_action_submit($form, $form_state) {
webmaster@1 2080 return array('keywords' => drupal_explode_tags($form_state['values']['keywords']));
webmaster@1 2081 }
webmaster@1 2082
webmaster@1 2083 /**
webmaster@1 2084 * Implementation of a configurable Drupal action.
webmaster@1 2085 * Unpublish a comment if it contains a certain string.
webmaster@1 2086 *
webmaster@1 2087 * @param $context
webmaster@1 2088 * An array providing more information about the context of the call to this action.
webmaster@1 2089 * Unused here since this action currently only supports the insert and update ops of
webmaster@1 2090 * the comment hook, both of which provide a complete $comment object.
webmaster@1 2091 * @param $comment
webmaster@1 2092 * A comment object.
webmaster@1 2093 */
webmaster@1 2094 function comment_unpublish_by_keyword_action($comment, $context) {
webmaster@1 2095 foreach ($context['keywords'] as $keyword) {
webmaster@1 2096 if (strstr($comment->comment, $keyword) || strstr($comment->subject, $keyword)) {
webmaster@1 2097 db_query('UPDATE {comments} SET status = %d WHERE cid = %d', COMMENT_NOT_PUBLISHED, $comment->cid);
webmaster@1 2098 watchdog('action', 'Unpublished comment %subject.', array('%subject' => $comment->subject));
webmaster@1 2099 break;
webmaster@1 2100 }
webmaster@1 2101 }
webmaster@1 2102 }