diff --git a/core/misc/vertical-tabs.es6.js b/core/misc/vertical-tabs.es6.js index 85f200f5f80..67a9b3ea4de 100644 --- a/core/misc/vertical-tabs.es6.js +++ b/core/misc/vertical-tabs.es6.js @@ -118,6 +118,21 @@ } }, ); + + // If a validation error is within a vertical tab, open that tab. + context.querySelectorAll('details .form-item .error').forEach((item) => { + const details = item.closest('details'); + + if (details.style.display === 'none') { + const tabSelect = document.querySelector( + "[href='#".concat(details.id, "']"), + ); + + if (tabSelect) { + tabSelect.click(); + } + } + }); }, }; diff --git a/core/misc/vertical-tabs.js b/core/misc/vertical-tabs.js index d873550624b..e63b638c951 100644 --- a/core/misc/vertical-tabs.js +++ b/core/misc/vertical-tabs.js @@ -55,6 +55,15 @@ tabFocus.data('verticalTab').focus(); } }); + context.querySelectorAll('details .form-item .error').forEach(function (item) { + var details = item.closest('details'); + if (details.style.display === 'none') { + var tabSelect = document.querySelector("[href='#".concat(details.id, "']")); + if (tabSelect) { + tabSelect.click(); + } + } + }); } }; Drupal.verticalTab = function (settings) { diff --git a/core/modules/ckeditor5/js/ckeditor5.admin.es6.js b/core/modules/ckeditor5/js/ckeditor5.admin.es6.js index c996d2f506f..5e79b7cd746 100644 --- a/core/modules/ckeditor5/js/ckeditor5.admin.es6.js +++ b/core/modules/ckeditor5/js/ckeditor5.admin.es6.js @@ -1049,21 +1049,4 @@ // Call the original behavior. originalFilterStatusAttach(context, settings); }; - - // Activates otherwise-inactive tabs that have form elements with validation - // errors. - // @todo Remove when https://www.drupal.org/project/drupal/issues/2911932 lands. - Drupal.behaviors.tabErrorsVisible = { - attach(context) { - context.querySelectorAll('details .form-item .error').forEach((item) => { - const details = item.closest('details'); - if (details.style.display === 'none') { - const tabSelect = document.querySelector(`[href='#${details.id}']`); - if (tabSelect) { - tabSelect.click(); - } - } - }); - }, - }; })(Drupal, drupalSettings, jQuery, JSON, once, Sortable, tabbable); diff --git a/core/modules/ckeditor5/js/ckeditor5.admin.js b/core/modules/ckeditor5/js/ckeditor5.admin.js index 5ace5317f28..d8c3e521dd8 100644 --- a/core/modules/ckeditor5/js/ckeditor5.admin.js +++ b/core/modules/ckeditor5/js/ckeditor5.admin.js @@ -513,17 +513,4 @@ function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input == $(filterStatusCheckboxes).off('click.filterUpdate'); originalFilterStatusAttach(context, settings); }; - Drupal.behaviors.tabErrorsVisible = { - attach: function attach(context) { - context.querySelectorAll('details .form-item .error').forEach(function (item) { - var details = item.closest('details'); - if (details.style.display === 'none') { - var tabSelect = document.querySelector("[href='#".concat(details.id, "']")); - if (tabSelect) { - tabSelect.click(); - } - } - }); - } - }; })(Drupal, drupalSettings, jQuery, JSON, once, Sortable, tabbable); \ No newline at end of file diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestGroupVerticalTabsForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestGroupVerticalTabsForm.php index 7a29d7d7ee0..3e47c908c8c 100644 --- a/core/modules/system/tests/modules/form_test/src/Form/FormTestGroupVerticalTabsForm.php +++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestGroupVerticalTabsForm.php @@ -44,9 +44,22 @@ class FormTestGroupVerticalTabsForm extends FormBase { '#type' => 'textfield', '#title' => 'Second nested element in details element', ]; + $form['submit'] = [ + '#type' => 'submit', + '#value' => 'Save', + ]; return $form; } + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, FormStateInterface $form_state) { + if ($form_state->getValue('element_2') === 'bad') { + $form_state->setErrorByName('element_2', $this->t('there was an error')); + } + } + /** * {@inheritdoc} */ diff --git a/core/tests/Drupal/FunctionalJavascriptTests/Core/Form/FormGroupingElementsTest.php b/core/tests/Drupal/FunctionalJavascriptTests/Core/Form/FormGroupingElementsTest.php index e4cfcb9bec2..488e07d20a7 100644 --- a/core/tests/Drupal/FunctionalJavascriptTests/Core/Form/FormGroupingElementsTest.php +++ b/core/tests/Drupal/FunctionalJavascriptTests/Core/Form/FormGroupingElementsTest.php @@ -135,4 +135,33 @@ class FormGroupingElementsTest extends WebDriverTestBase { $this->assertEquals('true', $summary->getAttribute('aria-pressed')); } + /** + * Confirms tabs containing a field with a validation error are open. + */ + public function testVerticalTabValidationVisibility() { + $page = $this->getSession()->getPage(); + $assert_session = $this->assertSession(); + + $this->drupalGet('form-test/group-vertical-tabs'); + $page->clickLink('Second group element'); + $input_field = $assert_session->waitForField('element_2'); + $this->assertNotNull($input_field); + + // Enter a value that will trigger a validation error. + $input_field->setValue('bad'); + + // Switch to a tab that does not have the error-causing field. + $page->clickLink('First group element'); + $this->assertNotNull($assert_session->waitForElementVisible('css', '#edit-meta')); + + // Submit the form. + $page->pressButton('Save'); + + // Confirm there is an error. + $assert_session->waitForText('there was an error'); + + // Confirm the tab containing the field with error is open. + $this->assertNotNull($assert_session->waitForElementVisible('css', '[name="element_2"].error')); + } + }