better_comments.module in Better Comments 7
Same filename and directory in other branches
Better Comments provides option to configure the comment system.
File
better_comments.moduleView source
<?php
/**
* @file
* Better Comments provides option to configure the comment system.
*/
/**
* Implements hook_menu().
*/
function better_comments_menu() {
$items['admin/config/content/better-comments'] = array(
'title' => 'Better Comments',
'description' => 'Provide a list of options to customize the comment forms and display',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'better_comments_settings',
),
'access arguments' => array(
'administer site configuration',
),
'file' => 'better_comments.admin.inc',
);
$items['better_comments/%/edit'] = array(
'page callback' => 'better_comments_edit',
'page arguments' => array(
1,
),
'access arguments' => array(
'edit own comments',
),
'delivery callback' => 'ajax_deliver',
'type' => MENU_CALLBACK,
);
$items['better_comments/edit/%/cancel'] = array(
'page callback' => 'better_comments_edit_cancel',
'page arguments' => array(
2,
),
'access arguments' => array(
'edit own comments',
),
'delivery callback' => 'ajax_deliver',
'type' => MENU_CALLBACK,
);
$items['better_comments/%/reply'] = array(
'page callback' => 'better_comments_reply',
'page arguments' => array(
1,
),
'access arguments' => array(
'post comments',
),
'delivery callback' => 'ajax_deliver',
'type' => MENU_CALLBACK,
);
$items['better_comments/reply/%/cancel'] = array(
'page callback' => 'better_comments_reply_cancel',
'page arguments' => array(
2,
),
'access arguments' => array(
'post comments',
),
'delivery callback' => 'ajax_deliver',
'type' => MENU_CALLBACK,
);
$items['better_comments/%/delete'] = array(
'page callback' => 'better_comments_delete',
'page arguments' => array(
1,
),
'access arguments' => array(
'delete own comment',
),
'delivery callback' => 'ajax_deliver',
'type' => MENU_CALLBACK,
);
$items['better_comments/delete/%/cancel'] = array(
'page callback' => 'better_comments_delete_cancel',
'page arguments' => array(
2,
),
'access arguments' => array(
'delete own comment',
),
'delivery callback' => 'ajax_deliver',
'type' => MENU_CALLBACK,
);
$items['better_comments/preview/%/cancel'] = array(
'page callback' => 'better_comments_preview_cancel',
'page arguments' => array(
2,
),
'access arguments' => array(
'post comments',
),
'delivery callback' => 'ajax_deliver',
'type' => MENU_CALLBACK,
);
$items['better_comments/preview/%/cancel/%'] = array(
'page callback' => 'better_comments_preview_cancel',
'page arguments' => array(
2,
4,
),
'access arguments' => array(
'post comments',
),
'delivery callback' => 'ajax_deliver',
'type' => MENU_CALLBACK,
);
$items['better_comments/reply/preview/cancel/%'] = array(
'page callback' => 'better_comments_reply_preview_cancel',
'page arguments' => array(
4,
),
'access arguments' => array(
'post comments',
),
'delivery callback' => 'ajax_deliver',
'type' => MENU_CALLBACK,
);
return $items;
}
/**
* Implements hook_form_comments_form_alter().
*/
function better_comments_form_comment_form_alter(&$form, &$form_state) {
global $user;
// $filepath = drupal_get_path('module', 'better_comments') . '/images/default.png';
// Disable author textarea.
/* $form['#attached']['css'] = array(
drupal_get_path('module', 'better_comments') . '/css/better_comments.css',
);*/
$form['#attached']['js'] = array(
drupal_get_path('module', 'better_comments') . '/js/better_comments.js',
);
if (variable_get('better_comments_author') == 1) {
$form['author']['#access'] = FALSE;
}
// Disable subject textarea.
if (variable_get('better_comments_subject') == 1) {
$form['subject']['#access'] = FALSE;
}
// Comment body title.
if (variable_get('better_comments_body_title') == 1) {
// Removes title above Comment body but not Star.
$form['comment_body'][LANGUAGE_NONE]['0']['#title'] = "";
// Removes the reqiured star.
$form['comment_body'][LANGUAGE_NONE]['0']['#required'] = FALSE;
}
// Remove format settings below comment body.
if (variable_get('better_comments_text_filters') == 1) {
$form['comment_body']['#after_build'][] = 'better_comments_customize_comment_form';
}
// Show user picture beside comment box.
if (variable_get('better_comments_picture') == 1) {
// if (!empty($user->picture)) {
// $filepath = file_load($user->picture)->uri;
// $pic = array(
// '#type' => 'image',
// '#access' => TRUE,
// 'path' => file_create_url($filepath),
// );
$picture = theme('user_picture', array(
'account' => $user,
));
// }
// else {
// $filepath = variable_get('user_picture_default', '');
// $pic = array(
// '#type' => 'image',
// '#access' => TRUE,
// 'path' => file_create_url($filepath),
// );
// $picture = theme('user_picture', array('account' => $pic));
// }
$form['comment_body'][LANGUAGE_NONE]['0']['#attributes']['id'][] = 'better-comments-text';
// Add user picture to comment form.
$form['comment_body']['#prefix'] = '<div class="better-comments">
<div class="comment-user-picture">' . $picture . '</div>';
$form['comment_body']['#suffix'] = '</div>';
}
// Ajaxify comment submit button.
$form['actions']['submit']['#ajax'] = array(
'callback' => 'better_comments_submit',
'wrapper' => 'comment-wrapper',
'method' => 'append',
'effect' => 'fade',
);
$form['#validate'][] = 'better_comments_validate';
// Add a Comment body placeholder text.
if (variable_get('better_comments_text_placeholder') == "") {
$form['comment_body'][LANGUAGE_NONE]['0']['#attributes']['placeholder'][] = t('Add a comment here.');
}
elseif (variable_get('better_comments_text_placeholder') == "<none>") {
$form['comment_body'][LANGUAGE_NONE]['0']['#attributes']['placeholder'][] = "";
}
else {
$value = variable_get('better_comments_text_placeholder');
$form['comment_body'][LANGUAGE_NONE]['0']['#attributes']['placeholder'][] = t('@value', array(
'@value' => $value,
));
}
// Disable the preview button.
if (variable_get('better_comments_preview') == 1) {
// Disable preview button.
$form['actions']['preview']['#access'] = FALSE;
}
else {
// Ajaxify comment preview button.
$form['actions']['preview']['#ajax'] = array(
'callback' => 'better_comments_preview',
'wrapper' => 'comment-wrapper',
'method' => 'append',
'effect' => 'fade',
);
$form['actions']['submit']['#attributes'] = array(
'class' => array(
'better-comments-submit',
),
);
$form['actions']['preview']['#attributes'] = array(
'class' => array(
'button',
),
);
}
return $form;
}
/**
* Edit the comment.
*/
function better_comments_edit($cid) {
$comment = comment_load($cid);
$node = node_load($comment->nid);
$form_build = drupal_get_form("comment_node_{$node->type}_form", $comment);
// Allow cancelling of edit.
$form_build['actions']['cancel'] = array(
'#markup' => l(t('Cancel'), 'better_comments/edit/' . $comment->cid . '/cancel', array(
'attributes' => array(
'class' => array(
'use-ajax',
'button',
),
),
)),
'#weight' => 21,
);
$form = trim(drupal_render($form_build));
$commands[] = ajax_command_replace('.comment-inner-' . $comment->cid . '>.comment-body', $form);
return array(
'#type' => 'ajax',
'#commands' => $commands,
);
}
/**
* Cancel the edit comment form.
*/
function better_comments_edit_cancel($cid) {
$comment = comment_load($cid);
$node = node_load($comment->nid);
$comment = comment_view($comment, $node);
unset($comment['#prefix']);
unset($comment['#suffix']);
$form = drupal_render($comment);
$commands[] = ajax_command_replace('.comment-inner-' . $cid, $form);
return array(
'#type' => 'ajax',
'#commands' => $commands,
);
}
/**
* Reply the comment.
*/
function better_comments_reply($pid) {
// If there is a pid this is a reply to a comment.
if ($pid) {
// Make sure the parent comment is valid and published.
if (!($comments = comment_load_multiple(array(
$pid,
), array(
'status' => COMMENT_PUBLISHED,
)))) {
return MENU_NOT_FOUND;
}
$comment = $comments[$pid];
$node = node_load($comment->nid);
// Make sure the comment belongs to this node.
if ($comment->nid != $node->nid) {
return MENU_NOT_FOUND;
}
}
// Build form.
$form_build = drupal_get_form("comment_node_{$node->type}_form", (object) array(
'nid' => $node->nid,
'pid' => $pid,
));
// Offer 'cancel' link for reply. This will just remove the reply form so
// there is no callback.
$form_build['actions']['cancel'] = array(
'#markup' => l(t('Cancel'), 'better_comments/reply/' . $pid . '/cancel', array(
'attributes' => array(
'class' => array(
'use-ajax',
'button',
'reply-cancel',
),
'id' => array(
'cancel-' . $pid,
),
),
)),
'#weight' => 21,
);
$form['#validate'][] = 'better_comments_validate';
$form = drupal_render($form_build);
$form = '<div class="indented-' . $pid . '">' . $form . '</div>';
$commands[] = ajax_command_append('#comment-wrap-' . $pid, $form);
return array(
'#type' => 'ajax',
'#commands' => $commands,
);
}
/**
* Cancel the replay comment form.
*/
function better_comments_reply_cancel($cid) {
$commands[] = ajax_command_remove('#comment-wrap-' . $cid . '>.indented-' . $cid);
return array(
'#type' => 'ajax',
'#commands' => $commands,
);
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function better_comments_form_comment_confirm_delete_alter(&$form, &$form_state, &$form_id) {
form_load_include($form_state, 'inc', 'comment', 'comment.admin');
$comment = $form['#comment'];
$form['actions']['submit']['#ajax'] = array(
'callback' => 'better_comments_confirm_delete_submit',
'wrapper' => 'comment-wrapper',
'method' => 'append',
'effect' => 'fade',
);
$form['actions']['cancel'] = array(
'#markup' => l(t('Cancel'), 'better_comments/delete/' . $comment->cid . '/cancel', array(
'attributes' => array(
'class' => array(
'use-ajax',
'button',
'delete-cancel',
),
'id' => array(
'delete-cancel-' . $comment->cid,
),
),
)),
'#weight' => 21,
);
return $form;
}
/**
* Cancel the delete option and resend the form.
*/
function better_comments_delete_cancel($cid) {
$commands[] = ajax_command_remove('#comment-wrap-' . $cid . '>.better-comments-confirm');
return array(
'#type' => 'ajax',
'#commands' => $commands,
);
}
/**
* Prepares the comment for delete.
*/
function better_comments_delete($cid) {
$comment = comment_load($cid);
$form_state = array();
$form_state['build_info']['args'] = array(
$comment,
);
// Load this using form_load_include so it's cached properly and works in the
// ajax callback.
form_load_include($form_state, 'inc', 'comment', 'comment.admin');
$form_build = drupal_get_form('comment_confirm_delete', $comment);
$form_build['#attributes']['class'] = 'better-comments-confirm';
$form = drupal_render($form_build);
$commands[] = ajax_command_append('#comment-wrap-' . $cid, $form);
return array(
'#type' => 'ajax',
'#commands' => $commands,
);
}
/**
* Delete the comment by calling comment_delete.
*/
function better_comments_confirm_delete_submit(&$form, &$form_state) {
form_load_include($form_state, 'inc', 'comment', 'comment.admin');
$comment = $form['#comment'];
// Delete the comment and its replies.
comment_delete($comment->cid);
watchdog('content', 'Deleted comment @cid and its replies.', array(
'@cid' => $comment->cid,
));
$commands[] = ajax_command_remove('#comment-wrap-' . $comment->cid);
return array(
'#type' => 'ajax',
'#commands' => $commands,
);
}
/**
* Validate the comment on submit.
*/
function better_comments_validate($form, &$form_state) {
if (empty($form_state['values']['comment_body'][LANGUAGE_NONE]['0']['value'])) {
form_set_error('comment_body', t('The comment body cannot be empty.'));
}
}
/**
* Previews the comment.
*/
function better_comments_preview($form, &$form_state) {
if (form_get_errors()) {
$form['comment_body']['#attributes'] = array(
'class' => array(
'error',
),
);
$form = drupal_render($form);
if (isset($form['cid']['#value'])) {
$cid = $form['cid']['#value'];
$commands[] = ajax_command_remove('#comment-wrap-' . $cid . ' .comment-form', $form);
}
elseif (isset($form_state['values']['pid'])) {
// Append comment to parent wrapper.
$pid = $form_state['values']['pid'];
$commands[] = ajax_command_replace('#comment-wrap-' . $pid . ' .comment-form', $form);
}
else {
$commands[] = ajax_command_replace('.comment-form', $form);
}
}
else {
if (isset($form['cid']['#value'])) {
$cid = $form['cid']['#value'];
}
$comment = $form_state['comment'];
$node = $form['#node'];
$comment_build = comment_view($comment, $node);
$comment_build['#prefix'] = '<div class="preview better-comments-confirm-' . $cid . '">';
$comment_build['links']['comment']['#links']['comment-delete'] = FALSE;
$comment_output = drupal_render($comment_build);
// Disable the preview buttom on form.
// Add a new form and not from cached.
$form_state = array();
$form_state['input'] = array();
$form_state['comment'] = $comment;
$form_state['build_info']['args'][] = (object) array(
'nid' => $node->nid,
);
$form_build = drupal_build_form($form['#form_id'], $form_state);
$form_build['actions']['preview']['#access'] = FALSE;
// Check if comment is being edited.
if (isset($form['cid']['#value'])) {
$cancel_url = 'better_comments/preview/' . $node->nid . '/cancel/' . $form['cid']['#value'];
}
elseif (isset($form_state['values']['pid'])) {
$cancel_url = 'better_comments/reply/preview/cancel/' . $form_state['values']['pid'];
}
else {
$cancel_url = 'better_comments/preview/' . $node->nid . '/cancel';
}
// Add a cancel preview button to the form.
$form_build['actions']['cancel'] = array(
'#markup' => l(t('Cancel'), $cancel_url, array(
'attributes' => array(
'class' => array(
'use-ajax',
'button',
'preview-cancel',
),
'id' => array(
'preview-' . $form_state['values']['pid'],
),
),
)),
'#weight' => 21,
);
$form = drupal_render($form_build);
// Check if it is a preview of edit form.
if (isset($cid)) {
$commands[] = ajax_command_replace('#comment-wrap-' . $cid . ' .comment-form', $form);
$commands[] = ajax_command_prepend('#comment-wrap-' . $cid, $comment_output);
}
elseif (isset($form_state['values']['pid'])) {
// Append comment to parent wrapper.
$pid = $form_state['values']['pid'];
$commands[] = ajax_command_replace('#comment-wrap-' . $pid . ' .comment-form', $form);
$commands[] = ajax_command_prepend('#comment-wrap-' . $pid . '> .indented-' . $pid, $comment_output);
}
else {
$commands[] = ajax_command_replace('.comment-form', $form);
$commands[] = ajax_command_prepend('.comment-form', $comment_output);
}
}
return array(
'#type' => 'ajax',
'#commands' => $commands,
);
}
/**
* Cancel the previews of the comment.
*/
function better_comments_preview_cancel($nid, $cid) {
// Add a new form and not from cached.
if ($cid) {
$comment = comment_load($cid);
$node = node_load($comment->nid);
$comment = comment_view($comment, $node);
$form = trim(drupal_render($comment));
$commands[] = ajax_command_replace('#comment-wrap-' . $cid, $form);
}
else {
$node = node_load($nid);
$form_build = drupal_get_form("comment_node_{$node->type}_form", (object) array(
'nid' => $nid,
));
$form = drupal_render($form_build);
$commands[] = ajax_command_replace('.comment-form', $form);
}
return array(
'#type' => 'ajax',
'#commands' => $commands,
);
}
/**
* Cancel the reply preview.
*/
function better_comments_reply_preview_cancel($pid) {
// Append comment to parent wrapper.
$commands[] = ajax_command_remove('#comment-wrap-' . $pid . '> .indented-' . $pid);
return array(
'#type' => 'ajax',
'#commands' => $commands,
);
}
/**
* Submit the comment.
*/
function better_comments_submit(&$form, &$form_state) {
if (form_get_errors()) {
$form['#attributes'] = array(
'id' => array(
'edit-comment-body',
'error',
),
);
// Check if this a replay form.
if (isset($form_state['values']['pid'])) {
$pid = $form_state['values']['pid'];
$form['actions']['cancel'] = array(
'#markup' => l(t('Cancel'), 'better_comments/reply/' . $pid . '/cancel', array(
'attributes' => array(
'class' => array(
'use-ajax',
'button',
),
),
)),
'#weight' => 21,
);
$form = drupal_render($form);
$commands[] = ajax_command_replace('#comment-wrap-' . $pid . '> .comment-form', $form);
}
else {
$form = drupal_render($form);
$commands[] = ajax_command_replace('.comment-form', $form);
}
return array(
'#type' => 'ajax',
'#commands' => $commands,
);
}
$form_state['redirect'] = '';
// Unset the preview mode for form submit.
unset($form_state['comment']->in_preview);
unset($form_state['comment']->preview);
$comment = $form_state['comment'];
$node = $form['#node'];
$comment_build = comment_view($comment, $node);
$comment_output = drupal_render($comment_build);
// Existing comment is edited.
if (isset($form['cid']['#value'])) {
$commands[] = ajax_command_remove('.better-comments-confirm-' . $comment->cid);
$commands[] = ajax_command_replace('.comment-inner-' . $comment->cid, $comment_output);
}
elseif (isset($form_state['values']['pid'])) {
// Else this is a reply.
// Append comment to parent wrapper.
$comment_output = '</div>' . $comment_output;
$commands[] = ajax_command_replace('.indented-' . $comment->pid, $comment_output);
// Delete the form.
$commands[] = ajax_command_invoke('#' . $form['#id'], 'remove');
}
else {
$commands[] = ajax_command_append('.comment-section', $comment_output);
}
// Add a new empty form and not the cached form with comment body text.
$form_state = array();
$form_state['input'] = array();
$form_state['build_info']['args'][] = (object) array(
'nid' => $node->nid,
);
$form_build = drupal_build_form($form['#form_id'], $form_state);
$form = drupal_render($form_build);
$commands[] = ajax_command_replace('.comment-form', $form);
return array(
'#type' => 'ajax',
'#commands' => $commands,
);
}
/**
* Remove the text filter format options.
*/
function better_comments_customize_comment_form(&$form) {
$form[LANGUAGE_NONE][0]['format']['guidelines']['#access'] = FALSE;
$form[LANGUAGE_NONE][0]['format']['help']['#access'] = FALSE;
$form[LANGUAGE_NONE][0]['format']['#attributes'] = array(
'style' => 'display: none;',
);
return $form;
}
/**
* Access callback for deleting own comment.
*/
function better_comments_delete_access($comment) {
global $user;
$access = $user->uid && $user->uid == $comment->uid && $comment->status == COMMENT_PUBLISHED && (user_access('delete own comment') || user_access('administer comments'));
// Deletion is not allowed if any comment has this comment as a parent.
return $access && 0 == db_query("SELECT COUNT(cid) FROM {comment} WHERE pid = :cid", array(
':cid' => $comment->cid,
))
->fetchField();
}
/**
* Implements hook_comments_comment_view().
*/
function better_comments_comment_view($comment, $view_mode, $langcode) {
// Reply.
if (isset($comment->content['links']['comment']['#links']['comment-reply'])) {
$comment->content['links']['comment']['#links']['comment-reply']['attributes']['class'] = array(
'use-ajax',
'better-comments-reply',
);
$comment->content['links']['comment']['#links']['comment-reply']['attributes']['id'] = array(
'reply-' . $comment->cid,
);
$comment->content['links']['comment']['#links']['comment-reply']['href'] = 'better_comments/' . $comment->cid . '/reply';
}
// Edit.
if (isset($comment->content['links']['comment']['#links']['comment-edit'])) {
$comment->content['links']['comment']['#links']['comment-edit']['attributes']['class'] = array(
'use-ajax',
);
$comment->content['links']['comment']['#links']['comment-edit']['href'] = 'better_comments/' . $comment->cid . '/edit';
}
// Delete.
if (isset($comment->content['links']['comment']['#links']['comment-delete']) || better_comments_delete_access($comment)) {
$comment->content['links']['comment']['#links']['comment-delete']['attributes']['class'] = array(
'use-ajax',
'better-comments-delete',
);
$comment->content['links']['comment']['#links']['comment-delete']['attributes']['id'] = array(
'delete-' . $comment->cid,
);
$comment->content['links']['comment']['#links']['comment-delete']['href'] = 'better_comments/' . $comment->cid . '/delete';
$comment->content['links']['comment']['#links']['comment-delete']['title'] = t('delete');
}
}
/**
* Implements hook_theme().
*/
function better_comments_theme($existing, $type, $theme, $path) {
return array(
'better_comments' => array(
'template' => 'theme/better-comments',
'render element' => 'comment',
),
'better_comments_wrapper' => array(
'template' => 'theme/better-comments-wrapper',
'render element' => 'comment-wrapper',
),
);
}
/**
* Implements hook_preprocess_comment().
*/
function better_comments_preprocess_comment(&$variables, $hook) {
$comment = $variables['elements']['#comment'];
$account = user_load($comment->uid);
$variables['theme_hook_suggestions'][] = 'better_comments';
$variables['picture_set'] = variable_get('better_comments_picture', 0);
$variables['user_picture'] = theme('user_picture', array(
'account' => $account,
));
}
/**
* Implement preprocess comment wrapper.
*/
function better_comments_preprocess_comment_wrapper(&$variables, $hook) {
$variables['theme_hook_suggestions'][] = 'better_comments_wrapper';
}
/**
* Implements hook_comment_view_alter().
*/
function better_comments_comment_view_alter(&$build, $view_mode) {
$comment = $build['#comment'];
$node = $build['#node'];
$prefix = '';
$build['#attached'] = array(
'css' => array(
drupal_get_path('module', 'better_comments') . '/css/better_comments.css',
),
);
// Add wrapper tag.
$indent = $comment->pid != 0 && variable_get('comment_default_mode_' . $node->type, COMMENT_MODE_THREADED) == COMMENT_MODE_THREADED;
$prefix .= '<div class="better-comment-wrapper' . ($indent == TRUE ? ' indented' : '') . '" id="comment-wrap-' . $comment->cid . '">';
// Add anchor tag.
$prefix .= "<a id=\"comment-{$comment->cid}\"></a>\n";
$build['#prefix'] = $prefix;
}
/**
* Prepares entity view.
*/
function better_comments_entity_prepare_view($entities, $entity_type, $langcode) {
if ($entity_type == 'comment') {
$i = 0;
$opened = 0;
foreach ($entities as $id => $entity) {
$depth = isset($entity->thread) ? count(explode('.', $entity->thread)) - 1 : 0;
$entity->wrappers_to_close = 0;
if ($depth > $opened) {
$opened++;
}
else {
$entity->wrappers_to_close = $depth == $opened ? 1 : $opened - $depth + 1;
while ($depth < $opened) {
$opened--;
}
}
$i++;
}
$entities[$id]->final_wrappers_to_close = $opened;
}
}
/**
* Implements hook_permission().
*/
function better_comments_permission() {
return array(
'delete own comment' => array(
'title' => 'Delete own comments',
'description' => t('Allows a user to delete his own comment'),
),
);
}