codeNinja
codeNinja

Reputation: 1462

full page drag and drop files website

I am trying to get similar functionality as dropbox has for drag and drop. I would like to achieve this using as basic web compoments/coding as possible. HTML or HTML5 would be best. This is for a prototype so faster the better. Here is what i am trying to achieve:

1) user should be able to drag and drop a file from their computer to anywhere on the web page. 2) The web page itself should show some indicator (ie: highlight or color overlay) when an item is dragged over it.

I have seen code snippets of several examples but they all limit to dropping containers that are already on the screen into others and not so much file into the webpage.

The dropped file does not need to be uploaded anywhere since this is going to be a demo.

Anyone have some code snippets that can get me going.

Upvotes: 11

Views: 13340

Answers (2)

kirelagin
kirelagin

Reputation: 13616

The basic idea is this:

  • Keep the drop zone hidden by default.
  • Attach a handler to the html element that will show the zone when something is being dragged over the page.
  • When the zone is visible, tap into its events to handle drag and drop.
  • When the mouse leaves the zone, hide it.

Here is the code that worked for me: https://jsfiddle.net/oL2akhtz/.


This part of HTML5 spec is a little bit strange. The most important things to keep in mind are these:

  • There are four interesting events: dragenter fires when we drag something and enter the bounds of an element; dragover fires every few ms while we are dragging something over the element; dragleave is the opposite of dragenter; drop fires when something is actually dropped.
  • You must listen to both dragenter and dragover on any element that is a valid drop target. That is, the element is turned into a valid drop target by listening to those events and cancelling their default actions. In our case this applies to the drop-zone overlay.

Now I’ll try to explain my code.

  1. First we add a listener that handles dragenter for the whole page. It just shows the overlay (and there is no need to prevent the default action as we actually do not intend to drop anything on the page, we will be dropping only on the overlay).
  2. Setup handlers for dragenter and dragover for the overlay. They prevent the default actions (which are to disallow dropping there) and also set dropEffect to give the user some nice feedback (although this seems to do nothing right now in modern browsers). This is a good place to test whether the item being dragged is valid.
  3. If the mouse leaves the drop zone (which is the same as the whole window, since the div covers everything) we hide it.
  4. Setup the actual drop handler.

That’s it, pretty straightforward. Here is what happens when someone drops a file:

  1. dragenter for the html element fires. It shows the dropzone.
  2. Since the mouse is now over the dropzone, dragleave for the html element fires, but we ignore it.
  3. dragenter for the dropzone fires and then dragover keeps firing. We just jeep saying that, yes, this is a valid drop target.
  4. Either drop fires, in which case we hide the dropzone and process the file, or dragleave for the dropzone fires in which case we just hide it.

Upvotes: 22

codeNinja
codeNinja

Reputation: 1462

Here is what ended up working

First the HTML Code:

<body id="drop1" align=center>
<DIV id="content" >Drop files here

<h1 align=center>A File Preview Demo</h1>

    <DIV id="status">Drag the files from a folder to a selected area ...</DIV>
    <DIV id="drop2">Drop files here.</DIV>
    <DIV id="list"></DIV>
    <DIV id="list2"></DIV>
</DIV>
</body>

Next the CSS code:

html,body{
    height: 96%;
    }

#drop1 {
    height: 100%;
    width: 97%;
    border: 2px solid blue;
    margin: 0px;
    padding: 10px;
    background-color: yellow;
    overflow:hidden; 
}
#drop2 {
    height: 30%;
    width: 30%;
    border: 1px solid red;
    margin: 10px;
    padding: 10px;
}
#content
{
    height: 100%;
    width: 100%;
}
.hoverClass {
    background-color: blue;
}
.dropClass {
    background-color: green;
}

Last the JS Code:

