poll.module 11 KB
Newer Older
1
<?php
2
// $Id$
3

4 5 6
function poll_access($op, $node) {
  if ($op == "view") {
    return $node->status;
7 8
  }

9 10
  if ($op == "create") {
    return 1;
Dries's avatar
 
Dries committed
11
  }
Steven Wittens's avatar
Steven Wittens committed
12 13
}

14
function poll_block() {
15
  $timestamp = db_result(db_query("SELECT MAX(created) FROM node WHERE type='poll' AND status='1' AND moderate='0'"));
16
  if ($timestamp) {
17
    $poll = node_load(array("type" => "poll", "created" => $timestamp, "moderate" => "0", "status" => "1"));
18 19
    if ($poll->nid) {
      // Poll_view dumps the output into $poll->body
Steven Wittens's avatar
Steven Wittens committed
20
      poll_view($poll, 1, 1);
21 22
    }
  }
Dries's avatar
 
Dries committed
23
  $blocks[0][subject] = t("Latest poll: %t", array("%t" => $poll->title));
24
  $blocks[0][content] = $poll->body;
25
  $blocks[0][info] = t("Most recent poll");
26
  return $blocks;
27 28
}

29 30
function poll_cron() {
  // Close polls that have exceeded their allowed runtime
Kjartan's avatar
Kjartan committed
31
  $result = db_query("SELECT p.nid FROM poll p LEFT JOIN node n ON p.nid=n.nid WHERE (n.created + p.runtime) < '". time() ."' AND p.active = '1' AND p.runtime != '0'");
Dries's avatar
 
Dries committed
32
  while ($poll = db_fetch_object($result)) {
Steven Wittens's avatar
Steven Wittens committed
33
    db_query("UPDATE poll SET active='0' WHERE nid='$poll->nid'");
Dries's avatar
 
Dries committed
34
  }
35 36
}

37 38 39
function poll_delete($node) {
  db_query("DELETE FROM poll WHERE nid='$node->nid'");
  db_query("DELETE FROM poll_choices WHERE nid='$node->nid'");
40 41
}

42 43
function poll_form(&$node, &$help, &$error) {
  $admin = user_access("administer nodes");
44

45
  $_duration = array(0 => t("Unlimited"), 86400 => format_interval(86400), 172800 => format_interval(172800), 345600 => format_interval(345600), 604800 => format_interval(604800), 1209600 => format_interval(1209600), 2419200 => format_interval(2419200), 4838400 => format_interval(4838400), 9676800 => format_interval(9676800), 31536000 => format_interval(31536000));
Steven Wittens's avatar
Steven Wittens committed
46
  $_active = array(0 => t("Closed"), 1 => t("Active"));
Dries's avatar
 
Dries committed
47

Steven Wittens's avatar
Steven Wittens committed
48
  $node->choices = $node->choices ? $node->choices : max(2, count($node->choice) ? count($node->choice) : 5);
49

50 51 52 53 54 55
  if (isset($node->title)) {
    // Check for at least two options and validate amount of votes:
    for ($i = 0; $i < $node->choices; $i++) {
      if ($node->choice[$i] != "") {
        $actualchoices++;
      }
Dries's avatar
 
Dries committed
56

57
      if ($node->chvotes[$i] < 0) {
Kjartan's avatar
Kjartan committed
58
        $error["chvotes][$i"] = "<span style=\"color: red;\">". t("Negative values are not allowed.") ."</span>";
59
      }
60
    }
Dries's avatar
 
Dries committed
61

62
    if ($actualchoices < 2) {
Kjartan's avatar
Kjartan committed
63
      $error["choice][0"] = "<span style=\"color: red;\">". t("You must fill in at least two choices.") ."</span>";
64 65 66 67 68
    }
  }
  else {
    $help = variable_get("poll_help", "");
  }
Dries's avatar
 
Dries committed
69

70 71 72 73
  if (function_exists("taxonomy_node_form")) {
    $output = implode("", taxonomy_node_form("poll", $node));
  }

74 75 76 77
  for ($c = 2; $c <= 20; $c++) {
    $opts[$c] = $c;
  }
  $output .= form_select(t("Number of choices"), "choices", $node->choices, $opts, t("This item only specifies the number of boxes in this form, but it doesn't have to equal the actual amount of options: you can leave the extra boxes empty."));
Kjartan's avatar
Kjartan committed
78
  $output .= form_submit(t("Preview")) ."<br /><br /><br />";
Dries's avatar
 
Dries committed
79

80
  for ($a = 0; $a < $node->choices; $a++) {
Kjartan's avatar
Kjartan committed
81
    $output .= form_textfield(t("Choice") ." ". ($a + 1), "choice][$a", $node->choice[$a], 50, 127, $error["choice][$a"]);
82
    if ($admin) {
Dries's avatar
 
Dries committed
83
      $output .= form_textfield(t("Votes for choice %n", array("%n" => ($a + 1))), "chvotes][$a", $node->chvotes[$a] ? $node->chvotes[$a] : 0, 7, 7, $error["chvotes][$a"]);
84 85
    }
  }
Dries's avatar
 
Dries committed
86

87 88 89
  if ($admin) {
    $output .= form_select(t("Poll status"), "active", isset($node->active) ? $node->active : 1, $_active);
  }
90

91
  $output .= form_select(t("Poll duration"), "runtime", $node->runtime ? $node->runtime : 0, $_duration, t("After this period, the poll will automatically be closed."));
92

93 94
  return $output;
}
Dries's avatar
 
