If you choose file, upload it and remove, choose another file again ( with invalid extension), then error message about extension is shown and hidden immediately. Bug may be in modules/file/file.js in validateExtension function:

validateExtension: function (event) {
    // Remove any previous errors.
    $('.file-upload-js-error').remove(); // !!!! PROBLEM HERE - this function is called twice, second time with this.value == ''
    // 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.", {
          '%filename': this.value,
          '%extensions': extensionPattern.replace(/\|/g, ', ')
        });
        $(this).parents('div.form-managed-file').prepend('<div class="messages error file-upload-js-error">' + error + '</div>');
        this.value = '';
        return false;
      }
    }
  },

Temporarily I override this function in my custom js-file with this code:

  Drupal.file.validateExtension = function (event) {
    // Remove any previous errors.
    if (this.value) // THIS CONDITION was added
    {
      $('.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.", {
            '%filename': this.value,
            '%extensions': extensionPattern.replace(/\|/g, ', ')
          });
          $(this).parents('div.form-managed-file').prepend('<div class="messages error file-upload-js-error">' + error + '</div>');
          this.value = '';
          return false;
        }
      }
    }
  }

Comments

czigor’s picture

Status: Active » Needs review
StatusFileSize
new1.94 KB

Tested this and the solution works for me even for files without extension or ending with a period (eg. "filename."). Added a patch. All credit goes to bazel.

czigor’s picture

By the way, does anyone know why validateExtension does not get called twice if we had not uploaded a file with a valid extension before? The line

this.value = '';

should trigger the fileValidateAutoAttach behavior shouldn't it? (Which in turn calls Drupal.file.validateExtension.)

sun’s picture

Version: 7.0 » 8.x-dev
Component: javascript » file.module
Priority: Major » Normal
Status: Needs review » Needs work
Issue tags: +Needs backport to D7
+++ b/modules/file/file.js
@@ -66,20 +66,23 @@ Drupal.file = Drupal.file || {
+    if (this.value)
+    {

1) Opening bracket must be on the same line as the control structure (if).

2) Instead of indenting the entire function body, implement an early-return.

Powered by Dreditor.

czigor’s picture

Hoops, that's been a bit long time. Corrections attached. D8.

czigor’s picture

Status: Needs work » Needs review

tagging

quicksketch’s picture

Title: Error message (file extension) is hidden » Wrong file extension JS error is hidden after adding then removing an upload
StatusFileSize
new1.35 KB

This problem is caused by this API change in jQuery (from http://api.jquery.com/bind/):

As of jQuery 1.4.2 duplicate event handlers can be bound to an element instead of being discarded. This is useful when the event data feature is being used, or when other unique data resides in a closure around the event handler function.

What's happening here is Drupal.attachBehaviors() gets called multiple times on new content. In previous versions of jQuery that was fine because .bind() would only attach a unique function one time. Now it binds the same function again each time, even if it's identical.

In Drupal-convention, we should use .once() to prevent the behavior from getting attached multiple times. It's not real pretty but it's consistent with our code throughout the rest of core.

guschilds’s picture

Thank you for supplying this patch! This worked for me in Drupal 7. I came across another issue for the same problem and commented in there as well: #1516492: File extension validation doesn't work after one upload.

Not marking as RTBC because I tested in 7.x and this is marked as 8.x-dev. I am not able to recreate this issue in 8 because it doesn't seem to be using validateExtension in file.js for any client-side validation, but I could be wrong.

David_Rothstein’s picture

Title: Wrong file extension JS error is hidden after adding then removing an upload » Wrong file extension JS error is hidden after an upload has already occurred (e.g., after adding then removing a file)

I marked #1516492: File extension validation doesn't work after one upload and #1992028: JavaScript error message for incorrect image field extension doesn't work for the second upload as duplicates.

As discussed in the latter issue, you can actually reproduce the bug without ever hitting the "remove" button. If you have a multivalued file field (I tested with image fields) then uploading a valid file for the first one followed by an invalid file for the second one triggers the problem.

The above patch seems to fix both cases, but I haven't been able to test this for Drupal 8 either.

David_Rothstein’s picture

Title: Wrong file extension JS error is hidden after an upload has already occurred (e.g., after adding then removing a file) » Wrong file extension JS error is hidden after an upload has already been attempted (e.g., after adding then removing a file)

Just marked the following two issues as duplicates as well:
#1996072: No Error message on selecting not allowed file in Image field
#1998998: Illegal image type error message not shown if other error message already present on screen

The second one points out that the first upload attempt doesn't even need to be successful (if it's prevented by another upload validator the bug will still occur on the second attempt).

nod_’s picture

Issue tags: +JavaScript

tagging

impol’s picture

Backport #4 to D7
In my case this error appears in IE11 only.

Status: Needs review » Needs work
chasingmaxwell’s picture

StatusFileSize
new1.33 KB

This is a backport of #6 for Drupal 7.

David_Rothstein’s picture

David_Rothstein’s picture

Status: Needs work » Needs review

The last submitted patch, 6: file_behaviors_once-1074214-6.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 13: file_behaviors_once_D7-1074214-13.patch, failed testing.

lokapujya’s picture

Version: 8.x-dev » 7.x-dev
Status: Needs work » Needs review
lokapujya’s picture

lokapujya’s picture

impol’s picture

StatusFileSize
new430 bytes

Recreated #11 patch.

David_Rothstein’s picture

Version: 7.x-dev » 8.x-dev
Status: Needs review » Needs work

Still needs fixing in Drupal 8, right? The latest Drupal 8 patch is #6 but needs a reroll.

lokapujya’s picture

I cannot recreate the issue in D8. The javascript in D8 seems to be reworked. Also, I don't know why we have 2 different D7 patches in #22 and #13.