if (window.FileReader) {
    var drop;
    var drop2;
    var fileNumber = 0;
    addEventHandler(window, 'load', function () {
        var status = document.getElementById('status');
        drop = document.getElementById('drop1');
        drop2 = document.getElementById('drop2');
        var list = document.getElementById('list');
        var list2 = document.getElementById('list2');


        function cancel(e) {
            if (e.preventDefault) {
                e.preventDefault();
            }
            return false;
        }

        // Tells the browser that we *can* drop on this target
        addEventHandler(drop, 'dragover', function (e) {
            e = e || window.event; // get window.event if e argument missing (in IE) 
            if (e.preventDefault) {
                e.preventDefault();
            }
            fileNumber = fileNumber + 1;
            status.innerHTML = fileNumber;
            $("#drop1").css("background-color", '#AA0000');

            return false;
        });
        // Tells the browser that we *can* drop on this target
        addEventHandler(drop, 'dragleave', function (e) {
            e = e || window.event; // get window.event if e argument missing (in IE) 
            if (e.preventDefault) {
                e.preventDefault();
            }
            fileNumber = fileNumber + 1;
            status.innerHTML = fileNumber;
            $("#drop1").css("background-color", '#FF0000');

            return false;
        });

        addEventHandler(drop, 'dragenter', cancel);
        addEventHandler(drop2, 'dragover', cancel);
        addEventHandler(drop2, 'dragenter', cancel);


        addEventHandler(drop, 'drop', function (e) {
            e = e || window.event; // get window.event if e argument missing (in IE)   
            if (e.preventDefault) {
                e.preventDefault();
            } // stops the browser from redirecting off to the image.

            var dt = e.dataTransfer;
            var files = dt.files;
            for (var i = 0; i < files.length; i++) {
                var file = files[i];
                var reader = new FileReader();

                //attach event handlers here...  
                reader.readAsDataURL(file);

                addEventHandler(reader, 'loadend', function (e, file) {
                    var bin = this.result;
                    var newFile = document.createElement('div');
                    newFile.innerHTML = 'Loaded : ' + file.name + ' size ' + file.size + ' B';
                    list.appendChild(newFile);
                    var fileNumber = list.getElementsByTagName('div').length;
                    status.innerHTML = fileNumber < files.length ? 'Loaded 100% of file ' + fileNumber + ' of ' + files.length + '...' : 'Done loading. processed ' + fileNumber + ' files.';

                    var img = document.createElement("img");
                    img.file = file;
                    img.src = bin;
                    list.appendChild(img);
                }.bindToEventHandler(file));
            }
            return false;
        });

        addEventHandler(drop2, 'drop', function (e) {
            e = e || window.event; // get window.event if e argument missing (in IE)   
            if (e.preventDefault) {
                e.preventDefault();
            } // stops the browser from redirecting off to the image.

            var dt = e.dataTransfer;
            var files = dt.files;
            for (var i = 0; i < files.length; i++) {
                var file = files[i];
                var reader = new FileReader();

                //attach event handlers here...  
                reader.readAsDataURL(file);

                addEventHandler(reader, 'loadend', function (e, file) {
                    var bin = this.result;
                    var newFile = document.createElement('div');
                    newFile.innerHTML = 'Loaded : ' + file.name + ' size ' + file.size + ' B';
                    list.appendChild(newFile);
                    var fileNumber = list.getElementsByTagName('div').length;
                    status.innerHTML = fileNumber < files.length ? 'Loaded2 100% of file ' + fileNumber + ' of ' + files.length + '...' : 'Done loading. processed ' + fileNumber + ' files.';

                    var img = document.createElement("img");
                    img.file = file;
                    img.src = bin;
                    list.appendChild(img);
                }.bindToEventHandler(file));
            }
            return true;
        });

        Function.prototype.bindToEventHandler = function bindToEventHandler() {
            var handler = this;
            var boundParameters = Array.prototype.slice.call(arguments);
            //create closure
            return function (e) {
                e = e || window.event; // get window.event if e argument missing (in IE)   
                boundParameters.unshift(e);
                handler.apply(this, boundParameters);
            }
        };
    });
} else {
    document.getElementById('status').innerHTML = 'Your browser does not support the HTML5 FileReader.';
}

function addFile(evt) {
    e = e || window.event; // get window.event if e argument missing (in IE)   
    if (e.preventDefault) {
        e.preventDefault();
    } // stops the browser from redirecting off to the image.

    var dt = e.dataTransfer;
    var files = dt.files;
    for (var i = 0; i < files.length; i++) {
        var file = files[i];
        var reader = new FileReader();

        //attach event handlers here...  
        reader.readAsDataURL(file);

        addEventHandler(reader, 'loadend', function (e, file) {
            var bin = this.result;
            var newFile = document.createElement('div');
            newFile.innerHTML = 'Loaded : ' + file.name + ' size ' + file.size + ' B';
            list.appendChild(newFile);
            var fileNumber = list.getElementsByTagName('div').length;
            status.innerHTML = fileNumber < files.length ? 'Loaded2 100% of file ' + fileNumber + ' of ' + files.length + '...' : 'Done loading. processed ' + fileNumber + ' files.';

            var img = document.createElement("img");
            img.file = file;
            img.src = bin;
            list.appendChild(img);
        }.bindToEventHandler(file));
    }
    return false;
}

//seperate event
function addEventHandler(obj, evt, handler) {
    if (obj.addEventListener) {
        // W3C method
        obj.addEventListener(evt, handler, false);
    } else if (obj.attachEvent) {
        // IE method.
        obj.attachEvent('on' + evt, handler);
    } else {
        // Old school method.
        obj['on' + evt] = handler;
    }
}

http://jsfiddle.net/JtJ5N/79/

Happy Coding!

Upvotes: -1

Related Questions