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

Uploading a PDF or non-image file fails when Scaling is enabled. #1238

Closed skoona closed 10 years ago

skoona commented 10 years ago

My objective is to allow for uploads of PDFs and only the scaled version of image files. I recently upgraded to V5.0.2 specifically to get the scaling() feature.

Scaling works as you've described it with one exception. Once scaling is enabled, PDFs and non-image files fail to be selected for upload, and no file is uploaded. tweaking the sendOriginal option overcomes this, but then causes original and scaled versions to be uploaded.

As a temporary workaround, I made the following change (added else to line 59), which seems to provide the desired result; sendOriginal=false,hideScaled=false. PDFs upload, and only Scaled image uploads.

File: fine-uploader / client / js / image-support / scaler.js

line 30: if (idenitifier.isPreviewableSync()) {
...
line 59: } else {
                // FIXME: Presume file was not an imagefile, send it anyway (i.e. a PDF will take this path
                records.push({
                    uuid: originalFileUuid,
                    name: originalFileName,
                    blob: originalBlob
                });
            }

I'm certain you could find a better way to incorporate this capability, and would like to offer a suggestion. Allow us to bypass the scaler workflow step if file.extension is not in the options 'scaleFileExtension=/regex/ or arrayList'

Please suggest how I can achieve the 'upload any file and still scale images' using fineUploader V5.

Thanks for a great package (job well done!) James,

rnicholus commented 10 years ago

Please provide your Fine Uploader related client-side code so we can attempt to reproduce the issue you are describing.

skoona commented 10 years ago

My setup is very basic using jquery-1.8.3. I added the 'scaling:' method to the options set and wha-la, it worked for images. At this point I happened to try uploading a PDF and it failed. changing 'sendOriginal: true' restored the pdf upload ability, but has the side effect of sending both scaled and original images.

The following is the snippet used to initialize fineUploader on a list of elements. Scaling is enabled, and sendOriginal=false because my patch is applied.

function attachmentHandlerForPolicyAndQuotes(keys) {
    var svcId,
        csrfToken = $('meta[name="csrf-token"]').attr('content'),
        lobName = $('#lob').val();

    keys.each(function(index, elem) {
        var qId = $(elem).data().fileId,
            fTarget = 'fineUploader-' + qId,
            svcId = $(elem).data().svcId;

        /*
         * initialize fineUploader on this Div
         * - scaling seems to want to scale every file, hence a pdf will cause an error of no files being uploaded
        */
        $(elem).fineUploader({
            button: $("#" + qId + "-action"),
            debug: logEnabled,     // true in rails development mode
            request: {
                endpoint: '/attachments/' + svcId + '/file_upload',
                customHeaders: { 'X-CSRF-Token': csrfToken },
                params: { authenticity_token: csrfToken, question_id: qId, lob_name: lobName }
            },
            deleteFile: {
                enabled: true,
                endpoint: '/attachments/' + svcId + '/file_delete',
                method: 'POST',
                customHeaders: { 'X-CSRF-Token': csrfToken },
                params: { authenticity_token: csrfToken, question_id: qId, lob_name: lobName }
            },
            template: 'qq-template-attachments',
            classes: {
                success: 'alert alert-success',
                fail: 'alert alert-error'
            },
            validation: {
                acceptFiles: allowedFileMimes,
                allowedExtensions: allowedFileTypes,
                sizeLimit: 12000000
            },
            scaling: { // This feature is supported on all browsers other than IE9 and older, Android 2.4 or older, and Safari 5.1 or older.
                sendOriginal: false, // FIXME  This may be preventing other files from uploading
                includeExif: true,
                hideScaled: false,
                sizes: [
                    {name: "scaled", maxSize: 1600}
                ]
            },
            showMessage: function(message) {
                $('#' + fTarget).append('<div class="alert alert-error"><a href="#" class="close" data-dismiss="alert">&times;</a>' + message + '</div>');
            }
        }).on("complete", function(event, id, name, responseJSON, xhr) {
            if (responseJSON.success) {
                addToTextFieldValue('#' + qId + 'z1', responseJSON.name);
                addToTextFieldValue('#' + qId + 'z2', responseJSON.fqfn);
                $('#upload-ok-button').removeAttr('disabled');
                // 1+ files already, hide attached-previous-cb
                if ( $('#' + qId + 'z1').val().split(',')[0].length &&
                    $('input[name="files[' + qId + '-attached_previous]"]').length) {
                    $('input[name="files[' + qId + '-attached_previous]"]').parent().slideUp().removeAttr('checked');
                }
            }
            $( event.target).find('li[qq-file-id="' + id + '"] div.qq-progress-bar-container-selector').slideUp();
            questionLog("attachmentHandlerForPolicyAndQuotes(complete) id=" + id + ", name=" + name + ", response=" + JSON.stringify(responseJSON));

        }).on("deleteComplete", function(event, id, xhr, isError) {   // isError does not work, only works if controller return non-200 code
            var index = removeFromTextFieldValue('#' + qId + 'z1', $(this).fineUploader("getName", id));
            removeFromTextFieldIndex('#' + qId + 'z2', index);
            // 0 files already, unhide cb
            if ( $('#' + qId + 'z1').val().split(',')[0].length === 0 &&
                $('input[name="files[' + qId + '-attached_previous]"]').length ) {
                $('input[name="files[' + qId + '-attached_previous]"]').parent().slideDown();
            }
            questionLog("attachmentHandlerForPolicyAndQuotes(deleteComplete) id=" + id + ", isError=" + isError + ", name=" + $(this).fineUploader("getName", id) + ", xhr=" + JSON.stringify(xhr.response));

        }).on("error", function(event, id, name, errorReason, xhr) {
            questionLog("attachmentHandlerForPolicyAndQuotes(error)  id=" + id + ", name=" + name + ", errorReason=" + errorReason + ", xhr=" + JSON.stringify(xhr.response));
        });
    });

}

