0

I am trying to un-jQuery-fy a clever piece of code, but one that is just a bit too clever.

The objective is simple. Drag images from the desktop to the browser.

During this unjQueryfication, I find that, lo and behold, a dollar-sign function is actually implemented in Chrome and Firefox. So even without including jQuery, it sort of works already.

Here is what I came up with so far. What am I missing?

var el = document.getElementById('holder');

function stop_and_prevent(e) {
    e.stopPropagation();
    e.preventDefault();
}

function load_images(files) {
    var images = document.getElementById("images");
    files.map(function(file) {
        var reader = new FileReader();
        reader.onload = function(event) {
            if (file.type.match('image.*')) {
                var img = document.createElement('img');
                img.src = event.target.result;
                images.appendChild(img);
                reader.readAsDataURL(file);
            }}
    });
}

function onDrop(e) {
    e.stop_and_prevent();
    load_images(e.dataTransfer.files);
    return false;
}

el.addEventListener('dragenter', stop_and_prevent, false);
el.addEventListener('dragover', stop_and_prevent, false);
el.addEventListener('dragleave', stop_and_prevent, false);
el.addEventListener('drop', onDrop, false);
div#holder {
    border: 5px dashed #ccc;
    height:400px;
    width:400px;
    font-family:Verdana;
    text-align:center;
}
    <div id="holder">
        <p>Drag files here</p>
        <div id="images"></div>
    </div>
Sebastian
  • 119
  • 12

1 Answers1

1

You probably meant to use:

stop_and_prevent(e);

in your drop handler instead of the current:

e.stop_and_prevent();

Also, since files is of type FileList and not Array you won't be able to use map() directly on it. Just use a normal loop or a [].forEach.call() instead.

You don't need to prevent events on the dragleave handler.

Updated code:

var el = document.getElementById('holder');

function stop_and_prevent(e) {
    e.stopPropagation();
    e.preventDefault();
}

function load_images(files) {
    var images = document.getElementById("images");
    [].forEach.call(files, function(file) {
      if (file.type.match('image.*')) {
        var reader = new FileReader();
        reader.onload = function() {
          var img = document.createElement('img');
          img.src = this.result;  //=reader.result, or use event.target.result
          images.appendChild(img);
        }
        reader.readAsDataURL(file);
      }
   });
}

function onDrop(e) {
    stop_and_prevent(e);
    load_images(e.dataTransfer.files);
    return false;
}

el.addEventListener('dragenter', stop_and_prevent);
el.addEventListener('dragover', stop_and_prevent);
el.addEventListener('drop', onDrop);
div#holder {
    border: 5px dashed #ccc;
    height:400px;
    width:400px;
    font-family:Verdana;
    text-align:center;
}
<div id="holder">
        <p>Drag files here</p>
        <div id="images"></div>
    </div>
  • Good catch. That's a nice hint. I now (sort-of) see why it was (kind-of) working **before** the change you suggest. The images dragged have themselves "draggable=true", and the first gets inserted regardless of the JS code. So now it's much better; it doesn't work at all :) – Sebastian Aug 02 '17 at 19:26
  • @Sebastian that's because you have other errors in your code, in for example how you read the images. Added a fix in the answer (see code snippet) –  Aug 02 '17 at 19:29
  • Nice. Thanks. One thing is not clear (I'm almost exhausted from tracking this one detail): What is `this` pointing to? – Sebastian Aug 02 '17 at 19:47
  • 1
    @Sebastian `this` inside the handler it will point to its parent, ie. the current `reader`, but you can use the event object as you do already too. –  Aug 02 '17 at 19:52