annotate modules/comment/comment.module @ 5:2427550111ae 6.2

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