Index: modules/poll/poll.module =================================================================== RCS file: /cvs/drupal/drupal/modules/poll/poll.module,v retrieving revision 1.234 diff -u -r1.234 poll.module --- modules/poll/poll.module 1 Jul 2007 17:41:16 -0000 1.234 +++ modules/poll/poll.module 9 Jul 2007 17:02:30 -0000 @@ -101,12 +101,9 @@ */ function poll_node_form_submit(&$form, &$form_state) { // Renumber fields - $form_state['values']['choice'] = array_values($form_state['values']['choice']); + $form_state['values']['choices'] = array_values($form_state['values']['choices']); $form_state['values']['teaser'] = poll_teaser((object)$form_state['values']); $form_state['choices'] = $form_state['values']['choices']; - if ($form_state['values']['morechoices']) { - $form_state['choices'] *= 2; - } } /** @@ -117,18 +114,18 @@ // Check for at least two options and validate amount of votes: $realchoices = 0; // Renumber fields - $node->choice = array_values($node->choice); - foreach ($node->choice as $i => $choice) { + $node->choices = array_values($node->choices); + foreach ($node->choices as $i => $choice) { if ($choice['chtext'] != '') { $realchoices++; } if ($choice['chvotes'] < 0) { - form_set_error("choice][$i][chvotes", t('Negative values are not allowed.')); + form_set_error("choices][$i][chvotes", t('Negative values are not allowed.')); } } if ($realchoices < 2) { - form_set_error("choice][$realchoices][chtext", t('You must fill in at least two choices.')); + form_set_error("choices][$realchoices][chtext", t('You must fill in at least two choices.')); } } } @@ -139,6 +136,11 @@ function poll_form(&$node, $form_state) { $admin = user_access('administer nodes'); $type = node_get_types('type', $node); + + $form = array( + '#cache' => TRUE, + ); + $form['title'] = array( '#type' => 'textfield', '#title' => check_plain($type->title_label), @@ -147,56 +149,48 @@ '#weight' => -1 ); - if (isset($form_state['choices'])) { - $choices = $form_state['choices']; + if (isset($form_state['choice_count'])) { + $choice_count = $form_state['choice_count']; } else { - $choices = max(2, empty($node->choice) ? 5 : count($node->choice)); + $choice_count = max(2, empty($node->choices) ? 5 : count($node->choices)); } - $form['choices'] = array( - '#type' => 'hidden', - '#value' => $choices, - ); - - // Poll choices - $form['choice'] = array( + // Add a wrapper for the choices and more button. + $form['choice_wrapper'] = array( '#type' => 'fieldset', '#title' => t('Choices'), - '#prefix' => '
', - '#suffix' => '
', - '#tree' => TRUE + '#tree' => FALSE, ); - // We'll manually set the #parents property of this checkbox so that - // it appears in the fieldset visually, but its value won't pollute - // the $form_state['values']['choice'] array. - $form['choice']['morechoices'] = array( - '#type' => 'checkbox', - '#parents' => array('morechoices'), - '#title' => t('Need more choices'), - '#default_value' => 0, - '#description' => t("If the amount of boxes above isn't enough, check this box and click the Preview button below to add some more."), - '#weight' => 1, + // Container for just the poll choices. + $form['choice_wrapper']['choices'] = array( + '#prefix' => '
', + '#suffix' => '
', ); - for ($a = 0; $a < $choices; $a++) { - $form['choice'][$a]['chtext'] = array( - '#type' => 'textfield', - '#title' => t('Choice @n', array('@n' => ($a + 1))), - '#default_value' => isset($node->choice[$a]) ? $node->choice[$a]['chtext'] : '', - ); - - if ($admin) { - $form['choice'][$a]['chvotes'] = array( - '#type' => 'textfield', - '#title' => t('Votes for choice @n', array('@n' => ($a + 1))), - '#default_value' => isset($node->choice[$a]) ? (int)$node->choice[$a]['chvotes'] : 0, - '#size' => 5, '#maxlength' => 7 - ); - } + // Add the current choices to the form. + for ($delta = 0; $delta < $choice_count; $delta++) { + $text = isset($node->choices[$delta]['chtext']) ? $node->choices[$delta]['chtext'] : ''; + $votes = isset($node->choices[$delta]['chvotes']) ? $node->choices[$delta]['chvotes'] : ''; + + $form['choice_wrapper']['choices'][$delta] = _poll_choice_form($delta, $text, $votes); } + // We name our button 'poll_more' to avoid conflicts with other modules with + // buttons with the id 'more'. + $form['choice_wrapper']['poll_more'] = array( + '#type' => 'submit', + '#value' => t('Add another choice'), + '#description' => t("If the amount of boxes above isn't enough, click here to add more choices."), + '#weight' => 1, + '#submit' => array('poll_more_choices_submit'), // If no javascript action. + '#ahah_path' => 'poll/js', + '#ahah_wrapper' => 'poll-choices', + '#ahah_method' => 'append', + '#ahah_effect' => 'slide', + ); + // Poll attributes $_duration = array(0 => t('Unlimited')) + drupal_map_assoc(array(86400, 172800, 345600, 604800, 1209600, 2419200, 4838400, 9676800, 31536000), "format_interval"); $_active = array(0 => t('Closed'), 1 => t('Active')); @@ -223,18 +217,95 @@ return $form; } +/** + * Submit handler to add more choices to a poll form. This handler is used when + * javascript is not available. It makes changes to the form state and the + * entire form is rebuilt during the page reload. + */ +function poll_more_choices_submit($form, &$form_state) { + // Set rebuild to true to make Drupal re-render the form with our changes. + $form_state['rebuild'] = TRUE; + + // Make the changes we want to the form state. + $form_state['node'] = $form_state['values']; + if ($form_state['values']['poll_more']) { + $form_state['choice_count'] = count($form_state['values']['choices']) + 5; + } +} + +function _poll_choice_form($delta, $value = NULL, $votes = NULL) { + $admin = user_access('administer nodes'); + + $form = array( + '#tree' => TRUE, + ); + + // We'll manually set the #parents property of these fields so that + // their values appear in the $form_state['values']['choices'] array. + $form['chtext'] = array( + '#type' => 'textfield', + '#title' => t('Choice @n', array('@n' => ($delta + 1))), + '#default_value' => isset($value) ? $value : '', + '#parents' => array('choices', $delta,'chtext'), + ); + + if ($admin) { + $form['chvotes'] = array( + '#type' => 'textfield', + '#title' => t('Votes for choice @n', array('@n' => ($delta + 1))), + '#default_value' => $votes ? $votes : 0, + '#size' => 5, + '#maxlength' => 7, + '#parents' => array('choices', $delta, 'chvotes'), + ); + } + + return $form; +} + +/** + * Menu callback for AHAH additions. + */ +function poll_choice_js() { + $delta = count($_POST['choices']); + + // Build our new form element. + $form_element = _poll_choice_form($delta); + drupal_alter('form', $form_element, array(), 'poll_choice_js'); + + // Add the new element to the stored form state. Without adding the element + // to the form, Drupal is not aware of this new elements existence and will + // not process it. We retreive the cached form, add the element, and resave. + $form = cache_get('form_'. $_POST['form_build_id'], 'cache_form'); + $form->data['choice_wrapper']['choices'][$delta] = $form_element; + cache_set('form_'. $_POST['form_build_id'], $form->data, 'cache_form'); + + // Render the new output. + $form_state = array('submitted' => FALSE); + $form_element += array( + '#post' => $_POST, + '#programmed' => FALSE, + ); + $form_element = form_builder('poll_choice_js', $form_element, $form_state); + $output = theme('status_messages') . drupal_render($form_element); + + // Return the new output. + print drupal_to_js(array('status' => TRUE, 'data' => $output)); + exit; +} + function poll_insert($node) { if (!user_access('administer nodes')) { // Make sure all votes are 0 initially - foreach ($node->choice as $i => $choice) { - $node->choice[$i]['chvotes'] = 0; + foreach ($node->choices as $i => $choice) { + $node->choices[$i]['chvotes'] = 0; } $node->active = 1; } db_query("INSERT INTO {poll} (nid, runtime, active) VALUES (%d, %d, %d)", $node->nid, $node->runtime, $node->active); - foreach ($node->choice as $choice) { + foreach ($node->choices as $choice) { if ($choice['chtext'] != '') { db_query("INSERT INTO {poll_choices} (nid, chtext, chvotes, chorder) VALUES (%d, '%s', %d, %d)", $node->nid, $choice['chtext'], $choice['chvotes'], $i++); } @@ -256,6 +327,13 @@ 'type' => MENU_SUGGESTED_ITEM, ); + $items['poll/js'] = array( + 'title' => 'Javascript Choice Form', + 'page callback' => 'poll_choice_js', + 'access arguments' => array('access content'), + 'type' => MENU_CALLBACK, + ); + $items['poll/cancel/%node'] = array( 'title' => 'Cancel', 'page callback' => 'poll_cancel', @@ -297,7 +375,7 @@ $result = db_query("SELECT chtext, chvotes, chorder FROM {poll_choices} WHERE nid = %d ORDER BY chorder", $node->nid); while ($choice = db_fetch_array($result)) { - $poll->choice[$choice['chorder']] = $choice; + $poll->choices[$choice['chorder']] = $choice; } // Determine whether or not this user is allowed to vote @@ -361,8 +439,8 @@ */ function poll_teaser($node) { $teaser = NULL; - if (is_array($node->choice)) { - foreach ($node->choice as $k => $choice) { + if (is_array($node->choices)) { + foreach ($node->choices as $k => $choice) { $teaser .= '* '. $choice['chtext'] .'\n'; } } @@ -372,10 +450,10 @@ /** * Generates the voting form for a poll. */ -function poll_view_voting($node, $block) { - if ($node->choice) { +function poll_view_voting($form_state, $node, $block) { + if ($node->choices) { $list = array(); - foreach ($node->choice as $i => $choice) { + foreach ($node->choices as $i => $choice) { $list[$i] = check_plain($choice['chtext']); } $form['choice'] = array( @@ -395,6 +473,7 @@ * Themes the voting form for a poll. */ function theme_poll_view_voting($form) { + $output = ''; $output .= '
'; $output .= '
'; $output .= '
'; @@ -415,13 +494,13 @@ // Count the votes and find the maximum $total_votes = 0; $max_votes = 0; - foreach ($node->choice as $choice) { + foreach ($node->choices as $choice) { $total_votes += $choice['chvotes']; $max_votes = max($max_votes, $choice['chvotes']); } $poll_results = ''; - foreach ($node->choice as $i => $choice) { + foreach ($node->choices as $i => $choice) { if ($choice['chtext'] != '') { $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); } @@ -503,7 +582,7 @@ while ($vote = db_fetch_object($result)) { $rows[] = array( $vote->name ? theme('username', $vote) : check_plain($vote->hostname), - check_plain($node->choice[$vote->chorder]['chtext'])); + check_plain($node->choices[$vote->chorder]['chtext'])); } $output .= theme('table', $header, $rows); $output .= theme('pager', NULL, 20, 0); @@ -524,9 +603,8 @@ if ($node = node_load($nid)) { $edit = $_POST; $choice = $edit['choice']; - $vote = $_POST['vote']; - if (isset($choice) && isset($node->choice[$choice])) { + if (isset($choice) && isset($node->choices[$choice])) { if ($node->allowvotes) { // Record the vote by this user or host. if ($user->uid) { @@ -540,7 +618,7 @@ db_query("UPDATE {poll_choices} SET chvotes = chvotes + 1 WHERE nid = %d AND chorder = %d", $node->nid, $choice); $node->allowvotes = FALSE; - $node->choice[$choice]['chvotes']++; + $node->choices[$choice]['chvotes']++; cache_clear_all(); drupal_set_message(t('Your vote was recorded.')); } @@ -578,7 +656,7 @@ // Subtract from the votes. db_query("UPDATE {poll_choices} SET chvotes = chvotes - 1 WHERE nid = %d AND chorder = %d", $node->nid, $node->vote); $node->allowvotes = TRUE; - $node->choice[$node->vote]['chvotes']--; + $node->choices[$node->vote]['chvotes']--; drupal_set_message(t('Your vote was canceled.')); } else { @@ -617,7 +695,7 @@ } if (!empty($node->allowvotes) && ($block || arg(2) != 'results')) { - if ($_POST['op'] == t('Vote')) { + if (isset($_POST['op']) && $_POST['op'] == t('Vote')) { poll_vote($node); } $node->content['body'] = array( @@ -642,7 +720,7 @@ db_query('DELETE FROM {poll_votes} WHERE nid = %d', $node->nid); $i = 0; - foreach ($node->choice as $choice) { + foreach ($node->choices as $choice) { $chvotes = (int)$choice['chvotes']; $chtext = $choice['chtext'];