diff --git a/core/lib/Drupal/Core/Form/FormErrorHandler.php b/core/lib/Drupal/Core/Form/FormErrorHandler.php index e2b3090..8fd3851 100644 --- a/core/lib/Drupal/Core/Form/FormErrorHandler.php +++ b/core/lib/Drupal/Core/Form/FormErrorHandler.php @@ -24,6 +24,13 @@ class FormErrorHandler implements FormErrorHandlerInterface { use LinkGeneratorTrait; /** + * Associated array of elements with errors which need to be linked to from the error message + * + * @var array[] + */ + protected $errorLinkElements = []; + + /** * Constructs a new FormErrorHandler. * * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation @@ -40,37 +47,46 @@ public function __construct(TranslationInterface $string_translation, LinkGenera * {@inheritdoc} */ public function handleFormErrors(array &$form, FormStateInterface $form_state) { - // Display error messages for each element. - $this->displayErrorMessages($form, $form_state); - // After validation, loop through and assign each element its errors. $this->setElementErrorsFromFormState($form, $form_state); + // Display error messages for each element. + $this->displayErrorMessages($form_state, $this->errorLinkElements); + + // Reset the list of elements with errors + $this->errorLinkElements = []; + return $this; } /** * Loops through and displays all form errors. * - * @param array $form - * An associative array containing the structure of the form. * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. + * @param array[] $error_elements + * An associative array of elements with errors */ - protected function displayErrorMessages(array $form, FormStateInterface $form_state) { + protected function displayErrorMessages(FormStateInterface $form_state, array $error_elements = []) { $error_links = []; - // Loop through all form errors and display a link for each error that is - // associated with a visible form element. - foreach ($form_state->getErrors() as $key => $error) { - if (($form_element = FormElementHelper::getElementByName($key, $form)) && Element::isVisibleElement($form_element)) { - $title = FormElementHelper::getElementTitle($form_element); - $error_links[] = $this->l($title, Url::fromRoute('', [], ['fragment' => 'edit-' . str_replace('_', '-', $key), 'external' => TRUE])); - } - else { - $this->drupalSetMessage($error, 'error'); + $errors = $form_state->getErrors(); + + // Create error links for all visible element with titles and with errors + foreach ($error_elements as $form_element) { + if (Element::isVisibleElement($form_element) && $title = FormElementHelper::getElementTitle($form_element)) { + $error_links[] = $this->l($title, Url::fromRoute('', [], [ + 'fragment' => $form_element['#id'], + 'external' => TRUE + ])); + unset($errors[implode('][', $form_element['#parents'])]); } } + // For all left over errors set normal error messages + foreach ($errors as $error) { + $this->drupalSetMessage($error, 'error'); + } + if (!empty($error_links)) { // We need to pass this through SafeMarkup::format() so // drupal_set_message() does not encode the links. @@ -105,8 +121,12 @@ protected function setElementErrorsFromFormState(array &$elements, FormStateInte $this->setElementErrorsFromFormState($elements[$key], $form_state); } } - // Store the errors for this element on the element directly. - $elements['#errors'] = $form_state->getError($elements); + + // Store the possible errors for this element on the element directly and + // keep a list of elements with errors for the error links + if ($elements['#errors'] = $form_state->getError($elements)) { + $this->errorLinkElements[$elements['#name']] = $elements; + }; } /** diff --git a/core/themes/seven/css/components/form.css b/core/themes/seven/css/components/form.css index 7db0a7f..bb9e1b4 100644 --- a/core/themes/seven/css/components/form.css +++ b/core/themes/seven/css/components/form.css @@ -43,7 +43,6 @@ label[for] { .form-disabled label { color: #737373; } - .form-disabled input.form-text, .form-disabled input.form-tel, .form-disabled input.form-email, @@ -58,7 +57,6 @@ label[for] { background-color: hsla(0, 0%, 0%, .08); box-shadow: none; } - .form-item input.error, .form-item textarea.error, .form-item select.error { @@ -68,12 +66,10 @@ label[for] { box-shadow: inset 0 5px 5px -5px #b8b8b8; color: #a51b00; } - .form-item textarea.error + .cke { border-width: 1px; border-color: #e62600; } - .form-item input.error:focus, .form-item textarea.error:focus, .form-item select.error:focus { @@ -88,16 +84,13 @@ label[for] { width: 7px; height: 7px; } - .form-error-message { margin-top: 0.15em; color: #ea2800; } - .fieldset-wrapper > .form-error-message { margin-top: 0; } - .text-format-wrapper .form-error-message { border: solid #ccc; border-width: 0 1px;