FineUploader / fine-uploader

Multiple file upload plugin with image previews, drag and drop, progress bars. S3 and Azure support, image scaling, form support, chunking, resume, pause, and tons of other features.
https://fineuploader.com
MIT License
8.18k stars 1.87k forks source link

Set "multiple: false", but drag and drop still allows multiple files to get uploaded. #1707

Open bs-thomas opened 7 years ago

bs-thomas commented 7 years ago

Type of issue [REQUIRED]

bug

Uploader type [REQUIRED]

S3 - qq.s3.FineUploaderBasic + qq.DragAndDrop

Bug details [DELETE EVERYTHING IN THIS SECTION IF THIS IS A FEATURE REQUEST]

Fine Uploader version [REQUIRED]

5.11.10

Browsers where the bug is reproducible [REQUIRED]

Chrome

Operating systems where the bug is reproducible [REQUIRED]

Windows 10

Exact steps required to reproduce the issue [REQUIRED]

For example:

  1. As options, set "multiple: false".
  2. Drag and Drop 2 files at once into the "dropzone" element.
  3. Both files get passed through, gets signed, and then gets uploaded successfully

All of your Fine Uploader initialization JavaScript code [REQUIRED]

{simply copy and paste the JS used to control Fine Uploader browsers-ide}


        var $field = $(this),
            $field_fileInput = $field.find('.input'),
            $field_fileInput_browse = $field_fileInput.find('.browse'),
            $field_fileInput_dropzones = $field_fileInput.find('.dropzone'),

            // Server-side profile parameters
            uploaderProfile = $field_fileInput.data('uploader-profile'),
            profileName = uploaderProfile.profileName,
            baseDirectory = uploaderProfile.baseDirectory,
            accessKey = uploaderProfile.key,
            bucket = uploaderProfile.bucket,
            bucketRegion = uploaderProfile.region,

            // Derived variables
            endpoint = 'https://' + bucket + '.s3.amazonaws.com',
            signatureEndpoint = site_url + '/api/storage/file/v1/' + profileName + '/sign',
            uploadSuccessEndpoint = site_url + '/api/storage/file/v1/' + profileName + '/upload-success',

            // User definitions
            uploadDirectory = $field_fileInput.data('upload-directory'),
            allowedExtensions = $field_fileInput.data('allowed-extensions'),
            sizeLimit = $field_fileInput.data('size-limit');

        var uploader = new qq.s3.FineUploaderBasic({

            // core options
            debug: true,
            button: $field_fileInput_browse[0],
            multiple: false,

            // core options

            objectProperties: {
                acl: 'public-read',
                key: function(fileId){
                    var filename = uploader.getName(fileId),
                        filenameWithoutExtension = jlib.helpers.getFilenameWithoutExtension(filename),
                        extension = qq.getExtension(filename),
                        uuid = uploader.getUuid(fileId);

                    // Modifying the filename
                    filename = filenameWithoutExtension + '_' + uuid + '.' + extension;

                    // If the file happens to be uploaded successfully, set some important parameters that need to be passed to server
                    this.setParams({
                        profile_name: profileName,
                        path: uploadDirectory + filename,
                        extension: extension
                    }, fileId);

                    // The absolute path ("key") to send to S3
                    return baseDirectory + uploadDirectory + filename;
                }
            },

            chunking: {
                enabled: true,
                concurrent: {
                    enabled: true
                }
            },
            deleteFile: {
                enabled: true,
                endpoint: "/vendor/fineuploader/php-s3-server/endpoint.php"
            },
            resume: {
                enabled: true
            },
            retry: {
                enableAuto: true
            },
            request: {
                endpoint: endpoint,
                accessKey: accessKey
            },
            validation: {
                sizeLimit: sizeLimit,
                allowedExtensions: allowedExtensions
            },

            // s3 options

            signature: {
                endpoint: signatureEndpoint
            },
            uploadSuccess: {
                endpoint: uploadSuccessEndpoint
            },

            // Callbacks

            callbacks: {
                // onAutoRetry
                // onCancel
                onComplete(id, name, responseJSON, xhr) {

                    if( !responseJSON.success ) {
                        // We do not need to display notification because this is handled in onError() callback.
                        return false;
                    }

                    console.log('onComplete', id, name, responseJSON, xhr);

                    if( typeof responseJSON.fileId === 'undefined' ) {
                        jlib.notification.error('An error has occurred.  Please try again later or contact the system administrator.');
                    }

                    // .responseJSON.fileId

                    jlib.notification.success(name + ' has been uploaded.');
                },
                // onAllComplete
                // onDelete
                // onDeleteComplete
                onError: function(id, name, errorReason, xhr) {
                    console.log('onError', id, name, errorReason, xhr);

                    jlib.notification.error(errorReason);

                },
                // onManualRetry
                onPasteReceived: function(a) {
                    console.log('onPasteReceived', a);
                },
                // onProgress
                // onResume
                // onSessionRequestComplete
                // onStatusChange
                onSubmit: function(a) {
                    console.log('onSubmit', a);
                }
                // onSubmitDelete
                // onSubmitted
                // onTotalProgress
                // onUpload
                // onUploadChunk
                // onUploadChunkSuccess
                // onValidate
                // onValidateBatch
            }
        }),

        dragAndDropModule = new qq.DragAndDrop({
            dropZoneElements: $field_fileInput_dropzones,
            classes: {
                dropActive: "dragging-hover"
            },
            callbacks: {
                processingDroppedFiles: function() {
                    //TODO: display some sort of a "processing" or spinner graphic
                    console.log('processingDroppedFiles');
                },
                processingDroppedFilesComplete: function(files, dropTarget) {
                    //TODO: hide spinner/processing graphic
                    console.log('processingDroppedFilesComplete');

                    // if( !$(dropTarget).hasClass('empty') ) {
                        // return false;
                    // }
                    uploader.addFiles(files); //this submits the dropped files to Fine Uploader
                }
            }
        });

