View source
<?php
module_load_include('inc', 'advpoll', 'includes/advpoll_voteapi');
module_load_include('inc', 'advpoll', 'includes/advpoll_helper');
function advpoll_ranking_node_view($node, $view_mode) {
if ($node->type == 'advpoll') {
$data = advpoll_get_data($node);
if ($data->behavior == 'borda' || $data->behavior == 'runoff' || $data->behavior == 'borda_all' || $data->behavior == 'runoff_all') {
drupal_add_css(drupal_get_path('module', 'advpoll') . '/css/advpoll.css', array(
'group' => CSS_DEFAULT,
'every_page' => TRUE,
));
$weight = 1;
if (!empty($node->content['advpoll_choice']['#weight'])) {
$weight = $node->content['advpoll_choice']['#weight'];
}
unset($node->content['advpoll_choice']);
if (advpoll_user_eligibility($node)) {
if ($data->behavior == 'borda' || $data->behavior == 'runoff') {
$rendered_form = drupal_get_form('advpoll_ranking_choice_form', $data, $node);
$voteform = '<div class="advpoll-ranking-wrapper">' . drupal_render($rendered_form) . '</div>';
$node->content['advpoll_choice'] = array(
'#markup' => $voteform,
'#weight' => $weight,
);
}
else {
$rendered_form = drupal_get_form('advpoll_draggable_form', $data, $node);
$voteform = '<div class="advpoll-ranking-wrapper">' . drupal_render($rendered_form) . '</div>';
$node->content['advpoll_choice'] = array(
'#markup' => $voteform,
'#weight' => $weight,
);
}
}
else {
if ($data->behavior == 'borda' || $data->behavior == 'borda_all') {
$results = advpoll_display_borda_results($node->nid, $data);
}
else {
$results = advpoll_display_runoff_results($node->nid, $data);
}
$node->content['advpoll_choice'] = array(
'#markup' => $results,
'#weight' => $weight,
);
}
}
drupal_add_js(drupal_get_path('module', 'advpoll_ranking') . '/js/advpoll-ranking.js', 'file');
drupal_add_js(array(
'advpoll_ranking' => array(
'display' => 'TRUE',
),
), 'setting');
}
}
function advpoll_ranking_menu_alter(&$items) {
$items['node/%node/advpoll/votes']['page callback'] = 'advpoll_ranking_votes_page';
$items['node/%node/advpoll/results']['page callback'] = 'advpoll_ranking_results_page';
}
function advpoll_ranking_results_page($node) {
drupal_add_css(drupal_get_path('module', 'advpoll') . '/css/advpoll.css', array(
'group' => CSS_DEFAULT,
'every_page' => TRUE,
));
drupal_set_title(check_plain($node->title));
$data = advpoll_get_data($node);
if ($data->behavior == 'borda' || $data->behavior == 'borda_all') {
$results = advpoll_display_borda_results($node->nid, $data, 1);
}
elseif ($data->behavior == 'runoff' || $data->behavior == 'runoff_all') {
$results = advpoll_display_runoff_results($node->nid, $data, 1);
}
else {
$results = advpoll_display_results($node->nid, $data, 1);
}
return $results;
}
function advpoll_ranking_votes_page($node) {
drupal_add_css(drupal_get_path('module', 'advpoll') . '/css/advpoll.css', array(
'group' => CSS_DEFAULT,
'every_page' => TRUE,
));
$data = advpoll_get_data($node);
$output = t('This table lists all the recorded votes for this poll.');
if ($data->mode == 'unlimited') {
$output = t('With unlimited voting, a timestamp is used to identify unique votes. If it is important to identify users by ID or IP, switch to normal voting mode which will use your Voting API settings to record votes.');
}
elseif ($data->mode == 'cookie') {
$output = t('With cookie-based voting, a timestamp is used to identify unique votes while the poll\'s id is set in the cookie to limit votes for a limited time. If it is important to identify users by ID or IP, switch to normal voting mode which will use your Voting API settings to record votes.');
}
else {
$output = t('If anonymous users are allowed to vote, they will be identified by the IP address of the computer they used when they voted.');
}
$header = array();
$header[] = array(
'data' => t('Visitor'),
'field' => 'uid',
);
$header[] = array(
'data' => t('Date'),
'field' => 'timestamp',
'sort' => 'asc',
);
$header[] = array(
'data' => t('Choice'),
'tag',
);
$nid = $node->nid;
$query = db_select('votingapi_vote', 'v')
->condition('entity_id', $nid)
->extend('PagerDefault')
->limit(20)
->extend('TableSort')
->orderByHeader($header)
->fields('v', array(
'uid',
'timestamp',
'tag',
'vote_source',
'value',
));
$results = $query
->execute();
$user_obj = NULL;
$rows = array();
foreach ($results as $item) {
$user_id = $item->uid;
if (!$user_id) {
$user_id = $item->vote_source;
}
else {
$user_obj = user_load($user_id);
if ($user_obj) {
$user_id = l($user_obj->name, 'user/' . $user_id);
}
}
if ($data->behavior == 'borda' || $data->behavior == 'borda_all' || $data->behavior == 'runoff' || $data->behavior == 'runoff_all') {
$rows[] = array(
'data' => array(
$user_id,
format_date($item->timestamp),
advpoll_match_tag_to_choice($data->choices, $item->tag),
$item->value,
),
);
}
else {
$rows[] = array(
'data' => array(
$user_id,
format_date($item->timestamp),
advpoll_match_tag_to_choice($data->choices, $item->tag),
),
);
}
}
if ($rows) {
if ($data->behavior == 'borda' || $data->behavior == 'borda_all' || $data->behavior == 'runoff' || $data->behavior == 'runoff_all') {
$rows = advpoll_ranking_process_rows($rows);
}
$output .= theme('table', array(
'header' => $header,
'rows' => $rows,
));
$output .= theme('pager', array(
'tags' => array(),
));
if (user_access('administer votes')) {
$rendered_form = drupal_get_form('advpoll_clear_votes_form');
$output .= drupal_render($rendered_form);
}
}
else {
$output .= '<hr /><p>' . t('No votes are currently recorded for %title', array(
'%title' => $node->title,
)) . '</p>';
}
return $output;
}
function advpoll_ranking_theme($existing, $type, $theme, $path) {
$theme_hooks = array(
'advpoll_runoff' => array(
'variables' => array(
'total' => 0,
'rows' => array(),
'percentage' => 0,
'nid' => NULL,
'cancel_form' => NULL,
),
'path' => drupal_get_path('module', 'advpoll_ranking') . '/templates',
'template' => 'advpoll-runoff',
),
'advpoll_borda_bar' => array(
'variables' => array(
'percentage' => 0,
'votes' => 0,
'voted' => 0,
),
'path' => drupal_get_path('module', 'advpoll_ranking') . '/templates',
'template' => 'advpoll-borda-bar',
),
'advpoll_draggable' => array(
'variables' => array(
'data' => NULL,
'node' => NULL,
),
'path' => drupal_get_path('module', 'advpoll_ranking') . '/templates',
'template' => 'advpoll-draggable',
),
'advpoll_ranking' => array(
'variables' => array(
'data' => NULL,
'node' => NULL,
),
'path' => drupal_get_path('module', 'advpoll_ranking') . '/templates',
'template' => 'advpoll-ranking',
),
);
return $theme_hooks;
}
function advpoll_draggable_form($form, &$form_state, $data, $node) {
$form['#id'] = 'advpoll-ranking-draggable-form-' . $node->nid;
$form['choices'] = array(
'#theme' => 'advpoll_draggable',
'#data' => $data,
'#node' => $node,
);
$form['submit'] = array(
'#type' => 'submit',
'#ajax' => array(
'callback' => 'advpoll_draggable_submit',
'wrapper' => 'advpoll-ranking-draggable-form-' . $node->nid,
'name' => 'submit1',
),
'#value' => t('Vote'),
);
return $form;
}
function advpoll_draggable_submit($form, &$form_state) {
$data = advpoll_get_form_data($form_state, 1);
$nid = $form_state['build_info']['args'][1]->nid;
$votes = array();
$message = advpoll_form_submit_check($data, $nid);
if ($message) {
$form['message'] = array(
'#type' => 'markup',
'#prefix' => '<div id="message">',
'#suffix' => '</div>',
'#markup' => $message,
);
return $form;
}
$votes = advpoll_ranking_process_results($form_state['input']['choice'], $data->choices, $votes);
advpoll_ranking_process_votes($data, $nid, $votes);
if ($data->behavior == 'borda' || $data->behavior == 'borda_all') {
$element['#markup'] = advpoll_display_borda_results($nid, $data);
}
else {
$element['#markup'] = advpoll_display_runoff_results($nid, $data);
}
return $element;
}
function advpoll_ranking_choice_form($form, &$form_state, $data, $node) {
$form['#id'] = 'advpoll-ranking-form-' . $node->nid;
$form['choices'] = array(
'#theme' => 'advpoll_ranking',
'#data' => $data,
'#node' => $node,
);
$form['submit'] = array(
'#type' => 'submit',
'#ajax' => array(
'callback' => 'advpoll_ranking_submit',
'wrapper' => 'advpoll-ranking-form-' . $node->nid,
'name' => 'submit1',
),
'#value' => t('Vote'),
);
$form['write_in_weight'] = array(
'#type' => 'hidden',
'#default_value' => 'no-js',
);
return $form;
}
function advpoll_ranking_submit($form, &$form_state) {
$data = advpoll_get_form_data($form_state, 1);
$count = count($data->choices);
$nid = $form_state['build_info']['args'][1]->nid;
$votes = array();
$writein = '';
$message = advpoll_form_submit_check($data, $nid);
if ($message) {
$form['message'] = array(
'#type' => 'markup',
'#prefix' => '<div id="message">',
'#suffix' => '</div>',
'#markup' => $message,
);
return $form;
}
if ($data->write_in) {
if (isset($form_state['input']['write_in'])) {
$writein = trim($form_state['input']['write_in']);
$writein_weight = $form_state['input']['write_in_weight'];
$writein = filter_xss($writein);
$writein = check_plain($writein);
if ($writein_weight == 'no-js' || $writein_weight > 0) {
if ($writein) {
$writein_choice = advpoll_process_writein($nid, $writein, $data);
$data->choices[] = $writein_choice;
if ($writein_weight == 'no-js') {
$writein_weight = 1;
}
$votes[] = array(
'rank' => $writein_weight,
'id' => $writein_choice['choice_id'],
);
}
elseif ($writein_weight != 'no-js') {
$form['message'] = array(
'#type' => 'markup',
'#prefix' => '<div id="message">',
'#suffix' => '</div>',
'#markup' => t('Please type in a valid write-in choice or select a different option.'),
);
return $form;
}
}
}
}
if ($data->max_choices > 1 || !$votes) {
$votes = advpoll_ranking_process_results($form_state['input']['choice'], $data->choices, $votes);
}
if (count($votes) > 0 && count($votes) <= $data->max_choices) {
advpoll_ranking_process_votes($data, $nid, $votes);
if ($data->behavior == 'borda' || $data->behavior == 'borda_all') {
$element['#markup'] = advpoll_display_borda_results($nid, $data);
}
else {
$element['#markup'] = advpoll_display_runoff_results($nid, $data);
}
return $element;
}
else {
$form['message'] = array(
'#type' => 'markup',
'#prefix' => '<div id="message">',
'#suffix' => '</div>',
'#markup' => t('Select up to @quantity @votes.', array(
'@quantity' => $data->max_choices,
'@votes' => format_plural($data->max_choices, 'vote', 'votes'),
)),
);
return $form;
}
}
function advpoll_ranking_process_votes($data, $nid, $votes) {
if ($data->behavior == 'borda' || $data->behavior == 'borda_all' || $data->behavior == 'runoff_all') {
$points = count($data->choices);
}
else {
$points = $data->max_choices;
}
foreach ($votes as $ranking) {
$vote = array();
$vote['type'] = 'node';
$vote['tag'] = $ranking['id'];
$vote['nid'] = $nid;
$vote['value'] = $points - ($ranking['rank'] - 1);
$vote['mode'] = $data->mode;
$vote['duration'] = $data->cookie_duration;
advpoll_add_votes($vote);
}
}
function advpoll_ranking_vote_has_rank($votes, $rank) {
foreach ($votes as $vote) {
if ($vote['rank'] == $rank) {
return TRUE;
}
}
}
function advpoll_ranking_process_results($results, $choices, $votes) {
foreach ($results as $key => $result) {
if ($result) {
while (advpoll_ranking_vote_has_rank($votes, $result)) {
++$result;
}
$votes[] = array(
'rank' => $result,
'id' => $choices[$key]['choice_id'],
);
}
}
return $votes;
}
function advpoll_display_runoff_results($nid, $data, $page = 0) {
$output = '';
$form = NULL;
$expired = FALSE;
if ($data->state == 'close') {
$expired = TRUE;
}
if ($data->start_date && $data->start_date > time() || $data->end_date && $data->end_date < time()) {
$expired = TRUE;
}
$uservotes = array();
if ($data->mode == 'normal') {
$uservotes = advpoll_get_user_votes($nid);
}
if (user_access('cancel own vote') && $uservotes && !$expired) {
$form = drupal_get_form('advpoll_ranking_cancel_form', $nid);
}
$rendered_form = drupal_render($form);
if (!$page && !$uservotes && $data->electoral && ($data->show_results == 'afterclose' || $data->show_results == 'never') && !$expired) {
$output .= theme('advpoll_ineligible', array(
'data' => $data,
));
}
elseif (!$page && ($data->show_results == 'never' || $data->show_results == 'afterclose' && !$expired)) {
$output .= theme('advpoll_noresults', array(
'data' => $data,
'votes' => $uservotes,
'nid' => $nid,
'cancel_form' => $rendered_form,
));
}
else {
$criteria = array();
$criteria['entity_id'] = $nid;
$criteria['entity_type'] = 'node';
$results = votingapi_select_votes($criteria);
$voters = array();
$votes = array();
$tally = array();
$user = '';
foreach ($results as $result) {
$result['uid'] ? $user = $result['uid'] : ($user = $result['vote_source']);
if (isset($voters[$user])) {
$voters[$user]++;
}
else {
$voters[$user] = 1;
}
if (isset($votes[$result['tag']])) {
$votes[$result['tag']] += $result['value'];
}
else {
$votes[$result['tag']] = $result['value'];
}
if (isset($tally[$result['tag']])) {
$tally[$result['tag']]++;
}
else {
$tally[$result['tag']] = 1;
}
}
asort($votes);
$votes = array_reverse($votes, TRUE);
$rows = array();
$all_by_key = array();
$write_in = array();
foreach ($data->choices as $choice) {
$all_by_key[$choice['choice_id']] = $choice['choice'];
$write_in[$choice['choice_id']] = $choice['write_in'];
}
foreach ($votes as $key => $vote) {
if ($uservotes && in_array($key, $uservotes)) {
$rows[] = array(
'id' => $key,
'total' => $vote,
'votes' => $tally[$key],
'choice' => $all_by_key[$key],
'user_choice' => TRUE,
'write_in' => $write_in[$key],
);
}
else {
$rows[] = array(
'id' => $key,
'total' => $vote,
'votes' => $tally[$key],
'choice' => $all_by_key[$key],
'user_choice' => FALSE,
'write_in' => $write_in[$key],
);
}
unset($all_by_key[$key]);
}
$divisor = count($voters) * 100;
$percentage = 0;
if ($divisor > 0) {
$percentage = advpoll_round($rows[0]['votes'] / count($voters) * 100, 1);
}
if ($all_by_key) {
foreach ($all_by_key as $key => $choice) {
$rows[] = array(
'id' => $key,
'total' => 0,
'votes' => 0,
'choice' => $choice,
'user_choice' => FALSE,
'write_in' => $write_in[$key],
);
}
}
$output .= theme('advpoll_runoff', array(
'total' => count($voters),
'rows' => $rows,
'percentage' => $percentage,
'nid' => $nid,
'cancel_form' => $rendered_form,
));
}
return $output;
}
function advpoll_display_borda_results($nid, $data, $page = 0) {
$output = '';
$form = NULL;
$expired = FALSE;
if ($data->start_date && $data->start_date > time() || $data->end_date && $data->end_date < time() || $data->state == 'close') {
$expired = TRUE;
}
$votes = array();
if ($data->mode == 'normal') {
$votes = advpoll_get_user_votes($nid);
}
if (user_access('cancel own vote') && $votes && !$expired) {
$form = drupal_get_form('advpoll_ranking_cancel_form', $nid);
}
$rendered_form = drupal_render($form);
if (!$page && !$votes && $data->electoral && ($data->show_results == 'afterclose' || $data->show_results == 'never') && !$expired) {
$output .= theme('advpoll_ineligible', array(
'data' => $data,
));
}
elseif (!$page && ($data->show_results == 'never' || $data->show_results == 'afterclose' && !$expired)) {
$output .= theme('advpoll_noresults', array(
'data' => $data,
'votes' => $votes,
'nid' => $nid,
'cancel_form' => $rendered_form,
));
}
else {
$results = advpoll_get_votes($nid, $data);
$bars = '';
$final = advpoll_update_choices($data->choices, $results['choices']);
$reordered = array();
foreach ($final as $item) {
$title = $item['title'];
$show_bar = TRUE;
if ($item['write_in']) {
$title .= ' ' . t('(Write in)');
$show_bar = _advpoll_show_writeins_access();
}
if ($show_bar) {
$voted = FALSE;
if (in_array($item['tag'], $votes)) {
$voted = TRUE;
}
if (!isset($reordered[$item['percentage']])) {
$reordered[$item['percentage']] = array();
}
$reordered[$item['percentage']][] = array(
'title' => $title,
'votes' => $item['votes'],
'voted' => $voted,
);
}
}
foreach ($reordered as $key => $candidates) {
$titles = array();
foreach ($candidates as $candidate) {
$class = $candidate['voted'] ? 'voted' : 'not-voted';
$titles[] = '<span class="' . $class . '">' . $candidate['title'] . '</span>';
}
$bars .= theme('advpoll_borda_bar', array(
'title' => implode(', ', $titles),
'percentage' => $key,
'votes' => isset($candidate['votes']) ? $candidate['votes'] : 0,
));
}
$output .= theme('advpoll_results', array(
'bars' => $bars,
'total' => $results['total'],
'voted' => $votes,
'nid' => $nid,
'cancel_form' => $rendered_form,
));
}
return $output;
}
function advpoll_ranking_process_rows($rows) {
$users = array();
$sorted = array();
$votes = array();
$final = array();
foreach ($rows as $row) {
$user = strip_tags($row['data'][0]);
$votes[$user][$row['data'][3]] = $row['data'][2];
if (!in_array($user, $users)) {
$users[] = $user;
unset($row['data'][3]);
$sorted[] = $row;
}
}
foreach ($sorted as $row) {
$user = strip_tags($row['data'][0]);
$choices = $votes[$user];
krsort($choices);
$choice = implode(' > ', $choices);
$row['data'][2] = $choice;
$final[] = $row;
}
$rows = $final;
return $rows;
}
function advpoll_ranking_cancel_form($form, &$form_state, $nid) {
$form['#nid'] = $nid;
$form['submit'] = array(
'#type' => 'submit',
'#ajax' => array(
'callback' => 'advpoll_ranking_cancel_vote_submit',
'wrapper' => 'advpoll-' . $nid,
'name' => 'submit1',
),
'#value' => t('Cancel your vote'),
);
return $form;
}
function advpoll_ranking_cancel_vote_submit($form, &$form_state) {
global $user;
if ($user->uid) {
$nid = $form['#nid'];
$criteria = array();
$criteria['entity_id'] = $nid;
$criteria['entity_type'] = 'node';
$criteria['uid'] = $user->uid;
votingapi_delete_votes(votingapi_select_votes($criteria));
$node = node_load($nid);
if (advpoll_user_eligibility($node)) {
$data = advpoll_get_data($node);
if ($data->behavior == 'borda' || $data->behavior == 'runoff') {
$update_form = drupal_get_form('advpoll_ranking_choice_form', $data, $node);
}
else {
$update_form = drupal_get_form('advpoll_draggable_form', $data, $node);
}
return drupal_render($update_form);
}
}
return '';
}