diff -u b/core/modules/file/file.js b/core/modules/file/file.js --- b/core/modules/file/file.js +++ b/core/modules/file/file.js @@ -25,7 +25,7 @@ attach: function (context) { var $context = $(context); - $context.find('.js-form-managed-file .js-form-file') + $context.find('[data-drupal-validate-extensions]') .once('fileValidate') .on('change.fileValidate', Drupal.file.validateExtension); }, @@ -33,7 +33,7 @@ var $context = $(context); if (trigger === 'unload') { - $context.find('.js-form-managed-file .js-form-file') + $context.find('[data-drupal-validate-extensions]') .removeOnce('fileValidate') .off('change.fileValidate', Drupal.file.validateExtension); } @@ -124,14 +124,11 @@ $('.file-upload-js-error').remove(); // Add client side validation for the input[type=file]. - 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 { + 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 = []; @@ -149,21 +146,7 @@ } } 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 += ''; - } - error += ' '; - error += Drupal.t('Only files with the following extensions are allowed: %extensions.', { - '%extensions': extensionPattern.replace(/\|/g, ', ') - }); - $(this).closest('div.js-form-managed-file').prepend('
' + error + '
'); + $(this).closest('div.js-form-managed-file').prepend(Drupal.theme('fileValidationError', invalidFiles, validExtensions)); this.value = ''; // Cancel all other change event handlers. event.stopImmediatePropagation(); @@ -266,2 +249,32 @@ + /** + * 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 += ''; + } + error += ' '; + error += Drupal.t('Only files with the following extensions are allowed: %extensions.', { + '%extensions': validExtensions.join(', ') + }); + + return '
' + error + '
'; + }; + })(jQuery, Drupal); diff -u b/core/modules/file/src/Element/ManagedFile.php b/core/modules/file/src/Element/ManagedFile.php --- b/core/modules/file/src/Element/ManagedFile.php +++ b/core/modules/file/src/Element/ManagedFile.php @@ -2,6 +2,7 @@ namespace Drupal\file\Element; +use Drupal\Component\Serialization\Json; use Drupal\Component\Utility\Crypt; use Drupal\Component\Utility\Html; use Drupal\Component\Utility\NestedArray; @@ -343,7 +344,8 @@ } if (isset($element['#upload_validators']['file_validate_extensions'][0])) { - $element['upload']['#attributes']['data-drupal-validate-extensions'] = $element['#upload_validators']['file_validate_extensions'][0]; + $extension_list = array_filter(explode(' ', $element['#upload_validators']['file_validate_extensions'][0])); + $element['upload']['#attributes']['data-drupal-validate-extensions'] = Json::encode($extension_list); } // Let #id point to the file element, so the field label's 'for' corresponds