diff --git a/core/includes/theme.inc b/core/includes/theme.inc index 2aef832c..d19c0ff 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -481,6 +481,10 @@ function template_preprocess_datetime_wrapper(&$variables) { $variables['title'] = $element['#title']; } + if (!empty($element['#errors'])) { + $variables['errors'] = $element['#errors']; + } + if (!empty($element['#description'])) { $variables['description'] = $element['#description']; } diff --git a/core/lib/Drupal/Core/Datetime/Element/Datelist.php b/core/lib/Drupal/Core/Datetime/Element/Datelist.php index c330a4f..f938a7e 100644 --- a/core/lib/Drupal/Core/Datetime/Element/Datelist.php +++ b/core/lib/Drupal/Core/Datetime/Element/Datelist.php @@ -265,6 +265,7 @@ public static function processDatelist(&$element, FormStateInterface $form_state '#attributes' => $element['#attributes'], '#options' => $options, '#required' => $element['#required'], + '#error_use_parent' => TRUE, ); } diff --git a/core/lib/Drupal/Core/Datetime/Element/Datetime.php b/core/lib/Drupal/Core/Datetime/Element/Datetime.php index d298e21..8af82f1 100644 --- a/core/lib/Drupal/Core/Datetime/Element/Datetime.php +++ b/core/lib/Drupal/Core/Datetime/Element/Datetime.php @@ -267,6 +267,7 @@ public static function processDatetime(&$element, FormStateInterface $form_state '#attributes' => $element['#attributes'] + $extra_attributes, '#required' => $element['#required'], '#size' => max(12, strlen($element['#value']['date'])), + '#error_use_parent' => TRUE, ); // Allows custom callbacks to alter the element. @@ -298,6 +299,7 @@ public static function processDatetime(&$element, FormStateInterface $form_state '#attributes' => $element['#attributes'] + $extra_attributes, '#required' => $element['#required'], '#size' => 12, + '#error_use_parent' => TRUE, ); // Allows custom callbacks to alter the element. diff --git a/core/lib/Drupal/Core/Form/FormErrorHandler.php b/core/lib/Drupal/Core/Form/FormErrorHandler.php index 75ef779..d8bf7d0 100644 --- a/core/lib/Drupal/Core/Form/FormErrorHandler.php +++ b/core/lib/Drupal/Core/Form/FormErrorHandler.php @@ -24,7 +24,7 @@ class FormErrorHandler implements FormErrorHandlerInterface { use LinkGeneratorTrait; /** - * Associated array of elements with errors which need to be linked to from + * Array of elements with errors which need to be linked to from * the error message * * @var array[] @@ -52,7 +52,7 @@ public function handleFormErrors(array &$form, FormStateInterface $form_state) { $this->setElementErrorsFromFormState($form, $form_state); // Display error messages for each element. - $this->displayErrorMessages($form_state, $this->errorLinkElements); + $this->displayErrorMessages($form_state); // Reset the list of elements with errors $this->errorLinkElements = []; @@ -66,14 +66,14 @@ public function handleFormErrors(array &$form, FormStateInterface $form_state) { * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. * @param array[] $error_elements - * An associative array of elements with errors + * An array of elements with errors */ - protected function displayErrorMessages(FormStateInterface $form_state, array $error_elements = []) { + protected function displayErrorMessages(FormStateInterface $form_state) { $error_links = []; $errors = $form_state->getErrors(); // Create error links - foreach ($error_elements as $form_element) { + foreach ($this->errorLinkElements as $form_element) { $title = FormElementHelper::getElementTitle($form_element); // Only show links to erroneous elements that are visible @@ -123,7 +123,7 @@ protected function displayErrorMessages(FormStateInterface $form_state, array $e * specific element. The most common usage of this is a #pre_render callback. * * @param array $elements - * An associative array containing the structure of a form element. + * An array containing the structure of a form element. * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. */ @@ -137,10 +137,8 @@ protected function setElementErrorsFromFormState(array &$elements, FormStateInte // Store the errors for this element on the element directly and // keep a list of elements with errors - // @todo get the element name differently when $elements['#name'] is not set - // like from #parents or the form structure - if (($elements['#errors'] = $form_state->getError($elements)) && !empty($elements['#name'])) { - $this->errorLinkElements[$elements['#name']] = $elements; + if (($elements['#errors'] = $form_state->getError($elements))) { + $this->errorLinkElements[] = $elements; }; } diff --git a/core/modules/file/src/Element/ManagedFile.php b/core/modules/file/src/Element/ManagedFile.php index 40d0c31..4c70ef1 100644 --- a/core/modules/file/src/Element/ManagedFile.php +++ b/core/modules/file/src/Element/ManagedFile.php @@ -328,7 +328,7 @@ public static function validateManagedFile(&$element, FormStateInterface $form_s // Check required property based on the FID. if ($element['#required'] && empty($element['fids']['#value']) && !in_array($clicked_button, ['upload_button', 'remove_button'])) { - $form_state->setError($element['upload'], t('!name field is required.', ['!name' => $element['#title']])); + $form_state->setError($element, t('!name is required.', ['!name' => $element['#title']])); } // Consolidate the array value of this field to array of FIDs. diff --git a/core/modules/shortcut/src/Tests/ShortcutSetsTest.php b/core/modules/shortcut/src/Tests/ShortcutSetsTest.php index 476a393..3d2c5cf 100644 --- a/core/modules/shortcut/src/Tests/ShortcutSetsTest.php +++ b/core/modules/shortcut/src/Tests/ShortcutSetsTest.php @@ -134,7 +134,7 @@ function testShortcutSetSwitchNoSetName() { $edit = array('set' => 'new'); $this->drupalPostForm('user/' . $this->adminUser->id() . '/shortcuts', $edit, t('Change set')); $this->assertRaw(\Drupal::translation()->formatPlural(1, '1 error has been found: !errors', '@count errors have been found: !errors', [ - '!errors' => SafeMarkup::set('New set') + '!errors' => SafeMarkup::set('Label') ])); $current_set = shortcut_current_displayed_set($this->adminUser); $this->assertEqual($current_set->id(), $this->set->id(), 'Attempting to switch to a new shortcut set without providing a set name does not succeed.'); diff --git a/core/tests/Drupal/Tests/Core/Form/FormErrorHandlerTest.php b/core/tests/Drupal/Tests/Core/Form/FormErrorHandlerTest.php index d785e27..4b14df0 100644 --- a/core/tests/Drupal/Tests/Core/Form/FormErrorHandlerTest.php +++ b/core/tests/Drupal/Tests/Core/Form/FormErrorHandlerTest.php @@ -44,14 +44,12 @@ public function testDisplayErrorMessages() { '#type' => 'textfield', '#title' => 'Test 1', '#parents' => ['test1'], - '#name' => 'test1', '#id' => 'edit-test1', ]; $form['test2'] = [ '#type' => 'textfield', '#title' => 'Test 2', '#parents' => ['test2'], - '#name' => 'test2', '#id' => 'edit-test2', ]; $form['fieldset'] = [ @@ -60,7 +58,6 @@ public function testDisplayErrorMessages() { '#type' => 'textfield', '#title' => 'Test 3', '#parents' => ['fieldset', 'test3'], - '#name' => 'test3', '#id' => 'edit-test3', ), ]; @@ -90,7 +87,6 @@ public function testSetElementErrorsFromFormState() { '#type' => 'textfield', '#title' => 'Test', '#parents' => ['test'], - '#name' => 'test', '#id' => 'edit-test', ]; $form_state = new FormState(); diff --git a/core/themes/classy/templates/form/datetime-wrapper.html.twig b/core/themes/classy/templates/form/datetime-wrapper.html.twig index 399dea2..56da173 100644 --- a/core/themes/classy/templates/form/datetime-wrapper.html.twig +++ b/core/themes/classy/templates/form/datetime-wrapper.html.twig @@ -23,6 +23,11 @@ {{ title }} {% endif %} {{ content }} +{% if errors %} +
+ {{ errors }} +
+{% endif %} {% if description %}
{{ description }}
{% endif %} diff --git a/core/themes/classy/templates/form/fieldset.html.twig b/core/themes/classy/templates/form/fieldset.html.twig index aa14b30..9286074 100644 --- a/core/themes/classy/templates/form/fieldset.html.twig +++ b/core/themes/classy/templates/form/fieldset.html.twig @@ -21,11 +21,6 @@ */ #} - {% if errors %} -
- {{ errors }} -
- {% endif %} {% set legend_span_classes = [ 'fieldset-legend', @@ -37,6 +32,11 @@ {{ legend.title }}
+ {% if errors %} +
+ {{ errors }} +
+ {% endif %} {% if prefix %} {{ prefix }} {% endif %} diff --git a/core/themes/classy/templates/form/form-element.html.twig b/core/themes/classy/templates/form/form-element.html.twig index d238ac5..ac2db3c 100644 --- a/core/themes/classy/templates/form/form-element.html.twig +++ b/core/themes/classy/templates/form/form-element.html.twig @@ -61,11 +61,6 @@ ] %} - {% if errors %} -
- {{ errors }} -
- {% endif %} {% if label_display in ['before', 'invisible'] %} {{ label }} {% endif %} @@ -84,6 +79,11 @@ {% if label_display == 'after' %} {{ label }} {% endif %} + {% if errors %} +
+ {{ errors }} +
+ {% endif %} {% if description_display in ['after', 'invisible'] and description.content %} {{ description.content }} diff --git a/core/themes/seven/templates/fieldset.html.twig b/core/themes/seven/templates/fieldset.html.twig deleted file mode 100644 index cf7db0d..0000000 --- a/core/themes/seven/templates/fieldset.html.twig +++ /dev/null @@ -1,53 +0,0 @@ -{# -/** - * @file - * Default theme implementation for a fieldset element and its children. - * - * Available variables: - * - attributes: HTML attributes for the fieldset element. - * - errors: (optional) Any errors for this fieldset element, may not be set. - * - required: Boolean indicating whether the fieldeset element is required. - * - legend: The legend element containing the following properties: - * - title: Title of the fieldset, intended for use as the text of the legend. - * - attributes: HTML attributes to apply to the legend. - * - description: The description element containing the following properties: - * - content: The description content of the fieldset. - * - attributes: HTML attributes to apply to the description container. - * - children: The rendered child elements of the fieldset. - * - prefix: The content to add before the fieldset children. - * - suffix: The content to add after the fieldset children. - * - * @see template_preprocess_fieldset() - * - * @ingroup themeable - */ -#} - - {% - set legend_span_classes = [ - 'fieldset-legend', - required ? 'form-required', - ] - %} - {# Always wrap fieldset legends in a SPAN for CSS positioning. #} - - {{ legend.title }} - -
- {% if errors %} -
- {{ errors }} -
- {% endif %} - {% if prefix %} - {{ prefix }} - {% endif %} - {{ children }} - {% if suffix %} - {{ suffix }} - {% endif %} - {% if description.content %} - {{ description.content }}
- {% endif %} -
- diff --git a/core/themes/seven/templates/form-element.html.twig b/core/themes/seven/templates/form-element.html.twig deleted file mode 100644 index 3a1ef12..0000000 --- a/core/themes/seven/templates/form-element.html.twig +++ /dev/null @@ -1,94 +0,0 @@ -{# -/** - * @file - * Default theme implementation for a form element. - * - * Available variables: - * - attributes: HTML attributes for the containing element. - * - errors: (optional) Any errors for this form element, may not be set. - * - prefix: (optional) The form element prefix, may not be set. - * - suffix: (optional) The form element suffix, may not be set. - * - required: The required marker, or empty if the associated form element is - * not required. - * - type: The type of the element. - * - name: The name of the element. - * - label: A rendered label element. - * - label_display: Label display setting. It can have these values: - * - before: The label is output before the element. This is the default. - * The label includes the #title and the required marker, if #required. - * - after: The label is output after the element. For example, this is used - * for radio and checkbox #type elements. If the #title is empty but the - * field is #required, the label will contain only the required marker. - * - invisible: Labels are critical for screen readers to enable them to - * properly navigate through forms but can be visually distracting. This - * property hides the label for everyone except screen readers. - * - attribute: Set the title attribute on the element to create a tooltip but - * output no label element. This is supported only for checkboxes and radios - * in \Drupal\Core\Render\Element\CompositeFormElementTrait::preRenderCompositeFormElement(). - * It is used where a visual label is not needed, such as a table of - * checkboxes where the row and column provide the context. The tooltip will - * include the title and required marker. - * - description: (optional) A list of description properties containing: - * - content: A description of the form element, may not be set. - * - attributes: (optional) A list of HTML attributes to apply to the - * description content wrapper. Will only be set when description is set. - * - description_display: Description display setting. It can have these values: - * - before: The description is output before the element. - * - after: The description is output after the element. This is the default - * value. - * - invisible: The description is output after the element, hidden visually - * but available to screen readers. - * - disabled: True if the element is disabled. - * - title_display: Title display setting. - * - * @see template_preprocess_form_element() - * - * @ingroup themeable - */ -#} -{% - set classes = [ - 'form-item', - 'form-type-' ~ type|clean_class, - 'form-item-' ~ name|clean_class, - title_display not in ['after', 'before'] ? 'form-no-label', - disabled == 'disabled' ? 'form-disabled', - errors ? 'form-error', - ] -%} -{% - set description_classes = [ - 'description', - description_display == 'invisible' ? 'visually-hidden', - ] -%} - - {% if label_display in ['before', 'invisible'] %} - {{ label }} - {% endif %} - {% if prefix is not empty %} - {{ prefix }} - {% endif %} - {% if description_display == 'before' and description.content %} - - {{ description.content }} - - {% endif %} - {{ children }} - {% if suffix is not empty %} - {{ suffix }} - {% endif %} - {% if label_display == 'after' %} - {{ label }} - {% endif %} - {% if errors %} -
- {{ errors }} -
- {% endif %} - {% if description_display in ['after', 'invisible'] and description.content %} - - {{ description.content }} - - {% endif %} -