? updown.patch Index: updown.info =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/updown/updown.info,v retrieving revision 1.1 diff -u -p -r1.1 updown.info --- updown.info 20 Aug 2008 23:35:09 -0000 1.1 +++ updown.info 22 Aug 2008 17:27:25 -0000 @@ -3,5 +3,4 @@ name = UpDown description = Provides a very simple up/down voting widget to use for nodes. package = Voting version = VERSION -core = 6.x -dependencies[] = votingapi \ No newline at end of file +dependencies = votingapi \ No newline at end of file Index: updown.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/updown/updown.module,v retrieving revision 1.1 diff -u -p -r1.1 updown.module --- updown.module 20 Aug 2008 23:35:09 -0000 1.1 +++ updown.module 22 Aug 2008 17:27:25 -0000 @@ -7,52 +7,214 @@ * ======================================================================== */ +define('UPDOWN_VALUE_HIGH', 100); +define('UPDOWN_VALUE_LOW', 0); +define('UPDOWN_VALUE_UNVOTE', 'undo'); + +/** + * Implementation of hook_perm(). + */ function updown_perm() { - return array('vote on logo'); + return array('rate content'); } -function updown_menu() { - $items['node/%/vote/%'] = array( - 'title' => 'Up/Down Vote', - 'type' => MENU_CALLBACK, - 'page callback' => '_updown_vote', - 'page arguments' => array(1, 3), - 'access callback' => 'user_access', - 'access arguments' => array('vote on logo'), - ); +/** + * Implementation of hook_menu(). + */ +function updown_menu($may_cache) { + if ($may_cache) { + } + else { + if (is_numeric(arg(1))) { + if ($node = node_load(arg(1))) { + $items[] = array( + 'path' => 'node/'.arg(1).'/vote', + 'title' => 'Up/Down Vote', + 'type' => MENU_CALLBACK, + 'callback' => 'updown_node_vote', + 'callback arguments' => array($node, arg(3)), + 'access' => user_access('rate content'), + ); + } + } + } return $items; } -function _updown_vote($nid, $vote) { - if ($vote == 'undo') { - _updown_delete_vote($nid); - } - elseif (is_numeric($nid)) { - $node = node_load($nid); +/** + * Implementation of hook_form_alter + * Adds updown enaable and position to the node-type configuration form. + * + */ +function updown_form_alter($form_id, &$form) { + if ($form_id == 'node_type_form' && isset($form['identity']['type'])) { + // Goofy hack to get the buttons at the end of the array. + $form['workflow']['#weight'] = isset($form['workflow']['#weight']) ? $form['workflow']['#weight'] + 1 : 1; + $form['submit']['#weight'] = isset($form['submit']['#weight']) ? $form['submit']['#weight'] + 1 : 1; + $form['delete']['#weight'] = isset($form['delete']['#weight']) ? $form['delete']['#weight'] + 1 : 1; + + $form['updown'] = array( + '#type' => 'fieldset', + '#title' => t('UpDown ratings'), + '#collapsible' => TRUE, + '#collapsed' => !variable_get('updown_'. $form['#node_type']->type, 0), + '#description' => t('To rate this content, enable UpDown rating below.'), + //'#theme' => 'updown_node_type_form', + '#attributes' => array('id' => 'updown-node-type-form'), + ); + + $form['updown']['updown'] = array( + '#type' => 'checkbox', + '#title' => t('Enable UpDown rating'), + '#default_value' => variable_get('updown_'. $form['#node_type']->type, 0), + '#return_value' => 1, + '#weight' => -5, + ); + + $form['updown']['updown_unvote'] = array( + '#type' => 'checkbox', + '#title' => t('Allow users to undo their votes'), + '#default_value' => variable_get('updown_unvote_'. $form['#node_type']->type, 0), + '#return_value' => 1, + ); + + $form['updown']['updown_position_teaser'] = array( + '#type' => 'select', + '#title' => t('Teaser display'), + '#default_value' => variable_get('updown_position_teaser_'. $form['#node_type']->type, 'hidden'), + '#options' => array( + 'above' => t('Clickable widget above teaser'), + 'below' => t('Clickable widget below teaser'), + 'above_static' => t('Static display above teaser'), + 'below_static' => t('Static display below teaser'), + 'link' => t('Teaser link to full node widget'), + 'hidden' => t(''), + ), + ); + + $form['updown']['updown_position'] = array( + '#type' => 'select', + '#title' => t('Full node display'), + '#default_value' => variable_get('updown_position_'. $form['#node_type']->type, 'below'), + '#options' => array( + 'above' => t('Clickable widget above node body'), + 'below' => t('Clickable widget below node body'), + 'above_static' => t('Static display above node body'), + 'below_static' => t('Static display below node body'), + 'hidden' => t(''), + ), + ); + $form['#submit'][] = 'updown_node_type_form_submit'; + } +} + +/** + * Additional submit handler for the node type form. + */ +function updown_node_type_form_submit($form, &$form_values) { + // Do not save any updown variables if updown is disabled. + if (isset($form_values['updown']) && $form_values['updown'] === 0) { + foreach ($form_values as $key => $value) { + if (strpos($key, 'updown') === 0) { + variable_del($key .'_'. $form_values['type']); + } + } + } +} + +/** + * Implementation of hook_node_type(). + */ +function updown_node_type($op, $info) { + $type = $info->type; + $variables = array( + 'updown', + 'updown_unvote', + 'updown_position_teaser', + 'updown_position', + ); + + // Be responsible and cleanup unneeded variables. + if ($op == 'delete') { + foreach ($variables as $variable) { + variable_del($variable .'_'. $type); + } + } + // When changing the type name, update the variables. + elseif ($op == 'update' && !empty($info->old_type) && $info->old_type != $info->type) { + foreach ($variables as $variable) { + $value = variable_get($variable .'_'. $type, -1); + if ($value != -1) { + variable_del($variable .'_'. $type); + variable_set($variable .'_'. $type, $value); + } + } + } +} + +/** + * Implementation of hook_nodeapi() + * + * Adds the updown widget to the node view. + */ +function updown_nodeapi(&$node, $op, $teaser, $page) { + switch ($op) { + case 'view': + if ($node->build_mode != NODE_BUILD_PREVIEW && !isset($node->modr8_form_teaser) && variable_get('updown_'. $node->type, 0)) { + if ($teaser) { + $position = variable_get('updown_position_teaser_'. $node->type, 'above'); + } + else { + $position = variable_get('updown_position_'. $node->type, 'above'); + } + switch ($position) { + case 'above': + case 'below': + if (user_access('rate content with updown')) { + $node->content['updown_widget'] = array( + '#value' => theme('updown_active_widget', $node, $teaser), + '#weight' => $position == 'above' ? -10 : 50, + ); + break; + } // Fall through to static if not allowed to rate. + case 'above_static': + case 'below_static': + $node->content['updown_widget'] = array( + '#value' => theme('updown_inactive_widget', $node, $teaser), + '#weight' => $position == 'above_static' ? -10 : 50, + ); + break; + default: + // We'll do nothing. + break; + } + } + break; + } +} + +function updown_node_vote($node, $vote) { + if ($vote == UPDOWN_VALUE_UNVOTE) { + if (variable_get('updown_unvote_'. $node->type, 0)) { + _updown_delete_vote($node); + } + } + else { // additional validity check - if (($node->type == 'logo' || $node->type = 'session_proposal') && is_numeric($vote) && $vote <= 100 && $vote >= 0) { + if (variable_get('updown_'. $node->type, 0) && is_numeric($vote) && $vote <= UPDOWN_VALUE_HIGH && $vote >= UPDOWN_VALUE_LOW) { global $user; - // assemble the vote array - $vote = array(array( - 'content_type' => 'node', - 'content_id' => $nid, - 'value_type' => 'percent', - 'value' => $vote, - 'uid' => $user->uid, - )); - // log the vote - votingapi_set_votes($vote); + votingapi_set_vote('node', $node->nid, $vote, $user->uid); } } // if the request came from a link, return the user to the page they were on; // otherwise, return the new score if ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') { - exit(print(_updown_get_current_score($nid))); + exit(print(_updown_get_current_score($node))); } else { header('Location: '. $_SERVER['HTTP_REFERER']); @@ -60,45 +222,46 @@ function _updown_vote($nid, $vote) { } } -function _updown_delete_vote($nid) { - // check the nid for validity - if (is_numeric($nid)) { - $node = node_load($nid); +function _updown_delete_vote($node) { + // additional validity check + if (variable_get('updown_'. $node->type, 0)) { + global $user; - // additional validity check - if (in_array($node->type, array('logo', 'session_proposal'))) { - global $user; - - $votes = array(); - $criteria = array( - 'content_type' => 'node', - 'content_id' => $nid, - 'uid' => $user->uid, - ); - - $votes = votingapi_select_votes($criteria); - votingapi_delete_votes($votes); + $votes = array(); + $criteria = array( + 'content_type' => 'node', + 'content_id' => $nid, + 'uid' => $user->uid, + ); + + $votes = votingapi_select_votes($criteria); + // can't use votingapi_delete_votes($votes) since it expects an array + // of objects and we have an array of arrays + if (is_array($votes)) { + foreach ($votes as $vobj) { + votingapi_delete_vote((object)$vobj); + } } } - return _updown_get_current_score($nid); + return _updown_get_current_score($node); } -function _updown_get_current_score($nid) { +function _updown_get_current_score($node) { $current_score = 0; $criteria = array( 'content_type' => 'node', - 'content_id' => $nid, + 'content_id' => $node->nid, ); $votes = votingapi_select_votes($criteria); foreach ($votes as $vote) { - if ($vote['value'] == 100) { + if ($vote['value'] == UPDOWN_VALUE_HIGH) { ++$current_score; } - elseif ($vote['value'] == 0) { + elseif ($vote['value'] == UPDOWN_VALUE_LOW) { --$current_score; } } @@ -106,107 +269,251 @@ function _updown_get_current_score($nid) return $current_score; } -function _updown_user_voted($nid) { +function _updown_user_voted($node, $account=NULL) { global $user; + if (empty($account)) { + $account = $user; + } + $criteria = array( 'content_type' => 'node', - 'content_id' => $nid, - 'uid' => $user->uid, + 'content_id' => $node->nid, + 'uid' => $account->uid, ); return count(votingapi_select_votes($criteria)); } - - /** * ======================================================================== * Theme Functions * ======================================================================== */ -function updown_theme() { - return array( - 'updown_widget' => array( - 'arguments' => array('nid' => NULL, 'type' => NULL), - ), - 'updown_inactive_widget' => array( - 'arguments' => array('nid' => NULL), - ), - 'updown_active_widget' => array( - 'arguments' => array('nid' => NULL), - ), - ); -} - -function theme_updown_widget($nid, $type) { - // no voting for anonymous users +function theme_updown_inactive_widget($node, $teaser=NULL, $user=NULL) { global $user; - if (!$user->uid || $type == 'logo') { - return theme('updown_inactive_widget', $nid); - } - else { - return theme('updown_active_widget', $nid); - } -} -function theme_updown_inactive_widget($nid) { - $current_score = _updown_get_current_score($nid); + if (empty($variables['user'])) { + $variables['user'] = $user; + } + + $current_score = _updown_get_current_score($node->nid); + $user_voted = _updown_user_voted($node->nid); + $can_unvote = variable_get('updown_unvote_'. $node->type, 0); + + ob_start(); + ?> +
+
score
+
+ -
{$current_score} score
- -MARKUP; + return $output; } -function theme_updown_active_widget($nid) { - $current_score = _updown_get_current_score($nid); - $vote_up_uri = base_path() .'node/'. $nid .'/vote/100'; - $vote_down_uri = base_path() .'node/'. $nid .'/vote/0'; - $vote_undo_uri = base_path() .'node/'. $nid .'/vote/undo'; - $vote_class = _updown_user_voted($nid) ? 'voted' : 'voting'; +function theme_updown_active_widget($node, $teaser=NULL, $user=NULL) { + global $user; + + if (empty($variables['user'])) { + $variables['user'] = $user; + } - return << - jQuery(document).ready(function() { - currentScore = $('#updown-widget-{$nid}').children('.updown-score').children('.updown-current-score'); - voteElement = $('#updown-widget-{$nid}').children('.updown-vote'); - voteUndoElement = $('#updown-widget-{$nid}').children('.updown-voteundo'); - - // clicking on the '+' or '-' buttons - voteElement.children().children('a').click(function() { - $.get($(this).attr('href'), function(data) { - currentScore.html(data); - voteElement.hide(); - voteUndoElement.show(); - }); + $current_score = _updown_get_current_score($node->nid); + $user_voted = _updown_user_voted($node->nid); + $can_unvote = variable_get('updown_unvote_'. $node->type, 0); + + $vote_up_uri = base_path() .'node/'. $node->nid .'/vote/'.UPDOWN_VALUE_HIGH; + $vote_down_uri = base_path() .'node/'. $node->nid .'/vote/'.UPDOWN_VALUE_LOW; + $vote_undo_uri = base_path() .'node/'. $node->nid .'/vote/'.UPDOWN_VALUE_UNVOTE; + $vote_class = $user_voted ? 'voted' : 'voting'; + + ob_start(); + ?> + -
-
{$current_score} score
-
- - + +
+
score
+
+ + +
+ + +
- -
-MARKUP; + NULL, + 'vote_cache_id' => NULL, + 'content_id' => NULL, + 'content_type' => NULL, + 'value_type' => NULL, + 'value' => NULL, + 'tag' => NULL, + 'uid' => NULL, + 'timestamp' => NULL, + 'vote_source' => NULL, + 'function' => NULL, + ); + + $query = ''; + $args = array(); + if (!empty($criteria['vote_id'])) { + _votingapi_query_builder($alias . 'vote_id', $criteria['vote_id'], $query, $args); + } elseif (!empty($criteria['vote_cache_id'])) { + _votingapi_query_builder($alias . 'vote_cache_id', $criteria['vote_cache_id'], $query, $args); + } else { + _votingapi_query_builder($alias . 'content_type', $criteria['content_type'], $query, $args, TRUE); + _votingapi_query_builder($alias . 'content_id', $criteria['content_id'], $query, $args); + _votingapi_query_builder($alias . 'value_type', $criteria['value_type'], $query, $args, TRUE); + _votingapi_query_builder($alias . 'tag', $criteria['tag'], $query, $args, TRUE); + _votingapi_query_builder($alias . 'function', $criteria['function'], $query, $args, TRUE); + _votingapi_query_builder($alias . 'uid', $criteria['uid'], $query, $args); + _votingapi_query_builder($alias . 'vote_source', $criteria['vote_source'], $query, $args, TRUE); + _votingapi_query_builder($alias . 'timestamp', $criteria['timestamp'], $query, $args); + } + return array('query' => $query, 'args' => $args); + } +} + +if (!function_exists('_votingapi_query_builder')) { + /** + * Internal helper function constructs individual elements of WHERE clauses. + * Don't use unless you're me. + */ + function _votingapi_query_builder($name, $value, &$query, &$args, $col_is_string = FALSE) { + if (!isset($value)) { + // Do nothing + } + elseif ($name === 'timestamp') { + $query .= " AND timestamp >= %d"; + $args[] = $value; + } + elseif ($name === 'v.timestamp') { + $query .= " AND v.timestamp >= %d"; + $args[] = $value; + } + else { + if (is_array($value)) { + if ($col_is_string) { + $query .= " AND $name IN ('". array_fill(1, count($value), "'%s'") ."')"; + $args += $value; + } + else { + $query .= " AND $name IN (". array_fill(1, count($value), "%d") .")"; + $args += $value; + } + } else { + if ($col_is_string) { + $query .= " AND $name = '%s'"; + $args[] = $value; + } + else { + $query .= " AND $name = %d"; + $args[] = $value; + } + } + } + } }