You are here

heartbeat_comments.module in Heartbeat 6.4

Same filename and directory in other branches
  1. 7 modules/heartbeat_comments/heartbeat_comments.module

heartbeat_comments.module Heartbeat comments can come with two possible

File

modules/heartbeat_comments/heartbeat_comments.module
View source
<?php

/**
 * @file
 *   heartbeat_comments.module
 *   Heartbeat comments can come with two possible
 */
define('HEARTBEAT_NODE_COMMENTS_PER_PAGE', variable_get('heartbeat_comments_node_count', 5));
define('HEARTBEAT_REACTIONS_PER_PAGE', variable_get('heartbeat_comments_comment_count', 5));

/**
 * Implementation of hook_perm().
 */
function heartbeat_comments_perm() {
  return array(
    'add heartbeat comment',
    'administer heartbeat comments',
    'delete own comments',
    'delete any comment',
  );
}

/**
 * Implementation of hook_theme().
 */
function heartbeat_comments_theme($existing, $type, $theme, $path) {
  return array(
    'heartbeat_comments_admin_overview' => array(
      'arguments' => array(
        'form' => NULL,
      ),
    ),
    'heartbeat_comments' => array(
      'arguments' => array(
        'comments' => NULL,
        'uaid' => 0,
        'node_comment' => FALSE,
        'has_more' => FALSE,
      ),
    ),
    'heartbeat_comment' => array(
      'arguments' => array(
        'comment' => NULL,
        'node_comment' => FALSE,
      ),
    ),
  );
}

/**
 * Implementation of hook_menu().
 */
