Index: includes/form.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/form.inc,v retrieving revision 1.502 diff -u -p -r1.502 form.inc --- includes/form.inc 7 Oct 2010 17:31:39 -0000 1.502 +++ includes/form.inc 9 Oct 2010 14:21:23 -0000 @@ -2727,21 +2727,24 @@ function weight_value(&$form) { function form_process_radios($element) { if (count($element['#options']) > 0) { foreach ($element['#options'] as $key => $choice) { - if (!isset($element[$key])) { - // Generate the parents as the autogenerator does, so we will have a - // unique id for each radio button. - $parents_for_id = array_merge($element['#parents'], array($key)); - $element[$key] = array( - '#type' => 'radio', - '#title' => $choice, - '#return_value' => check_plain($key), - '#default_value' => isset($element['#default_value']) ? $element['#default_value'] : NULL, - '#attributes' => $element['#attributes'], - '#parents' => $element['#parents'], - '#id' => drupal_html_id('edit-' . implode('-', $parents_for_id)), - '#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL, - ); - } + $element += array($key => array()); + // Generate the parents as the autogenerator does, so we will have a + // unique id for each radio button. + $parents_for_id = array_merge($element['#parents'], array($key)); + $element[$key] += array( + '#type' => 'radio', + '#title' => $choice, + '#return_value' => check_plain($key), + '#default_value' => isset($element['#default_value']) ? $element['#default_value'] : NULL, + '#attributes' => $element['#attributes'], + '#parents' => $element['#parents'], + '#id' => drupal_html_id('edit-' . implode('-', $parents_for_id)), + '#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL, + // Maintain order of options as defined in #options, in case the element + // defines custom option sub-elements, but does not define all option + // sub-elements. + '#weight' => 0, + ); } } return $element; @@ -2825,17 +2828,20 @@ function form_process_checkboxes($elemen $element['#default_value'] = array(); } foreach ($element['#options'] as $key => $choice) { - if (!isset($element[$key])) { - $element[$key] = array( - '#type' => 'checkbox', - '#processed' => TRUE, - '#title' => $choice, - '#return_value' => $key, - '#default_value' => isset($value[$key]) ? $key : NULL, - '#attributes' => $element['#attributes'], - '#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL, - ); - } + $element += array($key => array()); + $element[$key] += array( + '#type' => 'checkbox', + '#processed' => TRUE, + '#title' => $choice, + '#return_value' => $key, + '#default_value' => isset($value[$key]) ? $key : NULL, + '#attributes' => $element['#attributes'], + '#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL, + // Maintain order of options as defined in #options, in case the element + // defines custom option sub-elements, but does not define all option + // sub-elements. + '#weight' => 0, + ); } } return $element; Index: modules/comment/comment.module =================================================================== RCS file: /cvs/drupal/drupal/modules/comment/comment.module,v retrieving revision 1.904 diff -u -p -r1.904 comment.module --- modules/comment/comment.module 5 Oct 2010 06:17:28 -0000 1.904 +++ modules/comment/comment.module 9 Oct 2010 13:29:41 -0000 @@ -1179,31 +1179,13 @@ function comment_form_node_form_alter(&$ COMMENT_NODE_HIDDEN => t('Hidden'), ), COMMENT_NODE_OPEN => array( - '#type' => 'radio', - '#title' => t('Open'), '#description' => t('Users with the "Post comments" permission can post comments.'), - '#return_value' => COMMENT_NODE_OPEN, - '#default_value' => $comment_settings, - '#id' => 'edit-comment-2', - '#parents' => array('comment'), ), COMMENT_NODE_CLOSED => array( - '#type' => 'radio', - '#title' => t('Closed'), '#description' => t('Users cannot post comments, but existing comments will be displayed.'), - '#return_value' => COMMENT_NODE_CLOSED, - '#default_value' => $comment_settings, - '#id' => 'edit-comment-1', - '#parents' => array('comment'), ), COMMENT_NODE_HIDDEN => array( - '#type' => 'radio', - '#title' => t('Hidden'), '#description' => t('Comments are hidden from view.'), - '#return_value' => COMMENT_NODE_HIDDEN, - '#default_value' => $comment_settings, - '#id' => 'edit-comment-0', - '#parents' => array('comment'), ), ); // If the node doesn't have any comments, the "hidden" option makes no Index: modules/simpletest/tests/form.test =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/tests/form.test,v retrieving revision 1.72 diff -u -p -r1.72 form.test --- modules/simpletest/tests/form.test 4 Oct 2010 18:00:46 -0000 1.72 +++ modules/simpletest/tests/form.test 9 Oct 2010 14:40:59 -0000 @@ -370,6 +370,53 @@ class FormsTestCase extends DrupalWebTes } /** + * Tests building and processing of core form elements. + */ +class FormElementTestCase extends DrupalWebTestCase { + protected $profile = 'testing'; + + public static function getInfo() { + return array( + 'name' => 'Element building/processing', + 'description' => 'Tests building and processing of core form elements.', + 'group' => 'Form API', + ); + } + + function setUp() { + parent::setUp(array('form_test')); + } + + /** + * Tests expansion of #options for #type checkboxes and radios. + */ + function testOptions() { + $this->drupalGet('form-test/checkboxes-radios'); + + // Verify that all options appear in their defined order, taking a custom + // #weight into account. + foreach (array('checkbox', 'radio') as $type) { + $elements = $this->xpath('//input[@type=:type]', array(':type' => $type)); + $expected_values = array('0', 'foo', 'bar', '1'); + foreach ($elements as $element) { + $expected = array_shift($expected_values); + $this->assertIdentical((string) $element['value'], $expected); + } + } + // Verify that custom #description properties are output. + foreach (array('checkboxes', 'radios') as $type) { + $elements = $this->xpath('//input[@name=:name]/following-sibling::div[@class=:class]', array( + ':name' => $type . '[foo]', + ':class' => 'description', + )); + $this->assertTrue(count($elements), t('Custom %type option description found.', array( + '%type' => $type, + ))); + } + } +} + +/** * Test form alter hooks. */ class FormAlterTestCase extends DrupalWebTestCase { Index: modules/simpletest/tests/form_test.module =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/tests/form_test.module,v retrieving revision 1.51 diff -u -p -r1.51 form_test.module --- modules/simpletest/tests/form_test.module 4 Oct 2010 18:00:46 -0000 1.51 +++ modules/simpletest/tests/form_test.module 9 Oct 2010 14:21:51 -0000 @@ -98,6 +98,12 @@ function form_test_menu() { 'page arguments' => array('form_test_select'), 'access callback' => TRUE, ); + $items['form-test/checkboxes-radios'] = array( + 'title' => t('Checkboxes, Radios'), + 'page callback' => 'drupal_get_form', + 'page arguments' => array('form_test_checkboxes_radios'), + 'access callback' => TRUE, + ); $items['form-test/disabled-elements'] = array( 'title' => t('Form test'), @@ -180,6 +186,14 @@ function form_test_menu() { } /** + * Form submit handler to return form values as JSON. + */ +function _form_test_submit_values_json($form, &$form_state) { + drupal_json_output($form_state['values']); + drupal_exit(); +} + +/** * Form builder for testing hook_form_alter() and hook_form_FORM_ID_alter(). */ function form_test_alter_form($form, &$form_state) { @@ -886,6 +900,55 @@ function form_test_select_submit($form, } /** + * Form constructor to test expansion of #type checkboxes and radios. + */ +function form_test_checkboxes_radios($form, &$form_state) { + $form['#submit'] = array('_form_test_submit_values_json'); + + // Expand #type checkboxes, setting custom element properties for some but not + // all options. + $form['checkboxes'] = array( + '#type' => 'checkboxes', + '#title' => 'Checkboxes', + '#options' => array( + 0 => 'Zero', + 'foo' => 'Foo', + 1 => 'One', + 'bar' => 'Bar', + ), + 'foo' => array( + '#description' => 'Enable to foo.', + ), + 1 => array( + '#weight' => 10, + ), + ); + + // Expand #type radios, setting custom element properties for some but not + // all options. + $form['radios'] = array( + '#type' => 'radios', + '#title' => 'Radios', + '#options' => array( + 0 => 'Zero', + 'foo' => 'Foo', + 1 => 'One', + 'bar' => 'Bar', + ), + 'foo' => array( + '#description' => 'Enable to foo.', + ), + 1 => array( + '#weight' => 10, + ), + ); + + $form['submit'] = array('#type' => 'submit', '#value' => 'Submit'); + + return $form; +} + +/** * Build a form to test disabled elements. */ function _form_test_disabled_elements($form, &$form_state) {