Loading core/misc/details.js +13 −0 Original line number Diff line number Diff line Loading @@ -28,4 +28,17 @@ 'formFragmentLinkClickOrHashChange.details', handleFragmentLinkClickOrHashChange, ); /** * Binds a listener to handle required fields in details elements. */ window.addEventListener( 'invalid', (event) => { if (event.target.matches('details input[required]')) { handleFragmentLinkClickOrHashChange(event, $(event.target)); } }, { capture: true }, ); })(jQuery); core/modules/system/tests/modules/form_test/form_test.routing.yml +9 −0 Original line number Diff line number Diff line Loading @@ -433,6 +433,15 @@ form_test.details_form: requirements: _access: 'TRUE' form_test.details_contains_required_textfield: path: '/form_test/details-contains-required-textfield/{use_ajax}' defaults: _form: '\Drupal\form_test\Form\FormTestDetailsContainsRequiredTextfieldForm' _title: 'Form details contains required textfield test' use_ajax: FALSE requirements: _access: 'TRUE' form_test.description_display: path: '/form_test/form-descriptions' defaults: Loading core/modules/system/tests/modules/form_test/src/Form/FormTestDetailsContainsRequiredTextfieldForm.php 0 → 100644 +64 −0 Original line number Diff line number Diff line <?php declare(strict_types=1); namespace Drupal\form_test\Form; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; /** * Builds a form to test a required textfield within a details element. * * @internal */ class FormTestDetailsContainsRequiredTextfieldForm extends FormBase { /** * {@inheritdoc} */ public function getFormId(): string { return 'form_test_details_form'; } /** * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state, $use_ajax = FALSE): array { $form['meta'] = [ '#type' => 'details', '#title' => 'Details element', '#open' => FALSE, ]; $form['meta']['required_textfield_in_details'] = [ '#type' => 'textfield', '#required' => TRUE, '#title' => 'Required textfield', ]; $form['submit'] = [ '#type' => 'submit', '#value' => 'Submit', ]; if ($use_ajax) { $form['submitAjax'] = [ '#type' => 'submit', '#value' => 'Submit Ajax', '#ajax' => [ 'callback' => '::submitForm', 'event' => 'click', 'wrapper' => 'form-test-details-form', ], ]; } return $form; } /** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { return $form; } } core/tests/Drupal/FunctionalJavascriptTests/Core/Form/FormGroupingElementsTest.php +49 −0 Original line number Diff line number Diff line Loading @@ -165,4 +165,53 @@ public function testVerticalTabValidationVisibility() { $this->assertNotNull($assert_session->waitForElementVisible('css', '[name="element_2"].error')); } /** * Tests form submit with a required field in closed details element. */ public function testDetailsContainsRequiredTextfield(): void { $this->drupalGet('form_test/details-contains-required-textfield'); $details = $this->assertSession()->elementExists('css', 'details[data-drupal-selector="edit-meta"]'); // Make sure details element is not open at the beginning. $this->assertFalse($details->hasAttribute('open')); $textfield = $this->assertSession()->elementExists('css', 'input[name="required_textfield_in_details"]'); // The text field inside the details element is not visible too. $this->assertFalse($textfield->isVisible(), 'Text field is not visible'); // Submit the form with invalid data in the required fields. $this->assertSession() ->elementExists('css', 'input[data-drupal-selector="edit-submit"]') ->click(); // Confirm the required field is visible. $this->assertTrue($textfield->isVisible(), 'Text field is visible'); } /** * Tests required field in closed details element with ajax form. */ public function testDetailsContainsRequiredTextfieldAjaxForm(): void { $this->drupalGet('form_test/details-contains-required-textfield/true'); $assert_session = $this->assertSession(); $textfield = $assert_session->elementExists('css', 'input[name="required_textfield_in_details"]'); // Submit the ajax form to open the details element at the first time. $assert_session->elementExists('css', 'input[value="Submit Ajax"]') ->click(); $assert_session->waitForElementVisible('css', 'input[name="required_textfield_in_details"]'); // Close the details element. $assert_session->elementExists('css', 'form summary') ->click(); // Submit the form with invalid data in the required fields without ajax. $assert_session->elementExists('css', 'input[data-drupal-selector="edit-submit"]') ->click(); // Confirm the required field is visible. $this->assertTrue($textfield->isVisible(), 'Text field is visible'); } } Loading
core/misc/details.js +13 −0 Original line number Diff line number Diff line Loading @@ -28,4 +28,17 @@ 'formFragmentLinkClickOrHashChange.details', handleFragmentLinkClickOrHashChange, ); /** * Binds a listener to handle required fields in details elements. */ window.addEventListener( 'invalid', (event) => { if (event.target.matches('details input[required]')) { handleFragmentLinkClickOrHashChange(event, $(event.target)); } }, { capture: true }, ); })(jQuery);
core/modules/system/tests/modules/form_test/form_test.routing.yml +9 −0 Original line number Diff line number Diff line Loading @@ -433,6 +433,15 @@ form_test.details_form: requirements: _access: 'TRUE' form_test.details_contains_required_textfield: path: '/form_test/details-contains-required-textfield/{use_ajax}' defaults: _form: '\Drupal\form_test\Form\FormTestDetailsContainsRequiredTextfieldForm' _title: 'Form details contains required textfield test' use_ajax: FALSE requirements: _access: 'TRUE' form_test.description_display: path: '/form_test/form-descriptions' defaults: Loading
core/modules/system/tests/modules/form_test/src/Form/FormTestDetailsContainsRequiredTextfieldForm.php 0 → 100644 +64 −0 Original line number Diff line number Diff line <?php declare(strict_types=1); namespace Drupal\form_test\Form; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; /** * Builds a form to test a required textfield within a details element. * * @internal */ class FormTestDetailsContainsRequiredTextfieldForm extends FormBase { /** * {@inheritdoc} */ public function getFormId(): string { return 'form_test_details_form'; } /** * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state, $use_ajax = FALSE): array { $form['meta'] = [ '#type' => 'details', '#title' => 'Details element', '#open' => FALSE, ]; $form['meta']['required_textfield_in_details'] = [ '#type' => 'textfield', '#required' => TRUE, '#title' => 'Required textfield', ]; $form['submit'] = [ '#type' => 'submit', '#value' => 'Submit', ]; if ($use_ajax) { $form['submitAjax'] = [ '#type' => 'submit', '#value' => 'Submit Ajax', '#ajax' => [ 'callback' => '::submitForm', 'event' => 'click', 'wrapper' => 'form-test-details-form', ], ]; } return $form; } /** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { return $form; } }
core/tests/Drupal/FunctionalJavascriptTests/Core/Form/FormGroupingElementsTest.php +49 −0 Original line number Diff line number Diff line Loading @@ -165,4 +165,53 @@ public function testVerticalTabValidationVisibility() { $this->assertNotNull($assert_session->waitForElementVisible('css', '[name="element_2"].error')); } /** * Tests form submit with a required field in closed details element. */ public function testDetailsContainsRequiredTextfield(): void { $this->drupalGet('form_test/details-contains-required-textfield'); $details = $this->assertSession()->elementExists('css', 'details[data-drupal-selector="edit-meta"]'); // Make sure details element is not open at the beginning. $this->assertFalse($details->hasAttribute('open')); $textfield = $this->assertSession()->elementExists('css', 'input[name="required_textfield_in_details"]'); // The text field inside the details element is not visible too. $this->assertFalse($textfield->isVisible(), 'Text field is not visible'); // Submit the form with invalid data in the required fields. $this->assertSession() ->elementExists('css', 'input[data-drupal-selector="edit-submit"]') ->click(); // Confirm the required field is visible. $this->assertTrue($textfield->isVisible(), 'Text field is visible'); } /** * Tests required field in closed details element with ajax form. */ public function testDetailsContainsRequiredTextfieldAjaxForm(): void { $this->drupalGet('form_test/details-contains-required-textfield/true'); $assert_session = $this->assertSession(); $textfield = $assert_session->elementExists('css', 'input[name="required_textfield_in_details"]'); // Submit the ajax form to open the details element at the first time. $assert_session->elementExists('css', 'input[value="Submit Ajax"]') ->click(); $assert_session->waitForElementVisible('css', 'input[name="required_textfield_in_details"]'); // Close the details element. $assert_session->elementExists('css', 'form summary') ->click(); // Submit the form with invalid data in the required fields without ajax. $assert_session->elementExists('css', 'input[data-drupal-selector="edit-submit"]') ->click(); // Confirm the required field is visible. $this->assertTrue($textfield->isVisible(), 'Text field is visible'); } }