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') {
drupal_add_css(drupal_get_path('module', 'advpoll') . '/css/advpoll.css', array(
'group' => CSS_DEFAULT,
'every_page' => TRUE,
));
unset($node->content['advpoll_choice']);
if (advpoll_user_eligibility($node)) {
$rendered_form = drupal_get_form('advpoll_ranking_choice_form', $node);
$voteform = '<div class="advpoll-ranking-wrapper">' . drupal_render($rendered_form) . '</div>';
$node->content['advpoll_choice'] = array(
'#markup' => $voteform,
'#weight' => 1,
);
}
else {
$votes = array();
if ($data->mode == 'normal') {
$votes = advpoll_get_user_votes($node->nid, $node->nid);
}
if ($data->state == 'close' && $data->show_results != 'afterclose' || ($data->start_date > time() || $data->end_date < time())) {
$results = theme('advpoll_closed', array(
'data' => $data,
));
}
elseif ($data->electoral && $data->show_results != 'aftervote') {
$results = theme('advpoll_ineligible', array(
'data' => $data,
));
}
else {
if ($data->behavior == 'borda') {
$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' => 1,
);
}
}
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/results']['page callback'] = 'advpoll_ranking_results_page';
}
function advpoll_ranking_form_alter(&$form, $form_state, $form_id) {
if ($form_id == 'advpoll_node_form') {
$lang = $form['language']['#value'];
$form['#validate'][] = 'advpoll_ranking_validate_choices';
}
}
function advpoll_ranking_validate_choices($form, &$form_state) {
$input_choices = array();
$lang = $form_state['build_info']['args'][0]->language;
if (!isset($form_state['input']['advpoll_choice'][$lang])) {
$lang = 'und';
}
$choices = $form_state['input']['advpoll_choice'][$lang];
foreach ($choices as $choice) {
if ($choice['choice']) {
$input_choices[] = $choice['choice'];
}
}
$behavior = $form_state['input']['advpoll_behavior'][$lang];
if (count($input_choices) > 10 && ($behavior == 'borda' || $behavior == 'runoff')) {
form_set_error('advpoll_choice', t('A ranking poll may only have 10 choices. Please remove some choices.'));
}
}
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') {
$results = advpoll_display_borda_results($node->nid, $data);
}
elseif ($data->behavior == 'runoff') {
$results = advpoll_display_runoff_results($node->nid, $data);
}
else {
$results = advpoll_display_results($node->nid, $data);
}
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 == 'runoff') {
$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 == 'runoff') {
$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) {
return 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',
),
);
}
function advpoll_ranking_choice_form($form, &$form_state, $values) {
$data = advpoll_get_data($values);
$count = count($data->choices);
$ranking = array(
'--',
'1st',
'2nd',
'3rd',
'4th',
'5th',
'6th',
'7th',
'8th',
'9th',
'10th',
);
$options = array();
$form['#id'] = 'advpoll-ranking-form-' . $values->nid;
$form['choice'] = array(
'#tree' => TRUE,
);
$form['identity-markup'] = array(
'#type' => 'item',
'#markup' => '<script>Drupal.advpollSetup(' . $values->nid . ');</script>',
);
for ($i = 0; $i < $count; $i++) {
if (!$data->choices[$i]['write_in']) {
$form['choice'][$i] = array(
'#type' => 'select',
'#title' => check_plain(strip_tags($data->choices[$i]['choice'])),
'#options' => $ranking,
);
}
}
if ($data->write_in) {
$form['write_in'] = array(
'#type' => 'textfield',
'#title' => t('Write-in'),
'#size' => '30',
);
$form['write_in_weight'] = array(
'#type' => 'hidden',
'#default_value' => 'no-js',
);
}
$form['submit'] = array(
'#type' => 'submit',
'#ajax' => array(
'callback' => 'advpoll_ranking_submit',
'wrapper' => 'advpoll-ranking-form-' . $values->nid,
'name' => 'submit1',
),
'#value' => t('Vote'),
);
$rows = '';
for ($i = 0; $i < $data->max_choices; $i++) {
$rows .= '<tr class="draggable"><td valign="top" class="advpoll-weight item-' . $i . '"></td></tr>';
}
$form['advpoll-table'] = array(
'#type' => 'item',
'#prefix' => '<div class="advpoll-vote-region">',
'#suffix' => '</div>',
'#markup' => '<table id="advpolltable"><thead><tr><th>' . t('Your Vote') . '</th></tr><tbody>' . $rows . '</tbody></table>',
);
drupal_add_tabledrag('advpolltable', 'match', 'sibling', 'advpoll-weight');
return $form;
}
function advpoll_ranking_submit($form, &$form_state) {
$data = advpoll_get_form_data($form_state);
$count = count($data->choices);
$nid = $form_state['build_info']['args'][0]->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['values']['write_in'])) {
$writein = trim($form_state['values']['write_in']);
$writein_weight = $form_state['values']['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['values']['choice'], $data->choices, $votes);
}
if (count($votes) > 0 && count($votes) <= $data->max_choices) {
advpoll_ranking_process_votes($data, $nid, $votes);
if ($data->behavior == 'borda') {
$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') {
$points = count($data->choices);
}
else {
$points = $data->max_choices;
}
foreach ($votes as $ranking) {
$vote = array();
$vote['type'] = 'advpoll';
$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_process_results($results, $choices, $votes) {
foreach ($results as $key => $result) {
if ($result) {
$votes[] = array(
'rank' => $result,
'id' => $choices[$key]['choice_id'],
);
}
}
return $votes;
}
function advpoll_display_runoff_results($nid, $data) {
$output = '';
$form = NULL;
if (user_access('cancel own vote')) {
$rendered_form = drupal_get_form('advpoll_ranking_cancel_form', $nid);
$form = drupal_render($rendered_form);
}
$uservotes = array();
if ($data->mode == 'normal') {
$uservotes = advpoll_get_user_votes($nid);
}
if ($data->show_results == 'never' || $data->show_results == 'afterclose' && $data->end_date > time()) {
$output .= theme('advpoll_noresults', array(
'data' => $data,
'votes' => $uservotes,
'nid' => $nid,
'cancel_form' => $form,
));
}
else {
$criteria = array();
$criteria['entity_id'] = $nid;
$criteria['entity_type'] = 'advpoll';
$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();
foreach ($data->choices as $choice) {
$all_by_key[$choice['choice_id']] = $choice['choice'];
}
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,
);
}
else {
$rows[] = array(
'id' => $key,
'total' => $vote,
'votes' => $tally[$key],
'choice' => $all_by_key[$key],
'user_choice' => FALSE,
);
}
unset($all_by_key[$key]);
}
$percentage = 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,
);
}
}
$output .= theme('advpoll_runoff', array(
'total' => count($voters),
'rows' => $rows,
'percentage' => $percentage,
'nid' => $nid,
'cancel_form' => $form,
));
}
return $output;
}
function advpoll_display_borda_results($nid, $data) {
$output = '';
$form = NULL;
if (user_access('cancel own vote') && advpoll_get_user_votes($nid)) {
$rendered_form = drupal_get_form('advpoll_ranking_cancel_form', $nid);
$form = drupal_render($rendered_form);
}
$votes = array();
if ($data->mode == 'normal') {
$votes = advpoll_get_user_votes($nid);
}
if (!user_access('administer polls') && ($data->show_results == 'never' || $data->show_results == 'afterclose' && $data->end_date > time())) {
$output .= theme('advpoll_noresults', array(
'data' => $data,
'votes' => $votes,
'nid' => $nid,
'cancel_form' => $form,
));
}
else {
$results = advpoll_get_votes($nid, $data->behavior);
$bars = '';
$final = advpoll_update_choices($data->choices, $results['choices']);
$reordered = array();
foreach ($final as $item) {
$voted = FALSE;
if (in_array($item['tag'], $votes)) {
$voted = TRUE;
}
if (!isset($reordered[$item['percentage']])) {
$reordered[$item['percentage']] = array();
}
$reordered[$item['percentage']][] = array(
'title' => $item['title'],
'votes' => $item['votes'],
'voted' => $voted,
);
}
foreach ($reordered as $key => $candidates) {
$titles = array();
foreach ($candidates as $candidate) {
$candidate['voted'] ? $class = 'voted' : ($class = 'not-voted');
$titles[] = '<span class="' . $class . '">' . $candidate['title'] . '</span>';
}
$bars .= theme('advpoll_borda_bar', array(
'title' => implode(', ', $titles),
'percentage' => $key,
'votes' => $candidate['votes'],
));
}
$output .= theme('advpoll_results', array(
'bars' => $bars,
'total' => $results['total'],
'voted' => $votes,
'nid' => $nid,
'cancel_form' => $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];
rsort($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_submit',
'wrapper' => 'advpoll-' . $nid,
'name' => 'submit1',
),
'#value' => t('Cancel your vote'),
);
return $form;
}
function advpoll_ranking_cancel_submit($form, &$form_state) {
global $user;
if ($user) {
$nid = $form['#nid'];
$criteria = array();
$criteria['entity_id'] = $nid;
$criteria['entity_type'] = 'advpoll';
$criteria['uid'] = $user->uid;
votingapi_delete_votes(votingapi_select_votes($criteria));
$node = node_load($nid);
if (advpoll_user_eligibility($node)) {
$rendered_form = drupal_get_form('advpoll_ranking_choice_form', $node);
return '<div class="advpoll-ranking-wrapper">' . drupal_render($rendered_form) . '</div>';
}
}
}