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

4
5
6
7
8
function poll_system($field){
  $system["description"] = t("Enables submission of multiple choice questions for voting.");
  return $system[$field];
}

9
10
11
function poll_access($op, $node) {
  if ($op == "view") {
    return $node->status;
12
13
  }

14
15
  if ($op == "create") {
    return 1;
Dries's avatar
   
Dries committed
16
  }
Steven Wittens's avatar
Steven Wittens committed
17
18
}

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

34
35
function poll_cron() {
  // Close polls that have exceeded their allowed runtime
Kjartan's avatar
Kjartan committed
36
  $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
37
  while ($poll = db_fetch_object($result)) {
Steven Wittens's avatar
Steven Wittens committed
38
    db_query("UPDATE poll SET active='0' WHERE nid='$poll->nid'");
Dries's avatar
   
Dries committed
39
  }
40
41
}

42
43
44
function poll_delete($node) {
  db_query("DELETE FROM poll WHERE nid='$node->nid'");
  db_query("DELETE FROM poll_choices WHERE nid='$node->nid'");
45
46
}

47
48
function poll_form(&$node, &$help, &$error) {
  $admin = user_access("administer nodes");
49

50
  $_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
51
  $_active = array(0 => t("Closed"), 1 => t("Active"));
Dries's avatar
   
Dries committed
52

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

55
56
57
58
59
60
  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
61

62
      if ($node->chvotes[$i] < 0) {
Kjartan's avatar
Kjartan committed
63
        $error["chvotes][$i"] = "<span style=\"color: red;\">". t("Negative values are not allowed.") ."</span>";
64
      }
65
    }
Dries's avatar
   
Dries committed
66

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

75
76
77
78
  if (function_exists("taxonomy_node_form")) {
    $output = implode("", taxonomy_node_form("poll", $node));
  }

79
80
81
82
  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
83
  $output .= form_submit(t("Preview")) ."<br /><br /><br />";
Dries's avatar
   
Dries committed
84

85
  for ($a = 0; $a < $node->choices; $a++) {
Kjartan's avatar
Kjartan committed
86
    $output .= form_textfield(t("Choice") ." ". ($a + 1), "choice][$a", $node->choice[$a], 50, 127, $error["choice][$a"]);
87
    if ($admin) {
Dries's avatar
   
Dries committed
88
      $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"]);
89
90
    }
  }
Dries's avatar
   
Dries committed
91

92
93
94
  if ($admin) {
    $output .= form_select(t("Poll status"), "active", isset($node->active) ? $node->active : 1, $_active);
  }
95

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

98
99
  return $output;
}
Dries's avatar
   
Dries committed
100

101
function poll_help() {
Steven Wittens's avatar
Steven Wittens committed
102
 ?><p>Drupal's poll module allows users to submit multiple-choice questions that others can vote on.</p>
103
104
 <?php
}
105

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

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

115
116
117
118
  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
119

120
121
122
123
    if ($choice->chtext != "") {
      db_query("INSERT INTO poll_choices (nid, chtext, chvotes, chorder) VALUES ('$node->nid', '$choice->chtext', '$choice->chvotes', '$choice->chorder')");
    }
  }
124
125
}

126
127
function poll_link($type) {
  if ($type == "menu.create" && user_access("post content")) {
Dries's avatar
   
Dries committed
128
    $links[] = lm(t("create poll"), array("mod" => "node", "op" => "add", "type" => "poll"), "", array("title" => t("Add a new poll.")));
129
  }
Steven Wittens's avatar
Steven Wittens committed
130
131
132
  else if ($type == "page" && user_access("access content")) {
    $links[] = lm(t("polls"), array("mod" => "poll"), "", array("title" => t("View the list of polls on this site.")));
  }
133

134
135
  return $links ? $links : array();
}
Dries's avatar
   
Dries committed
136

137
138
139
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
140

141
142
143
144
145
146
147
  $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
148

149
150
151
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
152

153
154
  return $info[$field];
}
155

Steven Wittens's avatar
Steven Wittens committed
156
157
158
159
function poll_page() {
  global $theme;
  
  $theme->header();
Steven Wittens's avatar
Steven Wittens committed
160
  $result = db_query("SELECT n.nid, n.title, p.active, SUM(c.chvotes) AS votes FROM node n LEFT JOIN poll p ON n.nid=p.nid LEFT JOIN poll_choices c ON n.nid=c.nid WHERE type='poll' AND status='1' AND moderate='0' GROUP BY n.nid ORDER BY n.created DESC");
Steven Wittens's avatar
Steven Wittens committed
161
162
163
164
165
166
167
  while ($node = db_fetch_object($result)) {
    $output .= "<li>". l($node->title, array("id" => $node->nid)) ." - ". format_plural($node->votes, "vote", "votes") ." - ". ($node->active ? t("open") : t("closed")) ."</li>";
  }
  $theme->box(t("Polls"), $output);
  $theme->footer();
}

