- Patch #523950 by moshe weitzman, yched, catch: update comment rendering to take full advantage of the drupal_render() paradigm.

merge-requests/26/head
Dries Buytaert 2009-07-28 10:09:25 +00:00
parent 0ae1c4d9b7
commit 51e6389122
7 changed files with 392 additions and 416 deletions

View File

@ -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>

View File

@ -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,183 +1312,11 @@ 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;
}
/**
* Comment operations. Offer different update operations depending on
* which comment administration page is being viewed.
@ -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;
}

View File

@ -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.
*/

View File

@ -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.'));
}

View File

@ -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>

View File

@ -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>

View File

@ -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.
*/