diff --git a/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php b/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php index 6d945aa..41a2dfa 100644 --- a/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php +++ b/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php @@ -12,6 +12,8 @@ use Drupal\Core\Form\FormStateInterface; use Drupal\file\Entity\File; use Drupal\file\Plugin\Field\FieldWidget\FileWidget; +use Drupal\Core\Render\Element; +use Drupal\Core\Url; /** * Plugin implementation of the 'image_image' widget. @@ -248,7 +250,38 @@ public static function process($element, FormStateInterface $form_state, $form) '#element_validate' => $element['#title_field_required'] == 1 ? array(array(get_called_class(), 'validateRequiredFields')) : array(), ); - return parent::process($element, $form_state, $form); + // Adjust the Ajax settings so that on upload and remove of any individual + // file, the entire group of file fields is updated together. + if ($element['#cardinality'] != 1) { + $parents = array_slice($element['#array_parents'], 0, -1); + $new_url = Url::fromRoute('file.ajax_upload'); + $new_options = array( + 'query' => array( + 'element_parents' => implode('/', $parents), + 'form_build_id' => $form['form_build_id']['#value'], + ), + ); + $field_element = NestedArray::getValue($form, $parents); + $new_wrapper = $field_element['#id'] . '-ajax-wrapper'; + foreach (Element::children($element) as $key) { + if (isset($element[$key]['#ajax'])) { + $element[$key]['#ajax']['url'] = $new_url->setOptions($new_options); + $element[$key]['#ajax']['options'] = $new_options; + $element[$key]['#ajax']['wrapper'] = $new_wrapper; + } + } + unset($element['#prefix'], $element['#suffix']); + } + + // Add another submit handler to the upload and remove buttons, to implement + // functionality needed by the field widget. This submit handler requires + // the entire field, not just the individual item, to be valid. + foreach (array('upload_button', 'remove_button') as $key) { + $element[$key]['#submit'][] = array(get_called_class(), 'submit'); + $element[$key]['#limit_validation_errors'] = array(array_slice($element['#parents'], 0, -1)); + } + + return $element; } /** diff --git a/core/modules/image/src/Tests/ImageFieldValidateTest.php b/core/modules/image/src/Tests/ImageFieldValidateTest.php index 3822df6..64d44b5 100644 --- a/core/modules/image/src/Tests/ImageFieldValidateTest.php +++ b/core/modules/image/src/Tests/ImageFieldValidateTest.php @@ -49,6 +49,18 @@ function testResolution() { $this->assertRaw(t('The image is too small; the minimum dimensions are %dimensions pixels.', array('%dimensions' => '50x50'))); $this->uploadNodeImage($image_that_is_too_big, $field_name, 'article'); $this->assertText(t('The image was resized to fit within the maximum allowed dimensions of 100x100 pixels.')); + + // Test the validation message is displayed only once for ajax uploads. + $this->drupalGet('node/add/article'); + $edit = array( + 'files[' . $field_name . '_0]' => drupal_realpath($image_that_is_too_small->uri), + 'title[0][value]' => $this->randomMachineName(), + ); + $this->drupalPostAjaxForm(NULL, $edit, $field_name . '_0_upload_button'); + $elements = $this->xpath('//div[contains(@class, :class)]', array( + ':class' => 'messages--error', + )); + $this->assertEqual(count($elements), 1, 'Ajax validation messages are displayed once.'); } /**