Your Fine Uploader template markup (if using Fine Uploader UI and the issue is UI-related)

{simply copy and paste your template markup}

<div class="field file">
                                <label for="user_avatar_file_id">Avatar Image 1</label>
                                <input id="user_avatar_file_id" name="user_avatar_file_id" type="text" value="" required>
                                <div class="input"
                                    data-uploader-profile="{{ uploaderProfile.default | json_encode() }}"
                                    data-upload-directory="catalog/product/123/"
                                    data-allowed-extensions="{{ ['jpg', 'jpeg', 'png', 'gif'] | json_encode() }}"
                                    data-size-limit="5000000"
                                >
                                    {% set width, height = 300, 150 %}
                                    <div class="dropzone">
                                        <div class="placeholder" style="max-width:{{ width }}px;"><div class="aspect-ratio" style="padding-bottom:{{ height / width * 100 }}%;"></div></div>
                                        <div class="content">
                                            <span class="description"><span class="instructions">Drop file here</span> (<span class="dimensions">{{ width }}x{{ height }}</span>)</span>
                                            <a href="#" role="button" class="icon material-icons" tabindex="-1">cloud_upload</a>
                                        </div>
                                        <div class="overlay">
                                            <span class="description"><span class="instructions">Drop file here</span> (<span class="dimensions">{{ width }}x{{ height }}</span>)</span>
                                            <a href="#" role="button" class="icon material-icons" tabindex="-1">cloud_upload</a>
                                        </div>
                                    </div>
                                    <div class="browse">
                                        <div class="placeholder" style="max-width:{{ width }}px;"><div class="aspect-ratio" style="padding-bottom:{{ height / width * 100 }}%;"></div></div>
                                        <div class="content">
                                            <span class="description"><span class="instructions">No image</span> (<span class="dimensions">{{ width }}x{{ height }}</span>)</span>
                                            <a href="#" role="button" class="icon material-icons" tabindex="-1">insert_photo</a>
                                        </div>
                                        <div class="overlay">
                                            <span class="description"><span class="instructions">Browse</span> (<span class="dimensions">{{ width }}x{{ height }}</span>)</span>
                                            <a href="#" role="button" class="icon material-icons" tabindex="-1">cloud_upload</a>
                                        </div>
                                    </div>
                                    <div class="thumbnail">
                                        <img src="{{ baseUrl('300x150.png') }}">
                                        <div class="content"></div>
                                        <div class="overlay">
                                            <span class="description"><span class="filename">Some Image.png</span> (<span class="dimensions">{{ width }}x{{ height }}</span>)</span>
                                            <a href="#" role="button" class="icon material-icons">file_download</a>
                                            <a href="#" role="button" class="icon material-icons">delete</a>
                                        </div>
                                    </div>
                                </div>
                                <span class="error-message">Please enter your first name.</span>
                            </div>

Detailed explanation of the problem [REQUIRED]

{please describe the bug here}

