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)) {
        
        $voteform = '<div class="advpoll-ranking-wrapper">' . drupal_render(drupal_get_form('advpoll_ranking_choice_form', $node)) . '</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,
          ));
        }
        else {
          if ($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;
  $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);
  }
  else {
    if ($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.');
  }
  else {
    if ($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();
  $userObj = null;
  $rows = array();
  foreach ($results as $item) {
    $userID = $item->uid;
    if (!$userID) {
      $userID = $item->vote_source;
    }
    else {
      $userObj = user_load($userID);
      if ($userObj) {
        $userID = l($userObj->name, 'user/' . $userID);
      }
    }
    if ($data->behavior == 'borda' || $data->behavior == 'runoff') {
      $rows[] = array(
        'data' => array(
          $userID,
          format_date($item->timestamp),
          advpoll_match_tag_to_choice($data->choices, $item->tag),
          $item->value,
        ),
      );
    }
    else {
      $rows[] = array(
        'data' => array(
          $userID,
          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')) {
      $output .= drupal_render(drupal_get_form('advpoll_clear_votes_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' => '<div class="advpoll-identity" nid="' . $values->nid . '"></div>',
  );
  for ($i = 0; $i < $count; $i++) {
    if (!$data->choices[$i]['write_in']) {
      $form['choice'][$i] = array(
        '#type' => 'select',
        '#title' => 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'],
          );
        }
        else {
          if ($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')) {
    $form = drupal_render(drupal_get_form('advpoll_ranking_cancel_form', $nid));
  }
  
  $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')) {
    $form = drupal_render(drupal_get_form('advpoll_ranking_cancel_form', $nid));
  }
  
  $votes = array();
  if ($data->mode == 'normal') {
    $votes = 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' => $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)) {
      
      return '<div class="advpoll-ranking-wrapper">' . drupal_render(drupal_get_form('advpoll_ranking_choice_form', $node)) . '</div>';
    }
  }
}