poll.module 12.1 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
  }
Steven Wittens's avatar
Steven Wittens committed
125
126
127
  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.")));
  }
128

129
130
  return $links ? $links : array();
}
Dries's avatar
   
Dries committed
131

132
133
134
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
135

136
137
138
139
140
141
142
  $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
143

144
145
146
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
147

148
149
  return $info[$field];
}
150

Steven Wittens's avatar
Steven Wittens committed
151
152
153
154
function poll_page() {
  global $theme;
  
  $theme->header();
Steven Wittens's avatar
Steven Wittens committed
155
  $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
156
157
158
159
160
161
162
  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();
}

163
164
165
function poll_perm() {
  return array("vote on polls");
}
Dries's avatar
   
Dries committed
166

167
168
169
function poll_save($op, $node) {
  if ($op == "approve") {
    return array("status" => 1, "promote" => 1);
170
  }
Dries's avatar
   
Dries committed
171

172
173
174
175
176
177
178
  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));
    }
179
  }
Dries's avatar
   
Dries committed
180

181
182
  if ($op == "decline") {
    return array("status" => 0, "promote" => 0);
183
184
  }

185
186
187
  if ($op == "update") {
    return array("runtime", "active", "choice", "choices", "chvotes");
  }
188
189
}

190
191
192
193
194
195
196
197
198
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;
}
199

200
201
function poll_view(&$node, $main = 0, $block = 0) {
  global $theme, $user;
Dries's avatar
   
Dries committed
202

203
  /* 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
204
     we only want to vote on one of them. We keep count using $pollid */
Dries's avatar
   
Dries committed
205
  global $pollidcount, $pollvote, $pollid, $REMOTE_ADDR;
206
  $pollidcount++;
Dries's avatar
   
Dries committed
207

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

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

234
235
  if ($allowvotes) {
    // Display the vote form
Kjartan's avatar
Kjartan committed
236
    $url = request_uri() . (strstr(request_uri(), "?") ? "&amp;" : "?") ."pollid=". $pollidcount;
237
238
239
240
241
242
243
244
245
    $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
246
      $output .= "</td></tr><tr><td><div align=\"center\">". form_submit(t("Vote")) ."</div></td></tr></table>";
Kjartan's avatar
Kjartan committed
247
248
    }
    else {
Kjartan's avatar
Kjartan committed
249
      $output .= "</td><td valign=\"middle\"><div align=\"right\">&nbsp;&nbsp;&nbsp;". form_submit(t("Vote")) ."</div></td></tr></table>";
250
    }
Steven Wittens's avatar
Steven Wittens committed
251
252
253
    $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>" : "";
254
    $output .= "</form>";
255
  }
Dries's avatar
   
Dries committed
256
  else {
257
    // Display the results
Dries's avatar
   
Dries committed
258

259
260
261
262
263
264
    // 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
265

266
    // Define CSS classes for the bars
267
268
269
270
    $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
271

272
273
274
275
276
    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
277
        $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>";
278
        if ($width == 0) {
Dries's avatar
   
Dries committed
279
          $output .= "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"95%\" align=\"center\"><tr><td class=\"pollbg\" width=\"100%\">&nbsp;</td></tr></table>";
280
281
282
283
284
        }
        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
285
          $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>";
286
        }
Dries's avatar
   
Dries committed
287
      }
288
    }
Steven Wittens's avatar
Steven Wittens committed
289
290
291
292
    if ($block) {
      // Prevent a 'read more' link in the side-block.
      $node->body = $node->teaser = "";
    }
Steven Wittens's avatar
Steven Wittens committed
293
294
295
    $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>";
296
  }
297
298
299
  // Force the output on both the mainpage and elsewhere
  $node->body = $output;
  $node->teaser = $output;
300

301
302
303
  // We also use poll_view() for the side-block
  if ($block == 0) {
    $theme->node($node, $main);
304
305
306
  }
}

307
308
309
310
311
312
313
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
314
    $choice->chorder = $i;
315

316
317
318
    if ($choice->chtext != "") {
      db_query("INSERT INTO poll_choices (nid, chtext, chvotes, chorder) VALUES ('$node->nid', '$choice->chtext', '$choice->chvotes', '$choice->chorder')");
    }
319
320
  }
}
321

322
?>