Monday, February 4, 2013

Add html element behaviour to drop files

Use for you own risk, early dev version. No iframe, flash or other stuff. Js only.
First create helper object for adding and removing dragenter, dragleave, dragover, drop handlers and form submission using js FormData object. Modules structure code inspired by Raqy.Style code.
App = App || {};

(function($) {'use strict';
    // used to disable <body> files dropping
    function _disableBody() {
    $(document).bind('dragenter', function(e) {
        return false;
    }).bind('dragleave', function(e) {
        return false;
    }).bind('dragover', function(e) {
        var dt = e.originalEvent.dataTransfer;
        if (!dt) {
            return;
        }
        dt.dropEffect = 'none';
        return false;
    }.bind(this));
 }
    // add all handlers for specified selctor
    function _enableDrop(selector, options) {
        $(selector).bind("dragover", function(e) {
            options.dragover && options.dragover(e);
                return false;
            }).bind("dragenter", function(e) {
            options.dragenter && options.dragenter(e);
                return false;
            }).bind('dragleave', function(e) {
                options.dragleave && options.dragleave(e);
                return false;
            }).bind("drop", function(e) {
                options.drop && options.drop(e);
                return false;
            });
    }

 var module = {
  disableBody : _disableBody,
  enableDrop : _enableDrop,
 };

 // register new namespace
 App.DropArea = module;

})(jQuery);
Form sending helper:
(function($) {'use strict';
    var opts = {
        form : null,
        response : null
    }
    function mergeDataToFormData(formData, data) {
        $.each(data, function(k, v) {
            formData.append(k, v);
        });
        return formData;
    }

    function _send(options) {
        var opts = {
            url : options.url,
            type : 'POST',
        };
        if (options.beforeSend) {
            opts.beforeSend = options.beforeSend;
        }
        if (options.error) {
            opts.error = options.error;
        }
        var data = new FormData(options.form ? $(options.form)[0] : {});
        if (options.data && data != undefined) {
            data = mergeDataToFormData(data, options.data);
        }
    return $.ajax($.extend(opts, {
            success : options.success,
            data : data || {},
            cache : false,
            mimeType : 'multipart/form-data',
            contentType : false,
            processData : false
        }));
    }

    var module = {
        send : _send
    };

    App.FormDataSend = module;

})(jQuery);
Add drop behaviour:
"#files-drop-area" - block for adding handlers.
"/FileUpload" - url for submitting file form
App.DropArea.disableBody();
App.DropArea.enableDrop('#files-drop-area', {
    dragenter : function(e) {
        $(e.target).css('border', '1px solid #3F3F3F');
    },
    dragleave : function(e) {
        $(e.target).css('border', '0px');
    },
    drop : function(e) {
        e.preventDefault();
        var dt = e.originalEvent.dataTransfer;
        if (!dt && !dt.files)
            return;

        var root = $(e.target);
        var files = dt.files;
        var cntFinished = 0;

        var finishCallback = function(current, cnt) {
            if (current >= cnt) {
                root.css('border', '0px');
                // restore original state of uploading form: remove progress, hide messages etc ..
            } else {
                // show info about uploading (console)
                console.log('Uploaded: ' + current + ' / ' + cnt + ' images.');
                 // show progress message, loading indicatiors etc...
            }
        }
        for (var i = 0; i < files.length; i++) {
            finishCallback(cntFinished, files.length);
            // max allowed size for file checking, client side, fired immediate after 'drop'
            if (files[i].size > 2097152) {
                cntFinished++;
                finishCallback(cntFinished, files.length);
                console.log('File too big: ' + files[i].name);
                continue;
            }
            // send ajax form with file
            App.FormDataSend.send({
                url : '/FileUpload',
                data : {
                    'id' : 100500, // data for sorm submitting
                    'filename' : files[i]
                },
                error : function(e) {
                    cntFinished++;
                    finishCallback(cntFinished, files.length);
                    // show in form , if you need it
                    console.log('Error uploading file:' + e.responseText);
                },
                success : function(responce) {
                    cntFinished++;
                    finishCallback(cntFinished, files.length);
                    // I have json object as responce
                    var rObjs = jQuery.parseJSON(responce);
                    if (rObjs.error == false) {
                        // process added image object 'rObjs'
                    } else if (rObjs.error == true) {
                        // server-side errors, probably validation or allowed size etc 
                        // captured by form handler code
                    } else {
                        // else server-side errors
                    }
                }
            });
        }
        return false; // use this, or image will be displayed in browser, IMPORTANT !
    }
});