New module 'Nodecomment'

This commit is contained in:
Manuel Cillero 2017-07-26 11:36:38 +02:00
parent 09b74574f1
commit 3c2bb788b4
26 changed files with 3513 additions and 0 deletions

View file

@ -0,0 +1,102 @@
<?php
/**
* @file
* Admin UI of the nodecomment module.
*/
function nodecomment_admin_settings_form() {
$form = array();
$names = node_get_types('names');
if (!$names) {
// No content types at all.
$form['notice']['#value'] = t("You don't have content types.");
return $form;
}
$help_items[] = '<strong>' . t('Content type') . '</strong>' . ': ' .
t('If set to "Drupal comments" the normal Drupal comment system will be used. Otherwise, set this to a node type for the node comment system to be used.') .
t("It's strongly recommended that you configure the setting once and then don't touch it.");
$help_items[] = '<strong>' . t('Is content') . '</strong>' . ': ' .
t("If enabled, the content type will work as full featured content type, even if it's set as comment.") . ' ' . t('Only applicable for node comments.');
$help_items[] = '<strong>' . t('Comment view') . '</strong>' . ': ' .
t('The view to use when displaying comments for this node type.') . ' ' . t('Only applicable for node comments.');
$help_items[] = '<strong>' . t('Plural form of comment type') . '</strong>' .
': ' . t('The plural form of the comment node-type name, like <em>comments</em> or <em>replies</em>. The singular form is taken from the node type selected above. Only applicable for node comments.');
$help = theme('item_list', $help_items);
$warning = t("Changing comment type when comments of that type already exist
can turn them into orphans, and break the database consistency. You have been
warned!");
$form['top']['#value'] =
'<div id="nodecomment-admin-settings-help">
<div class="status">' . $help . '</div>
<div class="warning"><strong>' . $warning . '</strong></div>
</div>';
$view_options = array('' => t('Disabled'));
$default_views = views_get_all_views();
if (is_array($default_views)) {
foreach ($default_views as $key => $view) {
if (isset($view->display['nodecomment_comments_1'])) {
$view_options[$key] = $view->name;
}
}
}
foreach ($names as $type => $name) {
$comment_type = nodecomment_get_comment_type($type);
$form['#header'] = array(t('Content type'), t('Is content'), t('Comment type'), t('Comment view'), t('Plural form of comment type'));
$type_edit_path = "admin/content/node-type/" . str_replace('_', '-', $type);
$type_edit_link = l($name, $type_edit_path, array('fragment' => 'comment'));
$form['rows'][$type]['name']['#value'] = $type_edit_link;
$form['rows'][$type]['is_content']['node_comment_is_content_' . $type] = array(
'#type' => 'checkbox',
'#default_value' => nodecomment_is_content($type)
);
$form['rows'][$type]['select']['node_comment_type_' . $type] = array(
'#type' => 'select',
'#options' => array('' => t('Drupal comments')) + $names,
'#default_value' => $comment_type
);
$form['rows'][$type]['view']['node_comment_view_' . $type] = array(
'#type' => 'select',
'#options' => $view_options,
'#default_value' => $comment_type ? variable_get('node_comment_view_'. $type, 'nodecomments') : '',
);
// TODO: find a better way to deal with these strings.
$form['rows'][$type]['plural']['node_comment_plural_' . $type] = array(
'#type' => 'textfield',
'#size' => 20,
'#default_value' => variable_get('node_comment_plural_'. $type, 'comments'),
);
}
$form['bottom']['#value'] = '';
$form = system_settings_form($form);
$form['#theme'] = 'nodecomment_admin_settings_form';
return $form;
}
/**
* Validate the nodecomment settings form.
*/
function nodecomment_admin_settings_form_validate($form, &$form_state) {
foreach(node_get_types('names') as $type => $blank) {
if ($form_state['values']['node_comment_type_' . $type]) {
// Node comments are enabled for the type.
$id = 'node_comment_view_' . $type;
if (!$form_state['values'][$id]) {
form_set_error($id, t("You must choose a comment view."));
}
}
}
}
/**
* Submit callback for the nodecomment settings form.
*/
function nodecomment_admin_settings_form_submit($form, &$form_state) {
// Rebuild menu so that our menu access callbacks work properly.
// TODO: track configuration changes and rebuild only when needed.
menu_router_build(1);
}

View file

@ -0,0 +1,666 @@
<?php
/**
* @file
* Helper functions of the Node Comments module.
*/
/**
* Accepts a submission of new or changed comment content.
*
* @param $node
* The node that is serving as a comment to another node.
*
* @return
* If the comment is successfully saved the node ID of the comment is returned. If the comment
* is not saved, FALSE is returned.
*/
function nodecomment_save($node) {
global $user;
if (!isset($node->thread)) {
$node->thread = nodecomment_get_thread($node);
}
// MySQL-only upsert. Sorry Postgres guys.
// When updating, do not change the original submitted IP Address.
db_query(
"INSERT INTO {node_comments}
(cid, nid, pid, hostname, thread, name, uid, mail, homepage)
VALUES (%d, %d, %d, '%s', '%s', '%s', %d, '%s', '%s')
ON DUPLICATE KEY UPDATE
nid=VALUES(nid), pid=VALUES(pid), thread=VALUES(thread), name=VALUES(name),
uid=VALUES(uid), mail=VALUES(mail), homepage=VALUES(homepage)",
$node->nid, $node->comment_target_nid, $node->comment_target_cid,
ip_address(), $node->thread, $node->name, $node->uid, $node->mail,
$node->homepage
);
_nodecomment_update_node_statistics($node->comment_target_nid);
// Explain the approval queue if necessary, and then
// redirect the user to the node he's commenting on.
if ($node->moderate == 1) {
drupal_set_message(t('Your comment has been queued for moderation by site administrators and will be published after approval.'));
}
return $node->nid;
}
/**
* Set the breadcrumb trail to include another node.
*
* This is used when viewing or adding a comment so that the parent node's
* breadcrumb trail is used instead of the normal breadcrumb paths.
*
* @param $node
* The node to use.
*/
function nodecomment_set_breadcrumb($node) {
// If the node had any breadcrumb changes, they will be made via nodeapi('view')
// as a general rule, so this will make them happen.
node_invoke_nodeapi($node, 'view', FALSE, TRUE);
// Then add the parent node to the trail.
$breadcrumb = drupal_get_breadcrumb();
$breadcrumb[] = l($node->title, "node/$node->nid");
drupal_set_breadcrumb($breadcrumb);
}
/**
* Get number of new comments for current user and specified node
*
* @param $nid node-id to count comments for
* @param $timestamp time to count from (defaults to time of last user access
* to node)
*/
function nodecomment_num_new($nid, $timestamp = 0) {
global $user;
if ($user->uid) {
// Retrieve the timestamp at which the current user last viewed the
// specified node.
if (!$timestamp) {
$timestamp = node_last_viewed($nid);
}
$timestamp = ($timestamp > NODE_NEW_LIMIT ? $timestamp : NODE_NEW_LIMIT);
// Use the timestamp to retrieve the number of new comments.
$result = db_result(db_query(
"SELECT COUNT(cn.nid) FROM {node} n
INNER JOIN {node_comments} c ON n.nid = c.nid
INNER JOIN {node} cn ON c.cid = cn.nid
WHERE n.nid = %d AND (cn.created > %d OR cn.changed > %d) AND cn.status = %d",
$nid, $timestamp, $timestamp, 1
));
return $result;
}
else {
return 0;
}
}
/**
* Calculate page number for any given comment.
*
* @param $comment
* The comment.
* @return
* The page number.
*/
function nodecomment_page_count($comment, $node = NULL) {
if (!$node) {
if (empty($comment->comment_target_nid)) {
return '';
}
$node = node_load($comment->comment_target_nid);
if (!nodecomment_get_comment_type($node->type)) {
return '';
}
}
$comments_per_page = _comment_get_display_setting('comments_per_page', $node);
$mode = _comment_get_display_setting('mode', $node);
$order = _comment_get_display_setting('sort', $node);
$flat = in_array($mode, array(COMMENT_MODE_FLAT_COLLAPSED, COMMENT_MODE_FLAT_EXPANDED));
if ($flat) {
$field = 'n.nid';
$value = '%d';
$arg = $comment->nid;
}
else {
$field = 'nc.thread';
$value = "'%s'";
$arg = $comment->thread;
}
if ($order == COMMENT_ORDER_NEWEST_FIRST) {
$op = ' >= ';
}
else {
$op = ' <= ';
}
$query = "SELECT COUNT(*) FROM {node_comments} nc
INNER JOIN {node} n ON n.nid = nc.cid
WHERE $field $op $value AND n.status <> 0 AND n.nid != %d AND nc.nid = %d";
$count = db_result(db_query($query, $arg, $comment->nid, $node->nid));
$pageno = intval($count / $comments_per_page);
return $pageno;
}
/**
* Calculate page number for first new comment.
*
* This works for both comments and nodecomments.
*
* @param $num_comments
* Number of comments.
* @param $new_replies
* Number of new replies.
* @param $node
* The first new comment node.
* @return
* "page=X" if the page number is greater than zero; empty string otherwise.
*/
function nodecomment_new_page_count($num_comments, $new_replies, $node) {
// Default to normal comments so this function works either way.
if (!nodecomment_get_comment_type($node->type)) {
return comment_new_page_count($num_comments, $new_replies, $node);
}
$comments_per_page = _comment_get_display_setting('comments_per_page', $node);
$mode = _comment_get_display_setting('mode', $node);
$order = _comment_get_display_setting('sort', $node);
$pagenum = NULL;
$flat = in_array($mode, array(COMMENT_MODE_FLAT_COLLAPSED, COMMENT_MODE_FLAT_EXPANDED));
if ($num_comments <= $comments_per_page || ($flat && $order == COMMENT_ORDER_NEWEST_FIRST)) {
// Only one page of comments or flat forum and newest first.
// First new comment will always be on first page.
$pageno = 0;
}
else {
if ($flat) {
// Flat comments and oldest first.
$count = $num_comments - $new_replies;
}
else {
// Threaded comments. See the documentation for comment_render().
if ($order == COMMENT_ORDER_NEWEST_FIRST) {
// Newest first: find the last thread with new comment
$thread = db_result(db_query(
"(SELECT thread FROM {node_comments} nc
INNER JOIN {node} n ON n.nid = nc.cid
WHERE nc.nid = %d AND n.status <> 0
ORDER BY n.created DESC LIMIT %d)
ORDER BY thread DESC LIMIT 1",
$node->nid, $new_replies
));
$result_count = db_query(
"SELECT COUNT(*) FROM {node_comments} nc
INNER JOIN {node} n ON n.nid = nc.cid
WHERE nc.nid = %d AND n.status <> 0 AND nc.thread > '%s'",
$node->nid, $thread
);
}
else {
// Oldest first: find the first thread with new comment
$result = db_query(
'(SELECT thread FROM {node_comments} nc
INNER JOIN {node} n ON n.nid = nc.cid
WHERE nc.nid = %d AND n.status <> 0
ORDER BY n.created DESC LIMIT %d)
ORDER BY SUBSTRING(thread, 1, (LENGTH(thread) - 1)) LIMIT 1',
$node->nid, $new_replies
);
$thread = substr(db_result($result), 0, -1);
$result_count = db_query(
"SELECT COUNT(*) FROM {comments} nc
INNER JOIN {node} n ON n.nid = nc.cid
WHERE nc.nid = %d AND n.status <> 0 AND SUBSTRING(nc.thread, 1, (LENGTH(nc.thread) - 1)) < '%s'",
$node->nid, $thread
);
}
$count = db_result($result_count);
}
$pageno = $count / $comments_per_page;
}
if ($pageno >= 1) {
$pagenum = "page=". intval($pageno);
}
return $pagenum;
}
function nodecomment_get_thread($node) {
// Here we are building the thread field. See the documentation for
// comment_render().
if (empty($node->comment_target_cid)) {
// This is a comment with no parent comment (depth 0): we start
// by retrieving the maximum thread level.
$max = db_result(db_query(
"SELECT MAX(thread) FROM {node_comments} WHERE nid = %d",
$node->comment_target_nid
));
// Strip the "/" from the end of the thread.
$max = rtrim($max, '/');
// Finally, build the thread field for this new comment.
$thread = int2vancode(vancode2int($max) + 1) .'/';
}
else {
// This is comment with a parent comment: we increase
// the part of the thread value at the proper depth.
// Get the parent comment:
$parent = node_load($node->comment_target_cid);
// Strip the "/" from the end of the parent thread.
$parent->thread = (string) rtrim((string) $parent->thread, '/');
// Get the max value in _this_ thread.
$max = db_result(db_query(
"SELECT MAX(thread) FROM {node_comments}
WHERE thread LIKE '%s.%%' AND nid = %d",
$parent->thread, $node->comment_target_nid
));
if ($max == '') {
// First child of this parent.
$thread = $parent->thread .'.'. int2vancode(0) .'/';
}
else {
// Strip the "/" at the end of the thread.
$max = rtrim($max, '/');
// We need to get the value at the correct depth.
$parts = explode('.', $max);
$parent_depth = count(explode('.', $parent->thread));
$last = $parts[$parent_depth];
// Finally, build the thread field for this new comment.
$thread = $parent->thread .'.'. int2vancode(vancode2int($last) + 1) .'/';
}
}
return $thread;
}
/**
* Delete children comments from the same thread as comment.
*/
function _nodecomment_thread_delete_children($cid, $nid) {
// Delete the comment's replies.
// We have to be careful here to not delete comments from a separate thread
// started by this node, if it has own comments.
// To be sure about this, also check node id.
$result = db_query("SELECT cid FROM {node_comments} WHERE pid = %d AND nid = %d", $cid, $nid);
$delete = array();
while ($row = db_fetch_object($result)) {
$delete[] = $row->cid;
}
foreach ($delete as $cid) {
_nodecomment_delete_comment($cid);
}
}
/**
* Delete node comments of a node.
*/
function _nodecomment_delete_comments($nid) {
$result = db_query('SELECT cid FROM {node_comments} WHERE nid = %d', $nid);
$delete = array();
while ($row = db_fetch_object($result)) {
$delete[] = $row->cid;
}
foreach ($delete as $cid) {
_nodecomment_delete_comment($cid);
}
}
/**
* Delete a nodecomment.
*
* Based on code from node_delete() function but has different logics.
*
* Previously, the module used node_delete() which checks permissions.
* If the user didn't have the permission to delete the comment, the comment
* was left in the database as orphan.
*
* Having own function is better:
* 1) We don't check permissions, so we don't create orphans. Usually only
* moderators have the permission to delete other user's comments, so this
* is essential for any community site where users delete own comments.
* This also follows core comment behavior.
* 2) We warn other modules about the delete event, if nodeapi delete
* event is too late for them to react. They can also veto the deletion,
* provided they allow alternate action.
* 3) We don't print messages on screen.
*/
function _nodecomment_delete_comment($cid) {
// Clear the cache before the load, so if multiple nodes are deleted, the
// memory will not fill up with nodes (possibly) already removed.
// This also allows to find out easily if the node is already deleted.
$node = node_load($cid, NULL, TRUE);
// The node might not exist already for a number of reasons. This is
// generally ok.
if (!$node) {
return;
}
// Warn other modules about deletion and let them veto it.
$delete = TRUE;
$votes = nodecomment_invoke($node, 'delete_vote');
foreach ($votes as $vote) {
if ($vote === FALSE) {
$delete = FALSE;
break;
}
}
if ($delete) {
// Let the modules prepare for deleting.
nodecomment_invoke($node, 'delete');
db_query('DELETE FROM {node} WHERE nid = %d', $node->nid);
db_query('DELETE FROM {node_revisions} WHERE nid = %d', $node->nid);
db_query('DELETE FROM {node_access} WHERE nid = %d', $node->nid);
// Call the node-specific callback (if any):
node_invoke($node, 'delete');
node_invoke_nodeapi($node, 'delete');
// Clear the page and block caches.
cache_clear_all();
// Remove this node from the search index if needed.
if (function_exists('search_wipe')) {
search_wipe($node->nid, 'node');
}
// Log the event, but don't print messages on screen.
watchdog('content', '@type: deleted %title.', array('@type' => $node->type, '%title' => $node->title));
}
}
/**
* Updates the comment statistics for a given node. This should be called any
* time a comment is added, deleted, or updated.
*
* The following fields are contained in the node_comment_statistics table:
*
* - last_comment_timestamp: the timestamp of the last comment for this node
* or the node create stamp if no comments exist for the node.
*
* - last_comment_name: the name of the anonymous poster for the last comment.
*
* - last_comment_uid: the uid of the poster for the last comment for this node
* or the node authors uid if no comments exists for the node.
*
* - comment_count: the total number of approved/published comments on this node.
*/
function _nodecomment_update_node_statistics($nid) {
$count = db_result(db_query(
'SELECT COUNT(*) FROM {node_comments} nc
INNER JOIN {node} n ON n.nid = nc.cid
WHERE nc.nid = %d AND n.status = 1',
$nid
));
// Comments exist.
if ($count > 0) {
$last_reply = db_fetch_object(db_query_range(
'SELECT nc.cid, nc.name, n.created, n.changed, n.uid
FROM {node} n LEFT JOIN {node_comments} nc ON n.nid = nc.cid
WHERE nc.nid = %d AND n.status = 1
ORDER BY cid DESC',
$nid, 0, 1
));
$timestamp = max($last_reply->created, $last_reply->changed);
$name = $last_reply->uid ? '' : $last_reply->name;
db_query(
"UPDATE {node_comment_statistics}
SET comment_count = %d, last_comment_timestamp = %d, last_comment_name = '%s', last_comment_uid = %d
WHERE nid = %d",
$count, $timestamp, $name, $last_reply->uid, $nid
);
}
// No comments.
else {
// The node might not exist if called from hook_nodeapi($op = 'delete').
if ($node = db_fetch_object(db_query("SELECT uid, created FROM {node} WHERE nid = %d", $nid))) {
db_query(
"UPDATE {node_comment_statistics}
SET comment_count = 0, last_comment_timestamp = %d, last_comment_name = '', last_comment_uid = %d
WHERE nid = %d",
$node->created, $node->uid, $nid
);
}
else {
db_query("DELETE FROM {node_comment_statistics} WHERE nid = %d", $nid);
}
}
}
function nodecomment_form($node) {
$comment_type = nodecomment_get_comment_type($node->type);
if ($comment_type) {
global $user;
$new_node = array(
'uid' => $user->uid,
'name' => $user->name,
'type' => $comment_type,
'comment_target_nid' => $node->nid,
'comment_target_cid' => 0,
);
module_load_include('inc', 'node', 'node.pages');
return drupal_get_form($comment_type .'_node_form', $new_node);
}
}
/**
* Menu callback; view a single node.
*/
function nodecomment_node_view($node, $cid = NULL) {
drupal_set_title(check_plain($node->title));
$output = node_view($node, FALSE, TRUE);
if (nodecomment_get_commentable($node)) {
if ($node->comment_type) {
$output .= nodecomment_render($node, $cid);
}
else {
$output .= comment_render($node, $cid);
}
}
// Update the history table, stating that this user viewed this node.
node_tag_new($node->nid);
return $output;
}
/**
* Node comment's version of comment_render, to render all comments on a node.
*/
function nodecomment_render($node, $cid = 0) {
global $user;
$output = '';
if (user_access('access comments')) {
// Pre-process variables.
$nid = $node->nid;
if (empty($nid)) {
$nid = 0;
}
// Render nothing if there are no comments to render.
if (!empty($node->comment_count)) {
if ($cid && is_numeric($cid)) {
// Single comment view.
if ($comment = node_load($cid)) {
$output = theme('node', $comment, TRUE, TRUE);
}
}
else {
$view_name = variable_get('node_comment_view_'. $node->type, 'nodecomments');
if ($view_name) {
$output = views_embed_view($view_name, 'nodecomment_comments_1', $nid);
}
}
}
// If enabled, show new comment form.
$comment_type = nodecomment_get_comment_type($node->type);
if (user_access("create $comment_type content") && nodecomment_is_readwrite($node) && (variable_get('comment_form_location_'. $node->type, COMMENT_FORM_SEPARATE_PAGE) == COMMENT_FORM_BELOW)) {
// There is likely a cleaner way to do this, but for now it will have to do. -- JE
$friendly_name = node_get_types('name', $comment_type);
$output .= nodecomment_form_box($node, t('Post new !type', array('!type' => $friendly_name)));
}
if ($output) {
$output = theme('comment_wrapper', $output, $node);
}
}
return $output;
}
function nodecomment_form_box($node, $title = NULL) {
return theme('box', $title, nodecomment_form($node));
}
/**
* Public API function to retrieve the comment type for a node type.
*
* @param $node_type
* The name of the node type for which the comment type will be retreived.
* @return
* Returns a string containing the node type which will be used for comments.
* If node comments are not used for the passed in type, returns empty string.
*/
function nodecomment_get_comment_type($node_type) {
return variable_get('node_comment_type_'. $node_type, '');
}
/**
* Return array of content types which serve as nodecomments.
*/
function nodecomment_get_comment_types() {
$comment_types = array();
foreach (node_get_types('names') as $type => $blank) {
$comment_type = nodecomment_get_comment_type($type);
if ($comment_type) {
$comment_types[$comment_type] = $comment_type;
}
}
return $comment_types;
}
/**
* Redirect to target node page containing a comment. Supports comment threads
* spanning multiple pages.
*
* @param $node
* node comment object
*/
function _nodecomment_target_node_redirect($node) {
$pagenum = nodecomment_page_count($node);
$query = NULL;
if ($pagenum) {
$query = array('page' => $pagenum);
}
$fragment = 'comment-' . $node->nid;
drupal_goto("node/" . $node->comment_target_nid, $query, $fragment);
}
/**
* Check if the content type should be treated as full featured content type,
* even if it works as comment too.
*/
function nodecomment_is_content($type) {
// Types which are not comments are always treated as content.
if (!in_array($type, nodecomment_get_comment_types())) {
return TRUE;
}
return variable_get('node_comment_is_content_' . $type, FALSE);
}
/**
* Check if the node is commentable (read/write).
*/
function nodecomment_is_readwrite(&$node) {
$commentable = nodecomment_get_commentable($node);
return ($commentable == COMMENT_NODE_READ_WRITE);
}
/**
* Get "commentable" setting.
*/
function nodecomment_get_commentable(&$node) {
static $settings = array();
if (!isset($settings[$node->nid])) {
$commentable = isset($node->node_comment) ? $node->node_comment : $node->comment;
// Let modules override commentability dynamically.
drupal_alter('nodecomment_commentable', $commentable, $node);
$settings[$node->nid] = $commentable;
}
return $settings[$node->nid];
}
/**
* Return list of Node Comments module variables.
*
* @param $type
* content type
*/
function _nodecomment_vars() {
$vars = _nodecomment_type_vars();
$vars[] = 'node_comment_node_redirect';
return $vars;
}
/**
* Return list of Node Comments module variables, associated with a content type.
*
* @param $type
* Content type. If not provided, return variables for all content types.
*/
function _nodecomment_type_vars($type) {
if ($type) {
$types = array($type);
}
else {
$types = array_keys(node_get_types('names'));
}
$vars = array();
foreach ($types as $type) {
$vars[] = 'node_comment_type_' . $type;
$vars[] = 'node_comment_view_' . $type;
$vars[] = 'node_comment_plural_' . $type;
$vars[] = 'node_comment_is_content_' . $type;
}
return $vars;
}
function nodecomment_invoke($node, $op) {
$results = array();
$hook = 'nodecomment_' . $op;
foreach (module_implements($hook) as $module) {
$function = $module . '_' . $hook;
$results[] = $function($node);
}
return $results;
}
function nodecomment_include($inc) {
module_load_include('inc', 'nodecomment', "includes/nodecomment.$inc");
}

