| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
1 <?php 2 // $Id: poll.module,v 1.263.2.5 2010/05/11 12:40:43 goba 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($path, $arg) { 14 switch ($path) { 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 receive feedback from community members.') .'</p>'; 17 $output .= '<p>'. t('When creating a poll, enter the question being posed, as well as the potential choices (and beginning vote counts for each choice). The status and duration (length of time the poll remains active for new votes) can also be specified. Use the <a href="@poll">poll</a> menu item to view all current polls. To vote in or view the results of a specific poll, click on the poll itself.', array('@poll' => url('poll'))) .'</p>'; 18 $output .= '<p>'. t('For more information, see the online handbook entry for <a href="@poll">Poll module</a>.', array('@poll' => 'http://drupal.org/handbook/modules/poll/')) .'</p>'; 19 return $output; 20 } 21 } 22 23 /** 24 * Implementation of hook_init(). 25 */ 26 function poll_init() { 27 drupal_add_css(drupal_get_path('module', 'poll') .'/poll.css'); 28 } 29 30 /** 31 * Implementation of hook_theme() 32 */ 33 function poll_theme() { 34 return array( 35 'poll_vote' => array( 36 'template' => 'poll-vote', 37 'arguments' => array('form' => NULL), 38 ), 39 'poll_choices' => array( 40 'arguments' => array('form' => NULL), 41 ), 42 'poll_results' => array( 43 'template' => 'poll-results', 44 'arguments' => array('raw_title' => NULL, 'results' => NULL, 'votes' => NULL, 'raw_links' => NULL, 'block' => NULL, 'nid' => NULL, 'vote' => NULL), 45 ), 46 'poll_bar' => array( 47 'template' => 'poll-bar', 48 'arguments' => array('title' => NULL, 'votes' => NULL, 'total_votes' => NULL, 'vote' => NULL, 'block' => NULL), 49 ), 50 ); 51 } 52 53 /** 54 * Implementation of hook_perm(). 55 */ 56 function poll_perm() { 57 return array('create poll content', 'delete own poll content', 'delete any poll content', 'edit any poll content', 'edit own poll content', 'vote on polls', 'cancel own vote', 'inspect all votes'); 58 } 59 60 /** 61 * Implementation of hook_access(). 62 */ 63 function poll_access($op, $node, $account) { 64 switch ($op) { 65 case 'create': 66 return user_access('create poll content', $account) ? TRUE : NULL; 67 case 'update': 68 return user_access('edit any poll content', $account) || (user_access('edit own poll content', $account) && ($node->uid == $account->uid)) ? TRUE : NULL; 69 case 'delete': 70 return user_access('delete any poll content', $account) || (user_access('delete own poll content', $account) && ($node->uid == $account->uid)) ? TRUE : NULL; 71 } 72 } 73 74 /** 75 * Implementation of hook_menu(). 76 */ 77 function poll_menu() { 78 $items['poll'] = array( 79 'title' => 'Polls', 80 'page callback' => 'poll_page', 81 'access arguments' => array('access content'), 82 'type' => MENU_SUGGESTED_ITEM, 83 'file' => 'poll.pages.inc', 84 ); 85 86 $items['node/%node/votes'] = array( 87 'title' => 'Votes', 88 'page callback' => 'poll_votes', 89 'page arguments' => array(1), 90 'access callback' => '_poll_menu_access', 91 'access arguments' => array(1, 'inspect all votes', FALSE), 92 'weight' => 3, 93 'type' => MENU_LOCAL_TASK, 94 'file' => 'poll.pages.inc', 95 ); 96 97 $items['node/%node/results'] = array( 98 'title' => 'Results', 99 'page callback' => 'poll_results', 100 'page arguments' => array(1), 101 'access callback' => '_poll_menu_access', 102 'access arguments' => array(1, 'access content', TRUE), 103 'weight' => 3, 104 'type' => MENU_LOCAL_TASK, 105 'file' => 'poll.pages.inc', 106 ); 107 108 $items['poll/js'] = array( 109 'title' => 'Javascript Choice Form', 110 'page callback' => 'poll_choice_js', 111 'access arguments' => array('access content'), 112 'type' => MENU_CALLBACK, 113 ); 114 115 return $items; 116 } 117 118 /** 119 * Callback function to see if a node is acceptable for poll menu items. 120 */ 121 function _poll_menu_access($node, $perm, $inspect_allowvotes) { 122 return user_access($perm) && ($node->type == 'poll') && ($node->allowvotes || !$inspect_allowvotes); 123 } 124 125 /** 126 * Implementation of hook_block(). 127 * 128 * Generates a block containing the latest poll. 129 */ 130 function poll_block($op = 'list', $delta = 0) { 131 if (user_access('access content')) { 132 if ($op == 'list') { 133 $blocks[0]['info'] = t('Most recent poll'); 134 return $blocks; 135 } 136 else if ($op == 'view') { 137 // Retrieve the latest poll. 138 $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"); 139 $timestamp = db_result(db_query($sql)); 140 if ($timestamp) { 141 $poll = node_load(array('type' => 'poll', 'created' => $timestamp, 'status' => 1)); 142 143 if ($poll->nid) { 144 $poll = poll_view($poll, TRUE, FALSE, TRUE); 145 } 146 } 147 $block['subject'] = t('Poll'); 148 $block['content'] = drupal_render($poll->content); 149 return $block; 150 } 151 } 152 } 153 154 /** 155 * Implementation of hook_cron(). 156 * 157 * Closes polls that have exceeded their allowed runtime. 158 */ 159 function poll_cron() { 160 $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'); 161 while ($poll = db_fetch_object($result)) { 162 db_query("UPDATE {poll} SET active = 0 WHERE nid = %d", $poll->nid); 163 } 164 } 165 166 /** 167 * Implementation of hook_node_info(). 168 */ 169 function poll_node_info() { 170 return array( 171 'poll' => array( 172 'name' => t('Poll'), 173 'module' => 'poll', 174 'description' => t('A <em>poll</em> is a question with a set of possible responses. A <em>poll</em>, once created, automatically provides a simple running count of the number of votes received for each response.'), 175 'title_label' => t('Question'), 176 'has_body' => FALSE, 177 ) 178 ); 179 } 180 181 /** 182 * Implementation of hook_form(). 183 */ 184 function poll_form(&$node, $form_state) { 185 global $user; 186 187 $admin = user_access('administer nodes') || user_access('edit any poll content') || (user_access('edit own poll content') && $user->uid == $node->uid); 188 189 $type = node_get_types('type', $node); 190 191 $form = array( 192 '#cache' => TRUE, 193 ); 194 195 $form['title'] = array( 196 '#type' => 'textfield', 197 '#title' => check_plain($type->title_label), 198 '#required' => TRUE, 199 '#default_value' => $node->title, 200 '#weight' => -5, 201 ); 202 203 if (isset($form_state['choice_count'])) { 204 $choice_count = $form_state['choice_count']; 205 } 206 else { 207 $choice_count = max(2, empty($node->choice) ? 2 : count($node->choice)); 208 } 209 210 // Add a wrapper for the choices and more button. 211 $form['choice_wrapper'] = array( 212 '#tree' => FALSE, 213 '#weight' => -4, 214 '#prefix' => '<div class="clear-block" id="poll-choice-wrapper">', 215 '#suffix' => '</div>', 216 ); 217 218 // Container for just the poll choices. 219 $form['choice_wrapper']['choice'] = array( 220 '#prefix' => '<div id="poll-choices">', 221 '#suffix' => '</div>', 222 '#theme' => 'poll_choices', 223 ); 224 225 // Add the current choices to the form. 226 for ($delta = 0; $delta < $choice_count; $delta++) { 227 $text = isset($node->choice[$delta]['chtext']) ? $node->choice[$delta]['chtext'] : ''; 228 $votes = isset($node->choice[$delta]['chvotes']) ? $node->choice[$delta]['chvotes'] : 0; 229 230 $form['choice_wrapper']['choice'][$delta] = _poll_choice_form($delta, $text, $votes); 231 } 232 233 // We name our button 'poll_more' to avoid conflicts with other modules using 234 // AHAH-enabled buttons with the id 'more'. 235 $form['choice_wrapper']['poll_more'] = array( 236 '#type' => 'submit', 237 '#value' => t('More choices'), 238 '#description' => t("If the amount of boxes above isn't enough, click here to add more choices."), 239 '#weight' => 1, 240 '#submit' => array('poll_more_choices_submit'), // If no javascript action. 241 '#ahah' => array( 242 'path' => 'poll/js', 243 'wrapper' => 'poll-choices', 244 'method' => 'replace', 245 'effect' => 'fade', 246 ), 247 ); 248 249 // Poll attributes 250 $_duration = array(0 => t('Unlimited')) + drupal_map_assoc(array(86400, 172800, 345600, 604800, 1209600, 2419200, 4838400, 9676800, 31536000), "format_interval"); 251 $_active = array(0 => t('Closed'), 1 => t('Active')); 252 253 if ($admin) { 254 $form['settings'] = array( 255 '#type' => 'fieldset', 256 '#collapsible' => TRUE, 257 '#title' => t('Poll settings'), 258 '#weight' => -3, 259 ); 260 261 $form['settings']['active'] = array( 262 '#type' => 'radios', 263 '#title' => t('Poll status'), 264 '#default_value' => isset($node->active) ? $node->active : 1, 265 '#options' => $_active, 266 '#description' => t('When a poll is closed, visitors can no longer vote for it.') 267 ); 268 } 269 $form['settings']['runtime'] = array( 270 '#type' => 'select', 271 '#title' => t('Poll duration'), 272 '#default_value' => isset($node->runtime) ? $node->runtime : 0, 273 '#options' => $_duration, 274 '#description' => t('After this period, the poll will be closed automatically.'), 275 ); 276 277 return $form; 278 } 279 280 /** 281 * Submit handler to add more choices to a poll form. This handler is used when 282 * javascript is not available. It makes changes to the form state and the 283 * entire form is rebuilt during the page reload. 284 */ 285 function poll_more_choices_submit($form, &$form_state) { 286 // Set the form to rebuild and run submit handlers. 287 node_form_submit_build_node($form, $form_state); 288 289 // Make the changes we want to the form state. 290 if ($form_state['values']['poll_more']) { 291 $n = $_GET['q'] == 'poll/js' ? 1 : 5; 292 $form_state['choice_count'] = count($form_state['values']['choice']) + $n; 293 } 294 } 295 296 function _poll_choice_form($delta, $value = '', $votes = 0) { 297 $form = array( 298 '#tree' => TRUE, 299 ); 300 301 // We'll manually set the #parents property of these fields so that 302 // their values appear in the $form_state['values']['choice'] array. 303 $form['chtext'] = array( 304 '#type' => 'textfield', 305 '#title' => t('Choice @n', array('@n' => ($delta + 1))), 306 '#default_value' => $value, 307 '#parents' => array('choice', $delta, 'chtext'), 308 ); 309 $form['chvotes'] = array( 310 '#type' => 'textfield', 311 '#title' => t('Votes for choice @n', array('@n' => ($delta + 1))), 312 '#default_value' => $votes, 313 '#size' => 5, 314 '#maxlength' => 7, 315 '#parents' => array('choice', $delta, 'chvotes'), 316 '#access' => user_access('administer nodes'), 317 ); 318 319 return $form; 320 } 321 322 /** 323 * Menu callback for AHAH additions. 324 */ 325 function poll_choice_js() { 326 include_once 'modules/node/node.pages.inc'; 327 $form_state = array('storage' => NULL, 'submitted' => FALSE); 328 $form_build_id = $_POST['form_build_id']; 329 // Get the form from the cache. 330 $form = form_get_cache($form_build_id, $form_state); 331 $args = $form['#parameters']; 332 $form_id = array_shift($args); 333 // We will run some of the submit handlers so we need to disable redirecting. 334 $form['#redirect'] = FALSE; 335 // We need to process the form, prepare for that by setting a few internals 336 // variables. 337 $form['#post'] = $_POST; 338 $form['#programmed'] = FALSE; 339 $form_state['post'] = $_POST; 340 // Build, validate and if possible, submit the form. 341 drupal_process_form($form_id, $form, $form_state); 342 // This call recreates the form relying solely on the form_state that the 343 // drupal_process_form set up. 344 $form = drupal_rebuild_form($form_id, $form_state, $args, $form_build_id); 345 // Render the new output. 346 $choice_form = $form['choice_wrapper']['choice']; 347 unset($choice_form['#prefix'], $choice_form['#suffix']); // Prevent duplicate wrappers. 348 $output = theme('status_messages') . drupal_render($choice_form); 349 350 drupal_json(array('status' => TRUE, 'data' => $output)); 351 } 352 353 /** 354 * Renumbers fields and creates a teaser when a poll node is submitted. 355 */ 356 function poll_node_form_submit(&$form, &$form_state) { 357 // Renumber fields 358 $form_state['values']['choice'] = array_values($form_state['values']['choice']); 359 $form_state['values']['teaser'] = poll_teaser((object)$form_state['values']); 360 } 361 362 /** 363 * Implementation of hook_validate(). 364 */ 365 function poll_validate($node) { 366 if (isset($node->title)) { 367 // Check for at least two options and validate amount of votes: 368 $realchoices = 0; 369 // Renumber fields 370 $node->choice = array_values($node->choice); 371 foreach ($node->choice as $i => $choice) { 372 if ($choice['chtext'] != '') { 373 $realchoices++; 374 } 375 if (isset($choice['chvotes']) && $choice['chvotes'] < 0) { 376 form_set_error("choice][$i][chvotes", t('Negative values are not allowed.')); 377 } 378 } 379 380 if ($realchoices < 2) { 381 form_set_error("choice][$realchoices][chtext", t('You must fill in at least two choices.')); 382 } 383 } 384 } 385 386 /** 387 * Implementation of hook_load(). 388 */ 389 function poll_load($node) { 390 global $user; 391 392 $poll = db_fetch_object(db_query("SELECT runtime, active FROM {poll} WHERE nid = %d", $node->nid)); 393 394 // Load the appropriate choices into the $poll object. 395 $result = db_query("SELECT chtext, chvotes, chorder FROM {poll_choices} WHERE nid = %d ORDER BY chorder", $node->nid); 396 while ($choice = db_fetch_array($result)) { 397 $poll->choice[$choice['chorder']] = $choice; 398 } 399 400 // Determine whether or not this user is allowed to vote. 401 $poll->allowvotes = FALSE; 402 if (user_access('vote on polls') && $poll->active) { 403 if ($user->uid) { 404 $result = db_fetch_object(db_query('SELECT chorder FROM {poll_votes} WHERE nid = %d AND uid = %d', $node->nid, $user->uid)); 405 } 406 else { 407 $result = db_fetch_object(db_query("SELECT chorder FROM {poll_votes} WHERE nid = %d AND hostname = '%s'", $node->nid, ip_address())); 408 } 409 if (isset($result->chorder)) { 410 $poll->vote = $result->chorder; 411 } 412 else { 413 $poll->vote = -1; 414 $poll->allowvotes = TRUE; 415 } 416 } 417 return $poll; 418 } 419 420 /** 421 * Implementation of hook_insert(). 422 */ 423 function poll_insert($node) { 424 if (!user_access('administer nodes')) { 425 // Make sure all votes are 0 initially 426 foreach ($node->choice as $i => $choice) { 427 $node->choice[$i]['chvotes'] = 0; 428 } 429 $node->active = 1; 430 } 431 432 db_query("INSERT INTO {poll} (nid, runtime, active) VALUES (%d, %d, %d)", $node->nid, $node->runtime, $node->active); 433 434 $i = 0; 435 foreach ($node->choice as $choice) { 436 if ($choice['chtext'] != '') { 437 db_query("INSERT INTO {poll_choices} (nid, chtext, chvotes, chorder) VALUES (%d, '%s', %d, %d)", $node->nid, $choice['chtext'], $choice['chvotes'], $i++); 438 } 439 } 440 } 441 442 /** 443 * Implementation of hook_update(). 444 */ 445 function poll_update($node) { 446 // Update poll settings. 447 db_query('UPDATE {poll} SET runtime = %d, active = %d WHERE nid = %d', $node->runtime, $node->active, $node->nid); 448 449 // Clean poll choices. 450 db_query('DELETE FROM {poll_choices} WHERE nid = %d', $node->nid); 451 452 // Poll choices come in the same order with the same numbers as they are in 453 // the database, but some might have an empty title, which signifies that 454 // they should be removed. We remove all votes to the removed options, so 455 // people who voted on them can vote again. 456 $new_chorder = 0; 457 foreach ($node->choice as $old_chorder => $choice) { 458 $chvotes = isset($choice['chvotes']) ? (int)$choice['chvotes'] : 0; 459 $chtext = $choice['chtext']; 460 461 if (!empty($chtext)) { 462 db_query("INSERT INTO {poll_choices} (nid, chtext, chvotes, chorder) VALUES (%d, '%s', %d, %d)", $node->nid, $chtext, $chvotes, $new_chorder); 463 if ($new_chorder != $old_chorder) { 464 // We can only remove items in the middle, not add, so 465 // new_chorder is always <= old_chorder, making this safe. 466 db_query("UPDATE {poll_votes} SET chorder = %d WHERE nid = %d AND chorder = %d", $new_chorder, $node->nid, $old_chorder); 467 } 468 $new_chorder++; 469 } 470 else { 471 db_query("DELETE FROM {poll_votes} WHERE nid = %d AND chorder = %d", $node->nid, $old_chorder); 472 } 473 } 474 } 475 476 /** 477 * Implementation of hook_delete(). 478 */ 479 function poll_delete($node) { 480 db_query("DELETE FROM {poll} WHERE nid = %d", $node->nid); 481 db_query("DELETE FROM {poll_choices} WHERE nid = %d", $node->nid); 482 db_query("DELETE FROM {poll_votes} WHERE nid = %d", $node->nid); 483 } 484 485 /** 486 * Implementation of hook_view(). 487 * 488 * @param $block 489 * An extra parameter that adapts the hook to display a block-ready 490 * rendering of the poll. 491 */ 492 function poll_view($node, $teaser = FALSE, $page = FALSE, $block = FALSE) { 493 global $user; 494 $output = ''; 495 496 // Special display for side-block 497 if ($block) { 498 // No 'read more' link 499 $node->readmore = FALSE; 500 501 $links = module_invoke_all('link', 'node', $node, 1); 502 $links[] = array('title' => t('Older polls'), 'href' => 'poll', 'attributes' => array('title' => t('View the list of polls on this site.'))); 503 if ($node->allowvotes && $block) { 504 $links[] = array('title' => t('Results'), 'href' => 'node/'. $node->nid .'/results', 'attributes' => array('title' => t('View the current poll results.'))); 505 } 506 507 $node->links = $links; 508 } 509 510 if (!empty($node->allowvotes) && ($block || empty($node->show_results))) { 511 $node->content['body'] = array( 512 '#value' => drupal_get_form('poll_view_voting', $node, $block), 513 ); 514 } 515 else { 516 $node->content['body'] = array( 517 '#value' => poll_view_results($node, $teaser, $page, $block), 518 ); 519 } 520 return $node; 521 } 522 523 /** 524 * Creates a simple teaser that lists all the choices. 525 * 526 * This is primarily used for RSS. 527 */ 528 function poll_teaser($node) { 529 $teaser = NULL; 530 if (is_array($node->choice)) { 531 foreach ($node->choice as $k => $choice) { 532 if ($choice['chtext'] != '') { 533 $teaser .= '* '. check_plain($choice['chtext']) ."\n"; 534 } 535 } 536 } 537 return $teaser; 538 } 539 540 /** 541 * Generates the voting form for a poll. 542 * 543 * @ingroup forms 544 * @see poll_vote() 545 * @see phptemplate_preprocess_poll_vote() 546 */ 547 function poll_view_voting(&$form_state, $node, $block) { 548 if ($node->choice) { 549 $list = array(); 550 foreach ($node->choice as $i => $choice) { 551 $list[$i] = check_plain($choice['chtext']); 552 } 553 $form['choice'] = array( 554 '#type' => 'radios', 555 '#default_value' => -1, 556 '#options' => $list, 557 ); 558 } 559 560 $form['vote'] = array( 561 '#type' => 'submit', 562 '#value' => t('Vote'), 563 '#submit' => array('poll_vote'), 564 ); 565 566 // Store the node so we can get to it in submit functions. 567 $form['#node'] = $node; 568 $form['#block'] = $block; 569 570 // Set form caching because we could have multiple of these forms on 571 // the same page, and we want to ensure the right one gets picked. 572 $form['#cache'] = TRUE; 573 574 // Provide a more cleanly named voting form theme. 575 $form['#theme'] = 'poll_vote'; 576 return $form; 577 } 578 579 /** 580 * Validation function for processing votes 581 */ 582 function poll_view_voting_validate($form, &$form_state) { 583 if ($form_state['values']['choice'] == -1) { 584 form_set_error( 'choice', t('Your vote could not be recorded because you did not select any of the choices.')); 585 } 586 } 587 588 /** 589 * Submit handler for processing a vote 590 */ 591 function poll_vote($form, &$form_state) { 592 $node = $form['#node']; 593 $choice = $form_state['values']['choice']; 594 595 global $user; 596 if ($user->uid) { 597 db_query('INSERT INTO {poll_votes} (nid, chorder, uid) VALUES (%d, %d, %d)', $node->nid, $choice, $user->uid); 598 } 599 else { 600 db_query("INSERT INTO {poll_votes} (nid, chorder, hostname) VALUES (%d, %d, '%s')", $node->nid, $choice, ip_address()); 601 } 602 603 // Add one to the votes. 604 db_query("UPDATE {poll_choices} SET chvotes = chvotes + 1 WHERE nid = %d AND chorder = %d", $node->nid, $choice); 605 606 cache_clear_all(); 607 drupal_set_message(t('Your vote was recorded.')); 608 609 // Return the user to whatever page they voted from. 610 } 611 612 /** 613 * Themes the voting form for a poll. 614 * 615 * Inputs: $form 616 */ 617 function template_preprocess_poll_vote(&$variables) { 618 $form = $variables['form']; 619 $variables['choice'] = drupal_render($form['choice']); 620 $variables['title'] = check_plain($form['#node']->title); 621 $variables['vote'] = drupal_render($form['vote']); 622 $variables['rest'] = drupal_render($form); 623 $variables['block'] = $form['#block']; 624 // If this is a block, allow a different tpl.php to be used. 625 if ($variables['block']) { 626 $variables['template_files'][] = 'poll-vote-block'; 627 } 628 } 629 630 /** 631 * Generates a graphical representation of the results of a poll. 632 */ 633 function poll_view_results(&$node, $teaser, $page, $block) { 634 // Count the votes and find the maximum 635 $total_votes = 0; 636 $max_votes = 0; 637 foreach ($node->choice as $choice) { 638 if (isset($choice['chvotes'])) { 639 $total_votes += $choice['chvotes']; 640 $max_votes = max($max_votes, $choice['chvotes']); 641 } 642 } 643 644 $poll_results = ''; 645 foreach ($node->choice as $i => $choice) { 646 if (!empty($choice['chtext'])) { 647 $chvotes = isset($choice['chvotes']) ? $choice['chvotes'] : NULL; 648 $poll_results .= theme('poll_bar', $choice['chtext'], $chvotes, $total_votes, isset($node->vote) && $node->vote == $i, $block); 649 } 650 } 651 652 return theme('poll_results', $node->title, $poll_results, $total_votes, isset($node->links) ? $node->links : array(), $block, $node->nid, isset($node->vote) ? $node->vote : NULL); 653 } 654 655 656 /** 657 * Theme the admin poll form for choices. 658 * 659 * @ingroup themeable 660 */ 661 function theme_poll_choices($form) { 662 // Change the button title to reflect the behavior when using JavaScript. 663 drupal_add_js('if (Drupal.jsEnabled) { $(document).ready(function() { $("#edit-poll-more").val("'. t('Add another choice') .'"); }); }', 'inline'); 664 665 $rows = array(); 666 $headers = array( 667 t('Choice'), 668 t('Vote count'), 669 ); 670 671 foreach (element_children($form) as $key) { 672 // No need to print the field title every time. 673 unset($form[$key]['chtext']['#title'], $form[$key]['chvotes']['#title']); 674 675 // Build the table row. 676 $row = array( 677 'data' => array( 678 array('data' => drupal_render($form[$key]['chtext']), 'class' => 'poll-chtext'), 679 array('data' => drupal_render($form[$key]['chvotes']), 'class' => 'poll-chvotes'), 680 ), 681 ); 682 683 // Add additional attributes to the row, such as a class for this row. 684 if (isset($form[$key]['#attributes'])) { 685 $row = array_merge($row, $form[$key]['#attributes']); 686 } 687 $rows[] = $row; 688 } 689 690 $output = theme('table', $headers, $rows); 691 $output .= drupal_render($form); 692 return $output; 693 } 694 695 /** 696 * Preprocess the poll_results theme hook. 697 * 698 * Inputs: $raw_title, $results, $votes, $raw_links, $block, $nid, $vote. The 699 * $raw_* inputs to this are naturally unsafe; often safe versions are 700 * made to simply overwrite the raw version, but in this case it seems likely 701 * that the title and the links may be overridden by the theme layer, so they 702 * are left in with a different name for that purpose. 703 * 704 * @see poll-results.tpl.php 705 * @see poll-results-block.tpl.php 706 * @see theme_poll_results() 707 */ 708 function template_preprocess_poll_results(&$variables) { 709 $variables['links'] = theme('links', $variables['raw_links']); 710 if (isset($variables['vote']) && $variables['vote'] > -1 && user_access('cancel own vote')) { 711 $variables['cancel_form'] = drupal_get_form('poll_cancel_form', $variables['nid']); 712 } 713 $variables['title'] = check_plain($variables['raw_title']); 714 715 // If this is a block, allow a different tpl.php to be used. 716 if ($variables['block']) { 717 $variables['template_files'][] = 'poll-results-block'; 718 } 719 } 720 721 /** 722 * Preprocess the poll_bar theme hook. 723 * 724 * Inputs: $title, $votes, $total_votes, $voted, $block 725 * 726 * @see poll-bar.tpl.php 727 * @see poll-bar-block.tpl.php 728 * @see theme_poll_bar() 729 */ 730 function template_preprocess_poll_bar(&$variables) { 731 if ($variables['block']) { 732 $variables['template_files'][] = 'poll-bar-block'; 733 } 734 $variables['title'] = check_plain($variables['title']); 735 $variables['percentage'] = round($variables['votes'] * 100 / max($variables['total_votes'], 1)); 736 } 737 738 /** 739 * Builds the cancel form for a poll. 740 * 741 * @ingroup forms 742 * @see poll_cancel() 743 */ 744 function poll_cancel_form(&$form_state, $nid) { 745 // Store the nid so we can get to it in submit functions. 746 $form['#nid'] = $nid; 747 748 $form['submit'] = array( 749 '#type' => 'submit', 750 '#value' => t('Cancel your vote'), 751 '#submit' => array('poll_cancel') 752 ); 753 754 $form['#cache'] = TRUE; 755 756 return $form; 757 } 758 759 /** 760 * Submit callback for poll_cancel_form 761 */ 762 function poll_cancel($form, &$form_state) { 763 $node = node_load($form['#nid']); 764 global $user; 765 766 if ($user->uid) { 767 db_query('DELETE FROM {poll_votes} WHERE nid = %d and uid = %d', $node->nid, $user->uid); 768 } 769 else { 770 db_query("DELETE FROM {poll_votes} WHERE nid = %d and hostname = '%s'", $node->nid, ip_address()); 771 } 772 773 // Subtract from the votes. 774 db_query("UPDATE {poll_choices} SET chvotes = chvotes - 1 WHERE nid = %d AND chorder = %d", $node->nid, $node->vote); 775 } 776 777 /** 778 * Implementation of hook_user(). 779 */ 780 function poll_user($op, &$edit, &$user) { 781 if ($op == 'delete') { 782 db_query('UPDATE {poll_votes} SET uid = 0 WHERE uid = %d', $user->uid); 783 } 784 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |