poll.module 10.7 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
15
16
17
18
19
function poll_block() {
  $timestamp = db_result(db_query("SELECT MAX(created) FROM node WHERE type='poll' AND status='1'"));
  if ($timestamp) {
    $poll = node_load(array("type" => "poll", "created" => $timestamp, "status" => "1"));
    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
  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
74
  $output .= form_submit(t("Preview")) ."<br /><br /><br />";
Dries's avatar
   
Dries committed
75

76
  for ($a = 0; $a < $node->choices; $a++) {
Kjartan's avatar
Kjartan committed
77
    $output .= form_textfield(t("Choice") ." ". ($a + 1), "choice][$a", $node->choice[$a], 50, 127, $error["choice][$a"]);
78
    if ($admin) {
Dries's avatar
   
Dries committed
79
      $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"]);
80
81
    }
  }
Dries's avatar
   
Dries committed
82

83
84
85
  if ($admin) {
    $output .= form_select(t("Poll status"), "active", isset($node->active) ? $node->active : 1, $_active);
  }
86

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

89
90
  return $output;
}
Dries's avatar
   
Dries committed
91

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

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

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

106
107
108
109
  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
110

111
112
113
114
    if ($choice->chtext != "") {
      db_query("INSERT INTO poll_choices (nid, chtext, chvotes, chorder) VALUES ('$node->nid', '$choice->chtext', '$choice->chvotes', '$choice->chorder')");
    }
  }
115
116
}

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

122
123
  return $links ? $links : array();
}
Dries's avatar
   
Dries committed
124

125
126
127
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
128

129
130
131
132
133
134
135
  $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
136

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

141
142
  return $info[$field];
}
143

144
145
146
function poll_perm() {
  return array("vote on polls");
}
Dries's avatar
   
Dries committed
147

148
149
150
function poll_save($op, $node) {
  if ($op == "approve") {
    return array("status" => 1, "promote" => 1);
151
  }
Dries's avatar
   
Dries committed
152

153
154
155
156
157
158
159
  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));
    }
160
  }
Dries's avatar
   
Dries committed
161

162
163
  if ($op == "decline") {
    return array("status" => 0, "promote" => 0);
164
165
  }

166
167
168
  if ($op == "update") {
    return array("runtime", "active", "choice", "choices", "chvotes");
  }
169
170
}

171
172
173
174
175
176
177
178
179
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;
}
180

181
182
function poll_view(&$node, $main = 0, $block = 0) {
  global $theme, $user;
Dries's avatar
   
Dries committed
183

184
  /* 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
185
     we only want to vote on one of them. We keep count using $pollid */
Dries's avatar
   
Dries committed
186
  global $pollidcount, $pollvote, $pollid, $REMOTE_ADDR;
187
  $pollidcount++;
Dries's avatar
   
Dries committed
188

189
190
191
192
193
  // 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
194
      $id = "_". $user->uid ."_";
195
196
197
198
199
200
201
    }
    else {
      $id = $REMOTE_ADDR;
    }
    if (!strstr($node->voters, $id)) {
      $allowvotes = $node->active;
    }
Dries's avatar
   
Dries committed
202
  }
203
204
205

  if (($pollid == $pollidcount) && isset($pollvote) && ($allowvotes)) {
    // The user has submitted a valid vote
Dries's avatar
   
Dries committed
206
    if (!empty($node->choice[$pollvote])) {
Kjartan's avatar
Kjartan committed
207
      $node->voters = $node->voters ? ($node->voters ." ". $id) : $id;
208
209
210
211
212
      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]++;
    }
213
  }
Dries's avatar
   
Dries committed
214

215
216
  if ($allowvotes) {
    // Display the vote form
Kjartan's avatar
Kjartan committed
217
    $url = request_uri() . (strstr(request_uri(), "?") ? "&amp;" : "?") ."pollid=". $pollidcount;
218
219
220
221
222
223
224
225
226
    $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
227
      $output .= "</td></tr><tr><td><div align=\"center\">". form_submit(t("Vote")) ."</div></td></tr></table>";
Kjartan's avatar
Kjartan committed
228
229
    }
    else {
Kjartan's avatar
Kjartan committed
230
      $output .= "</td><td valign=\"middle\"><div align=\"right\">&nbsp;&nbsp;&nbsp;". form_submit(t("Vote")) ."</div></td></tr></table>";
231
232
    }
    $output .= "</form>";
233
  }
Dries's avatar
   
Dries committed
234
  else {
235
    // Display the results
Dries's avatar
   
Dries committed
236

237
238
239
240
241
242
    // 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
243

244
    // Define CSS classes for the bars
245
246
247
248
    $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
249

250
251
252
253
254
    foreach ($node->choice as $key => $value) {
      if ($value != "") {
        $width = round($node->chvotes[$key] * 100 / $votesmax);
        $percentage = round($node->chvotes[$key] * 100 / max($votestotal, 1));

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

277
278
279
  // We also use poll_view() for the side-block
  if ($block == 0) {
    $theme->node($node, $main);
280
281
282
  }
}

283
284
285
286
287
288
289
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
290
    $choice->chorder = $i;
291

292
293
294
    if ($choice->chtext != "") {
      db_query("INSERT INTO poll_choices (nid, chtext, chvotes, chorder) VALUES ('$node->nid', '$choice->chtext', '$choice->chvotes', '$choice->chorder')");
    }
295
296
  }
}
297

298
?>