'fivestar/vote',
'callback' => 'fivestar_vote',
'type' => MENU_CALLBACK,
'access' => user_access('rate content'),
);
}
else {
drupal_add_css(drupal_get_path('module', 'fivestar') .'/theme/fivestar.css');
}
return $items;
}
function fivestar_form_alter($form_id, &$form) {
if ($form_id == 'node_type_form' && isset($form['identity']['type'])) {
$form['workflow']['fivestar'] = array(
'#type' => 'checkbox',
'#title' => t('Use Five Star rating'),
'#default_value' => variable_get('fivestar_'. $form['#node_type']->type, 1),
'#return_value' => 1,
'#description' => t('Allow users to rate this content type with a five star voting widget.'),
);
$form['workflow']['fivestar_position'] = array(
'#type' => 'select',
'#title' => t('Five Star widget location'),
'#default_value' => variable_get('fivestar_position_'. $form['#node_type']->type, 'above'),
'#options' => array(
'above' => t('Above the node body'),
'below' => t('Below the node body'),
'hidden' => t('Hidden -- my theme will display it'),
),
);
}
}
function fivestar_perm() {
return array('rate content', 'use PHP for fivestar target');
}
function fivestar_vote($type, $cid, $value) {
$result = _fivestar_cast_vote($type, $cid, $value);
if (count($result)) {
$output = '';
$output .= '';
$output .= '';
foreach ($result as $data) {
$output .= '<'. $data->function .'>' . $data->value . ''. $data->function .'>';
}
$output .= '';
$output .= '';
$output .= '' . $value . '';
$output .= '' . $type . '';
$output .= '' . $cid . '';
$output .= '';
}
else {
$output = 'false';
}
exit($output);
}
function _fivestar_cast_vote($type, $cid, $value) {
global $user;
// Bail out if the user's trying to vote on an invalid object.
if (!_fivestar_validate_target($type, $cid)) {
return array();
}
// Prep variables for anonymous vs. registered voting
if ($user->uid) {
$uid = $user->uid;
}
else {
$uid = 0;
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$hostname = $_SERVER['HTTP_X_FORWARDED_FOR'];
}
else {
$hostname = $_SERVER['REMOTE_ADDR'];
}
}
// sanity-check the incoming values.
if (is_numeric($cid) && is_numeric($value)) {
if ($value > 100) {
$value = 100;
}
// If the vote value is 0, blindly nuke any votes for this content by the user.
if ($value == 0) {
if ($uid) {
// If the user is logged in, we'll look for votes from that uid.
$sql = "DELETE FROM {votingapi_vote} WHERE content_type='%s' AND content_id=%d AND value_type='percent' AND uid=%d";
db_query($sql, $type, $cid, $uid);
return votingapi_recalculate_results($type, $cid);
}
else {
// Otherwise, we'll look for votes from the same IP address in the past day.
$sql = "DELETE FROM {votingapi_vote} WHERE content_type='%s' AND content_id=%d AND value_type='percent' AND uid=%d AND hostname='%s' AND timestamp > %d";
db_query($sql, $type, $cid, $uid, $hostname, time() - (60 * 60 * 24));
return votingapi_recalculate_results($type, $cid);
}
}
// If the vote ISN'T zero, check for existing botes in the database.
else {
if ($uid) {
// If the user is logged in, we'll look for votes from that uid.
$sql = "SELECT vote_id FROM {votingapi_vote} WHERE content_type='%s' AND content_id=%d AND value_type='percent' AND uid=%d";
$result = db_query($sql, $type, $cid, $uid);
}
else {
// Otherwise, we'll look for votes from the same IP address in the past day.
$sql = "SELECT vote_id FROM {votingapi_vote} WHERE content_type='%s' AND content_id=%d AND value_type='percent' AND uid=%d AND hostname='%s' AND timestamp > %d";
$result = db_query($sql, $type, $cid, $uid, $hostname, time() - (60 * 60 * 24));
}
}
// If the old vote exists, either delete it (if the new one is zero)
// or change it. If it doesn't exist and the vote is non-zero, cast
// it and recalculate.
if ($old_vote = db_fetch_object($result)) {
votingapi_change_vote($old_vote, $value);
}
elseif ($value != 0) {
votingapi_add_vote($type, $cid, $value, 'percent', 'vote', $uid);
}
return votingapi_recalculate_results($type, $cid);
}
else {
return array();
}
}
function _fivestar_validate_target($type, $id) {
switch ($type) {
case 'node':
if ($node = node_load($id)) {
if (variable_get('fivestar_' . $node->type, 0)) {
return TRUE;
}
else {
return FALSE;
}
}
else {
return FALSE;
}
default:
return FALSE;
}
}
function fivestar_nodeapi(&$node, $op, $teaser, $page) {
switch ($op) {
case 'view':
if ($teaser == FALSE && $node->in_preview == FALSE && user_access('rate content') && variable_get('fivestar_' . $node->type, 0)) {
switch (variable_get('fivestar_position_' . $node->type, 'above')) {
case 'above':
$node->content['fivestar_widget'] = array(
'#value' => fivestar_widget_form($node),
'#weight' => -10,
);
break;
case 'below':
$node->content['fivestar_widget'] = array(
'#value' => fivestar_widget_form($node),
'#weight' => 50,
);
break;
default:
// We'll do nothing.
break;
}
}
break;
}
}
function fivestar_widget_form($node) {
if (strpos(drupal_get_js(), 'jquery.rating.js') === FALSE) {
drupal_add_js(drupal_get_path('module', 'fivestar') . '/jquery.rating.js');
drupal_add_js("jQuery(function(){jQuery('div.fivestar-widget').rating();});", 'inline');
}
if (strpos(drupal_get_js(), "jQuery('input.fivestar-submit').hide()") === FALSE) {
drupal_add_js("jQuery(function(){jQuery('input.fivestar-submit').hide();});", 'inline');
}
return drupal_get_form('fivestar_form_node_' . $node->nid, 'node', $node->nid);
}
function fivestar_forms() {
$args = func_get_args();
if (strpos($args[0][0], 'fivestar_form') !== FALSE) {
if ($args[0][0] == 'fivestar_form_' . $args[0][1] . '_' . $args[0][2]) {
$forms[$args[0][0]] = array('callback' => 'fivestar_form');
return $forms;
}
}
}
function fivestar_form($content_type, $content_id) {
global $user;
$current_avg = votingapi_get_voting_result($content_type, $content_id, 'percent', 'vote', 'average');
$current_count = votingapi_get_voting_result($content_type, $content_id, 'percent', 'vote', 'count');
if ($user->uid) {
$current_vote = votingapi_get_vote($content_type, $content_id, 'percent', 'vote', $user->uid);
}
else {
// If the user is anonymous, we never both loading their existing votes.
// Not only would it be hit-or-miss, it would break page caching. Safer to always
// show the 'fresh' version to anon users.
$current_vote = 0;
}
$form = array();
$form['content_type'] = array(
'#type' => 'hidden',
'#value' => $content_type,
);
$form['content_id'] = array(
'#type' => 'hidden',
'#value' => $content_id,
);
$form['vote'] = array(
'#type' => 'fivestar',
'#vote_count' => $current_count->value,
'#vote_average' => $current_avg->value,
'#default_value' => $current_vote->value,
'#auto_submit' => TRUE,
'#auto_submit_path' => 'fivestar/vote/' . $content_type . '/' . $content_id,
'#allow_clear' => variable_get('fivestar_allow_cancel', TRUE),
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit rating'),
'#attributes' => array('class' => 'fivestar-submit'),
);
$form['#attributes']['class'] = 'fivestar-widget';
$form['#base'] = 'fivestar_form';
$form['#redirect'] = FALSE;
return $form;
}
function fivestar_form_submit($form_id, $form_values) {
if ($form_id == 'fivestar_form_' . $form_values['content_type'] . '_' . $form_values['content_id']) {
_fivestar_cast_vote($form_values['content_type'], $form_values['content_id'], $form_values['vote']);
}
}
function fivestar_elements() {
$type['fivestar'] = array(
'#input' => TRUE,
'#stars' => 5,
'#allow_clear' => TRUE,
'#auto_submit' => FALSE,
'#auto_submit_path' => '',
'#process' => array('fivestar_expand' => array()),
);
return $type;
}
/**
* Format a five star voting element.
*
* @param $element
* An associative array containing the properties of the element.
* Properties used: title, value, options, description, extra, multiple, required
* @return
* A themed HTML string representing the form element.
*
* It is possible to group options together; to do this, change the format of
* $options to an associative array in which the keys are group labels, and the
* values are associative arrays in the normal $options format.
*/
function theme_fivestar($element) {
$element['#children'] = '
'. $element['#children'] .'
';
if ($element['#title'] || $element['#description']) {
unset($element['#id']);
return theme('form_element', $element, $element['#children']);
}
else {
return $element['#children'];
}
}
/**
* Display a plain HTML VIEW ONLY version of the widget
* with the specified rating
*
* @param $rating
* The desired rating to display out of 100 (i.e. 80 is 4 out of 5 stars)
* @param $stars
* The total number of stars this rating is out of
* @return
* A themed HTML string representing the star widget
*
*/
function theme_fivestar_static($rating, $stars = 5) {
$output = '';
$output .= '';
return $output;
}
function fivestar_expand($element) {
if (isset($element['#vote_count'])) {
$element['vote_count'] = array(
'#type' => 'hidden',
'#value' => $element['#vote_count'],
);
}
if (isset($element['#vote_average'])) {
$element['vote_average'] = array(
'#type' => 'hidden',
'#value' => $element['#vote_average'],
);
}
if ($element['#auto_submit'] && !empty($element['#auto_submit_path'])) {
$element['auto_submit_path'] = array(
'#type' => 'hidden',
'#value' => url($element['#auto_submit_path']),
'#attributes' => array('class' => 'fivestar-path'),
);
}
for ($i = ($element['#allow_clear'] == TRUE) ? 0 : 1; $i <= $element['#stars']; $i++) {
$this_value = ceil($i * 100/$element['#stars']);
$next_value = ceil(($i+1) * 100/$element['#stars']);
$element['vote'][$i]['#type'] = 'radio';
$element['vote'][$i]['#return_value'] = $this_value;
$element['vote'][$i]['#attributes'] = $element['#attributes'];
$element['vote'][$i]['#parents'] = $element['#parents'];
$element['vote'][$i]['#spawned'] = TRUE;
// If a default value is not exactly on a radio value, round up to the next one
if ($element['#default_value'] > $this_value && $element['#default_value'] <= $next_value) {
$element['vote'][$i+1]['#default_value'] = $next_value;
}
}
return $element;
}