168
169
170
function poll_perm() {
  return array("vote on polls");
}
Dries's avatar
   
Dries committed
171

172
173
174
function poll_save($op, $node) {
  if ($op == "approve") {
    return array("status" => 1, "promote" => 1);
175
  }
Dries's avatar
   
Dries committed
176

177
178
179
180
181
182
183
  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));
    }
184
  }
Dries's avatar
   
Dries committed
185

186
187
  if ($op == "decline") {
    return array("status" => 0, "promote" => 0);
188
189
  }

190
191
192
  if ($op == "update") {
    return array("runtime", "active", "choice", "choices", "chvotes");
  }
193
194
}

195
196
197
198
199
200
201
202
203
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;
}
204

205
206
function poll_view(&$node, $main = 0, $block = 0) {
  global $theme, $user;
Dries's avatar
   
Dries committed
207

208
  /* 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
209
     we only want to vote on one of them. We keep count using $pollid */
Dries's avatar
   
Dries committed
210
  global $pollidcount, $pollvote, $pollid, $REMOTE_ADDR;
211
  $pollidcount++;
Dries's avatar
   
Dries committed
212

213
214
215
216
217
  // 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
218
      $id = "_". $user->uid ."_";
219
220
221
222
223
224
225
    }
    else {
      $id = $REMOTE_ADDR;
    }
    if (!strstr($node->voters, $id)) {
      $allowvotes = $node->active;
    }
Dries's avatar
   
Dries committed
226
  }
227
228
229

  if (($pollid == $pollidcount) && isset($pollvote) && ($allowvotes)) {
    // The user has submitted a valid vote
Dries's avatar
   
Dries committed
230
    if (!empty($node->choice[$pollvote])) {
Kjartan's avatar
Kjartan committed
231
      $node->voters = $node->voters ? ($node->voters ." ". $id) : $id;
232
233
234
235
236
      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]++;
    }
237
  }
Dries's avatar
   
Dries committed
238

239
240
  if ($allowvotes) {
    // Display the vote form
Kjartan's avatar
Kjartan committed
241
    $url = request_uri() . (strstr(request_uri(), "?") ? "&amp;" : "?") ."pollid=". $pollidcount;
242
243
244
245
246
247
248
249
250
    $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
251
      $output .= "</td></tr><tr><td><div align=\"center\">". form_submit(t("Vote")) ."</div></td></tr></table>";
Kjartan's avatar
Kjartan committed
252
253
    }
    else {
Kjartan's avatar
Kjartan committed
254
      $output .= "</td><td valign=\"middle\"><div align=\"right\">&nbsp;&nbsp;&nbsp;". form_submit(t("Vote")) ."</div></td></tr></table>";
255
    }
Steven Wittens's avatar
Steven Wittens committed
256
257
258
    $links = link_node($node, $main);
    $links[] = lm(t("older polls"), array("mod" => "poll"), "", array("title" => t("View the list of polls on this site.")));
    $output .= $block ? "<div align=\"center\">". $theme->links($links) ."</div>" : "";
259
    $output .= "</form>";
260
  }
Dries's avatar
   
Dries committed
261
  else {
262
    // Display the results
Dries's avatar
   
Dries committed
263

264
265
266
267
268
269
    // 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
270

271
    // Define CSS classes for the bars
272
273
274
275
    $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
276

277
278
279
280
281
    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
282
        $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>";
283
        if ($width == 0) {
Dries's avatar
   
Dries committed
284
          $output .= "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"95%\" align=\"center\"><tr><td class=\"pollbg\" width=\"100%\">&nbsp;</td></tr></table>";
285
286
287
288
289
        }
        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
290
          $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>";
291
        }
Dries's avatar
   
Dries committed
292
      }
293
    }
Steven Wittens's avatar
Steven Wittens committed
294
295
296
297
    if ($block) {
      // Prevent a 'read more' link in the side-block.
      $node->body = $node->teaser = "";
    }
Steven Wittens's avatar
Steven Wittens committed
298
299
300
    $links = link_node($node, $main);
    $links[] = lm(t("older polls"), array("mod" => "poll"), "", array("title" => t("View the list of polls on this site.")));
    $output .= "<br /><div align=\"center\">Total votes: ". $votestotal . ($block ? "<br />". $theme->links($links) : "") ."</div>";
301
  }
302
303
304
  // Force the output on both the mainpage and elsewhere
  $node->body = $output;
  $node->teaser = $output;
305

306
307
308
  // We also use poll_view() for the side-block
  if ($block == 0) {
    $theme->node($node, $main);
309
310
311
  }
}

312
313
314
315
316
317
318
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
319
    $choice->chorder = $i;
320

321
322
323
    if ($choice->chtext != "") {
      db_query("INSERT INTO poll_choices (nid, chtext, chvotes, chorder) VALUES ('$node->nid', '$choice->chtext', '$choice->chvotes', '$choice->chorder')");
    }
324
325
  }
}
326

327
?>