diff --git a/core/lib/Drupal/Core/Render/Element/File.php b/core/lib/Drupal/Core/Render/Element/File.php
index d37d5c7..e15f89f 100644
--- a/core/lib/Drupal/Core/Render/Element/File.php
+++ b/core/lib/Drupal/Core/Render/Element/File.php
@@ -44,7 +44,7 @@ public function getInfo() {
*/
public static function processFile(&$element, FormStateInterface $form_state, &$complete_form) {
if ($element['#multiple']) {
- $element['#attributes'] = array('multiple' => 'multiple');
+ $element['#attributes']['multiple'] = 'multiple';
$element['#name'] .= '[]';
}
return $element;
diff --git a/core/modules/file/file.js b/core/modules/file/file.js
index 8ed377e..547cb52 100644
--- a/core/modules/file/file.js
+++ b/core/modules/file/file.js
@@ -22,35 +22,21 @@
* Detaches validation for file extensions.
*/
Drupal.behaviors.fileValidateAutoAttach = {
- attach: function (context, settings) {
+ attach: function (context) {
var $context = $(context);
- var elements;
-
- function initFileValidation(selector) {
- $context.find(selector)
- .once('fileValidate')
- .on('change.fileValidate', {extensions: elements[selector]}, Drupal.file.validateExtension);
- }
- if (settings.file && settings.file.elements) {
- elements = settings.file.elements;
- Object.keys(elements).forEach(initFileValidation);
- }
+ $context.find('.js-form-managed-file .js-form-file')
+ .once('fileValidate')
+ .on('change.fileValidate', Drupal.file.validateExtension);
},
detach: function (context, settings, trigger) {
var $context = $(context);
- var elements;
- function removeFileValidation(selector) {
- $context.find(selector)
+ if (trigger === 'unload') {
+ $context.find('.js-form-managed-file .js-form-file')
.removeOnce('fileValidate')
.off('change.fileValidate', Drupal.file.validateExtension);
}
-
- if (trigger === 'unload' && settings.file && settings.file.elements) {
- elements = settings.file.elements;
- Object.keys(elements).forEach(removeFileValidation);
- }
}
};
@@ -138,11 +124,20 @@
$('.file-upload-js-error').remove();
// Add client side validation for the input[type=file].
- var extensionPattern = event.data.extensions.replace(/,\s*/g, '|');
- if (extensionPattern.length > 1 && this.value.length > 0) {
- var acceptableMatch = new RegExp('\\.(' + extensionPattern + ')$', 'gi');
- if (!acceptableMatch.test(this.value)) {
- var error = Drupal.t('The selected file %filename cannot be uploaded. Only files with the following extensions are allowed: %extensions.', {
+ var extensionPattern = $(event.target).attr('data-drupal-validate-extensions').replace(/,|\s+/g, '|');
+ if (extensionPattern.length > 1 && event.target.value.length > 0) {
+ var acceptableMatch = new RegExp('\\.(' + extensionPattern + ')$', 'i');
+ var testSubjects;
+ if (event.target.files) {
+ testSubjects = event.target.files;
+ }
+ else {
+ testSubjects = [{name: event.target.value}];
+ }
+ var invalidFiles = [];
+ for (var i = 0; i < testSubjects.length; i++) {
+ var testSubject = testSubjects[i];
+ if (!acceptableMatch.test(testSubject.name)) {
// According to the specifications of HTML5, a file upload control
// should not reveal the real local path to the file that a user
// has selected. Some web browsers implement this restriction by
@@ -150,7 +145,22 @@
// confusion by leaving the user thinking perhaps Drupal could not
// find the file because it messed up the file path. To avoid this
// confusion, therefore, we strip out the bogus fakepath string.
- '%filename': this.value.replace('C:\\fakepath\\', ''),
+ invalidFiles.push(testSubject.name.replace('C:\\fakepath\\', ''));
+ }
+ }
+ if (invalidFiles.length) {
+ var error = Drupal.formatPlural(invalidFiles.length, 'The selected file %filename cannot be uploaded.', '@count of the selected files cannot be uploaded.', {
+ '%filename': invalidFiles[0]
+ });
+ if (invalidFiles.length > 1) {
+ error += '