These are the UI templates used to contain upload results and guide the user.

var attachTemplates = {
    miscItem: '\
    <div class="control-group <%= item.qid %> misc-docs well">\
        <ul class="breadcrumb span12">\
            <li><strong><%= item.type %></strong><span class="divider">/</span></li>\
            <li><%= item.section %><span class="divider">/</span></li>\
            <li><%= item.description %></li>\
            <li class="pull-right span1">\
                <a href="#" class="btn btn-mini misc-plus" data-description="<%= item.description %>"><i class="icon-plus-sign"></i></a>\
                <a href="#" class="btn btn-mini misc-minus" data-description="<%= item.description %>"><i class="icon-minus-sign"></i></a>\
            </li>\
            <li class="pull-right span3">\
                <a  id="<%= item.qid %>-action" href="#" class="btn btn-primary" data-file-id="<%= item.qid %>">\
                    <i class="icon-upload  icon-white"></i>\
                    <span> Select Files</span>\
                </a>\
            </li>\
        </ul>\
        <input class="text" id="<%= item.qid %>z1" name="files[<%= item.qid %>z1]" type="hidden" value=""/>\
        <input class="text" id="<%= item.qid %>z2" name="files[<%= item.qid %>z2]" type="hidden" value=""/>\
        <div id="fineUploader-<%= item.qid %>" class="fineUploader" data-file-id="<%= item.qid %>" data-svc-id="<%= item.svcId %>"></div>\
    </div>',
    missingItem: '\
    <div class="control-group <%= item.qid %> well">\
        <ul class="breadcrumb span12">\
            <li><strong><%= item.type %></strong><span class="divider">/</span></li>\
            <li><%= item.section %><span class="divider">/</span></li>\
            <li><%= item.description %></li>\
            <li class="pull-right span3">\
                <a  id="<%= item.qid %>-action" href="#" class="btn btn-primary" data-file-id="<%= item.qid %>">\
                    <i class="icon-upload  icon-white"></i>\
                    <span> Select Files</span>\
                </a>\
            </li>\
        </ul>\
        <input class="text"  name="files[<%= item.qid %>]" type="hidden" value="<%= item.detailId %>"/>\
        <input class="text" id="<%= item.qid %>z1" name="files[<%= item.qid %>z1]" type="hidden" value=""/>\
        <input class="text" id="<%= item.qid %>z2" name="files[<%= item.qid %>z2]" type="hidden" value=""/>\
        <div id="fineUploader-<%= item.qid %>" class="fineUploader" data-file-id="<%= item.qid %>" data-svc-id="<%= item.svcId %>"></div>\
    </div>',
    missingBldgItem: '\
    <div class="control-group <%= item.qid %> well">\
        <ul class="breadcrumb span12">\
            <li><strong><%= item.type %></strong><span class="divider">/</span></li>\
            <li><%= item.section %><span class="divider">/</span></li>\
            <li><%= item.description %></li>\
            <li class="pull-right span3">\
                <a  id="<%= item.qid %>-action" href="#" class="btn btn-primary" data-file-id="<%= item.qid %>">\
                    <i class="icon-upload  icon-white"></i>\
                    <span> Select Files</span>\
                </a>\
            </li>\
            <li>\
                <label class="checkbox pull-left">\
                    <input class="checkbox" name="files[<%= item.qid %>-attached_previous]" type="checkbox" value="yes" /> Attached to a previous building\
                </label>\
            </li>\
        </ul>\
        <input class="text"  name="files[<%= item.qid %>]" type="hidden" value="<%= item.detailId %>"/>\
        <input class="text" id="<%= item.qid %>z1" name="files[<%= item.qid %>z1]" type="hidden" value=""/>\
        <input class="text" id="<%= item.qid %>z2" name="files[<%= item.qid %>z2]" type="hidden" value=""/>\
        <div id="fineUploader-<%= item.qid %>" class="fineUploader" data-file-id="<%= item.qid %>" data-svc-id="<%= item.svcId %>"></div>\
    </div>',
    noSelection: '<p><strong>You must first select/check items from the <strong>Missing Items</strong> table, only checked items will be listed here.</strong></p>',
    regularSelection: '<p><strong>Please provide descriptive file names and limit file types to PDFs or Images.</strong></p>'
};