Dries committed
95

96
function poll_help() {
Steven Wittens's avatar
Steven Wittens committed
97
 ?><p>Drupal's poll module allows users to submit multiple-choice questions that others can vote on.</p>
98 99
 <?php
}
100

101 102 103
function poll_insert($node) {
  if (!user_access("administer nodes")) {
    // Make sure all votes are 0 initially
Kjartan's avatar
Kjartan committed
104
    for ($i = 0; $i < count($node->chvotes); $i++) $node->chvotes[$i] = 0;
105 106
    $node->active = 1;
  }
107

108
  db_query("INSERT INTO poll (nid, runtime, voters, active) VALUES ('$node->nid', '$node->runtime', '', '$node->active')");
Dries's avatar
 
Dries committed
109

110 111 112 113
  for ($i = 0; $i < $node->choices; $i++) {
    $choice->chtext = filter($node->choice[$i]);
    $choice->chvotes = (int)$node->chvotes[$i];
    $choice->chorder = $i;
Dries's avatar
 
Dries committed
114

115 116 117 118
    if ($choice->chtext != "") {
      db_query("INSERT INTO poll_choices (nid, chtext, chvotes, chorder) VALUES ('$node->nid', '$choice->chtext', '$choice->chvotes', '$choice->chorder')");
    }
  }
119 120
}

121 122
function poll_link($type) {
  if ($type == "menu.create" && user_access("post content")) {
Dries's avatar
 
Dries committed
123
    $links[] = lm(t("create poll"), array("mod" => "node", "op" => "add", "type" => "poll"), "", array("title" => t("Add a new poll.")));
124
  }
125

126 127
  return $links ? $links : array();
}
Dries's avatar
 
Dries committed
128

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

133 134 135 136 137 138 139
  $result = db_query("SELECT chtext, chvotes, chorder FROM poll_choices WHERE nid='$node->nid' ORDER BY chorder");
  while ($choice = db_fetch_object($result)) {
    $poll->choice[$choice->chorder]  = $choice->chtext;
    $poll->chvotes[$choice->chorder] = $choice->chvotes;
  }
  return $poll;
}
Dries's avatar
 
Dries committed
140

141 142 143
function poll_node($field) {
  $info["name"] = t("poll");
  $info["description"] = t("A poll is a multiple-choice question which visitors can vote on.");
Dries's avatar
 
Dries committed
144

145 146
  return $info[$field];
}
147

148 149 150
function poll_perm() {
  return array("vote on polls");
}
Dries's avatar
 
Dries committed
151