When I'm using the s3 core (not the UI version), and set the option "multiple: false", drag and dropping 2 files at once still seem to pass through, and get uploaded successfully. I expect to:

I did notice that "clicking the button" disables multiple select, which means this seems to be only happening in the drag and drop feature.

Your help is appreciated. Thank you in advance!

Cheers, Thomas

rnicholus commented 7 years ago

The issue you are reporting appears to be unrelated to the drag and drop feature. You're simply sending files to the uploader via addFiles correct? Is that where the issue occurs? Is addFiles allowing multiple files to be sent through?

Looks like the fact that you are using a non-UI instance is related. Can you post the logs after attempting to drop 2 files with debug: true set?

bs-thomas commented 7 years ago

Thanks for your prompt response Ray.

Yes that's correct, it simply directs to addFiles(). This is an example I got from the fineuploader website I believe.

Here is the log I just did now according to your request:


app.js:1126 processingDroppedFiles
all.fine-uploader.js:163 Grabbed 2 dropped files.
app.js:1130 processingDroppedFilesComplete
all.fine-uploader.js:163 [Fine Uploader 5.11.10] Received 2 files.
all.fine-uploader.js:163 [Fine Uploader 5.11.10] Attempting to validate image.
app.js:1105 onSubmit 0
all.fine-uploader.js:163 [Fine Uploader 5.11.10] Sending simple upload request for 0
all.fine-uploader.js:163 [Fine Uploader 5.11.10] Submitting S3 signature request for 0
all.fine-uploader.js:163 [Fine Uploader 5.11.10] Sending POST request for 0
all.fine-uploader.js:163 [Fine Uploader 5.11.10] Attempting to validate image.
app.js:1105 onSubmit 1
all.fine-uploader.js:163 [Fine Uploader 5.11.10] Sending simple upload request for 1
all.fine-uploader.js:163 [Fine Uploader 5.11.10] Submitting S3 signature request for 1
all.fine-uploader.js:163 [Fine Uploader 5.11.10] Sending POST request for 1
all.fine-uploader.js:163 [Fine Uploader 5.11.10] Sending upload request for 0
all.fine-uploader.js:163 [Fine Uploader 5.11.10] Sending upload request for 1
all.fine-uploader.js:163 [Fine Uploader 5.11.10] Received response status 200 with body: 
all.fine-uploader.js:163 [Fine Uploader 5.11.10] Simple upload request succeeded for 0
all.fine-uploader.js:163 [Fine Uploader 5.11.10] Submitting upload success request/notification for 0
all.fine-uploader.js:163 [Fine Uploader 5.11.10] Sending POST request for 0
all.fine-uploader.js:163 [Fine Uploader 5.11.10] Received response status 200 with body: 
all.fine-uploader.js:163 [Fine Uploader 5.11.10] Simple upload request succeeded for 1
all.fine-uploader.js:163 [Fine Uploader 5.11.10] Submitting upload success request/notification for 1
all.fine-uploader.js:163 [Fine Uploader 5.11.10] Sending POST request for 1
all.fine-uploader.js:163 [Fine Uploader 5.11.10] Received the following response body to an upload success request for id 1: {"fileId":46}
all.fine-uploader.js:163 [Fine Uploader 5.11.10] Upload success was acknowledged by the server.
app.js:1073 onComplete 1 bbb.jpg Object {success: true, fileId: 46} XMLHttpRequest {readyState: 4, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, responseURL: "https://beamstyle-web-localhost.s3.amazonaws.com/"…}
all.fine-uploader.js:163 [Fine Uploader 5.11.10] Received the following response body to an upload success request for id 0: {"fileId":45}
all.fine-uploader.js:163 [Fine Uploader 5.11.10] Upload success was acknowledged by the server.
app.js:1073 onComplete 0 aaa.jpg Object {success: true, fileId: 45} XMLHttpRequest {readyState: 4, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, responseURL: "https://beamstyle-web-localhost.s3.amazonaws.com/"…}

Thank you again!

rnicholus commented 7 years ago

Until I get a chance to look into this further, i would suggest using the itemLimit validation option described at http://docs.fineuploader.com/branch/master/api/options.html#validation.itemLimit.

rnicholus commented 7 years ago

...you can also simply reject the dropped files yourself before calling addFiles if more than one file is dropped. In fact there are a number of ways to deal with this. I consider this to be a low priority bug as a result, so I'm not sure when I will get around to fixing. However a pull request that fixes this and includes unit tests will push this through quicker.

DonGiulio commented 6 years ago

Got this same problem, +1 on the issue.