function heartbeat_comments_menu() {
  $items['admin/content/heartbeat/comments'] = array(
    'title' => 'Published heartbeat comments',
    'description' => 'List and edit heartbeat comments.',
    'page callback' => 'heartbeat_comments_admin',
    'access arguments' => array(
      'administer heartbeat comments',
    ),
    'file' => 'heartbeat_comments.admin.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => -10,
  );
  $items['heartbeat/comment/post'] = array(
    'title' => 'heartbeat comment post',
    'description' => 'Make a comment on an activity message',
    'access arguments' => array(
      'add heartbeat comment',
    ),
    'page callback' => 'heartbeat_comments_form_submit',
    'type' => MENU_CALLBACK,
  );
  $items['heartbeat/comment/delete/%'] = array(
    'title' => t('Delete comment'),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'heartbeat_comments_delete_confirm',
      3,
    ),
    'access callback' => '_heartbeat_comments_delete_access',
    'access arguments' => array(
      3,
    ),
    'type' => MENU_CALLBACK,
  );
  $items['heartbeat/nodecomment/delete/%'] = array(
    'title' => t('Delete comment'),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'heartbeat_comments_node_delete_confirm',
      3,
    ),
    'access callback' => '_heartbeat_comments_node_delete_access',
    'access arguments' => array(
      3,
    ),
    'type' => MENU_CALLBACK,
  );
  $items['heartbeat/comments/load/js'] = array(
    'title' => 'heartbeat comments load',
    'access arguments' => array(
      'add heartbeat comment',
    ),
    'page callback' => 'heartbeat_comments_load_js',
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Implementation of hook_form_alter().
 */
function heartbeat_comments_form_alter(&$form, $form_state, $form_id) {
  if ($form_id == 'heartbeat_admin_settings') {

    // heartbeat_relations_api
    $form['hb_comments'] = array(
      '#type' => 'fieldset',
      '#weight' => -1,
      '#title' => t('Heartbeat comment settings'),
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
    );
    $form['hb_comments']['heartbeat_comments_cache'] = array(
      '#title' => t('Enable heartbeat comments cache'),
      '#description' => t('When enabled, heartbeat will cache the cache with the form foreach activity. This means times and so will not be updated untill new comment is made.'),
      '#type' => 'checkbox',
      '#default_value' => variable_get('heartbeat_comments_cache', 1),
      '#weight' => -5,
    );
    $form['hb_comments']['heartbeat_comments_position'] = array(
      '#title' => t('Choose the position of the comment box'),
      '#type' => 'select',
      '#options' => array(
        'down' => t('Comment list is beneath the comment box'),
        'up' => t('Comment list is on top of the comment box'),
      ),
      '#default_value' => variable_get('heartbeat_comments_position', 'down'),
      '#weight' => -5,
    );
    $form['hb_comments']['heartbeat_comments_order'] = array(
      '#title' => t('Select the sort order of the comments'),
      '#type' => 'select',
      '#options' => array(
        'recent_on_top' => t('Most recent comments on top'),
        'oldest_on_top' => t('Oldest comments on top'),
      ),
      '#default_value' => variable_get('heartbeat_comments_order', 'recent_on_top'),
      '#weight' => -5,
    );
    $form['hb_comments']['heartbeat_comments_comment_count'] = array(
      '#title' => t('Maximum of displayed heartbeat comments'),
      '#type' => 'textfield',
      '#default_value' => variable_get('heartbeat_comments_comment_count', 5),
      '#weight' => -5,
    );
    $form['hb_comments']['heartbeat_comments_node_count'] = array(
      '#title' => t('Maximum of displayed heartbeat node comments'),
      '#type' => 'textfield',
      '#default_value' => variable_get('heartbeat_comments_node_count', 5),
      '#weight' => -5,
    );
    $form['hb_comments']['heartbeat_comments_load_more'] = array(
      '#title' => t('Choose the behaviour of the more comments button'),
      '#type' => 'select',
      '#options' => array(
        'ajax' => t('Load with ajax'),
        'page' => t('Load on detail page'),
      ),
      '#default_value' => variable_get('heartbeat_comments_load_more', 'page'),
      '#description' => t('Note that the ajax loading will be very heavy on for high traffic sites. Use this feature wisely!'),
    );
  }
}

/**
 * Implementation of hook_heartbeat_load().
 */
function heartbeat_comments_heartbeat_load(&$messages, HeartbeatAccess $stream) {
  drupal_add_js(drupal_get_path('module', 'heartbeat_comments') . '/heartbeat_comments.js');
  $comments_order = variable_get('heartbeat_comments_order', 'recent_on_top');
  drupal_add_js(array(
    'heartbeat_comments_order' => $comments_order,
  ), "setting");
  $comments_position = variable_get('heartbeat_comments_position', 'down');
  drupal_add_js(array(
    'heartbeat_comments_position' => $comments_position,
  ), "setting");
  $comment_cache_enabled = variable_get('heartbeat_comments_cache', 1);
  foreach ($messages as $key => $message) {
    if (!empty($message->template->attachments['heartbeat_comments'])) {

      // Get the original message from the translation table if needed.
      $messages[$key]->tuaid = heartbeat_get_tuaid($message->uaid);
      $node = NULL;
      $node_comment = 0;
      if ($message->nid > 0) {
        $message_nid_cache = $message->nid;

        // Only nid & type is needed here (also for heartbeat_get_reactions)
        // so node_load is really over the top here.
        $node = new stdClass();
        $node->nid = $message->nid;
        $node->uid = $message->nid_info['uid'];
        $node->type = $message->nid_info['type'];
        $node->format = $message->nid_info['format'];
        $node->status = 1;

        // unpublished nodes ignore access control
        $node_comment = $message->template->attachments['comment_comments'] && variable_get('comment_' . $node->type, 2) > 0;
      }
      if (!$node_comment) {

        // Reset the nid to 0 since we don't use it for node-type disabled comments.
        $message_nid_cache = 0;
      }

      // Check access on the form submission.
      $show_form = user_access('add heartbeat comment');
      if ($message_nid_cache && $node_comment) {
        $show_form = user_access('post comments');
      }
      $messages[$key]->additions->object_type = '';
      if (!$show_form && $GLOBALS['user']->uid == 0) {
        $output = '<div class="user-login-teaser">' . t('!login or !register to make a comment', array(
          '!login' => l(t('Login'), 'user'),
          '!register' => l(t('register'), 'user/register'),
        )) . '</div>';
      }
      elseif ($comment_cache_enabled && ($objects_cache = cache_get('heartbeat:comments:' . $messages[$key]->tuaid . ':' . $message_nid_cache))) {

        // Make sure the textarea.js script is attached.
        drupal_add_js('misc/textarea.js');
        $output = $objects_cache->data;
      }
      else {
        $messages[$key]->additions->comments_order = $comments_order;
        $messages[$key]->additions->comments_position = $comments_position;

        // Normal heartbeat comments
        $messages[$key]->additions->node_comment = 0;
        $messages[$key]->additions->object_type = 'activity';

        // For the single message, make sure all comments are loaded.
        $messages[$key]->additions->all_comments = $stream instanceof SingleHeartbeat;

        // HeartbeatActivity.additions.comment_count is cached in the message itself.
        // Node comment reactions follow core. Here an extra query is needed to
        // the node comment statistics table.
        if (isset($node) && $message->template->attachments['comment_comments'] && variable_get('comment_' . $node->type, 2) > 0) {
          $messages[$key]->additions->node_comment = 1;
          $messages[$key]->additions->object_type = $node->type;
          $messages[$key]->additions->comment_count = db_result(db_query('SELECT comment_count FROM {node_comment_statistics} WHERE nid = %d', $node->nid));
        }

        // Fetch the comments if needed.
        $messages[$key]->additions->reactions = array();
        if ($messages[$key]->additions->comment_count > 0) {
          $messages[$key]->additions->reactions = heartbeat_get_reactions($messages[$key]->tuaid, $messages[$key]->additions->node_comment, $node, $messages[$key]->additions->all_comments);
          $messages[$key]->classes .= 'has-comments';
        }
        else {
          $messages[$key]->classes .= 'no-comments';
        }
        $output = heartbeat_comments_widget($message->template->attachments, $messages[$key]);
        if ($comment_cache_enabled) {
          cache_set('heartbeat:comments:' . $messages[$key]->tuaid . ':' . $message_nid_cache, $output);
        }
      }
      $message->additions->heartbeat_comments = array(
        '_cached' => $output,
      );
    }
  }
}

/**
 * Function to fetch reactions on a heartbeat message.
 */
function heartbeat_get_reactions($uaid, $node_comment, $node = NULL, $all = FALSE) {
  if ($node_comment && isset($node)) {
    static $node_comments = array();
    if (!isset($node_comments[$node->nid])) {
      $node_comments[$node->nid] = heartbeat_get_node_comments($node, $all);
    }
    return $node_comments[$node->nid];
  }
  else {
    static $reactions = array();
    if (!isset($reactions[$uaid])) {
      $reactions[$uaid] = heartbeat_get_message_reactions($uaid, $all);
    }
    return $reactions[$uaid];
  }
}

/**
 * Implementation of hook_heartbeat_activity_delete().
 *   Delete the attached comments to a heartbeat activity object.
 * @param $message
 *   HeartbeatActivity ID
 * @see module_invoke_all('heartbeat_activity_delete', $activity);
 */
function heartbeat_comments_heartbeat_activity_delete($activity) {
  db_query("DELETE FROM {heartbeat_comments} WHERE uaid = %d", $activity->uaid);
}

/**
 * Implementation of hook_heartbeat_attachments().
 * @param $message
 *   HeartbeatActivity object
 * @return unknown_type
 */
function heartbeat_comments_heartbeat_attachments($message = NULL) {
  return array(
    'heartbeat_comments' => array(
      '#type' => 'checkbox',
      '#default_value' => isset($message->attachments['heartbeat_comments']) ? $message->attachments['heartbeat_comments'] : 0,
      '#title' => t('Add heartbeat react field to this message'),
      '#weight' => 20,
    ),
    'comment_comments' => array(
      '#type' => 'checkbox',
      '#default_value' => isset($message->attachments['comment_comments']) ? $message->attachments['comment_comments'] : 0,
      '#title' => t('Use the node comment within node contexts if available and possible'),
      '#description' => t('Enabling this option will save a normal node comment when within node context(nid known). When enabled, normal reactions are <b>replaced</b> with the node comments, not appended!'),
      '#weight' => 21,
    ),
  );
}

/**
 * Implementation of <attchement>_widget().
 */
function heartbeat_comments_widget($attachments, &$message) {
  $list = '<div id="heartbeat-comments-wrapper-' . $message->tuaid . '" class="heartbeat-comments-wrapper">';
  $extraCssClass = "heartbeat-comments-nocomments";
  if ($message->additions->comment_count > 0) {
    $extraCssClass = "heartbeat-comments-comments";
    $has_more = FALSE;
    $comments_per_page = HEARTBEAT_REACTIONS_PER_PAGE;
    if ($message->template->attachments['comment_comments'] && variable_get('comment_' . $message->additions->object_type, 2) > 0) {
      $comments_per_page = HEARTBEAT_NODE_COMMENTS_PER_PAGE;
    }
    if (!$message->additions->all_comments && $message->additions->comment_count > $comments_per_page) {
      $has_more = TRUE;
      $message->additions->reactions = array_slice($message->additions->reactions, 0, $comments_per_page);
    }
    if ($message->additions->comments_order == 'oldest_on_top') {
      $message->additions->reactions = array_reverse($message->additions->reactions);
    }
    $list .= theme('heartbeat_comments', $message->additions->reactions, $message->tuaid, $message->additions->node_comment, $has_more);
  }
  $list .= '</div>';
  $output = '';
  $output .= '<div class="heartbeat-comments heartbeat-comments-' . $message->additions->object_type . ' ' . $extraCssClass . '">';
  if ($message->additions->comments_position == 'up') {
    $output .= $list;
  }
  $output .= drupal_get_form('heartbeat_comments_form', $message->tuaid, $message->additions->node_comment, $message->nid);
  if ($message->additions->comments_position == 'down') {
    $output .= $list;
  }
  $output .= '</div>';
  return $output;
}

/**
 * Implementation of hook_token_values().
 */
function heartbeat_comments_token_values($type, $object = NULL, $options = array()) {
  $values = array();
  switch ($type) {
    case 'heartbeat_comment':
      $comment = (object) $object;
      $values['heartbeat-comment-id'] = isset($comment->nid) ? $comment->cid : $comment->hcid;
      $values['heartbeat-comment-body'] = check_markup($comment->comment);
      $values['heartbeat-comment-body-raw'] = $comment->comment;
      $values['heartbeat-comment-author-uid'] = $comment->uid;
      $values['heartbeat-comment-date'] = isset($comment->nid) ? format_date($comment->timestamp, 'small') : $comment->time;
      $activity = heartbeat_load_message_instance($comment->uaid);
      $values['heartbeat-comment-uaid'] = $comment->uaid;
      $values['heartbeat-message'] = check_plain($activity->message);
      $values['heartbeat-message-raw'] = $activity->message;
      $values['heartbeat-message-url'] = url('heartbeat/message/' . $activity->uaid, array(
        'absolute' => TRUE,
      ));
      $values['heartbeat-message-link'] = l(_theme_time_ago($activity->timestamp), 'heartbeat/message/' . $activity->uaid, array(
        'html' => TRUE,
      ));
      break;
  }
  return $values;
}

/**
 * Implementation of hook_token_list().
 */
function heartbeat_comments_token_list($type = 'all') {
  if ($type == 'heartbeat_comment') {
    $tokens['heartbeat_comment']['heartbeat-comment-id'] = t('ID of the heartbeat comment or node comment');
    $tokens['heartbeat_comment']['heartbeat-comment-body'] = t('Body of the heartbeat comment or node comment');
    $tokens['heartbeat_comment']['heartbeat-comment-body-raw'] = t('Body of the heartbeat comment or node comment. WARNING - raw user input');
    $tokens['heartbeat_comment']['heartbeat-comment-author-uid'] = t("Comment author's user id");
    $tokens['heartbeat_comment']['heartbeat-comment-date'] = t("Comment creation year (four digit)");
    $tokens['heartbeat_comment']['heartbeat-comment-uaid'] = t("Parent activity message ID");
    $tokens['heartbeat_comment']['heartbeat-message'] = t("Parent activity message");
    $tokens['heartbeat_comment']['heartbeat-message-raw'] = t("Parent activity message in raw format");
    $tokens['heartbeat_comment']['heartbeat-message-url'] = t("Absolute url to the parent activity message");
    $tokens['heartbeat_comment']['heartbeat-message-link'] = t("Link to the parent activity message, the title is the moment it occurred");
    return $tokens;
  }
}

/**
 * Heartbeat comments form
 */
function heartbeat_comments_form($form_state = array(), $uaid = 0, $node_comment = FALSE, $nid = 0) {
  global $user;
  $show_form = user_access('add heartbeat comment');
  $form = array();
  if ($show_form) {
    $form['message'] = array(
      '#title' => t('React'),
      '#type' => 'textarea',
      '#required' => TRUE,
      '#rows' => 1,
      '#attributes' => array(
        'class' => 'heartbeat-message-comment',
      ),
    );

    // Get the original message from the translation table if needed.
    $form['uaid'] = array(
      '#type' => 'hidden',
      '#value' => $uaid,
      '#attributes' => array(
        'class' => 'heartbeat-message-uaid',
      ),
    );
    $form['submit'] = array(
      '#type' => 'submit',
      '#value' => t('Submit'),
      '#prefix' => '<span class="heartbeat-comments-wrapper">',
      '#suffix' => '<span class="heartbeat-messages-throbber">&nbsp;</span></span>',
      '#attributes' => array(
        'class' => 'heartbeat-comment-submit',
      ),
    );
    $form['heartbeat_comment_token'] = array(
      '#id' => 'heartbeat_comment_' . $uaid,
      '#default_value' => drupal_get_token('heartbeat_comment_' . $uaid),
      '#type' => 'hidden',
    );
    if ($nid && $node_comment) {
      $show_form = user_access('post comments');
      if ($show_form) {
        $form['node_comment'] = array(
          '#type' => 'hidden',
          '#value' => 1,
          '#attributes' => array(
            'class' => 'heartbeat-message-node-comment',
          ),
        );
        $form['nid'] = array(
          '#type' => 'hidden',
          '#value' => $nid,
          '#attributes' => array(
            'class' => 'heartbeat-message-nid',
          ),
        );
      }
    }
  }
  return $form;
}

/**
 * User submitted a heartbeat comment.
 */
function heartbeat_comments_form_submit($form = array(), &$form_state = array()) {
  $ahah = empty($form) && empty($form_state);
  global $user;
  $uid = $user->uid;
  $message = '';
  $message = $ahah ? $_POST['message'] : $form_state['values']['message'];
  $uaid = $ahah ? $_POST['uaid'] : (isset($form_state['values']['uaid']) ? $form_state['values']['uaid'] : $form_state['clicked_button']['#post']['uaid']);
  $nid = $ahah ? $_POST['nid'] : (isset($form_state['values']['nid']) ? $form_state['values']['nid'] : 0);
  $node_comment = $nid > 0 && ($ahah ? $_POST['node_comment'] : $form_state['values']['node_comment']);
  $first_comment = $ahah ? isset($_POST['first_comment']) ? $_POST['first_comment'] : 0 : (isset($form_state['values']['first_comment']) ? $form_state['values']['first_comment'] : 0);

  // Check the token.
  $token = 'heartbeat_comment_' . $uaid;
  if (!drupal_valid_token($_POST['heartbeat_comment_token'], $token)) {
    drupal_json(array(
      'status' => FALSE,
      'data' => t('Access denied'),
    ));
    exit;
  }
  if (!user_access('add heartbeat comment') || empty($message)) {
    drupal_json(array(
      'status' => FALSE,
      'data' => t('No comments'),
    ));
    exit;
  }
  $saved = NULL;

  // Save the (node) comment.
  if ($node_comment) {
    $comment = array(
      'subject' => '',
      'format' => '',
      'pid' => 0,
      'cid' => 0,
      'comment' => $message,
      'nid' => $nid,
      'uid' => $uid,
    );
    $cid = comment_save($comment);
    if ($cid) {
      $saved = db_fetch_object(db_query('SELECT c.*, u.uid,
        u.name AS registered_name, u.name AS name, u.signature, u.signature_format, u.picture
        FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid
        WHERE cid = %d', $cid));
    }

    // Clear the heartbeat comment cache.
    if (variable_get('heartbeat_comments_cache', 1)) {
      cache_clear_all('heartbeat:comments:' . $uaid . ':' . $nid, 'cache');
    }
    $tuaid = $uaid;
  }
  else {

    // Get the original message from the translation table if needed.
    $tuaid = heartbeat_get_tuaid($uaid);
    if (db_query("INSERT INTO {heartbeat_comments} (uid, uaid, message, time) VALUES (%d, %d, '%s', '%s')", $uid, $tuaid, $message, date('Y-m-d H:i:s'))) {
      $hcid = db_last_insert_id('heartbeat_comments', 'hcid');
      $saved = db_fetch_object(db_query("SELECT s.hcid, s.uid, s.uaid, s.message AS 'comment', s.time,\n        u.uid, u.name AS registered_name, u.name AS name, u.signature, u.signature_format, u.picture, u.data\n        FROM {heartbeat_comments} s INNER JOIN {users} u ON s.uid = u.uid\n        WHERE s.hcid = %d", $hcid));
    }
    $uaids = heartbeat_get_uaids($tuaid);
    if (empty($uaids)) {
      $uaids = array(
        $uaid,
      );
    }

    // Alter the uaid_comments field for this user activity id.
    db_query("UPDATE {heartbeat_activity} SET uaid_comments = uaid_comments + 1 WHERE uaid IN ( %s ) ", implode(',', $uaids));

    // Clear the heartbeat comment cache.
    if (variable_get('heartbeat_comments_cache', 1)) {
      cache_clear_all('heartbeat:comments:' . $tuaid . ':0', 'cache');
    }
  }
  $authorid = db_result(db_query("SELECT uid FROM {heartbeat_activity} WHERE uaid = %d", $uaid));
  $author = heartbeat_user_load($authorid);
  module_invoke_all('heartbeat_comment_post', $user, $saved, $author);

  // Let rules know there is a comment event.
  if (!$node_comment && module_exists('rules')) {
    rules_invoke_event('heartbeat_comment_post', $user, $saved, $author);

    // For actions on related users
    $result = db_query("SELECT DISTINCT(uid) FROM {heartbeat_comments} WHERE uaid = %d AND (uid != %d AND uid != %d)", $uaid, $user->uid, $author->uid);
    while ($row = db_fetch_object($result)) {
      $related_uids[$row->uid] = heartbeat_user_load($row->uid);
    }
    if (!empty($related_uids)) {
      foreach ($related_uids as $related_user) {
        rules_invoke_event('heartbeat_related_comment_post', $user, $saved, $author, $related_user);
      }
    }
  }
  if ($ahah) {
    if (isset($saved)) {
      if (!$first_comment || $first_comment == "false") {
        $content = theme('heartbeat_comment', $saved, $node_comment);
      }
      else {
        $content = theme('heartbeat_comments', array(
          $saved,
        ), $tuaid, $node_comment);
      }
      drupal_json(array(
        'status' => TRUE,
        'data' => $content,
        'id' => $tuaid,
      ));
    }
    else {
      drupal_json(array(
        'status' => TRUE,
        'data' => 'error',
      ));
    }
    exit;
  }
  else {
    if ($saved) {
      drupal_set_message(t('Comment has been posted.'));
    }
    else {
      drupal_set_message(t('Error while posting comment.'));
    }
    return TRUE;
  }
}

/**
 * Ajax callback to load all the comments.
 */
function heartbeat_comments_load_js() {
  if (!isset($_POST['uaid'])) {
    drupal_json(array(
      'status' => TRUE,
      'data' => 'No message id given',
    ));
  }
  $uaid = $_POST['uaid'];
  $nid = 0;
  $node = NULL;
  if (isset($_POST['nid'])) {
    $nid = $_POST['nid'];
    $node = node_load($nid);
  }
  $node_comment = isset($_POST['node_comment']) ? $_POST['node_comment'] : 0;
  $node_comment = (int) ($node_comment && $nid);
  $reactions = heartbeat_get_reactions($uaid, $node_comment, $node, TRUE);
  $output = theme('heartbeat_comments', $reactions, $uaid, $node_comment, FALSE);
  drupal_json(array(
    'status' => TRUE,
    'data' => $output,
    'uaid' => $uaid,
  ));
}

/**
 * Theme function for heartbeat comments
 * @param $comments Array of comment/reaction objects
 * @param $type Boolean to indicate whether it is a node comment or not
 * @return String Themed output for comments
 */
function theme_heartbeat_comments($comments, $uaid, $node_comment = FALSE, $has_more = FALSE) {
  if (empty($comments)) {
    return '';
  }
  $output = '';

  //$output .= '<h4>' . t('Reactions') . '</h4>';
  $comment = current($comments);
  $output .= '<ul class="summary" id="heartbeat-comments-list-' . $uaid . '">';
  $i = 1;
  $max = count($comments);
  foreach ($comments as $comment) {
    $i++;
    $output .= theme('heartbeat_comment', $comment, $node_comment, $i == $max);
  }

  // Add more button.
  if ($has_more) {
    $link = heartbeat_comments_load_more_link($uaid, $node_comment, isset($comment->nid) ? $comment->nid : 0);
    $output .= '<li class="heartbeat-comment heartbeat-comment-more">' . $link . '</li>';
  }
  $output .= '</ul>';
  return $output;
}

/**
 * Create a more link within the current context.
 * @param $uaid Integer
 * @param $node_comment Boolean
 * @param $nid Integer
 * @return String Link to all the comments.
 */
function heartbeat_comments_load_more_link($uaid, $node_comment, $nid = 0) {
  $attributes = array();
  $load_more = variable_get('heartbeat_comments_load_more', 'page');
  if ($load_more == 'ajax') {
    $attributes['onclick'] = 'javascript: Drupal.heartbeat.comments.load(' . $uaid . ', ' . (int) $node_comment . ', ' . $nid . '); return false;';
  }
  $attributes['class'] = ' heartbeat-comment-more-' . $load_more;
  if ($node_comment && $nid) {
    return l(t('More &raquo;'), 'node/' . $nid, array(
      'html' => TRUE,
      'attributes' => $attributes,
    ));
  }
  else {
    return l(t('More &raquo;'), 'heartbeat/message/' . $uaid, array(
      'alias' => TRUE,
      'html' => TRUE,
      'attributes' => $attributes,
    ));
  }
}

/**
 * Theme function for heartbeat comment
 * @param $comment Object comment with user in it
 * @param $type Boolean to indicate whether it is a node comment or not
 * @param $last Boolean to indicate if an extra class has to be used
 * @return String Themed output for a comment
 */
function theme_heartbeat_comment($comment, $node_comment = FALSE, $last = FALSE) {
  $output = '';
  if ($last == TRUE) {
    $class = "heartbeat-comment-last";
  }
  else {
    $class = "";
  }
  $output .= '<li class="heartbeat-comment ' . $class . '" id="heartbeat-comment-' . ($node_comment ? $comment->cid : $comment->hcid) . '">';
  $avatar = theme('user_picture', $comment);
  $output .= '<span class="avatar">' . l($avatar, 'user/' . $comment->uid, array(
    'html' => TRUE,
  )) . '</span>';
  $account = heartbeat_user_load($comment->uid);
  $output .= '<div class="heartbeat-teaser">';
  $output .= l($account->name, 'user/' . $comment->uid) . ' ';
  $output .= $comment->comment;
  $output .= '</div>';

  // For node comments link to the standard Drupal comment deletion form under comment/delete/%
  // Only users who have the right permissions should see the delete link.
  // Permissions are provided by the "Comment Delete" module.
  global $user;
  $redirect_path = isset($_POST['path']) ? 'destination=' . $_POST['path'] : drupal_get_destination();
  if ($node_comment) {
    if (user_access('delete any comment') || $user->uid == $comment->uid && user_access('delete own comments')) {
      $output .= l(t('Delete'), 'heartbeat/nodecomment/delete/' . $comment->cid, array(
        'attributes' => array(
          'class' => 'heartbeat-comment-delete',
        ),
        'query' => $redirect_path,
        'alias' => TRUE,
      ));
    }
  }
  elseif (user_access('administer heartbeat comments') || $comment->uid && $user->uid && $comment->uid == $user->uid) {
    $output .= l(t('Delete'), 'heartbeat/comment/delete/' . $comment->hcid, array(
      'attributes' => array(
        'class' => 'heartbeat-comment-delete',
      ),
      'query' => $redirect_path,
      'alias' => TRUE,
    ));
  }
  $output .= '</li>';
  return $output;
}

/**
 * Get heartbeat comments on a message
 *
 * @param $uid user_id of comment to load
 */
function heartbeat_get_message_reactions($uaid, $all = FALSE) {
  static $locale;
  if (!isset($locale)) {
    $locale = module_exists('locale');
  }
  $reactions = array();

  // When locale is enabled, we need to look up the translation id,
  // the only problem here is that locale could have been enabled.
  // This comments will never be fetched since locale will target
  // a translation that is not there, consequently.
  // That is hard coded taken care of while saving the comment.
  if ($locale) {
    $query = "SELECT s.hcid, s.uid, s.message AS 'comment', s.cleared, s.time, u.uid,\n      u.name, u.signature, u.signature_format, u.picture, u.data, ht.tuaid\n      FROM {heartbeat_comments} s INNER JOIN {users} u ON s.uid = u.uid\n      INNER JOIN {heartbeat_activity} ha ON ha.uaid = s.uaid\n      INNER JOIN {heartbeat_translations} ht ON ht.tuaid = s.uaid\n      WHERE ht.uaid = %d ORDER BY time DESC";
  }
  else {
    $query = "SELECT s.hcid, s.uid, s.message AS 'comment', s.cleared, s.time,\n      u.uid, u.name, u.signature, u.signature_format, u.picture, u.data\n      FROM {heartbeat_comments} s INNER JOIN {users} u ON s.uid = u.uid\n      WHERE uaid = %d ORDER BY time DESC";
  }
  if ($all) {
    $result = db_query($query, $uaid);
  }
  else {
    $result = db_query_range($query, $uaid, 0, HEARTBEAT_REACTIONS_PER_PAGE);
  }
  while ($comment = db_fetch_object($result)) {

    // Sanitize the comment messages.
    $comment->comment = filter_xss($comment->comment);
    $reactions[] = $comment;
  }
  return $reactions;
}

/**
 * Theme function to render comment(s) on a node
 */
function heartbeat_get_node_comments($node, $all = FALSE) {
  global $user;
  $comments = array();
  $count = 0;
  if (user_access('access comments')) {

    // Pre-process variables.
    $nid = $node->nid;
    $comments_per_page = HEARTBEAT_NODE_COMMENTS_PER_PAGE;
    $query = 'SELECT c.cid as cid, c.pid, c.nid, c.subject, c.comment,
      c.format, c.timestamp, c.name, c.mail, c.homepage,
      u.uid, u.name AS registered_name, u.signature,
      u.signature_format, u.picture, u.data, c.thread, c.status
      FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid
      WHERE c.nid = %d AND c.status = %d';
    $query_args = array(
      $nid,
    );
    $query_args[] = COMMENT_PUBLISHED;
    $query .= ' ORDER BY c.cid DESC';
    $query = db_rewrite_sql($query, 'c', 'cid');
    if ($all) {
      $result = db_query($query, $query_args);
    }
    else {
      $result = db_query_range($query, $query_args, 0, $comments_per_page);
    }

    //drupal_add_css(drupal_get_path('module', 'comment') .'/comment.css');
    while ($comment = db_fetch_object($result)) {
      $comment = drupal_unpack($comment);

      // Sanitize the comment messages.
      $comment->comment = check_markup($comment->comment, $comment->format, FALSE);
      $comment->name = $comment->uid ? $comment->registered_name : $comment->name;
      $comment->depth = count(explode('.', $comment->thread)) - 1;
      $comments[] = $comment;
    }
  }
  return $comments;
}

/**
 * Delete a heartbeat comment checking permissions.
 * @param $hcid Integer Heartbeat comment ID
 */
function _heartbeat_comments_delete_access($hcid) {

  // users with the administer permission should always be allowed to access our deletion form
  if (user_access('administer heartbeat comments')) {
    return TRUE;
  }
  else {
    global $user;
    $uid = db_result(db_query("SELECT uid FROM {heartbeat_comments} WHERE hcid = %d", $hcid));
    return $uid == $user->uid;
  }

  // TODO: Allow message owner to delete comment as well
}

/**
 * Confirmation page to delete a heartbeat comment.
 * @param $form_state
 * @param $hcid
 */
function heartbeat_comments_delete_confirm(&$form_state, $hcid) {
  $path = isset($_GET['destination']) ? $_GET['destination'] : (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '<front>');
  $form = array(
    'hcid' => array(
      '#type' => 'hidden',
      '#value' => $hcid,
    ),
    'redirect_path' => array(
      '#type' => 'hidden',
      '#value' => $path,
    ),
  );
  return confirm_form($form, t('Are you sure you want to delete this comment?'), $path, t('This action cannot be undone.'), t('Delete'), t('Cancel'));
}

/**
 * Submit callback te delete a heartbeat comment.
 * @param $form
 * @param $form_state
 */
function heartbeat_comments_delete_confirm_submit($form, &$form_state) {
  _heartbeat_comments_delete($form_state['values']['hcid']);
  $form_state['redirect'] = isset($_GET['destination']) ? $_GET['destination'] : $form_state['values']['redirect_path'];
  drupal_set_message('Comment deleted.');
}

/**
 * Deletes a heartbeat comment.
 */
function _heartbeat_comments_delete($hcid) {
  $lang_uaid = db_result(db_query("SELECT uaid FROM {heartbeat_comments} WHERE hcid = %d", $hcid));
  $uaids = heartbeat_get_uaids($lang_uaid);
  db_query("DELETE FROM {heartbeat_comments} WHERE hcid = %d", $hcid);
  db_query("UPDATE {heartbeat_activity} SET uaid_comments = uaid_comments - 1 WHERE uaid IN ( %s ) ", implode(',', $uaids));
  if (variable_get('heartbeat_comments_cache', 1)) {
    cache_clear_all('heartbeat:comments:' . $lang_uaid . ':0', 'cache');
  }
}

/**
 * Checks access to delete heartbeat node comment.
 * @param $cid Integer Node comment ID
 */
function _heartbeat_comments_node_delete_access($cid) {
  if (user_access('administer comments') || user_access('delete any comment')) {
    return TRUE;
  }
  else {
    global $user;
    $uid = db_result(db_query("SELECT uid FROM {comments} WHERE cid = %d ", $cid));
    return $uid == $user->uid && user_access('delete own comments');
  }
}

/**
 * Confirmation page to delete a node comment.
 * @param $form_state
 * @param $cid
 */
function heartbeat_comments_node_delete_confirm(&$form_state, $cid) {
  $form = array(
    'cid' => array(
      '#type' => 'hidden',
      '#value' => $cid,
    ),
    'redirect_path' => array(
      '#type' => 'hidden',
      '#value' => isset($_GET['destination']) ? $_GET['destination'] : $_SERVER['HTTP_REFERER'],
    ),
  );
  return confirm_form($form, t('Are you sure you want to delete this comment?'), $_GET['destination'], t('This action cannot be undone.'), t('Delete'), t('Cancel'));
}

/**
 * Submit callback te delete a node comment.
 * @param $form
 * @param $form_state
 */
function heartbeat_comments_node_delete_confirm_submit($form, &$form_state) {
  db_query("DELETE FROM {comments} WHERE cid = %d", $form_state['values']['cid']);
  $form_state['redirect'] = isset($_GET['destination']) ? $_GET['destination'] : $form_state['values']['redirect_path'];

  // TODO Make uaid somehow available here.

  //if (variable_get('heartbeat_comments_cache', 1)) {

  //  cache_clear_all('heartbeat:comments:'. $uaid. ':0', 'cache');

  //}
  drupal_set_message('Comment deleted.');
}

/**
 * eof().
 */

Functions

Namesort descending Description
heartbeat_comments_delete_confirm Confirmation page to delete a heartbeat comment.
heartbeat_comments_delete_confirm_submit Submit callback te delete a heartbeat comment.
heartbeat_comments_form Heartbeat comments form
heartbeat_comments_form_alter Implementation of hook_form_alter().
heartbeat_comments_form_submit User submitted a heartbeat comment.
heartbeat_comments_heartbeat_activity_delete Implementation of hook_heartbeat_activity_delete(). Delete the attached comments to a heartbeat activity object.
heartbeat_comments_heartbeat_attachments Implementation of hook_heartbeat_attachments().
heartbeat_comments_heartbeat_load Implementation of hook_heartbeat_load().
heartbeat_comments_load_js Ajax callback to load all the comments.
heartbeat_comments_load_more_link Create a more link within the current context.
heartbeat_comments_menu Implementation of hook_menu().
heartbeat_comments_node_delete_confirm Confirmation page to delete a node comment.
heartbeat_comments_node_delete_confirm_submit Submit callback te delete a node comment.
heartbeat_comments_perm Implementation of hook_perm().
heartbeat_comments_theme Implementation of hook_theme().
heartbeat_comments_token_list Implementation of hook_token_list().
heartbeat_comments_token_values Implementation of hook_token_values().
heartbeat_comments_widget Implementation of <attchement>_widget().
heartbeat_get_message_reactions Get heartbeat comments on a message
heartbeat_get_node_comments Theme function to render comment(s) on a node
heartbeat_get_reactions Function to fetch reactions on a heartbeat message.
theme_heartbeat_comment Theme function for heartbeat comment
theme_heartbeat_comments Theme function for heartbeat comments
_heartbeat_comments_delete Deletes a heartbeat comment.
_heartbeat_comments_delete_access Delete a heartbeat comment checking permissions.
_heartbeat_comments_node_delete_access Checks access to delete heartbeat node comment.

Constants

Namesort descending Description
HEARTBEAT_NODE_COMMENTS_PER_PAGE @file heartbeat_comments.module Heartbeat comments can come with two possible
HEARTBEAT_REACTIONS_PER_PAGE