View file

@ -0,0 +1,326 @@
<?php
/**
* Node Comment terminology:
*
* "target node"
* node which is being commented on
*
* "target comment"
* nodecomment which is being replied to
*/
/**
* Implementation of hook_form_alter().
*/
function nodecomment_form_alter(&$form, &$form_state, $form_id) {
global $user;
// Make sure we alter node form.
if (!isset($form['type']) ||
!isset($form['type']['#value']) ||
$form['type']['#value'] .'_node_form' != $form_id) {
return;
}
$node = &$form['#node'];
$mode = _comment_get_display_setting('mode', $node);
$flat = in_array($mode, array(COMMENT_MODE_FLAT_COLLAPSED, COMMENT_MODE_FLAT_EXPANDED));
// Convert dashes to underscores as we get type from menu path.
$type = str_replace('-', '_', arg(2));
// Prepare nodecomment data for a newly created node.
if (arg(0) == 'node'
&& arg(1) == 'add'
&& is_numeric(arg(3))
&& !empty($type)
&& in_array($type, nodecomment_get_comment_types())
) {
$node_context = arg(3);
$comment_context = arg(4);
$node->comment_target_nid = $node_context;
// If the parrent comment context is not set, use 0 (thread root).
$node->comment_target_cid = is_numeric($comment_context) ? $comment_context : 0;
$target_node = node_load($node_context);
$target_comment = node_load(is_numeric($comment_context) ? $comment_context : $node_context);
// Show the node which this comment is replying to.
if (!isset($form['#prefix'])) {
$form['#prefix'] = '';
}
// In flat mode we use target comment context to store the data, but
// still show the target node.
$form['#prefix'] .= node_view($flat ? $target_node : $target_comment);
}
if (isset($node->comment_target_nid)) {
// We're altering a nodecomment form.
_nodecomment_alter_nodecomment_form($form, $node, $target_node, $target_comment);
}
if (nodecomment_get_comment_type($node->type)) {
// This is node edit form for a content type with nodecomments.
// Make sure that node_comment property is set up, if the node wasn't
// loaded using node_load(), e.g. if it was passed from API call.
if (!isset($node->node_comment) && isset($node->comment)) {
$node->node_comment = $node->comment;
}
// Load real value because it's the form to change it.
$form['comment_settings']['comment']['#default_value'] = $node->node_comment;
// Add workaround for fake forms: some modules (for example, Node Gallery)
// use node form id in their special forms. They don't always copy comment
// setting form element from the real node form, which can lead to breakage
// of our logics.
// To protect against these fake forms, we insert special marker
// into form which will continue its life in node object. Fake forms won't
// have the marker, which will allow us to detect them in
// hook_nodeapi('presave') and to react properly.
// This is not bullet-proof though, cause if the faked form decided to
// change the setting, we would overwrite it's values in 'presave'.
// This will stay for now, until better solution replaces it.
$form['comment_settings']['nodecomment_real_node_form'] = array(
'#type' => 'value',
'#value' => 1
);
}
}
function _nodecomment_alter_nodecomment_form(&$form, $node, $target_node = NULL, $target_comment = NULL) {
// Store Node Comments additional properties in the form. Otherwise
// they won't be passed by nodeapi.
$form['comment_target_nid'] = array(
'#type' => 'value',
'#value' => $node->comment_target_nid,
);
$form['comment_target_cid'] = array(
'#type' => 'value',
'#value' => $node->comment_target_cid,
);
$form['thread'] = array(
'#type' => 'value',
'#value' => $node->thread,
);
// Load our nodes. It's possible they may have been loaded during the
// node/add discovery above.
if (!isset($target_node)) {
$target_node = node_load($node->comment_target_nid);
}
if (!isset($target_comment)) {
$target_comment = node_load(!empty($node->comment_target_cid) ? $node->comment_target_cid : $node->comment_target_nid);
}
// Process breadcrumbs for node pages.
if (arg(1) == 'add' || arg(1) == 'edit') {
// Reset the breadcrumb trail to get rid of the 'create content' stuff.
drupal_set_breadcrumb(array(l(t('Home'), NULL)));
// Then add the target node.
nodecomment_set_breadcrumb($target_node);
if (!empty($node->nid)) {
// And then add the current node:
$breadcrumb = drupal_get_breadcrumb();
$breadcrumb[] = l($node->title, "node/$node->nid");
drupal_set_breadcrumb($breadcrumb);
}
}
// Add fields for anonymous commenting.
// Use settings of target node, not target comment.
_nodecomment_add_anon_contact_fields($form, $node, $target_node);
// Does this nodecomment work as content ?
if (nodecomment_is_content($node->type)) {
// This type is full content type. It has title, own page, etc.
// Do something useful here.
}
else {
// This is a pure comment.
// Remove settings that have no meaning on comments.
$form['menu']['#access'] = FALSE;
$form['path']['#access'] = FALSE;
$form['comment_settings']['#access'] = FALSE;
// Remove the teaser splitter if body field is present.
if (isset($form['body_field'])) {
$teaser_js_build = array_search('node_teaser_js', $form['body_field']['#after_build']);
unset($form['body_field']['#after_build'][$teaser_js_build]);
$form['body_field']['teaser_js']['#access'] = FALSE;
$form['body_field']['teaser_include']['#access'] = FALSE;
}
// Set up an automatic title in case it's new nodecomment.
// Use target comment title, not target node.
if (empty($node->nid)) {
$re = t('Re: ');
$re_len = drupal_strlen($re);
if (drupal_substr($target_comment->title, 0, $re_len) == $re) {
$form['title']['#default_value'] = $target_comment->title;
}
else {
$form['title']['#default_value'] = $re . $target_comment->title;
}
}
// Make the title not required:
$form['title']['#required'] = FALSE;
if (variable_get('comment_subject_field_'. $target_node->type, 1) != 1) {
$form['title']['#access'] = FALSE;
}
}
// File attachments dropdown should remain open:
$form['attachments']['#collapsed'] = FALSE;
// If nodecomments are language enabled (but not translation enabled)
// set the language to that of the parent node.
if (variable_get('language_content_type_' . $node->type, 1)) {
$form['language'] = array(
'#type' => 'value',
'#value' => $target_node->language
);
}
// When previewing nodecomment, scroll to preview.
// Note that we add anchor for blank node so that scrolling works on first
// preview too.
if ($node->build_mode === NODE_BUILD_PREVIEW || !isset($node->nid)) {
$form['#action'] .= '#preview';
}
$form['buttons']['submit']['#submit'][] = 'nodecomment_node_form_submit';
}
function _nodecomment_add_anon_contact_fields(&$form, $node, $target_node) {
global $user;
$anon = variable_get('comment_anonymous_'. $target_node->type, COMMENT_ANONYMOUS_MAYNOT_CONTACT);
if ($user->uid == 0 &&
($anon == COMMENT_ANONYMOUS_MAY_CONTACT || $anon == COMMENT_ANONYMOUS_MUST_CONTACT)) {
$form['comment_info'] = array('#weight' => -10);
$form['comment_info']['name'] = array(
'#type' => 'textfield',
'#title' => t('Your name'),
'#maxlength' => 60,
'#size' => 30,
'#default_value' => $node->name ? $node->name : variable_get('anonymous', t('Anonymous')),
'#required' => ($anon == COMMENT_ANONYMOUS_MUST_CONTACT)
);
$form['comment_info']['mail'] = array(
'#type' => 'textfield',
'#title' => t('E-mail'),
'#maxlength' => 64,
'#size' => 30,
'#default_value' => $node->mail,
'#description' => t('The content of this field is kept private and will not be shown publicly.'),
'#required' => ($anon == COMMENT_ANONYMOUS_MUST_CONTACT)
);
$form['comment_info']['homepage'] = array(
'#type' => 'textfield',
'#title' => t('Homepage'),
'#maxlength' => 255,
'#size' => 30,
'#default_value' => $node->homepage,
);
// Store target type in the form for the validate callback.
$form['comment_info']['target_node_type'] = array(
'#type' => 'value',
'#value' => $target_node->type,
);
// Attach anonymous info validation.
$form['#validate'][] = 'nodecomment_node_form_validate';
}
else {
$form['comment_info']['mail'] = array(
'#type' => 'value',
'#value' => '',
);
$form['comment_info']['homepage'] = array(
'#type' => 'value',
'#value' => '',
);
}
}
/**
* Validate anonymous info (mail, homepage etc).
*/
function nodecomment_node_form_validate(&$form, &$form_state) {
$target_node_type = $form['comment_info']['target_node_type']['#value'];
$requirement = variable_get('comment_anonymous_'. $target_node_type, COMMENT_ANONYMOUS_MAYNOT_CONTACT);
if ($form_state['values']['name']) {
$taken = db_result(db_query("SELECT COUNT(uid) FROM {users} WHERE LOWER(name) = '%s'", $form_state['values']['name']));
if ($taken != 0) {
form_set_error('name', t('The name you used belongs to a registered user.'));
}
}
else if ($requirement == COMMENT_ANONYMOUS_MUST_CONTACT) {
form_set_error('name', t('You have to leave your name.'));
}
if ($form_state['values']['mail']) {
if (!valid_email_address($form_state['values']['mail'])) {
form_set_error('mail', t('The e-mail address you specified is not valid.'));
}
}
else if ($requirement == COMMENT_ANONYMOUS_MUST_CONTACT) {
form_set_error('mail', t('You have to leave an e-mail address.'));
}
if ($form_state['values']['homepage']) {
if (!valid_url($form_state['values']['homepage'], TRUE)) {
form_set_error('homepage', t('The URL of your homepage is not valid. Remember that it must be fully qualified, i.e. of the form <code>http://example.com/directory</code>.'));
}
}
}
/**
* Redirect the node form to the right place.
*/
function nodecomment_node_form_submit(&$form, &$form_state) {
$node = $form['#node'];
$nid = $form_state['nid'];
if (empty($node->nid)) {
$node->nid = $nid;
}
if (nodecomment_is_content($node->type)) {
// This is a full content type. Do something useful here.
}
else {
// This is a pure comment. Redirect to the target node page which contains
// the comment.
_nodecomment_target_node_redirect($node);
}
}
/**
* Implementation of hook_form_FORMID_alter().
*/
function nodecomment_form_node_delete_confirm_alter(&$form, &$form_state) {
// Node delete form.
if (!isset($_GET['destination'])) {
$node = node_load($form['nid']['#value']);
if (isset($node->comment_target_nid)) {
// Change the redirect and cancel link to the parent node page.
$form['destination'] = array(
'#type' => 'hidden',
'#value' => 'node/'. $node->comment_target_nid,
);
$form['actions']['cancel']['#value'] = l(t('Cancel'), 'node/'. $node->comment_target_nid);
}
}
}