The modal which contains the above: rails 3.2 erg file.

<%# Upload Attachments Modal %>
<div id="upload-attachments-modal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="upload-attachments-label" aria-hidden="true">
    <%= form_tag action_target, :id => "upload-attachments-form", :class => "modal-form form-horizontal", :remote => false, :method => :post, :multipart => :true do %>
        <div class="modal-header">
            <h3 id="upload-attachments-label" class="text-left">Attach Documents</h3>
        </div>
        <div id="upload-attachments-body" class="modal-body" data-lob-id="<%= lob_id %>" data-lob-cis="<%= lob_cis %>">
            <div class="alert alert-block span12">
                <span id="banner-message" data-opt-quotes="<%= opt_quotes_bool %>" class="text-center">Please provide descriptive file names and limit file types to PDFs or Images.</span>
            </div>
            <fieldset><legend></legend>
            </fieldset>
            <input id="lob" name="lob_name" type="hidden" value="<%= lob_name %>" />
            <div id="general-error-div" class="control-group"></div>
        </div>
        <div class="modal-footer">
            <%= button_tag "Save", type: :submit, name: 'process_upload_modal_action', value: 'save', class: "btn btn-primary", id: "upload-ok-button" %>
            <a id='upload-cancel-btn' href="#" data-dismiss="modal" class="btn">Cancel</a>
        </div>
    <% end %>
</div>

A snippet of js code to create an Misc entry in the modal.

 /* add misc doc type, with plus/minus keys */
        mItem = {
            qid: 'misc-1',
            type: 'Miscellaneous Documents',
            section: lobName,
            description: 1,
            svcId: lobName + '-' + lobId + '-9999',
            detail_id: '0'
        };
        mBody.append(_.template(attachTemplates.miscItem, {item: mItem}));
        mBody.find('a.misc-minus').last().remove();

I hope this is want you need?

James,

rnicholus commented 10 years ago

Ugh, thanks for reporting this. Definitely a bug in Fine Uploader. We should, of course, only prevent "originals" from being uploaded if the file is scalable in the current browser. We'll fix this in an upcoming 5.0.3 hotfix release.

skoona commented 10 years ago

Thanks, I will watch for the update.

rnicholus commented 10 years ago

James - I believe I have a fix for this in a hotfix branch. Before we release a hotfix, we'd like to give you the opportunity to test this yourself to verify that it fixes your issue. I needed to write some tests, and fix other code that was dependant on the original faulty logic. Send us an email when you'd like to get a copy for testing.

On Mon, Jun 23, 2014 at 2:31 PM, James Scott, Jr notifications@github.com wrote:

Thanks, I will watch for the update.

— Reply to this email directly or view it on GitHub https://github.com/Widen/fine-uploader/issues/1238#issuecomment-46890613 .

skoona commented 10 years ago

It works for me. I tried uploading two files, a pdf and a jpeg. With hideScaled: true, no update was driven (no filename displayed) to the UI, but upload the scaled image; kinda thought it would show the original filename. Instead is showed nothing and uploaded the scaled image. Switching back to hideScaled: false, caused the UI to update with the scaled filename; which is fine for me.

I used this config:

scaling: { 
                sendOriginal: false, 
                includeExif: true,
                hideScaled: false,
                sizes: [
                    {name: "scaled", maxSize: 1600}
                ]
            }

As far as I can tell, it seems to be working for me. Thank you for the quick update.

James,

rnicholus commented 10 years ago

Glad the fix worked for you.

I'm assuming the PDFs always showed up in the file list UI, regardless of the settings, correct?

What you are seeing - nothing in the file list with hideScaled: true and sendOriginal: false for scalable images - is expected. If you don't want scaled versions to be represented in the UI, and don't want originals to be uploaded, there isn't anything left to display in the UI. I suppose we could display a list item to represent the batch, but it's not clear what that would look like and what actions would be available, if any. That is certainly open for discussion.

skoona commented 10 years ago

Yes, PDFs were always shown regardless.

Not really concerned about the blind UI updates, as long as the :complete callback is called, and/or there is a local listing of uploaded files. I will check this out over the weekend.

James,

skoona commented 10 years ago

I've covered all my bases, everything I need it to do is working as expected. Thanks for the quick turn around, and a great package.

James,

rnicholus commented 10 years ago

Good to hear James. Thanks for the update. We'll probably do a hotfix release today or tomorrow.

On Mon, Jun 30, 2014 at 9:28 AM, James Scott, Jr notifications@github.com wrote:

I've covered all my bases, everything I need it to do is working as expected. Thanks for the quick turn around, and a great package.

James,

— Reply to this email directly or view it on GitHub https://github.com/Widen/fine-uploader/issues/1238#issuecomment-47538073 .

rnicholus commented 10 years ago

This is part of the 5.0.3 release.