[ Index ] |
|
Code source de Drupal 5.3 |
1 <?php 2 // $Id: poll.module,v 1.222.2.2 2007/10/07 00:21:18 drumm Exp $ 3 4 /** 5 * @file 6 * Enables your site to capture votes on different topics in the form of multiple 7 * choice questions. 8 */ 9 10 /** 11 * Implementation of hook_help(). 12 */ 13 function poll_help($section) { 14 switch ($section) { 15 case 'admin/help#poll': 16 $output = '<p>'. t('The poll module can be used to create simple polls for site users. A poll is a simple multiple choice questionnaire which displays the cumulative results of the answers to the poll. Having polls on the site is a good way to get instant feedback from community members.') .'</p>'; 17 $output .= '<p>'. t('Users can create a poll. 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.The <a href="@poll">poll</a> item in the navigation menu 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.', array('@poll' => url('poll'))) .'</p>'; 18 $output .= '<p>'. t('For more information please read the configuration and customization handbook <a href="@poll">Poll page</a>.', array('@poll' => 'http://drupal.org/handbook/modules/poll/')) .'</p>'; 19 return $output; 20 } 21 } 22 23 /** 24 * Implementation of hook_access(). 25 */ 26 function poll_access($op, $node) { 27 if ($op == 'create') { 28 return user_access('create polls'); 29 } 30 } 31 32 /** 33 * Implementation of hook_block(). 34 * 35 * Generates a block containing the latest poll. 36 */ 37 function poll_block($op = 'list', $delta = 0) { 38 if (user_access('access content')) { 39 if ($op == 'list') { 40 $blocks[0]['info'] = t('Most recent poll'); 41 return $blocks; 42 } 43 else if ($op == 'view') { 44 // Retrieve the latest poll. 45 $sql = db_rewrite_sql("SELECT MAX(n.created) FROM {node} n INNER JOIN {poll} p ON p.nid = n.nid WHERE n.status = 1 AND p.active = 1"); 46 $timestamp = db_result(db_query($sql)); 47 if ($timestamp) { 48 $poll = node_load(array('type' => 'poll', 'created' => $timestamp, 'status' => 1)); 49 50 if ($poll->nid) { 51 $poll = poll_view($poll, TRUE, FALSE, TRUE); 52 } 53 } 54 $block['subject'] = t('Poll'); 55 $block['content'] = drupal_render($poll->content); 56 return $block; 57 } 58 } 59 } 60 61 /** 62 * Implementation of hook_cron(). 63 * 64 * Closes polls that have exceeded their allowed runtime. 65 */ 66 function poll_cron() { 67 $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'); 68 while ($poll = db_fetch_object($result)) { 69 db_query("UPDATE {poll} SET active = 0 WHERE nid = %d", $poll->nid); 70 } 71 } 72 73 /** 74 * Implementation of hook_delete(). 75 */ 76 function poll_delete($node) { 77 db_query("DELETE FROM {poll} WHERE nid = %d", $node->nid); 78 db_query("DELETE FROM {poll_choices} WHERE nid = %d", $node->nid); 79 db_query("DELETE FROM {poll_votes} WHERE nid = %d", $node->nid); 80 } 81 82 /** 83 * Implementation of hook_submit(). 84 */ 85 function poll_submit(&$node) { 86 // Renumber fields 87 $node->choice = array_values($node->choice); 88 $node->teaser = poll_teaser($node); 89 } 90 91 /** 92 * Implementation of hook_validate(). 93 */ 94 function poll_validate($node) { 95 if (isset($node->title)) { 96 // Check for at least two options and validate amount of votes: 97 $realchoices = 0; 98 // Renumber fields 99 $node->choice = array_values($node->choice); 100 foreach ($node->choice as $i => $choice) { 101 if ($choice['chtext'] != '') { 102 $realchoices++; 103 } 104 if ($choice['chvotes'] < 0) { 105 form_set_error("choice][$i][chvotes", t('Negative values are not allowed.')); 106 } 107 } 108 109 if ($realchoices < 2) { 110 form_set_error("choice][$realchoices][chtext", t('You must fill in at least two choices.')); 111 } 112 } 113 } 114 115 /** 116 * Implementation of hook_form(). 117 */ 118 function poll_form($node, $form_values = NULL) { 119 $admin = user_access('administer nodes'); 120 $type = node_get_types('type', $node); 121 $form['title'] = array( 122 '#type' => 'textfield', 123 '#title' => check_plain($type->title_label), 124 '#required' => TRUE, 125 '#default_value' => $node->title, 126 '#weight' => -1 127 ); 128 129 if (isset($form_values)) { 130 $choices = $form_values['choices']; 131 if ($form_values['morechoices']) { 132 $choices *= 2; 133 } 134 } 135 else { 136 $choices = max(2, count($node->choice) ? count($node->choice) : 5); 137 } 138 139 $form['choices'] = array( 140 '#type' => 'hidden', 141 '#value' => $choices, 142 ); 143 144 // Poll choices 145 $form['choice'] = array( 146 '#type' => 'fieldset', 147 '#title' => t('Choices'), 148 '#prefix' => '<div class="poll-form">', 149 '#suffix' => '</div>', 150 '#tree' => TRUE 151 ); 152 153 // We'll manually set the #parents property of this checkbox so that 154 // it appears in the fieldset visually, but its value won't pollute 155 // the $form_values['choice'] array. 156 $form['choice']['morechoices'] = array( 157 '#type' => 'checkbox', 158 '#parents' => array('morechoices'), 159 '#title' => t('Need more choices'), 160 '#value' => 0, 161 '#description' => t("If the amount of boxes above isn't enough, check this box and click the Preview button below to add some more."), 162 '#weight' => 1, 163 ); 164 165 for ($a = 0; $a < $choices; $a++) { 166 $form['choice'][$a]['chtext'] = array( 167 '#type' => 'textfield', 168 '#title' => t('Choice @n', array('@n' => ($a + 1))), 169 '#default_value' => $node->choice[$a]['chtext'], 170 ); 171 172 if ($admin) { 173 $form['choice'][$a]['chvotes'] = array( 174 '#type' => 'textfield', 175 '#title' => t('Votes for choice @n', array('@n' => ($a + 1))), 176 '#default_value' => (int)$node->choice[$a]['chvotes'], 177 '#size' => 5, '#maxlength' => 7 178 ); 179 } 180 } 181 182 // Poll attributes 183 $_duration = array(0 => t('Unlimited')) + drupal_map_assoc(array(86400, 172800, 345600, 604800, 1209600, 2419200, 4838400, 9676800, 31536000), "format_interval"); 184 $_active = array(0 => t('Closed'), 1 => t('Active')); 185 186 if ($admin) { 187 $form['settings'] = array('#type' => 'fieldset', '#title' => t('Settings')); 188 189 $form['settings']['active'] = array( 190 '#type' => 'radios', 191 '#title' => t('Poll status'), 192 '#default_value' => isset($node->active) ? $node->active : 1, 193 '#options' => $_active, 194 '#description' => t('When a poll is closed, visitors can no longer vote for it.') 195 ); 196 } 197 $form['settings']['runtime'] = array( 198 '#type' => 'select', 199 '#title' => t('Poll duration'), 200 '#default_value' => $node->runtime, 201 '#options' => $_duration, 202 '#description' => t('After this period, the poll will be closed automatically.'), 203 ); 204 205 $form['#multistep'] = TRUE; 206 return $form; 207 } 208 209 function poll_insert($node) { 210 if (!user_access('administer nodes')) { 211 // Make sure all votes are 0 initially 212 foreach ($node->choice as $i => $choice) { 213 $node->choice[$i]['chvotes'] = 0; 214 } 215 $node->active = 1; 216 } 217 218 db_query("INSERT INTO {poll} (nid, runtime, active) VALUES (%d, %d, %d)", $node->nid, $node->runtime, $node->active); 219 220 foreach ($node->choice as $choice) { 221 if ($choice['chtext'] != '') { 222 db_query("INSERT INTO {poll_choices} (nid, chtext, chvotes, chorder) VALUES (%d, '%s', %d, %d)", $node->nid, $choice['chtext'], $choice['chvotes'], $i++); 223 } 224 } 225 } 226 227 /** 228 * Implementation of hook_menu(). 229 */ 230 function poll_menu($may_cache) { 231 $items = array(); 232 233 if ($may_cache) { 234 $items[] = array('path' => 'poll', 'title' => t('Polls'), 235 'callback' => 'poll_page', 236 'access' => user_access('access content'), 237 'type' => MENU_SUGGESTED_ITEM); 238 239 $items[] = array('path' => 'poll/vote', 240 'title' => t('Vote'), 241 'callback' => 'poll_vote', 242 'access' => user_access('vote on polls'), 243 'type' => MENU_CALLBACK); 244 245 $items[] = array('path' => 'poll/cancel', 246 'title' => t('Cancel'), 247 'callback' => 'poll_cancel', 248 'access' => user_access('cancel own vote'), 249 'type' => MENU_CALLBACK); 250 } 251 else { 252 // Add the CSS for this module 253 // We put this in !$may_cache so it's only added once per request 254 drupal_add_css(drupal_get_path('module', 'poll') .'/poll.css'); 255 256 if (arg(0) == 'node' && is_numeric(arg(1))) { 257 $node = node_load(arg(1)); 258 if ($node->type == 'poll') { 259 $items[] = array('path' => 'node/'. arg(1) .'/votes', 260 'title' => t('Votes'), 261 'callback' => 'poll_votes', 262 'access' => user_access('inspect all votes'), 263 'weight' => 3, 264 'type' => MENU_LOCAL_TASK); 265 } 266 if ($node->type == 'poll' && $node->allowvotes) { 267 $items[] = array('path' => 'node/'. arg(1) .'/results', 268 'title' => t('Results'), 269 'callback' => 'poll_results', 270 'access' => user_access('access content'), 271 'weight' => 3, 272 'type' => MENU_LOCAL_TASK); 273 } 274 } 275 } 276 277 return $items; 278 } 279 280 /** 281 * Implementation of hook_load(). 282 */ 283 function poll_load($node) { 284 global $user; 285 286 // Load the appropriate choices into the $node object 287 $poll = db_fetch_object(db_query("SELECT runtime, active FROM {poll} WHERE nid = %d", $node->nid)); 288 289 $result = db_query("SELECT chtext, chvotes, chorder FROM {poll_choices} WHERE nid = %d ORDER BY chorder", $node->nid); 290 while ($choice = db_fetch_array($result)) { 291 $poll->choice[$choice['chorder']] = $choice; 292 } 293 294 // Determine whether or not this user is allowed to vote 295 $poll->allowvotes = FALSE; 296 if (user_access('vote on polls') && $poll->active) { 297 if ($user->uid) { 298 $result = db_fetch_object(db_query('SELECT chorder FROM {poll_votes} WHERE nid = %d AND uid = %d', $node->nid, $user->uid)); 299 } 300 else { 301 $result = db_fetch_object(db_query("SELECT chorder FROM {poll_votes} WHERE nid = %d AND hostname = '%s'", $node->nid, $_SERVER['REMOTE_ADDR'])); 302 } 303 if (isset($result->chorder)) { 304 $poll->vote = $result->chorder; 305 } 306 else { 307 $poll->vote = -1; 308 $poll->allowvotes = TRUE; 309 } 310 } 311 return $poll; 312 } 313 314 /** 315 * Implementation of hook_node_info(). 316 */ 317 function poll_node_info() { 318 return array( 319 'poll' => array( 320 'name' => t('Poll'), 321 'module' => 'poll', 322 'description' => t("A poll is a multiple-choice question which visitors can vote on."), 323 'title_label' => t('Question'), 324 'has_body' => FALSE, 325 ) 326 ); 327 } 328 329 function poll_page() { 330 // List all polls. 331 $sql = "SELECT n.nid, n.title, p.active, n.created, 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 n.status = 1 GROUP BY n.nid, n.title, p.active, n.created ORDER BY n.created DESC"; 332 // Count all polls for the pager. 333 $count_sql = 'SELECT COUNT(*) FROM {node} n INNER JOIN {poll} p ON n.nid = p.nid WHERE n.status = 1'; 334 $sql = db_rewrite_sql($sql); 335 $result = pager_query($sql, 15, 0, $count_sql); 336 $output = '<ul>'; 337 while ($node = db_fetch_object($result)) { 338 $output .= '<li>'. l($node->title, "node/$node->nid") .' - '. format_plural($node->votes, '1 vote', '@count votes') .' - '. ($node->active ? t('open') : t('closed')) .'</li>'; 339 } 340 $output .= '</ul>'; 341 $output .= theme("pager", NULL, 15); 342 return $output; 343 } 344 345 /** 346 * Implementation of hook_perm(). 347 */ 348 function poll_perm() { 349 return array('create polls', 'vote on polls', 'cancel own vote', 'inspect all votes'); 350 } 351 352 /** 353 * Creates a simple teaser that lists all the choices. 354 */ 355 function poll_teaser($node) { 356 $teaser = NULL; 357 if (is_array($node->choice)) { 358 foreach ($node->choice as $k => $choice) { 359 if ($choice['chtext'] != '') { 360 $teaser .= '* '. check_plain($choice['chtext']) ."\n"; 361 } 362 } 363 } 364 return $teaser; 365 } 366 367 /** 368 * Generates the voting form for a poll. 369 */ 370 function poll_view_voting($node, $block) { 371 if ($node->choice) { 372 $list = array(); 373 foreach ($node->choice as $i => $choice) { 374 $list[$i] = check_plain($choice['chtext']); 375 } 376 $form['choice'] = array( 377 '#type' => 'radios', 378 '#title' => $block ? check_plain($node->title) : '', 379 '#default_value' => -1, 380 '#options' => $list, 381 ); 382 } 383 $form['nid'] = array('#type' => 'hidden', '#value' => $node->nid); 384 $form['vote'] = array('#type' => 'submit', '#value' => t('Vote')); 385 $form['#action'] = url('node/'. $node->nid); 386 return $form; 387 } 388 389 /** 390 * Themes the voting form for a poll. 391 */ 392 function theme_poll_view_voting($form) { 393 $output .= '<div class="poll">'; 394 $output .= ' <div class="vote-form">'; 395 $output .= ' <div class="choices">'; 396 $output .= drupal_render($form['choice']); 397 $output .= ' </div>'; 398 $output .= drupal_render($form['nid']); 399 $output .= drupal_render($form['vote']); 400 $output .= ' </div>'; 401 $output .= drupal_render($form); 402 $output .= '</div>'; 403 return $output; 404 } 405 406 /** 407 * Generates a graphical representation of the results of a poll. 408 */ 409 function poll_view_results(&$node, $teaser, $page, $block) { 410 // Count the votes and find the maximum 411 foreach ($node->choice as $choice) { 412 $total_votes += $choice['chvotes']; 413 $max_votes = max($max_votes, $choice['chvotes']); 414 } 415 416 foreach ($node->choice as $i => $choice) { 417 if ($choice['chtext'] != '') { 418 $poll_results .= theme('poll_bar', check_plain($choice['chtext']), round($choice['chvotes'] * 100 / max($total_votes, 1)), format_plural($choice['chvotes'], '1 vote', '@count votes'), $block); 419 } 420 } 421 422 $output .= theme('poll_results', check_plain($node->title), $poll_results, $total_votes, $node->links, $block, $node->nid, $node->vote); 423 424 return $output; 425 } 426 427 function theme_poll_results($title, $results, $votes, $links, $block, $nid, $vote) { 428 if ($block) { 429 $output .= '<div class="poll">'; 430 $output .= '<div class="title">'. $title .'</div>'; 431 $output .= $results; 432 $output .= '<div class="total">'. t('Total votes: %votes', array('%votes' => $votes)) .'</div>'; 433 $output .= '</div>'; 434 $output .= '<div class="links">'. theme('links', $links) .'</div>'; 435 } 436 else { 437 $output .= '<div class="poll">'; 438 $output .= $results; 439 $output .= '<div class="total">'. t('Total votes: %votes', array('%votes' => $votes)) .'</div>'; 440 if (isset($vote) && $vote > -1 && user_access('cancel own vote')) { 441 $output .= drupal_get_form('poll_cancel_form', $nid); 442 } 443 $output .= '</div>'; 444 } 445 446 return $output; 447 } 448 449 function poll_cancel_form($nid) { 450 $form['#action'] = url("poll/cancel/$nid"); 451 $form['submit'] = array('#type' => 'submit', '#value' => t('Cancel your vote')); 452 return $form; 453 } 454 455 function theme_poll_bar($title, $percentage, $votes, $block) { 456 if ($block) { 457 $output = '<div class="text">'. $title .'</div>'; 458 $output .= '<div class="bar"><div style="width: '. $percentage .'%;" class="foreground"></div></div>'; 459 $output .= '<div class="percent">'. $percentage .'%</div>'; 460 } 461 else { 462 $output = '<div class="text">'. $title .'</div>'; 463 $output .= '<div class="bar"><div style="width: '. $percentage .'%;" class="foreground"></div></div>'; 464 $output .= '<div class="percent">'. $percentage .'% ('. $votes .')</div>'; 465 } 466 467 return $output; 468 } 469 470 /** 471 * Callback for the 'results' tab for polls you can vote on 472 */ 473 function poll_results() { 474 if ($node = node_load(arg(1))) { 475 drupal_set_title(check_plain($node->title)); 476 return node_show($node, 0); 477 } 478 else { 479 drupal_not_found(); 480 } 481 } 482 483 /** 484 * Callback for the 'votes' tab for polls you can see other votes on 485 */ 486 function poll_votes() { 487 if ($node = node_load(arg(1))) { 488 drupal_set_title(check_plain($node->title)); 489 $output = t('This table lists all the recorded votes for this poll. If anonymous users are allowed to vote, they will be identified by the IP address of the computer they used when they voted.'); 490 491 $header[] = array('data' => t('Visitor'), 'field' => 'u.name'); 492 $header[] = array('data' => t('Vote'), 'field' => 'pv.chorder'); 493 494 $result = pager_query("SELECT pv.chorder, pv.uid, pv.hostname, u.name FROM {poll_votes} pv LEFT JOIN {users} u ON pv.uid = u.uid WHERE pv.nid = %d" . tablesort_sql($header), 20, 0, NULL, $node->nid); 495 $rows = array(); 496 while ($vote = db_fetch_object($result)) { 497 $rows[] = array( 498 $vote->name ? theme('username', $vote) : check_plain($vote->hostname), 499 check_plain($node->choice[$vote->chorder]['chtext'])); 500 } 501 $output .= theme('table', $header, $rows); 502 $output .= theme('pager', NULL, 20, 0); 503 print theme('page', $output); 504 } 505 else { 506 drupal_not_found(); 507 } 508 } 509 510 /** 511 * Callback for processing a vote 512 */ 513 function poll_vote(&$node) { 514 global $user; 515 $nid = arg(1); 516 517 if ($node = node_load($nid)) { 518 $edit = $_POST; 519 $choice = $edit['choice']; 520 $vote = $_POST['vote']; 521 522 if (isset($choice) && isset($node->choice[$choice])) { 523 if ($node->allowvotes) { 524 // Record the vote by this user or host. 525 if ($user->uid) { 526 db_query('INSERT INTO {poll_votes} (nid, chorder, uid) VALUES (%d, %d, %d)', $node->nid, $choice, $user->uid); 527 } 528 else { 529 db_query("INSERT INTO {poll_votes} (nid, chorder, hostname) VALUES (%d, %d, '%s')", $node->nid, $choice, $_SERVER['REMOTE_ADDR']); 530 } 531 532 // Add one to the votes. 533 db_query("UPDATE {poll_choices} SET chvotes = chvotes + 1 WHERE nid = %d AND chorder = %d", $node->nid, $choice); 534 535 $node->allowvotes = FALSE; 536 $node->choice[$choice]['chvotes']++; 537 cache_clear_all(); 538 drupal_set_message(t('Your vote was recorded.')); 539 } 540 else { 541 drupal_set_message(t("You are not allowed to vote on this poll."), 'error'); 542 } 543 } 544 else { 545 drupal_set_message(t("You did not specify a valid poll choice."), 'error'); 546 } 547 drupal_goto('node/'. $nid); 548 } 549 else { 550 drupal_not_found(); 551 } 552 } 553 554 555 /** 556 * Callback for canceling a vote 557 */ 558 function poll_cancel(&$node) { 559 global $user; 560 561 $nid = arg(2); 562 if ($node = node_load($nid)) { 563 if ($node->type == 'poll' && $node->allowvotes == FALSE) { 564 if ($user->uid) { 565 db_query('DELETE FROM {poll_votes} WHERE nid = %d and uid = %d', $node->nid, $user->uid); 566 } 567 else { 568 db_query("DELETE FROM {poll_votes} WHERE nid = %d and hostname = '%s'", $node->nid, $_SERVER['REMOTE_ADDR']); 569 } 570 571 // Subtract from the votes. 572 db_query("UPDATE {poll_choices} SET chvotes = chvotes - 1 WHERE nid = %d AND chorder = %d", $node->nid, $node->vote); 573 $node->allowvotes = TRUE; 574 $node->choice[$node->vote]['chvotes']--; 575 drupal_set_message(t('Your vote was canceled.')); 576 } 577 else { 578 drupal_set_message(t("You are not allowed to cancel an invalid poll choice."), 'error'); 579 } 580 drupal_goto('node/'. $nid); 581 } 582 else { 583 drupal_not_found(); 584 } 585 } 586 587 /** 588 * Implementation of hook_view(). 589 * 590 * @param $block 591 * An extra parameter that adapts the hook to display a block-ready 592 * rendering of the poll. 593 */ 594 function poll_view($node, $teaser = FALSE, $page = FALSE, $block = FALSE) { 595 global $user; 596 $output = ''; 597 598 // Special display for side-block 599 if ($block) { 600 // No 'read more' link 601 $node->readmore = FALSE; 602 603 $links = module_invoke_all('link', 'node', $node, 1); 604 $links[] = array('title' => t('Older polls'), 'href' => 'poll', 'attributes' => array('title' => t('View the list of polls on this site.'))); 605 if ($node->allowvotes && $block) { 606 $links[] = array('title' => t('Results'), 'href' => 'node/'. $node->nid .'/results', 'attributes' => array('title' => t('View the current poll results.'))); 607 } 608 609 $node->links = $links; 610 } 611 612 if ($node->allowvotes && ($block || arg(2) != 'results')) { 613 if ($_POST['op'] == t('Vote')) { 614 poll_vote($node); 615 } 616 $node->content['body'] = array( 617 '#value' => drupal_get_form('poll_view_voting', $node, $block), 618 ); 619 } 620 else { 621 $node->content['body'] = array( 622 '#value' => poll_view_results($node, $teaser, $page, $block), 623 ); 624 } 625 return $node; 626 } 627 628 /** 629 * Implementation of hook_update(). 630 */ 631 function poll_update($node) { 632 db_query('UPDATE {poll} SET runtime = %d, active = %d WHERE nid = %d', $node->runtime, $node->active, $node->nid); 633 634 db_query('DELETE FROM {poll_choices} WHERE nid = %d', $node->nid); 635 db_query('DELETE FROM {poll_votes} WHERE nid = %d', $node->nid); 636 637 $i = 0; 638 foreach ($node->choice as $choice) { 639 $chvotes = (int)$choice['chvotes']; 640 $chtext = $choice['chtext']; 641 642 if ($chtext != '') { 643 db_query("INSERT INTO {poll_choices} (nid, chtext, chvotes, chorder) VALUES (%d, '%s', %d, %d)", $node->nid, $chtext, $chvotes, $i++); 644 } 645 } 646 } 647 648 /** 649 * Implementation of hook_user(). 650 */ 651 function poll_user($op, &$edit, &$user) { 652 if ($op == 'delete') { 653 db_query('UPDATE {poll_votes} SET uid = 0 WHERE uid = %d', $user->uid); 654 } 655 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Fri Nov 30 16:20:15 2007 | par Balluche grâce à PHPXref 0.7 |
![]() |