diff --git a/modules/comment/comment-wrapper.tpl.php b/modules/comment/comment-wrapper.tpl.php index 313510d06b3342e6223dbb28422d27295c78618e..aabf3850fa8ca4610b37f0cc824f7dd6d80924ad 100644 --- a/modules/comment/comment-wrapper.tpl.php +++ b/modules/comment/comment-wrapper.tpl.php @@ -6,8 +6,9 @@ * Default theme implementation to wrap comments. * * Available variables: - * - $content: All comments for a given page. Also contains comment form - * if enabled. + * - $content: The array of content-related elements for the node. Use + * render($content) to print them all, or + * print a subset such as render($content['comment_form']). * - $classes: String of classes that can be used to style contextually through * CSS. It can be manipulated through the variable $classes_array from * preprocess functions. The default value has the following: @@ -30,5 +31,16 @@ */ ?> <div id="comments" class="<?php print $classes; ?>"> - <?php print $content; ?> + <?php if ($node->type != 'forum'): ?> + <h2 class="comments"><?php print t('Comments'); ?></h2> + <?php endif; ?> + + <?php print render($content['comments']); ?> + + <?php if ($content['comment_form']): ?> + <h2 class="title"><?php print t('Post new comment'); ?></h2> + <div> + <?php print render($content['comment_form']); ?> + </div> + <?php endif; ?> </div> diff --git a/modules/comment/comment.module b/modules/comment/comment.module index 3fc8663482f6f2ea47222c28bcac886244ab51e9..da6d8b7fe9d7200e5f1e68e684a5c594047c3959 100644 --- a/modules/comment/comment.module +++ b/modules/comment/comment.module @@ -104,34 +104,18 @@ function comment_theme() { 'arguments' => array(), ), 'comment_preview' => array( - 'arguments' => array('comment' => NULL, 'node' => NULL, 'links' => array(), 'visible' => 1), - ), - 'comment_view' => array( - 'arguments' => array('comment' => NULL, 'node' => NULL, 'links' => array(), 'visible' => 1), + 'arguments' => array('comment' => NULL), ), 'comment' => array( 'template' => 'comment', - 'arguments' => array('comment' => NULL, 'node' => NULL, 'links' => array()), - ), - 'comment_form_box' => array( - 'arguments' => array('edit' => NULL, 'title' => NULL), - ), - 'comment_folded' => array( - 'template' => 'comment-folded', - 'arguments' => array('comment' => NULL, 'node' => NULL), - ), - 'comment_flat_expanded' => array( - 'arguments' => array('comment' => NULL, 'node' => NULL), - ), - 'comment_thread_expanded' => array( - 'arguments' => array('comment' => NULL, 'node' => NULL), + 'arguments' => array('elements' => NULL), ), 'comment_post_forbidden' => array( 'arguments' => array('nid' => NULL), ), 'comment_wrapper' => array( 'template' => 'comment-wrapper', - 'arguments' => array('content' => NULL, 'node' => NULL), + 'arguments' => array('content' => NULL), ), 'comment_submitted' => array( 'arguments' => array('comment' => NULL), @@ -168,10 +152,12 @@ function comment_menu() { 'access arguments' => array('administer comments'), 'type' => MENU_CALLBACK, ); - $items['comment/edit'] = array( + $items['comment/edit/%comment'] = array( 'title' => 'Edit comment', 'page callback' => 'comment_edit', - 'access arguments' => array('post comments'), + 'access callback' => 'comment_access', + 'page arguments' => array(2), + 'access arguments' => array('edit', 2), 'type' => MENU_CALLBACK, ); $items['comment/reply/%node'] = array( @@ -532,16 +518,311 @@ function comment_node_view($node, $build_mode) { '#attributes' => array('class' => 'links inline'), ); - // Append the list of comments to $node->content for node detail pages. - if ($node->comment && (bool)menu_get_object() && empty($node->in_preview)) { - $node->content['comments'] = array( - '#markup' => comment_render($node), - '#sorted' => TRUE, - ); + // Only append comments when we are building a node on its own node detail + // page. We compare $node and $page_node to ensure that comments are not + // appended to other nodes shown on the page, for example a node_reference + // displayed in 'full' build mode within another node. + $page_node = menu_get_object(); + if ($node->comment && isset($page_node->nid) && $page_node->nid == $node->nid && empty($node->in_preview) && user_access('access comments')) { + $node->content['comments'] = comment_node_page_additions($node); } } } +/** + * Build the comment-related elements for node detail pages. + * + * @param $node + * A node object. + */ +function comment_node_page_additions($node) { + $additions = array(); + + // Only attempt to render comments if the node has visible comments. + // Unpublished comments are not included in $node->comment_count, so show + // comments unconditionally if the user is an administrator. + if ($node->comment_count || user_access('administer comments')) { + if ($cids = comment_get_thread($node)) { + $comments = comment_load_multiple($cids); + comment_prepare_thread($comments); + $build = comment_build_multiple($comments); + $build['#attached_css'][] = drupal_get_path('module', 'comment') . '/comment.css'; + $build['pager']['#theme'] = 'pager'; + $additions['comments'] = $build; + } + } + + // Append comment form if needed. + if (user_access('post comments') && $node->comment == COMMENT_NODE_OPEN && (variable_get('comment_form_location_' . $node->type, COMMENT_FORM_BELOW) == COMMENT_FORM_BELOW)) { + $build = drupal_get_form('comment_form', array('nid' => $node->nid)); + $additions['comment_form'] = $build; + } + + if ($additions) { + $additions += array( + '#theme' => 'comment_wrapper', + '#node' => $node, + 'comments' => array(), + 'comment_form' => array(), + ); + } + + return $additions; +} + +/** + * Retrieve comment(s) for a thread. + * + * @param $node + * The node whose comment(s) needs rendering. + * + * To display threaded comments in the correct order we keep a 'thread' field + * and order by that value. This field keeps this data in + * a way which is easy to update and convenient to use. + * + * A "thread" value starts at "1". If we add a child (A) to this comment, + * we assign it a "thread" = "1.1". A child of (A) will have "1.1.1". Next + * brother of (A) will get "1.2". Next brother of the parent of (A) will get + * "2" and so on. + * + * First of all note that the thread field stores the depth of the comment: + * depth 0 will be "X", depth 1 "X.X", depth 2 "X.X.X", etc. + * + * Now to get the ordering right, consider this example: + * + * 1 + * 1.1 + * 1.1.1 + * 1.2 + * 2 + * + * If we "ORDER BY thread ASC" we get the above result, and this is the + * natural order sorted by time. However, if we "ORDER BY thread DESC" + * we get: + * + * 2 + * 1.2 + * 1.1.1 + * 1.1 + * 1 + * + * Clearly, this is not a natural way to see a thread, and users will get + * confused. The natural order to show a thread by time desc would be: + * + * 2 + * 1 + * 1.2 + * 1.1 + * 1.1.1 + * + * which is what we already did before the standard pager patch. To achieve + * this we simply add a "/" at the end of each "thread" value. This way, the + * thread fields will look like this: + * + * 1/ + * 1.1/ + * 1.1.1/ + * 1.2/ + * 2/ + * + * we add "/" since this char is, in ASCII, higher than every number, so if + * now we "ORDER BY thread DESC" we get the correct order. However this would + * spoil the reverse ordering, "ORDER BY thread ASC" -- here, we do not need + * to consider the trailing "/" so we use a substring only. + */ + function comment_get_thread($node) { + $mode = _comment_get_display_setting('mode', $node); + $comments_per_page = _comment_get_display_setting('comments_per_page', $node); + + $query = db_select('comment', 'c')->extend('PagerDefault'); + $query->addField('c', 'cid'); + $query + ->condition('c.nid', $node->nid) + ->addTag('node_access') + ->limit($comments_per_page); + + $count_query = db_select('comment', 'c'); + $count_query->addExpression('COUNT(*)'); + $count_query + ->condition('c.nid', $node->nid) + ->addTag('node_access'); + + if (!user_access('administer comments')) { + $query->condition('c.status', COMMENT_PUBLISHED); + $count_query->condition('c.status', COMMENT_PUBLISHED); + } + if ($mode === COMMENT_MODE_FLAT) { + $query->orderBy('c.cid', 'ASC'); + } + else { + // See comment above. Analysis reveals that this doesn't cost too + // much. It scales much much better than having the whole comment + // structure. + $query->orderBy('SUBSTRING(c.thread, 1, (LENGTH(c.thread) - 1))', 'ASC'); + } + + $query->setCountQuery($count_query); + $cids = $query->execute()->fetchCol(); + + return $cids; +} + +/** + * Loop over comment thread, noting indentation level. + * + * @param array $comments + * An array of comment objects, keyed by cid. + * @return + * The $comments argument is altered by reference with indentation information. + */ +function comment_prepare_thread(&$comments) { + // A flag stating if we are still searching for first new comment on the thread. + $first_new = TRUE; + + // A counter that helps track how indented we are. + $divs = 0; + + foreach ($comments as $key => $comment) { + if ($first_new && $comment->new != MARK_READ) { + // Assign the anchor only for the first new comment. This avoids duplicate + // id attributes on a page. + $first_new = FALSE; + $comment->first_new = TRUE; + } + + // The $divs element instructs #prefix whether to add an indent div or + // close existing divs (a negative value). + $comment->depth = count(explode('.', $comment->thread)) - 1; + if ($comment->depth > $divs) { + $comment->divs = 1; + $divs++; + } + else { + $comment->divs = $comment->depth - $divs; + while ($comment->depth < $divs) { + $divs--; + } + } + $comments[$key] = $comment; + } + + // The final comment must close up some hanging divs + $comments[$key]->divs_final = $divs; +} + +/** + * Generate an array for rendering the given comment. + * + * @param $comment + * A comment object. + * @param $build_mode + * Build mode, e.g. 'full', 'teaser'... + * + * @return + * An array as expected by drupal_render(). + */ +function comment_build($comment, $build_mode = 'full') { + $node = node_load($comment->nid); + $comment = comment_build_content($comment, $build_mode); + + $build = $comment->content; + + $build += array( + '#theme' => 'comment', + '#comment' => $comment, + '#build_mode' => $build_mode, + ); + + $prefix = ''; + $is_threaded = isset($comment->divs) && _comment_get_display_setting('mode', $node) == COMMENT_MODE_THREADED; + + // Add 'new' anchor if needed. + if (!empty($comment->first_new)) { + $prefix .= "<a id=\"new\"></a>\n"; + } + + // Add indentation div or close open divs as needed. + if ($is_threaded) { + $prefix .= $comment->divs <= 0 ? str_repeat('</div>', abs($comment->divs)) : "\n" . '<div class="indented">'; + } + + // Add anchor for each comment. + $prefix .= "<a id=\"comment-$comment->cid\"></a>\n"; + $build['#prefix'] = $prefix; + + // Close all open divs. + if ($is_threaded && !empty($comment->divs_final)) { + $build['#suffix'] = str_repeat('</div>', $comment->divs_final); + } + + return $build; +} + +/** + * Builds a structured array representing the comment's content. + * + * The content built for the comment (field values, comments, file attachments or + * other comment components) will vary depending on the $build_mode parameter. + * + * @param $comment + * A comment object. + * @param $build_mode + * Build mode, e.g. 'full', 'teaser'... + * @return + * A structured array containing the individual elements + * of the comment's content. + */ +function comment_build_content($comment, $build_mode = 'full') { + if (empty($comment->content)) { + $comment->content = array(); + } + + // Build comment body. + $comment->content['comment_body'] = array( + '#markup' => check_markup($comment->comment, $comment->format, '', FALSE), + ); + + if (empty($comment->in_preview)) { + $comment->content['links']['comment'] = array( + '#theme' => 'links', + '#links' => comment_links($comment), + '#attributes' => array('class' => 'links inline'), + ); + } + + // Allow modules to make their own additions to the comment. + module_invoke_all('comment_view', $comment, $build_mode); + + // Allow modules to modify the structured comment. + drupal_alter('comment_build', $comment, $build_mode); + + return $comment; +} + +/** + * Construct a drupal_render() style array from an array of loaded comments. + * + * @param $comments + * An array of comments as returned by comment_load_multiple(). + * @param $build_mode + * Build mode, e.g. 'full', 'teaser'... + * @param $weight + * An integer representing the weight of the first comment in the list. + * @return + * An array in the format expected by drupal_render(). + */ +function comment_build_multiple($comments, $build_mode = 'full', $weight = 0) { + $build = array( + '#sorted' => TRUE, + ); + foreach ($comments as $comment) { + $build[$comment->cid] = comment_build($comment, $build_mode); + $build[$comment->cid]['#weight'] = $weight; + $weight++; + } + return $build; +} + /** * Implement hook_form_FORM_ID_alter(). */ @@ -878,7 +1159,7 @@ function comment_save($comment) { } else { // Add the comment to database. This next section builds the thread field. - // Also see the documentation for comment_render(). + // Also see the documentation for comment_build(). if ($comment->pid == 0) { // This is a comment with no parent comment (depth 0): we start // by retrieving the maximum thread level. @@ -977,24 +1258,13 @@ function comment_link($type, $object, $build_mode) { * * @param $comment * The comment to which the links will be related. - * @param $return - * Not used. * @return * An associative array containing the links. */ -function comment_links($comment, $return = 1) { +function comment_links(&$comment) { global $user; $links = array(); - // If viewing just this comment, link back to the in-context view. - if ($return) { - $links['comment_parent'] = array( - 'title' => t('parent'), - 'href' => 'comment/' . $comment->cid, - 'fragment' => "comment-$comment->cid" - ); - } - $node = node_load($comment->nid); if ($node->comment == COMMENT_NODE_OPEN) { if (user_access('administer comments') && user_access('post comments')) { @@ -1042,181 +1312,9 @@ function comment_links($comment, $return = 1) { } } - return $links; -} - -/** - * Renders comment(s). - * - * @param $node - * The node which comment(s) needs rendering. - * @param $cid - * Optional, if given, only one comment is rendered. - * - * To display threaded comments in the correct order we keep a 'thread' field - * and order by that value. This field keeps this data in - * a way which is easy to update and convenient to use. - * - * A "thread" value starts at "1". If we add a child (A) to this comment, - * we assign it a "thread" = "1.1". A child of (A) will have "1.1.1". Next - * brother of (A) will get "1.2". Next brother of the parent of (A) will get - * "2" and so on. - * - * First of all note that the thread field stores the depth of the comment: - * depth 0 will be "X", depth 1 "X.X", depth 2 "X.X.X", etc. - * - * Now to get the ordering right, consider this example: - * - * 1 - * 1.1 - * 1.1.1 - * 1.2 - * 2 - * - * If we "ORDER BY thread ASC" we get the above result, and this is the - * natural order sorted by time. However, if we "ORDER BY thread DESC" - * we get: - * - * 2 - * 1.2 - * 1.1.1 - * 1.1 - * 1 - * - * Clearly, this is not a natural way to see a thread, and users will get - * confused. The natural order to show a thread by time desc would be: - * - * 2 - * 1 - * 1.2 - * 1.1 - * 1.1.1 - * - * which is what we already did before the standard pager patch. To achieve - * this we simply add a "/" at the end of each "thread" value. This way, the - * thread fields will look like this: - * - * 1/ - * 1.1/ - * 1.1.1/ - * 1.2/ - * 2/ - * - * we add "/" since this char is, in ASCII, higher than every number, so if - * now we "ORDER BY thread DESC" we get the correct order. However this would - * spoil the reverse ordering, "ORDER BY thread ASC" -- here, we do not need - * to consider the trailing "/" so we use a substring only. - */ -function comment_render($node, $cid = 0) { - global $user; - $output = ''; - - if (user_access('access comments')) { - // Pre-process variables. - $nid = $node->nid; - if (empty($nid)) { - $nid = 0; - } - - $mode = _comment_get_display_setting('mode', $node); - $comments_per_page = _comment_get_display_setting('comments_per_page', $node); - if ($cid && is_numeric($cid)) { - $comment = current(comment_load_multiple(array('cid' => $cid, 'status' => COMMENT_PUBLISHED))); - // Single comment view. - if ($comment) { - $comment->name = $comment->uid ? $comment->registered_name : $comment->name; - $links = module_invoke_all('link', 'comment', $comment, 1); - drupal_alter('link', $links, $node); - - $output .= theme('comment_view', $comment, $node, $links); - } - } - // Only attempt to render comments if the node has visible comments. - // Unpublished comments are not included in $node->comment_count, so show - // comments unconditionally if the user is an administrator. - elseif ($node->comment_count || user_access('administer comments')) { - - // Multiple comment view. - $query = db_select('comment', 'c')->extend('PagerDefault'); - $query->addField('c', 'cid'); - $query - ->condition('c.nid', $nid) - ->addTag('node_access') - ->limit($comments_per_page); - - $count_query = db_select('comment', 'c'); - $count_query->addExpression('COUNT(*)'); - $count_query - ->condition('c.nid', $nid) - ->addTag('node_access'); - if (!user_access('administer comments')) { - $query->condition('c.status', COMMENT_PUBLISHED); - $count_query->condition('c.status', COMMENT_PUBLISHED); - } - if ($mode === COMMENT_MODE_FLAT) { - $query->orderBy('c.cid', 'ASC'); - } - else { - // See comment above. Analysis reveals that this doesn't cost too - // much. It scales much much better than having the whole comment - // structure. - $query->orderBy('SUBSTRING(c.thread, 1, (LENGTH(c.thread) - 1))', 'ASC'); - } - - $query->setCountQuery($count_query); - $cids = $query->execute()->fetchCol(); - - $divs = 0; - $num_rows = FALSE; - $render = ''; - $comments = comment_load_multiple($cids); - drupal_add_css(drupal_get_path('module', 'comment') . '/comment.css'); - foreach ($comments as $comment) { - $comment = drupal_unpack($comment); - $comment->name = $comment->uid ? $comment->registered_name : $comment->name; - $comment->depth = count(explode('.', $comment->thread)) - 1; - - if ($mode == COMMENT_MODE_THREADED) { - if ($comment->depth > $divs) { - $divs++; - $render .= '<div class="indented">'; - } - else { - while ($comment->depth < $divs) { - $divs--; - $render .= '</div>'; - } - } - } - - if ($mode == COMMENT_MODE_FLAT) { - $render .= theme('comment_flat_expanded', $comment, $node); - } - elseif ($mode == COMMENT_MODE_THREADED) { - $render .= theme('comment_thread_expanded', $comment, $node); - } - $num_rows = TRUE; - } - while ($divs-- > 0) { - $render .= '</div>'; - } - $output .= $render; - $output .= theme('pager', NULL); - } - - // If enabled, show new comment form if it's not already being displayed. - $reply = arg(0) == 'comment' && arg(1) == 'reply'; - if (user_access('post comments') && $node->comment == COMMENT_NODE_OPEN && (variable_get('comment_form_location_' . $node->type, COMMENT_FORM_BELOW) == COMMENT_FORM_BELOW) && !$reply) { - $output .= theme('comment_form_box', array('nid' => $nid), t('Post new comment')); - } - if ($output) { - $output = theme('comment_wrapper', $output, $node); - } - } - - return $output; + return $links; } /** @@ -1287,6 +1385,14 @@ function comment_load_multiple($cids = array(), $conditions = array()) { $comments = $query->execute()->fetchAllAssoc('cid'); } + // Setup standard comment properties. + foreach ($comments as $key => $comment) { + $comment = drupal_unpack($comment); + $comment->name = $comment->uid ? $comment->registered_name : $comment->name; + $comment->new = node_mark($comment->nid, $comment->timestamp); + $comments[$key] = $comment; + } + // Invoke hook_comment_load(). if (!empty($comments)) { module_invoke_all('comment_load', $comments); @@ -1396,7 +1502,7 @@ function comment_get_display_ordinal($cid, $node_type) { else { // For threaded comments, the c.thread column is used for ordering. We can // use the vancode for comparison, but must remove the trailing slash. - // @see comment_render(). + // @see comment_build_multiple(). $query->where('SUBSTRING(c1.thread, 1, (LENGTH(c1.thread) -1)) < SUBSTRING(c2.thread, 1, (LENGTH(c2.thread) -1))'); } @@ -1425,20 +1531,18 @@ function comment_get_display_page($cid, $node_type) { /** * Generate the basic commenting form, for appending to a node or display on a separate page. * - * @param $title - * Not used. * @ingroup forms * @see comment_form_validate() * @see comment_form_submit() */ -function comment_form(&$form_state, $edit, $title = NULL) { +function comment_form(&$form_state, $edit = array()) { global $user; $op = isset($_POST['op']) ? $_POST['op'] : ''; $node = node_load($edit['nid']); if (!$user->uid && variable_get('comment_anonymous_' . $node->type, COMMENT_ANONYMOUS_MAYNOT_CONTACT) != COMMENT_ANONYMOUS_MAYNOT_CONTACT) { - drupal_add_js(drupal_get_path('module', 'comment') . '/comment.js'); + $form_state['#attached_js'][] = drupal_get_path('module', 'comment') . '/comment.js'; } // Take into account multi-step rebuilding. @@ -1675,22 +1779,6 @@ function comment_form(&$form_state, $edit, $title = NULL) { return $form; } -/** - * Theme the comment form box. - * - * @param $edit - * The form structure. - * @param $title - * The form title. - * @return - * A string containing the box output. - */ -function theme_comment_form_box($edit, $title = NULL) { - $content = drupal_render(drupal_get_form('comment_form', $edit, $title)); - $output = '<h2 class="title">' . $title . '</h2><div>' . $content . '</div>'; - return $output; -} - /** * Build a preview from submitted form values. */ @@ -1729,38 +1817,31 @@ function comment_preview($comment) { } $comment->timestamp = !empty($edit['timestamp']) ? $edit['timestamp'] : REQUEST_TIME; - $output = theme('comment_view', $comment, $node); - } - else { - $output = ''; - } + $comment->in_preview = TRUE; + $comment_build = comment_build($comment); + $comment_build += array( + '#weight' => -100, + '#prefix' => '<div class="preview">', + '#suffix' => '</div>', + ); - $form['comment_preview'] = array( - '#markup' => $output, - '#weight' => -100, - '#prefix' => '<div class="preview">', - '#suffix' => '</div>', - ); + $form['comment_preview'] = $comment_build; + } if ($comment->pid) { $parent_comment = db_query('SELECT c.*, u.uid, u.name AS registered_name, u.signature, u.picture, u.data FROM {comment} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = :cid AND c.status = :status', array( ':cid' => $comment->pid, ':status' => COMMENT_PUBLISHED, ))->fetchObject(); - $parent_comment = drupal_unpack($parent_comment); - $parent_comment->name = $parent_comment->uid ? $parent_comment->registered_name : $parent_comment->name; - $output_below = theme('comment_view', $parent_comment, $node); + + $build = comment_build($parent_comment); } else { - $suffix = empty($form['#suffix']) ? '' : $form['#suffix']; - $form['#suffix'] = $suffix . drupal_render(node_build($node)); - $output_below = ''; + $build = node_build($node); } - $form['comment_preview_below'] = array( - '#markup' => $output_below, - '#weight' => 100, - ); + $form['comment_output_below'] = $build; + $form['comment_output_below']['#weight'] = 100; return $form; } @@ -1904,68 +1985,26 @@ function comment_form_submit($form, &$form_state) { $form_state['redirect'] = $redirect; } -/** - * Theme a single comment block. - * - * @param $comment - * The comment object. - * @param $node - * The comment node. - * @param $links - * An associative array containing control links. - * @param $visible - * Switches between folded/unfolded view. - * @ingroup themeable - */ -function theme_comment_view($comment, $node, $links = array(), $visible = TRUE) { - $first_new = &drupal_static(__FUNCTION__, TRUE); - $comment->new = node_mark($comment->nid, $comment->timestamp); - $output = ''; - - if ($first_new && $comment->new != MARK_READ) { - // Assign the anchor only for the first new comment. This avoids duplicate - // id attributes on a page. - $first_new = FALSE; - $output .= "<a id=\"new\"></a>\n"; - } - - $output .= "<a id=\"comment-$comment->cid\"></a>\n"; - - // Switch to folded/unfolded view of the comment. - if ($visible) { - $comment->comment = check_markup($comment->comment, $comment->format, '', FALSE); - // Comment API hook. - module_invoke_all('comment_view', $comment); - $output .= theme('comment', $comment, $node, $links); - } - else { - $output .= theme('comment_folded', $comment, $node); - } - - return $output; -} - /** * Process variables for comment.tpl.php. * * @see comment.tpl.php - * @see theme_comment() */ function template_preprocess_comment(&$variables) { - $comment = $variables['comment']; - $node = $variables['node']; + $comment = $variables['elements']['#comment']; + $variables['comment'] = $comment; + $variables['node'] = node_load($comment->nid); $variables['author'] = theme('username', $comment); - $variables['content'] = $comment->comment; + $variables['content'] = $comment->content; $variables['date'] = format_date($comment->timestamp); - $variables['links'] = isset($variables['links']) ? theme('links', $variables['links']) : ''; - $variables['new'] = $comment->new ? t('new') : ''; + $variables['new'] = !empty($comment->new) ? t('new') : ''; $variables['picture'] = theme_get_setting('toggle_comment_user_picture') ? theme('user_picture', $comment) : ''; $variables['signature'] = $comment->signature; $variables['submitted'] = theme('comment_submitted', $comment); $variables['title'] = l($comment->subject, 'comment/' . $comment->cid, array('fragment' => "comment-$comment->cid")); - $variables['template_files'][] = 'comment-' . $node->type; + $variables['template_files'][] = 'comment-' . $variables['node']->type; // Set status to a string representation of comment->status. - if (isset($comment->preview)) { + if (isset($comment->in_preview)) { $variables['status'] = 'comment-preview'; } else { @@ -1986,71 +2025,12 @@ function template_preprocess_comment(&$variables) { if ($comment->uid === $variables['user']->uid) { $variables['classes_array'][] = 'comment-by-viewer'; } - if ($comment->new) { + if ($variables['new']) { $variables['classes_array'][] = 'comment-new'; } } } -/** - * Process variables for comment-folded.tpl.php. - * - * @see comment-folded.tpl.php - * @see theme_comment_folded() - */ -function template_preprocess_comment_folded(&$variables) { - $comment = $variables['comment']; - $variables['author'] = theme('username', $comment); - $variables['date'] = format_date($comment->timestamp); - $variables['new'] = $comment->new ? t('new') : ''; - $variables['title'] = l($comment->subject, 'comment/' . $comment->cid, array('fragment' => "comment-$comment->cid")); - // Gather comment classes. - if ($comment->uid === 0) { - $variables['classes_array'][] = 'comment-by-anonymous'; - } - else { - if ($comment->status == COMMENT_NOT_PUBLISHED) { - $variables['classes_array'][] = 'comment-unpublished'; - } - if ($comment->uid === $variables['node']->uid) { - $variables['classes_array'][] = 'comment-by-node-author'; - } - if ($comment->uid === $variables['user']->uid) { - $variables['classes_array'][] = 'comment-by-viewer'; - } - if ($comment->new) { - $variables['classes_array'][] = 'comment-new'; - } - } - -} - -/** - * Theme comment flat expanded view. - * - * @param $comment - * The comment to be themed. - * @param $node - * The comment node. - * @ingroup themeable - */ -function theme_comment_flat_expanded($comment, $node) { - return theme('comment_view', $comment, $node, module_invoke_all('link', 'comment', $comment, 0)); -} - -/** - * Theme comment thread expanded view. - * - * @param $comment - * The comment to be themed. - * @param $node - * The comment node. - * @ingroup themeable - */ -function theme_comment_thread_expanded($comment, $node) { - return theme('comment_view', $comment, $node, module_invoke_all('link', 'comment', $comment, 0)); -} - /** * Theme a "you can't post comments" notice. * @@ -2096,7 +2076,8 @@ function theme_comment_post_forbidden($node) { */ function template_preprocess_comment_wrapper(&$variables) { // Provide contextual information. - $variables['display_mode'] = _comment_get_display_setting('mode', $variables['node']); + $variables['node'] = $variables['content']['#node']; + $variables['display_mode'] = _comment_get_display_setting('mode', $variables['node']); $variables['template_files'][] = 'comment-wrapper-' . $variables['node']->type; } diff --git a/modules/comment/comment.pages.inc b/modules/comment/comment.pages.inc index 5748c4f46f1c9a1ecc71e17cf81fce7d2ef56380..dc18f803516f39a96a60921009cb31068522e9d4 100644 --- a/modules/comment/comment.pages.inc +++ b/modules/comment/comment.pages.inc @@ -7,24 +7,14 @@ */ /** - * Form builder; generate a comment editing form. + * A menu callback; build a comment editing form. * - * @param $cid - * ID of the comment to be edited. + * @param $comment + * The comment to be edited. * @ingroup forms */ -function comment_edit($cid) { - global $user; - $comment = db_query('SELECT c.*, u.uid, u.name AS registered_name, u.data FROM {comment} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = :cid', array(':cid' => $cid))->fetchObject(); - $comment = drupal_unpack($comment); - $comment->name = $comment->uid ? $comment->registered_name : $comment->name; - - if (comment_access('edit', $comment)) { - return theme('comment_form_box', (array)$comment); - } - else { - drupal_access_denied(); - } +function comment_edit($comment) { + return drupal_get_form('comment_form', (array)$comment); } /** @@ -52,13 +42,13 @@ function comment_reply($node, $pid = NULL) { // Set the breadcrumb trail. drupal_set_breadcrumb(array(l(t('Home'), NULL), l($node->title, 'node/' . $node->nid))); $op = isset($_POST['op']) ? $_POST['op'] : ''; - $output = ''; + $build = array(); if (user_access('access comments')) { // The user is previewing a comment prior to submitting it. if ($op == t('Preview')) { if (user_access('post comments')) { - $output .= theme('comment_form_box', array('pid' => $pid, 'nid' => $node->nid), NULL); + $build['comment_form'] = drupal_get_form('comment_form', array('pid' => $pid, 'nid' => $node->nid)); } else { drupal_set_message(t('You are not authorized to post comments.'), 'error'); @@ -84,7 +74,7 @@ function comment_reply($node, $pid = NULL) { // Display the parent comment $comment = drupal_unpack($comment); $comment->name = $comment->uid ? $comment->registered_name : $comment->name; - $output .= theme('comment_view', $comment, $node); + $build['comment_parent'] = comment_build($comment); } else { drupal_set_message(t('The comment you are replying to does not exist.'), 'error'); @@ -93,7 +83,7 @@ function comment_reply($node, $pid = NULL) { } // This is the case where the comment is in response to a node. Display the node. elseif (user_access('access content')) { - $output .= drupal_render(node_build($node)); + $build['comment_node'] = node_build($node); } // Should we show the reply box? @@ -102,7 +92,8 @@ function comment_reply($node, $pid = NULL) { drupal_goto("node/$node->nid"); } elseif (user_access('post comments')) { - $output .= theme('comment_form_box', array('pid' => $pid, 'nid' => $node->nid), t('Add new comment')); + $edit = array('nid' => $node->nid, 'pid' => $pid); + $build['comment_form'] = drupal_get_form('comment_form', $edit); } else { drupal_set_message(t('You are not authorized to post comments.'), 'error'); @@ -115,11 +106,11 @@ function comment_reply($node, $pid = NULL) { drupal_goto("node/$node->nid"); } - return $output; + return $build; } /** - * Publish specified comment. + * Menu callback; publish specified comment. * * @param $cid ID of comment to be published. */ diff --git a/modules/comment/comment.test b/modules/comment/comment.test index 146a8538cd7b52f66223f5df052e067ac2711f4f..082d8ed228070f5bc1c50aad7f7eb6e3ea651804 100644 --- a/modules/comment/comment.test +++ b/modules/comment/comment.test @@ -76,7 +76,7 @@ class CommentHelperCase extends DrupalWebTestCase { $regex .= '<div(.*?)'; // Begin in comment div. $regex .= $comment->subject . '(.*?)'; // Match subject. $regex .= $comment->comment . '(.*?)'; // Match comment. - $regex .= '<\/div>/s'; // Dot matches newlines and ensure that match doesn't bleed outside comment div. + $regex .= '/s'; return (boolean)preg_match($regex, $this->drupalGetContent()); } @@ -446,7 +446,7 @@ class CommentAnonymous extends CommentHelperCase { // "Login or register to post comments" type link may be shown. $this->drupalLogout(); $this->drupalGet('node/' . $this->node->nid); - $this->assertNoRaw('<div id="comments">', t('Comments were not displayed.')); + $this->assertNoPattern('/<div ([^>]*?)id="comments"([^>]*?)>/', t('Comments were not displayed.')); $this->assertNoLink('Add new comment', t('Link to add comment was found.')); // Attempt to view node-comment form while disallowed. @@ -459,7 +459,7 @@ class CommentAnonymous extends CommentHelperCase { $this->setAnonymousUserComment(TRUE, FALSE, FALSE); $this->drupalLogout(); $this->drupalGet('node/' . $this->node->nid); - $this->assertRaw('<div id="comments">', t('Comments were displayed.')); + $this->assertPattern('/<div ([^>]*?)id="comments"([^>]*?)>/', t('Comments were displayed.')); $this->assertLink('Login', 1, t('Link to login was found.')); $this->assertLink('register', 1, t('Link to register was found.')); } diff --git a/modules/comment/comment.tpl.php b/modules/comment/comment.tpl.php index 07360a04436deb8b875ddcddc39761b07c7e236d..abcca937803dbf7c95857a51df5d6208dbf9b3ec 100644 --- a/modules/comment/comment.tpl.php +++ b/modules/comment/comment.tpl.php @@ -7,9 +7,11 @@ * * Available variables: * - $author: Comment author. Can be link or plain text. - * - $content: Body of the post. + * - $content: An array of comment items. Use render($content) to print them all, or + * print a subset such as render($content['field_example']). Use + * hide($content['field_example']) to temporarily suppress the printing of a + * given element. * - $date: Date and time of posting. - * - $links: Various operational links. * - $new: New comment marker. * - $picture: Authors picture. * - $signature: Authors signature. @@ -46,7 +48,7 @@ <div class="<?php print $classes; ?> clearfix"> <?php print $picture ?> - <?php if ($comment->new): ?> + <?php if ($new): ?> <span class="new"><?php print $new ?></span> <?php endif; ?> @@ -57,7 +59,11 @@ </div> <div class="content"> - <?php print $content ?> + <?php + // We hide the comments and links now so that we can render them later. + hide($content['links']); + print render($content); + ?> <?php if ($signature): ?> <div class="user-signature clearfix"> <?php print $signature ?> @@ -65,5 +71,5 @@ <?php endif; ?> </div> - <?php print $links ?> + <?php print render($content['links']) ?> </div> diff --git a/themes/garland/comment.tpl.php b/themes/garland/comment.tpl.php index e2edf0dc0c94fdbebb843341d4535b2362271dc4..c9daefc003c1a408d61827568479301e34bd52d4 100644 --- a/themes/garland/comment.tpl.php +++ b/themes/garland/comment.tpl.php @@ -8,7 +8,7 @@ <span class="submitted"><?php print $submitted; ?></span> <?php endif; ?> - <?php if ($comment->new) : ?> + <?php if ($new) : ?> <span class="new"><?php print drupal_ucfirst($new) ?></span> <?php endif; ?> @@ -17,7 +17,7 @@ <h3><?php print $title ?></h3> <div class="content"> - <?php print $content ?> + <?php hide($content['links']); print render($content); ?> <?php if ($signature): ?> <div class="clearfix"> <div>—</div> @@ -27,7 +27,5 @@ </div> </div> - <?php if ($links): ?> - <div class="links"><?php print $links ?></div> - <?php endif; ?> + <?php print render($content['links']) ?> </div> diff --git a/themes/garland/template.php b/themes/garland/template.php index 24d1e64e334e33a3d946556fe4d149bc22a429ef..e1be8efc075e4c89f5b9b77e5284addd052ec981 100644 --- a/themes/garland/template.php +++ b/themes/garland/template.php @@ -14,18 +14,6 @@ function garland_breadcrumb($breadcrumb) { } } -/** - * Allow themable wrapping of all comments. - */ -function garland_comment_wrapper($content, $node) { - if (!$content || $node->type == 'forum') { - return '<div id="comments">' . $content . '</div>'; - } - else { - return '<div id="comments"><h2 class="comments">' . t('Comments') . '</h2>' . $content . '</div>'; - } -} - /** * Override or insert variables into the page template. */