diff --git a/includes/form.inc b/includes/form.inc index aa90eca..cb3d4f6 100644 --- a/includes/form.inc +++ b/includes/form.inc @@ -1598,13 +1598,59 @@ function form_set_error($name = NULL, $message = '', $limit_validation_errors = } if ($record) { $form[$name] = $message; - if ($message) { + form_set_error_scoped($name,$message,$limit_validation_errors); + } + } + + return $form; +} + +function form_set_error_scoped($name = NULL, $message = '', $limit_validation_errors = NULL) { + $errors = &drupal_static(__FUNCTION__ . ':scoped_errors', array()); + $sections = &drupal_static(__FUNCTION__ . ':limit_validation_errors'); + if (isset($limit_validation_errors)) { + $sections = $limit_validation_errors; + } + + if (isset($name) && isset($_POST['form_id']) && $message) { + $record = TRUE; + if (isset($sections)) { + // #limit_validation_errors is an array of "sections" within which user + // input must be valid. If the element is within one of these sections, + // the error must be recorded. Otherwise, it can be suppressed. + // #limit_validation_errors can be an empty array, in which case all + // errors are suppressed. For example, a "Previous" button might want its + // submit action to be triggered even if none of the submitted values are + // valid. + $record = FALSE; + foreach ($sections as $section) { + // Exploding by '][' reconstructs the element's #parents. If the + // reconstructed #parents begin with the same keys as the specified + // section, then the element's values are within the part of + // $form_state['values'] that the clicked button requires to be valid, + // so errors for this element must be recorded. As the exploded array + // will all be strings, we need to cast every value of the section + // array to string. + if (array_slice(explode('][', $name), 0, count($section)) === array_map('strval', $section)) { + $record = TRUE; + break; + } + } + } + if ($record) { + $form_id = $_POST['form_id']; + if (!isset($errors[$form_id][$name])) { + $errors[$form_id][$name] = array(); + } + $msgs = &$errors[$form_id][$name]; + if (!in_array($message, $msgs)) { + $msgs[] = $message; drupal_set_message($message, 'error'); } } } - return $form; + return $errors; } /** @@ -1642,6 +1688,28 @@ function form_get_error($element) { } } +function form_get_error_scoped($element) { + if (!isset($element['#form_id'])) { + return; + } + + $form_id = $element['#form_id']; // Try to make the error form specific + $errors = form_set_error_scoped(); + if (!isset($errors[$form_id])) { + return; // Form has no errors + } + $form_errors = $errors[$form_id]; + + $parents = array(); + foreach ($element['#parents'] as $parent) { + $parents[] = $parent; + $key = implode('][', $parents); + if(isset($form_errors[$key])) { + return $form_errors[$key]; + } + } +} + /** * Flags an element as having an error. */ @@ -1844,6 +1912,7 @@ function form_builder($form_id, &$element, &$form_state) { $array_parents = $element['#array_parents']; $array_parents[] = $key; $element[$key]['#array_parents'] = $array_parents; + $element[$key]['#form_id'] = $form_id; // Assign a decimal placeholder weight to preserve original array order. if (!isset($element[$key]['#weight'])) { @@ -4199,7 +4268,7 @@ function _form_set_class(&$element, $class = array()) { if (!empty($element['#required'])) { $element['#attributes']['class'][] = 'required'; } - if (isset($element['#parents']) && form_get_error($element) !== NULL) { + if (isset($element['#parents']) && form_get_error_scoped($element) !== NULL) { $element['#attributes']['class'][] = 'error'; } }