Index: modules/poll/poll.css
===================================================================
RCS file: /cvs/drupal/drupal/modules/poll/poll.css,v
retrieving revision 1.4
diff -u -r1.4 poll.css
--- modules/poll/poll.css	2 Aug 2007 10:46:53 -0000	1.4
+++ modules/poll/poll.css	5 Oct 2007 16:55:06 -0000
@@ -31,6 +31,6 @@
   font-weight: bold;
 }
 
-.node-form .poll-form fieldset {
-  display: block;
+.node-form .poll-form .form-item {
+  margin-top: 0;
 }
Index: modules/poll/poll.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/poll/poll.module,v
retrieving revision 1.242
diff -u -r1.242 poll.module
--- modules/poll/poll.module	6 Sep 2007 12:18:01 -0000	1.242
+++ modules/poll/poll.module	5 Oct 2007 16:55:06 -0000
@@ -96,6 +96,14 @@
     'type' => MENU_LOCAL_TASK,
     'file' => 'poll.pages.inc',
   );
+
+  $items['poll/js'] = array(
+    'title' => 'Javascript Choice Form',
+    'page callback' => 'poll_choice_js',
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
+
   return $items;
 }
 
@@ -168,64 +176,65 @@
 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),
     '#required' => TRUE,
     '#default_value' => $node->title,
-    '#weight' => -1
+    '#weight' => -5,
   );
 
-  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->choice) ? 5 : count($node->choice));
   }
 
-  $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' => '<div class="poll-form">',
-    '#suffix' => '</div>',
-    '#tree' => TRUE
+    '#tree' => FALSE,
+    '#attributes' => array('class' => 'clear-block'),
+    '#weight' => -5,
   );
 
-  // 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']['choice'] = array(
+    '#prefix' => '<div class="poll-form" id="poll-choices">',
+    '#suffix' => '</div>',
   );
 
-  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'] : '',
-    );
+  // Add the current choices to the form.
+  for ($delta = 0; $delta < $choice_count; $delta++) {
+    $text = isset($node->choice[$delta]['chtext']) ? $node->choice[$delta]['chtext'] : '';
+    $votes = isset($node->choice[$delta]['chvotes']) ? $node->choice[$delta]['chvotes'] : '';
 
-    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
-      );
-    }
+    $form['choice_wrapper']['choice'][$delta] = _poll_choice_form($delta, $text, $votes);
   }
 
+  // We name our button 'poll_more' to avoid conflicts with other modules using
+  // AHAH-enabled 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' => array(
+      'path' => 'poll/js',
+      'wrapper' => 'poll-choices',
+      'method' => 'append',
+      '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'));
@@ -253,16 +262,88 @@
 }
 
 /**
+ * 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']['choice']) + 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']['choice'] array.
+  $form['chtext'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Choice @n', array('@n' => ($delta + 1))),
+    '#default_value' => isset($value) ? $value : '',
+    '#parents' => array('choice', $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('choice', $delta, 'chvotes'),
+    );
+  }
+  
+  return $form;
+}
+
+/**
+ * Menu callback for AHAH additions.
+ */
+function poll_choice_js() {
+  $delta = count($_POST['choice']);
+
+  // 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']['choice'][$delta] = $form_element;
+  cache_set('form_'. $_POST['form_build_id'], $form->data, 'cache_form', $form->expire);
+
+  // 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.
+  drupal_json(array('status' => TRUE, 'data' => $output));
+}
+
+/**
  * Implementation of hook_submit().
  */
 function poll_node_form_submit(&$form, &$form_state) {
   // Renumber fields
   $form_state['values']['choice'] = array_values($form_state['values']['choice']);
   $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;
-  }
 }
 
 /**
Index: misc/ahah.js
===================================================================
RCS file: /cvs/drupal/drupal/misc/ahah.js,v
retrieving revision 1.3
diff -u -r1.3 ahah.js
--- misc/ahah.js	5 Oct 2007 09:35:08 -0000	1.3
+++ misc/ahah.js	5 Oct 2007 16:55:06 -0000
@@ -128,11 +128,6 @@
   progress_element.remove();
   $(this.element).removeClass('progess-disabled').attr('disabled', false);
 
-  // Hide the new content before adding to page.
-  if (this.showEffect != 'show') {
-    new_content.hide();
-  }
-
   // Add the new content to the page.
   Drupal.freezeHeight();
   if (this.method == 'replace') {
@@ -142,10 +137,18 @@
     wrapper[this.method](new_content);
   }
 
+  // Immediately hide the new content if we're using any effects.
+  if (this.showEffect != 'show') {
+    new_content.hide();
+  }
+
   // Determine what effect use and what content will receive the effect, then
   // show the new content. For browser compatibility, Safari is excluded from
   // using effects on table rows.
-  if ($('.ahah-new-content', new_content).size() > 0 && !($.browser.safari && $("tr.ahah-new-content", new_content).size() > 0)) {
+  if (($.browser.safari && $("tr.ahah-new-content", new_content).size() > 0)) {
+    new_content.show();
+  }
+  else if ($('.ahah-new-content', new_content).size() > 0) {
     $('.ahah-new-content', new_content).hide();
     new_content.show();
     $(".ahah-new-content", new_content)[this.showEffect](this.showSpeed);