152 153 154
function poll_save($op, $node) {
  if ($op == "approve") {
    return array("status" => 1, "promote" => 1);
155
  }
Dries's avatar
 
Dries committed
156

157 158 159 160 161 162 163
  if ($op == "create") {
    if (user_access("administer nodes")) {
      return array("runtime", "active", "choice", "choices", "chvotes", "body" => "", "teaser" => poll_teaser($node));
    }
    else {
      return array("runtime", "active", "choice", "choices", "chvotes", "body" => "", "moderate" => 1, "teaser" => poll_teaser($node));
    }
164
  }
Dries's avatar
 
Dries committed
165

166 167
  if ($op == "decline") {
    return array("status" => 0, "promote" => 0);
168 169
  }

170 171 172
  if ($op == "update") {
    return array("runtime", "active", "choice", "choices", "chvotes");
  }
173 174
}

175 176 177 178 179 180 181 182 183
function poll_teaser($node) {
  // Create a simple teaser that lists all the choices
  foreach ($node->choice as $k => $v) {
    if ($v != "") {
      $teaser .= "* $v\n";
    }
  }
  return $teaser;
}
184

185 186
function poll_view(&$node, $main = 0, $block = 0) {
  global $theme, $user;
Dries's avatar
 
Dries committed
187

188
  /* When a poll is displayed twice on the same page (e.g. on the front page and in the side bar)
Dries's avatar
 
Dries committed
189
     we only want to vote on one of them. We keep count using $pollid */
Dries's avatar
 
Dries committed
190
  global $pollidcount, $pollvote, $pollid, $REMOTE_ADDR;
191
  $pollidcount++;
Dries's avatar
 
Dries committed
192

193 194 195 196 197
  // Only accept votes on specific cases to prevent double voting
  $allowvotes = false;
  if (user_access("vote on polls")) {
    if ($user->uid) {
      // Pad the UID with underscores to allow a simple strstr() search
Kjartan's avatar
Kjartan committed
198
      $id = "_". $user->uid ."_";
199 200 201 202 203 204 205
    }
    else {
      $id = $REMOTE_ADDR;
    }
    if (!strstr($node->voters, $id)) {
      $allowvotes = $node->active;
    }
Dries's avatar
 
Dries committed
206
  }
207 208 209

  if (($pollid == $pollidcount) && isset($pollvote) && ($allowvotes)) {
    // The user has submitted a valid vote
Dries's avatar
 
Dries committed
210
    if (!empty($node->choice[$pollvote])) {
Kjartan's avatar
Kjartan committed
211
      $node->voters = $node->voters ? ($node->voters ." ". $id) : $id;
212 213 214 215 216
      db_query("UPDATE poll SET voters='$node->voters' WHERE nid='$node->nid'");
      db_query("UPDATE poll_choices SET chvotes = chvotes + 1 WHERE nid='$node->nid' AND chorder='$pollvote'");
      $allowvotes = false;
      $node->chvotes[$pollvote]++;
    }
217
  }
Dries's avatar
 
Dries committed
218

219 220
  if ($allowvotes) {
    // Display the vote form
Kjartan's avatar
Kjartan committed
221
    $url = request_uri() . (strstr(request_uri(), "?") ? "&amp;" : "?") ."pollid=". $pollidcount;
222 223 224 225 226 227 228 229 230
    $output .= "<form action=\"$url\" method=\"post\">";
    $output .= "<table border=\"0\" align=\"center\"><tr><td>";

    foreach ($node->choice as $key => $value) {
      if ($value != "") {
        $output .= "<input type=\"radio\" name=\"pollvote\" value=\"$key\" /> $value<br />";
      }
    }
    if ($block) {
Kjartan's avatar
Kjartan committed
231
      $output .= "</td></tr><tr><td><div align=\"center\">". form_submit(t("Vote")) ."</div></td></tr></table>";
Kjartan's avatar
Kjartan committed
232 233
    }
    else {
Kjartan's avatar
Kjartan committed
234
      $output .= "</td><td valign=\"middle\"><div align=\"right\">&nbsp;&nbsp;&nbsp;". form_submit(t("Vote")) ."</div></td></tr></table>";
235
    }
Steven Wittens's avatar
Steven Wittens committed
236
    $output .= $block ? "<div align=\"center\">". $theme->links(link_node($node, $main)) ."</div>" : "";
237
    $output .= "</form>";
238
  }
Dries's avatar
 
Dries committed
239
  else {
240
    // Display the results
Dries's avatar
 
Dries committed
241

242 243 244 245 246 247
    // Count the votes and find the maximum
    foreach ($node->choice as $key => $value) {
      $votestotal += $node->chvotes[$key];
      $votesmax = max($votesmax, $node->chvotes[$key]);
    }
    $votesmax = max($votesmax, 1);
Dries's avatar
 
Dries committed
248

249
    // Define CSS classes for the bars
250 251 252 253
    $output .= "<style type=\"text/css\">";
    $output .= "td.pollfg { background-color: ". $theme->foreground ."; font-size: 5pt; }";
    $output .= "td.pollbg { background-color: ". $theme->background ."; font-size: 5pt; }";
    $output .= "</style>";
Dries's avatar
 
Dries committed
254

255 256 257 258 259
    foreach ($node->choice as $key => $value) {
      if ($value != "") {
        $width = round($node->chvotes[$key] * 100 / $votesmax);
        $percentage = round($node->chvotes[$key] * 100 / max($votestotal, 1));

Steven Wittens's avatar
Steven Wittens committed
260
        $output .= "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"95%\" align=\"center\"><tr><td>$value</td><td><div align=\"right\"> $percentage%". (!$block ? " (". format_plural($node->chvotes[$key], "vote", "votes") .")" : "") ."</div></td></tr></table>";
261
        if ($width == 0) {
Dries's avatar
 
Dries committed
262
          $output .= "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"95%\" align=\"center\"><tr><td class=\"pollbg\" width=\"100%\">&nbsp;</td></tr></table>";
263 264 265 266 267
        }
        else if ($width == 100) {
          $output .= "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"95%\" align=\"center\"><tr><td class=\"pollfg\" width=\"100%\">&nbsp;</td></tr></table>";
        }
        else {
Kjartan's avatar
Kjartan committed
268
          $output .= "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"95%\" align=\"center\"><tr><td class=\"pollfg\" width=\"". $width ."%\">&nbsp;</td><td class=\"pollbg\" width=\"". (100 - $width) ."%\">&nbsp;</td></tr></table>";
269
        }
Dries's avatar
 
Dries committed
270
      }
271
    }
Steven Wittens's avatar
Steven Wittens committed
272 273 274 275
    if ($block) {
      // Prevent a 'read more' link in the side-block.
      $node->body = $node->teaser = "";
    }
Steven Wittens's avatar
Steven Wittens committed
276
    $output .= "<br /><div align=\"center\">Total votes: ". $votestotal . ($block ? "<br />". $theme->links(link_node($node, $main)) : "") ."</div>";
277
  }
278 279 280
  // Force the output on both the mainpage and elsewhere
  $node->body = $output;
  $node->teaser = $output;
281

282 283 284
  // We also use poll_view() for the side-block
  if ($block == 0) {
    $theme->node($node, $main);
285 286 287
  }
}

288 289 290 291 292 293 294
function poll_update($node) {
  db_query("UPDATE poll SET runtime='$node->runtime', active='$node->active' WHERE nid='$node->nid'");

  db_query("DELETE FROM poll_choices WHERE nid='$node->nid'");
  for ($i = 0; $i < $node->choices; $i++) {
    $choice->chtext = filter($node->choice[$i]);
    $choice->chvotes = (int)$node->chvotes[$i];
Dries's avatar
 
Dries committed
295
    $choice->chorder = $i;
296

297 298 299
    if ($choice->chtext != "") {
      db_query("INSERT INTO poll_choices (nid, chtext, chvotes, chorder) VALUES ('$node->nid', '$choice->chtext', '$choice->chvotes', '$choice->chorder')");
    }
300 301
  }
}
302

303
?>