Skip to content
Snippets Groups Projects
poll.module 13.7 KiB
Newer Older
/**
 * Implementation of hook_help().
 */
function poll_help($section) {
Steven Wittens's avatar
Steven Wittens committed
  switch ($section) {
    case 'admin/help#poll':
Steven Wittens's avatar
Steven Wittens committed
      <p>Users with the correct <a href=\"%permissions\">permissions</a> can create and/or vote on polls.</p>
      <ul>
      <li>To create a poll a user needs the \"create polls\" permission.</li>
      <li>To vote on a poll question a user must have the \"vote on polls\" permission.</li>
      <li>To view the results one needs the \"access content\" permission.</li>
      <li>To administer polls you need the \"administer nodes\" permission.</li>
      </ul>
      <p>Creating a poll is much like creating any other node. Click \"create poll\" in your user box. The title of the poll should be the question, then enter the answers and the \"base\" vote counts. You can also choose the time period over which the vote will run.</p><p>The <a href=\"%poll\">Poll</a> item in the navigation links will take you to a page where you can see all the current polls, vote on them (if you haven't already) and view the results.</p>", array("%permissions" => url("admin/user/configure/permission"), "%poll" => url("poll")));
Dries Buytaert's avatar
 
Dries Buytaert committed
    case 'admin/modules#description':
      return t("Enables your site to capture votes on different topics in the form of multiple choice questions.");
Steven Wittens's avatar
Steven Wittens committed
    case 'node/add#poll':
      return t("A poll is a multiple-choice question which visitors can vote on.");
function poll_access($op, $node) {
Steven Wittens's avatar
Steven Wittens committed
  if ($op == 'view') {
    return $node->status;
Steven Wittens's avatar
Steven Wittens committed
  if ($op == 'create') {
    return user_access('create polls');
Dries Buytaert's avatar
 
Dries Buytaert committed
  }
/**
 * Implementation of hook_block().
 *
 * Generates a block containing the latest poll.
 */
Steven Wittens's avatar
Steven Wittens committed
function poll_block($op = 'list', $delta = 0) {
  if (user_access('access content')) {
    if ($op == 'list') {
      $blocks[0]['info'] = t('Most recent poll');
Dries Buytaert's avatar
 
Dries Buytaert committed
      return $blocks;
    }
    else {
Dries Buytaert's avatar
 
Dries Buytaert committed
      $timestamp = db_result(db_query("SELECT MAX(created) FROM {node} WHERE type = 'poll' AND status = '1' AND moderate = '0'"));
Dries Buytaert's avatar
 
Dries Buytaert committed
      if ($timestamp) {
Steven Wittens's avatar
Steven Wittens committed
        $poll = node_load(array('type' => 'poll', 'created' => $timestamp, 'moderate' => 0, 'status' => 1));

Dries Buytaert's avatar
 
Dries Buytaert committed
        if ($poll->nid) {
          // poll_view() dumps the output into $poll->body.
Dries Buytaert's avatar
 
Dries Buytaert committed
        }
Dries Buytaert's avatar
 
Dries Buytaert committed
      }
Steven Wittens's avatar
Steven Wittens committed
      $block['subject'] = t('Poll');
      $block['content'] = $poll->body;
Dries Buytaert's avatar
 
Dries Buytaert committed
      return $block;
/**
 * Implementation of hook_cron().
 *
 * Closes polls that have exceeded their allowed runtime.
 */
function poll_cron() {
Dries Buytaert's avatar
 
Dries Buytaert committed
  $result = db_query("SELECT p.nid FROM {poll} p INNER JOIN {node} n ON p.nid=n.nid WHERE (n.created + p.runtime) < '". time() ."' AND p.active = '1' AND p.runtime != '0'");
Dries Buytaert's avatar
 
Dries Buytaert committed
  while ($poll = db_fetch_object($result)) {
Dries Buytaert's avatar
 
Dries Buytaert committed
    db_query("UPDATE {poll} SET active='0' WHERE nid = %d", $poll->nid);
Dries Buytaert's avatar
 
Dries Buytaert committed
  }
function poll_delete($node) {
Dries Buytaert's avatar
 
Dries Buytaert committed
  db_query("DELETE FROM {poll} WHERE nid=%d", $node->nid);
  db_query("DELETE FROM {poll_choices} WHERE nid = %d", $node->nid);
  if (isset($node->title)) {
    // Check for at least two options and validate amount of votes:
Steven Wittens's avatar
Steven Wittens committed
    $realchoices = 0;
    foreach ($node->choice as $i => $choice) {
      if ($choice['chtext'] != '') {
        $realchoices++;
Dries Buytaert's avatar
 
Dries Buytaert committed

Steven Wittens's avatar
Steven Wittens committed
      if ($choice['chvotes'] < 0) {
Dries Buytaert's avatar
 
Dries Buytaert committed
        form_set_error("choice][$i][chvotes", t("Negative values are not allowed."));
Dries Buytaert's avatar
 
Dries Buytaert committed

Steven Wittens's avatar
Steven Wittens committed
    if ($realchoices < 2) {
Dries Buytaert's avatar
 
Dries Buytaert committed
      form_set_error("choice][$realchoices][chtext", t("You must fill in at least two choices."));
Dries Buytaert's avatar
 
Dries Buytaert committed
function poll_form(&$node) {
Steven Wittens's avatar
Steven Wittens committed
  $admin = user_access('administer nodes');
Steven Wittens's avatar
Steven Wittens committed
  if (function_exists('taxonomy_node_form')) {
    $output = implode('', taxonomy_node_form('poll', $node));
  }
Steven Wittens's avatar
Steven Wittens committed
  if (!isset($node->choices)) {
    $node->choices = max(2, count($node->choice) ? count($node->choice) : 5);
  }
Dries Buytaert's avatar
 
Dries Buytaert committed

Steven Wittens's avatar
Steven Wittens committed
  if ($node->morechoices) {
    $node->choices *= 2;
Steven Wittens's avatar
Steven Wittens committed
  $output .= '<div class="poll-form">';
Dries Buytaert's avatar
 
Dries Buytaert committed

Steven Wittens's avatar
Steven Wittens committed
  // Poll choices
Dries Buytaert's avatar
 
Dries Buytaert committed
  $opts = drupal_map_assoc(range(2, $node->choices * 2 + 5));
  for ($a = 0; $a < $node->choices; $a++) {
Dries Buytaert's avatar
 
Dries Buytaert committed
    $group1 .= form_textfield(t('Choice %n', array('%n' => ($a + 1))), "choice][$a][chtext", $node->choice[$a]['chtext'], 50, 127);
    if ($admin) {
Dries Buytaert's avatar
 
Dries Buytaert committed
      $group1 .= form_textfield(t('Votes for choice %n', array('%n' => ($a + 1))), "choice][$a][chvotes", (int)$node->choice[$a]['chvotes'], 7, 7);
Steven Wittens's avatar
Steven Wittens committed
  $group1 .= form_hidden('choices', $node->choices);
  $group1 .= form_checkbox(t('Need more choices'), 'morechoices', 1, 0, t("If the amount of boxes above isn't enough, check this box and click the Preview button below to add some more."));
  $output .= form_group(t('Choices'), $group1);
Dries Buytaert's avatar
 
Dries Buytaert committed

Dries Buytaert's avatar
 
Dries Buytaert committed

Steven Wittens's avatar
Steven Wittens committed
  // Poll attributes
  $_duration = array(0 => t('Unlimited')) + drupal_map_assoc(array(86400, 172800, 345600, 604800, 1209600, 2419200, 4838400, 9676800, 31536000), "format_interval");
Steven Wittens's avatar
Steven Wittens committed
  $_active = array(0 => t('Closed'), 1 => t('Active'));
Dries Buytaert's avatar
 
Dries Buytaert committed

Steven Wittens's avatar
Steven Wittens committed
  if ($admin) {
    $group2 .= form_radios(t('Poll status'), 'active', isset($node->active) ? $node->active : 1, $_active, t('When a poll is closed, visitors can no longer vote for it.'));
Dries Buytaert's avatar
 
Dries Buytaert committed
  }
Steven Wittens's avatar
Steven Wittens committed
  $group2 .= form_select(t('Poll duration'), 'runtime', $node->runtime ? $node->runtime : 0, $_duration, t('After this period, the poll will be closed automatically.'));
Dries Buytaert's avatar
 
Dries Buytaert committed

  $output .= form_group(t('Settings'), $group2);
Steven Wittens's avatar
Steven Wittens committed
  $output .= '</div>';
Dries Buytaert's avatar
 
Dries Buytaert committed

  return $output;
function poll_insert($node) {
Steven Wittens's avatar
Steven Wittens committed
  if (!user_access('administer nodes')) {
    // Make sure all votes are 0 initially
Steven Wittens's avatar
Steven Wittens committed
    foreach ($node->choice as $i => $choice) {
      $node->choice[$i]['chvotes'] = 0;
    }
    $node->active = 1;
  }
Dries Buytaert's avatar
 
Dries Buytaert committed
  db_query("INSERT INTO {poll} (nid, runtime, voters, active) VALUES (%d, %d, '', %d)", $node->nid, $node->runtime, $node->active);
Dries Buytaert's avatar
 
Dries Buytaert committed

Steven Wittens's avatar
Steven Wittens committed
  foreach ($node->choice as $choice) {
    if ($choice['chtext'] != '') {
      db_query("INSERT INTO {poll_choices} (nid, chtext, chvotes, chorder) VALUES (%d, '%s', %d, %d)", $node->nid, $choice['chtext'], $choice['chvotes'], $i++);
Dries Buytaert's avatar
 
Dries Buytaert committed
/**
 * Implementation of hook_link().
 */
function poll_link($type, $node = 0, $main) {
Dries Buytaert's avatar
 
Dries Buytaert committed
  $links = array();

Dries Buytaert's avatar
 
Dries Buytaert committed
  if ($type == 'page' && user_access('access content')) {
Steven Wittens's avatar
Steven Wittens committed
    $links[] = l(t('polls'), 'poll', array('title' => t('View the list of polls on this site.')));
Steven Wittens's avatar
Steven Wittens committed
  }
Steven Wittens's avatar
Steven Wittens committed
  else if ($type == 'node' && $node->type == 'poll') {
    /*
    ** Add links to allow the user to switch between the results and the voting
    ** form, if he/she hasn't voted yet.
    */

Steven Wittens's avatar
Steven Wittens committed
    if ($node->allowvotes) {
      if (arg(3) == 'results') {
Dries Buytaert's avatar
 
Dries Buytaert committed
        $links[] = l(t('voting form'), 'node/'. $node->nid);
      }
      else {
Dries Buytaert's avatar
 
Dries Buytaert committed
        $links[] = l(t('view results'), 'node/'. $node->nid .'/results');
Dries Buytaert's avatar
 
Dries Buytaert committed

  return $links;
Dries Buytaert's avatar
 
Dries Buytaert committed

Dries Buytaert's avatar
 
Dries Buytaert committed
/**
 * Implementation of hook_menu().
 */
function poll_menu() {
  $items = array();
  $items[] = array('path' => 'node/add/poll', 'title' => t('poll'),
    'access' => user_access('create polls'));
  $items[] = array('path' => 'poll', 'title' => t('polls'),
    'callback' => 'poll_page',
    'access' => user_access('access content'),
    'type' => MENU_SUGGESTED_ITEM);
  return $items;
}

Steven Wittens's avatar
Steven Wittens committed
/**
 * Determine an adjusted user id, to allow for basic tracking of anonymous
 * users (IP-based).
 */
function poll_uid() {
  global $user;
  if ($user->uid) {
     // Pad the UID with underscores to allow a simple strstr() search
    $id = '_'. $user->uid .'_';
  }
  else {
    $id = $_SERVER['REMOTE_ADDR'];
  }
  return $id;
}

function poll_load($node) {
  // Load the appropriate choices into the $node object
Dries Buytaert's avatar
 
Dries Buytaert committed
  $poll = db_fetch_object(db_query("SELECT runtime, voters, active FROM {poll} WHERE nid = %d", $node->nid));
Dries Buytaert's avatar
 
Dries Buytaert committed

Dries Buytaert's avatar
 
Dries Buytaert committed
  $result = db_query("SELECT chtext, chvotes, chorder FROM {poll_choices} WHERE nid=%d ORDER BY chorder", $node->nid);
Steven Wittens's avatar
Steven Wittens committed
  while ($choice = db_fetch_array($result)) {
    $poll->choice[$choice['chorder']] = $choice;
Steven Wittens's avatar
Steven Wittens committed
  // Determine whether or not this user is allowed to vote
  $poll->allowvotes = false;
  if (user_access('vote on polls')) {
    if (!strstr($poll->voters, poll_uid())) {
      $poll->allowvotes = $poll->active;
    }
  }
Dries Buytaert's avatar
 
Dries Buytaert committed

Dries Buytaert's avatar
 
Dries Buytaert committed
function poll_node_name($node) {
  return t("poll");
Steven Wittens's avatar
Steven Wittens committed
function poll_page() {
Steven Wittens's avatar
Steven Wittens committed
  // List all polls
  $result = pager_query("SELECT n.nid, n.title, p.active, SUM(c.chvotes) AS votes FROM {node} n INNER JOIN {poll} p ON n.nid=p.nid INNER JOIN {poll_choices} c ON n.nid=c.nid WHERE type = 'poll' AND status = '1' AND moderate = '0' GROUP BY n.nid, n.title, p.active, n.created ORDER BY n.created DESC", 15);
  $output = '<ul>';
Steven Wittens's avatar
Steven Wittens committed
  while ($node = db_fetch_object($result)) {
Dries Buytaert's avatar
 
Dries Buytaert committed
    $output .= '<li>'. l($node->title, "node/$node->nid") .' - '. format_plural($node->votes, '1 vote', '%count votes') .' - '. ($node->active ? t('open') : t('closed')) .'</li>';
Steven Wittens's avatar
Steven Wittens committed
  }
Steven Wittens's avatar
Steven Wittens committed
  $output .= '</ul>';
  $output .= theme("pager", NULL, 15);
  print theme('page', $output);
Steven Wittens's avatar
Steven Wittens committed
}

function poll_perm() {
Steven Wittens's avatar
Steven Wittens committed
  return array('create polls', 'vote on polls');
Dries Buytaert's avatar
 
Dries Buytaert committed

/**
 * Creates a simple teaser that lists all the choices.
 */
function poll_teaser($node) {
Dries Buytaert's avatar
Dries Buytaert committed
  if (is_array($node->choice)) {
Steven Wittens's avatar
Steven Wittens committed
    foreach ($node->choice as $k => $choice) {
      $teaser .= '* '. $choice['chtext'] .'\n';
Steven Wittens's avatar
Steven Wittens committed
/**
Steven Wittens's avatar
Steven Wittens committed
 */
function poll_view_voting(&$node, $main, $page, $block) {
  $url = request_uri();
Steven Wittens's avatar
Steven Wittens committed
  $output .= '<div class="poll">';
Dries Buytaert's avatar
 
Dries Buytaert committed

Steven Wittens's avatar
Steven Wittens committed
  $form .= '<div class="vote-form">';
  $form .= '<div class="choices">';
Dries Buytaert's avatar
 
Dries Buytaert committed
  if ($node->choice) {
Steven Wittens's avatar
Steven Wittens committed
    $list = array();
    foreach ($node->choice as $i => $choice) {
      $list[$i] = drupal_specialchars($choice['chtext']);
Steven Wittens's avatar
Steven Wittens committed
    $form .= form_radios($page ? '' : $node->title, 'choice', -1, $list);
Dries Buytaert's avatar
 
Dries Buytaert committed
  }
Steven Wittens's avatar
Steven Wittens committed
  $form .= '</div>';
  $form .= form_hidden('nid', $node->nid);
  $form .= form_submit(t('Vote'), 'vote') .'</div>';

Dries Buytaert's avatar
 
Dries Buytaert committed
  $output .= form($form, 'post', url('node/'. $node->nid));
Steven Wittens's avatar
Steven Wittens committed
  $output .= '</div>';

  return $output;
}

/**
 * Generates a graphical representation of the results of a poll.
 */
Steven Wittens's avatar
Steven Wittens committed
function poll_view_results(&$node, $main, $page, $block) {
  // Display the results
Dries Buytaert's avatar
 
Dries Buytaert committed

  // Count the votes and find the maximum
Steven Wittens's avatar
Steven Wittens committed
  foreach ($node->choice as $choice) {
    $votestotal += $choice['chvotes'];
    $votesmax = max($votesmax, $choice['chvotes']);
Dries Buytaert's avatar
 
Dries Buytaert committed
  // Output the divs for the text, bars and percentages
Steven Wittens's avatar
Steven Wittens committed
  $output .= '<div class="poll">';
  if ($block) {
    $output .= '<div class="title">'. $node->title .'</div>';
  }
  foreach ($node->choice as $i => $choice) {
    if ($choice['chtext'] != '') {
      $percentage = round($choice['chvotes'] * 100 / max($votestotal, 1));
      $output .= '<div class="text">'. drupal_specialchars($choice['chtext']) .'</div>';
      $output .= '<div class="bar">';
      $output .= '<div style="width: '. $percentage .'%;" class="foreground"></div>';
      $output .= '</div>';
      $output .= '<div class="percent">'. $percentage .'%'. (!$block ? ' ('. format_plural($choice['chvotes'], '1 vote', '%count votes') .')' : '') .'</div>';
Steven Wittens's avatar
Steven Wittens committed
  $output .= '<div class="total">'. t('Total votes') .": $votestotal</div>";
Dries Buytaert's avatar
 
Dries Buytaert committed

Steven Wittens's avatar
Steven Wittens committed
  $output .= '</div>';

  return $output;
}

function poll_view_processvote(&$node) {
Steven Wittens's avatar
Steven Wittens committed
  $edit = $_POST['edit'];
  $choice = $edit['choice'];
  $vote = $_POST['vote'];

  if ($vote == t('Vote')) {
    if (isset($choice) && isset($node->choice[$choice])) {
      if ($node->allowvotes) {
        $id = poll_uid();
        $node->voters = $node->voters ? ($node->voters .' '. $id) : $id;
        db_query("UPDATE {poll} SET voters='%s' WHERE nid = %d", $node->voters, $node->nid);
        db_query("UPDATE {poll_choices} SET chvotes = chvotes + 1 WHERE nid = %d AND chorder = %d", $node->nid, $choice);
        $node->allowvotes = false;
        $node->choice[$choice]['chvotes']++;
        drupal_set_message(t('Your vote was recorded.'));
      }
      else {
        drupal_set_message(t("You're not allowed to vote on this poll."), 'error');
      }
    }
    else {
      drupal_set_message(t("You didn't specify a valid poll choice."), 'error');
Steven Wittens's avatar
Steven Wittens committed
    }
/**
 * Implementation of hook_view().
 *
 * @param $block
 *   An extra parameter that adapts the hook to display a block-ready
 *   rendering of the poll.
 */
function poll_view(&$node, $main = 0, $page = 0, $block = 0) {
Dries Buytaert's avatar
 
Dries Buytaert committed
  global $user;
Steven Wittens's avatar
Steven Wittens committed
  if (!$block) {
    // Because the voting form is embedded in the node-display, we process the data here
    poll_view_processvote($node);
  }
Steven Wittens's avatar
Steven Wittens committed
  if ($node->allowvotes && (arg(2) != $node->nid || arg(3) != 'results')) {
    $output .= poll_view_voting($node, $main, $page, $block);
  }
  else {
    $output .= poll_view_results($node, $main, $page, $block);
  }
Steven Wittens's avatar
Steven Wittens committed
  // Special display for side-block
  if ($block) {
Steven Wittens's avatar
Steven Wittens committed
    // No 'read more' link
    $node->body = $node->teaser = '';
Steven Wittens's avatar
Steven Wittens committed
    $links = link_node($node, $main);
Steven Wittens's avatar
Steven Wittens committed
    $links[] = l(t('older polls'), 'poll', array('title' => t('View the list of polls on this site.')));
Steven Wittens's avatar
Steven Wittens committed
    $output .= '<div class="links">'. theme("links", $links) .'</div>';
  }

  $node->body = $node->teaser = $output;
  // We also use poll_view() for the side-block
  if (!$block) {
Steven Wittens's avatar
Steven Wittens committed
    return theme('node', $node, $main, $page);
function poll_update($node) {
Steven Wittens's avatar
Steven Wittens committed
  db_query('UPDATE {poll} SET runtime = %d, active = %d WHERE nid = %d', $node->runtime, $node->active, $node->nid);
Steven Wittens's avatar
Steven Wittens committed
  db_query('DELETE FROM {poll_choices} WHERE nid = %d', $node->nid);
  foreach ($node->choice as $choice) {
    $chvotes = (int)$choice['chvotes'];
    $chtext = $choice['chtext'];
Steven Wittens's avatar
Steven Wittens committed
    if ($chtext != '') {
      db_query("INSERT INTO {poll_choices} (nid, chtext, chvotes, chorder) VALUES (%d, '%s', %d, %d)", $node->nid, $chtext, $chvotes, $i++);