chasingmaxwell’s picture

@lokapujya, The reason there are two is that they solve the problem in two different ways. I preferred the once() approach originally provided by @quicksketch because it follows convention in Drupal behaviors elsewhere in core. So I backported it to D7.

evilehk’s picture

Version: 8.0.x-dev » 7.x-dev
Status: Needs work » Reviewed & tested by the community
Issue tags: -Needs backport to D7

Here is a quick recap of the problem that currently exists in Drupal 7 core:

  • Add content to a node type with a file field (like Article)
  • Select a VALID file in the field field and press Upload
  • Remove the uploaded file by pressing Remove
  • Select a file with an invalid extension

The expected result to see invalid file extension message outputted from file.js, but the message is quickly removed because validateExtension is called twice. The patch in #13 solves the problem. The same issue does not, or no longer, exists in Drupal 8 core. Therefore I set this issues Version back to 7.x-dev and removed the needs backport tag.

lokapujya’s picture

Issue tags: +Needs manual testing
zestagio’s picture

Status: Reviewed & tested by the community » Needs review
StatusFileSize
new3.05 KB
new1.72 KB

Hello,
I tested manualy, and I have next behaviours:

  • Without patch #13
    1. Add content to a node type with a file field (like Article). Select a file with an invalid extension. Result: JS validation run, file not selected, added error message before upload field. Working as designed.
    2. Add content to a node type with a file field (like Article). Press Upload (without select any file). Select a file with an invalid extension. Result: JS validation not run, file selected and will be validated only on click "Upload", there is no error message before upload field. From my view point it's a bug.
    3. Add content to a node type with a file field (like Article). Select a VALID file in the field and press "Upload". Remove the uploaded file by pressing "Remove". Select a file with an invalid extension. Result: JS validation run partially, file not selected but there is no error message before upload field. From my view point it's a bug.
  • With patch #13
    1. Seems like without patch #13.

I inspected js and found problem. On first render an upload field, this element has html id like edit-field-image-und-0-upload and added js settings for validation this element by id (Upload field use id of parent element and on each ajax request, js settings not updated, that error):

    $element['upload']['#attached']['js'] = array(
      array(
        'type' => 'setting',
        'data' => array('file' => array('elements' => array('#' . $element['#id'] => $extension_list)))
      )
    );

After click on "Upload" or "Remove" button, upload field will be re-generated with new html id like edit-field-image-und-0-upload--2, but js settings use old html id, and error message not added to page.

I attached the patch, wich fixed this problem

rafalB’s picture

Patch from comment #29 works for me.

neha.gangwar’s picture

Patch #29 worked for me also.
Please include this in core module.

jsobiecki’s picture

StatusFileSize
new3.43 KB
new973 bytes

Patch #29 also worked for me, but it also introduced regression.

I have a form, that one of elements (select list) executes custom ajax call and updates other element.
Ajax callback returns single element, that will be updated after ajax call. There are no other actions in callback.
This form includes also two file upload fields, that are not related to this custom ajax call.

And scenario to reproduce is following:

1. I'm triggering custom ajax call.
2. This triggers Drupal.behaviors.fileValidateAutoAttach.detach method. This method

    if (settings.file && settings.file.elements) {
      $.each(settings.file.elements, function (selector) {
        $(selector, context).unbind('change', Drupal.file.validateExtension);
     }

removes validation callback from all file elements.
3. Later Drupal.behaviors.fileValidateAutoAttach.attach is executed. This code should re-register validation callback:

      $.each(settings.file.elements, function (selector) {
        var extensions = settings.file.elements[selector];
        $(selector, context).once( function () {
          $(this).bind('change', {extensions: extensions}, Drupal.file.validateExtension);
        }

But it will not do that,s because once class was not removed from existing elements.

4. After that, existing file elements doesn't have validation callback registered and they accept any file type provided by user.

Attached file updates #29 with fix to described problem

jsobiecki’s picture

StatusFileSize
new3.43 KB

Fixed typo in last patch.

yvesmarie’s picture

As describe in #29, this bug seems to have two parts:
1. a behaviors attach issue: in some case Drupal.behaviors.fileValidateAutoAttach is attached twice. First in the insert ajax command, and then again in the Drupal.ajax.success function.
2. a buggy id generation issue: the file input id added to the ajax settings doesn't match the one in the generated markup when a counter is added to the base id.

However the second issue is a bit more complicated as it impacts other part of the managed file widget. Especially when we want to use the id for the widget label for attribute. This issue is better addressed in https://www.drupal.org/project/drupal/issues/2594955 for which a patch already successfully fix the issue: https://www.drupal.org/files/issues/file-managed_file_duplicate_id_error...

I submit a new patch that only address the first issue (the one initially describe in this topic). As previous patches it wraps every behaviors with jQuery.once; but, for better retrocompatibility, it also use removeOnce for cleaner behaviors detach.

taran2l’s picture

Issue tags: -JavaScript +JavaScript
StatusFileSize
new2.99 KB
new1.47 KB

Deleted

taran2l’s picture

StatusFileSize
new3.6 KB

Deleted

taran2l’s picture

StatusFileSize
new3.61 KB
new1.47 KB

@yvesmarie, thanks for the patch. It almost works, but there is a case when it does not: existing code relies on HTML id, which is not guaranteed to match $element['#id'].

Attached patch fixes this. Please review

taran2l’s picture

StatusFileSize
new3.04 KB
new414 bytes
taran2l’s picture

StatusFileSize
new3.63 KB

Status: Needs review » Closed (outdated)

Automatically closed because Drupal 7 security and bugfix support has ended as of 5 January 2025. If the issue verifiably applies to later versions, please reopen with details and update the version.