View file

@ -0,0 +1,111 @@
<?php
/**
* Implementation of hook_theme().
*/
function nodecomment_theme() {
$items = array();
$items['nodecomment_convert_page'] = array(
'arguments' => array('convert_counts' => NULL, 'form' => NULL),
'file' => 'includes/nodecomment.convert.inc',
);
$items['nodecomment_comment_count'] = array(
'arguments' => array('count' => NULL, 'type' => NULL),
'file' => 'includes/nodecomment.theme.inc',
);
$items['nodecomment_new_comment_count'] = array(
'arguments' => array('count' => NULL, 'type' => NULL),
'file' => 'includes/nodecomment.theme.inc',
);
$items['nodecomment_admin_settings_form'] = array(
'arguments' => array('form' => NULL)
);
return $items;
}
/**
* Add some additional suggestions for comment node templates.
*/
function nodecomment_preprocess_node(&$vars) {
// Test to see if it's a comment.
if (isset($vars['node']->comment_target_nid)) {
$node = &$vars['node'];
// First comment checking.
static $first_new = TRUE;
$vars['new'] = '';
$vars['new_class'] = '';
$vars['new_output'] = '';
$vars['first_new'] = '';
$node->new = node_mark($node->comment_target_nid, $node->created);
if ($node->new) {
$vars['new'] = t('new');
$vars['new_class'] = 'comment-new';
$vars['classes'] = (isset($vars['classes']) ? $vars['classes'] . ' ' : '') . 'comment-new';
$vars['new_output'] ='<span class="new">' . $vars['new'] . '</span>';
if ($first_new) {
$vars['first_new'] = "<a id=\"new\"></a>\n";
$first_new = FALSE;
}
}
$query = NULL;
if ($vars['page']) {
$pagenum = nodecomment_page_count($node);
}
else {
$pagenum = !empty($_GET['page']) ? $_GET['page'] : 0;
}
if ($pagenum) {
$query = array('page' => $pagenum);
}
$vars['comment_link'] = l($node->title, 'node/'. $node->comment_target_nid, array('query' => $query, 'fragment' => 'comment-' . $node->nid));
$vars['signature'] = !empty($node->signature) ? theme('user_signature', $node->signature) : '';
}
}
/**
* Return plural form of number of comments.
*
* Use $type to provide different strings per nodetype.
*/
function theme_nodecomment_comment_count($count, $type) {
return format_plural($count, '1 comment', '@count comments');
}
/**
* Return plural form of number of new comments.
*
* Use $type to provide different strings per nodetype.
*/
function theme_nodecomment_new_comment_count($count, $type) {
return format_plural($count, '1 new comment', '@count new comments');
}
/**
* Theme relationships table
*/
function theme_nodecomment_admin_settings_form($form) {
$rows = array();
foreach (element_children($form['rows']) as $type) {
$cells = $form['rows'][$type];
foreach (element_children($cells) as $col) {
$rows[$type][$col] = drupal_render($cells[$col]);
}
}
unset($form['rows']);
$header = $form['#header'];
unset($form['#header']);
$attributes = array(
'id' => 'nodecomment-admin-settings-table',
);
$output = drupal_render($form['top']);
$output .= theme('table', $header, $rows, $attributes);
$output .= drupal_render($form['bottom']);
return $output . drupal_render($form);
}