diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 5bae4736b0cb2d4d944f5f30b8a02cd7035d3ba7..776237e6e0a0add36b609122e580a9cd3fafad93 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,6 +1,9 @@ Drupal 7.17, xxxx-xx-xx (development version) ----------------------- +- Prevented duplicate HTML IDs from appearing when two forms are displayed on + the same page and one of them was submitted with invalid data (minor markup + change). - Fixed the theme settings form to properly clean up submitted values in $form_state['values'] when the form is submitted (data structure change). - Updated various admin tables to use the default "empty table" text UX diff --git a/includes/form.inc b/includes/form.inc index 826b6777bcdeb1eaa67dfceb90abcd6bbefc78f2..fa49839e4570397e7c576b734fc4778c6d6563f1 100644 --- a/includes/form.inc +++ b/includes/form.inc @@ -850,7 +850,10 @@ function drupal_process_form($form_id, &$form, &$form_state) { // cache when a form is processed, so scenarios that result in // the form being built behind the scenes and again for the // browser don't increment all the element IDs needlessly. - drupal_static_reset('drupal_html_id'); + if (!form_get_errors()) { + // In case of errors, do not break HTML IDs of other forms. + drupal_static_reset('drupal_html_id'); + } if ($form_state['submitted'] && !form_get_errors() && !$form_state['rebuild']) { // Execute form submit handlers. diff --git a/modules/simpletest/tests/form.test b/modules/simpletest/tests/form.test index 675e8d189086251b5283b0f11793470b25c21f8a..620621a69d349ef61e670e925dbce141288464cf 100644 --- a/modules/simpletest/tests/form.test +++ b/modules/simpletest/tests/form.test @@ -1750,3 +1750,34 @@ class FormCheckboxTestCase extends DrupalWebTestCase { } } } + +/** + * Tests uniqueness of generated HTML IDs. + */ +class HTMLIdTestCase extends DrupalWebTestCase { + + public static function getInfo() { + return array( + 'name' => 'Unique HTML IDs', + 'description' => 'Tests functionality of drupal_html_id().', + 'group' => 'Form API', + ); + } + + function setUp() { + parent::setUp('form_test'); + } + + /** + * Tests that HTML IDs do not get duplicated when form validation fails. + */ + function testHTMLId() { + $this->drupalGet('form-test/double-form'); + $this->assertNoDuplicateIds('There are no duplicate IDs'); + + // Submit second form with empty title. + $edit = array(); + $this->drupalPost(NULL, $edit, 'Save', array(), array(), 'form-test-html-id--2'); + $this->assertNoDuplicateIds('There are no duplicate IDs'); + } +} diff --git a/modules/simpletest/tests/form_test.module b/modules/simpletest/tests/form_test.module index 5d6527680f0f5b2d0c5aa20aa02ffcc22e3083e6..6af18c6aff4c403961994c6ce79071b85c4aa88a 100644 --- a/modules/simpletest/tests/form_test.module +++ b/modules/simpletest/tests/form_test.module @@ -194,6 +194,12 @@ function form_test_menu() { 'type' => MENU_CALLBACK, ); } + $items['form-test/double-form'] = array( + 'title' => 'Double form test', + 'page callback' => 'form_test_double_form', + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ); $items['form-test/load-include-menu'] = array( 'title' => 'FAPI test loading includes', @@ -1787,3 +1793,29 @@ function form_test_checkboxes_zero($form, &$form_state, $json = TRUE) { function _form_test_checkboxes_zero_no_redirect($form, &$form_state) { $form_state['redirect'] = FALSE; } + +/** + * Menu callback returns two instances of the same form. + */ +function form_test_double_form() { + return array( + 'form1' => drupal_get_form('form_test_html_id'), + 'form2' => drupal_get_form('form_test_html_id'), + ); +} + +/** + * Builds a simple form to test duplicate HTML IDs. + */ +function form_test_html_id($form, &$form_state) { + $form['name'] = array( + '#type' => 'textfield', + '#title' => 'name', + '#required' => TRUE, + ); + $form['submit'] = array( + '#type' => 'submit', + '#value' => 'Save', + ); + return $form; +}