diff --git a/core/lib/Drupal/Core/Render/Element/File.php b/core/lib/Drupal/Core/Render/Element/File.php
index 07bd415..bf2310a 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'] = ['multiple' => 'multiple'];
+ $element['#attributes']['multiple'] = 'multiple';
$element['#name'] .= '[]';
}
return $element;
diff --git a/core/modules/file/file.es6.js b/core/modules/file/file.es6.js
index 8ed377e..7e7a6ca 100644
--- a/core/modules/file/file.es6.js
+++ b/core/modules/file/file.es6.js
@@ -22,35 +22,22 @@
* 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('[data-drupal-validate-extensions]')
+ .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('[data-drupal-validate-extensions]')
.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 +125,17 @@
$('.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 validExtensions = JSON.parse(event.target.getAttribute('data-drupal-validate-extensions'));
+ if (validExtensions.length > 1 && event.target.value.length > 0) {
+ var acceptableMatch = new RegExp('\\.(' + validExtensions.join('|') + ')$', 'i');
+ var testSubjects = event.target.files;
+ if (!testSubjects) {
+ 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,10 +143,11 @@
// 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\\', ''),
- '%extensions': extensionPattern.replace(/\|/g, ', ')
- });
- $(this).closest('div.js-form-managed-file').prepend('
' + error + '
');
+ invalidFiles.push(testSubject.name.replace('C:\\fakepath\\', ''));
+ }
+ }
+ if (invalidFiles.length) {
+ $(this).closest('div.js-form-managed-file').prepend(Drupal.theme('fileValidationError', invalidFiles, validExtensions));
this.value = '';
// Cancel all other change event handlers.
event.stopImmediatePropagation();
@@ -254,4 +248,34 @@
}
};
+ /**
+ * Error message of file validation.
+ *
+ * @param {Array.} invalidFiles
+ * Array of invalid filenames.
+ * @param {string} validExtensions
+ * List of accepted files extensions.
+ *
+ * @return {string}
+ * Error message.
+ */
+ Drupal.theme.fileValidationError = function (invalidFiles, validExtensions) {
+ 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 += '