Get element that a file was dropped onto

I've created a page in Hype to allows the identification of dropped file information, that is, the user can drag and drop a file from their desktop onto an element on my page and the javascript (below) gets information on the dropped file. This all works :smile: however I have numerous elements that the user can 'drop' onto and I'd like to identify which element the user chose to drop the file onto.

The javascript I'm using to setup drag and drop is as follows:

function handleFileSelect(evt) {
evt.stopPropagation();
evt.preventDefault();

var files = evt.dataTransfer.files; // FileList object.
// files is a FileList of File objects. List some properties.
var output = [];
for (var i = 0, f; f = files[i]; i++) {
  output.push('<li><strong>', escape(f.name), '</strong> (', f.type || 'n/a', ') - ',
              f.size, ' bytes, last modified: ',
              f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a',
              '</li>');
}
hypeDocument.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';

}

function handleDragOver(evt) {
evt.stopPropagation();
evt.preventDefault();
evt.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
}

// Setup the dnd listeners.
var dropZone = hypeDocument.getElementById('drop_zone');
dropZone.addEventListener('dragover', handleDragOver, false);
dropZone.addEventListener('drop', handleFileSelect, false);

1 Like

Are you able to post a hype doc as an example of what you are doing. My thoughts are that you should be able to use the element.id which should be the id of the element that triggers the function. But without seeing how you are actually triggering it ??

So the code I have above is run on scene load. I have two elements, one for the file drop and another to show the file details. I hope that helps…

I’ve attached an example file as request. Imagine this having multiple drop and list elements.

HypeDnDDemo.zip (11.6 KB)

Here you go it was easier than I thought it would be when I first looked at the code.

You cannot use the normal hype function parameter for the element that fires the function because of the functions are in effect outside of the hype documents control. ( someone else probably can put that better)

But we can get the id by tapping into the *event.target.id*

  function handleFileSelect(evt) {
    evt.stopPropagation();
    evt.preventDefault();

    var files = evt.dataTransfer.files; // FileList object.

    // files is a FileList of File objects. List some properties.
    var output = [];
    for (var i = 0, f; f = files[i]; i++) {
      output.push('<li>',evt.target.id ,'<li><strong>', escape(f.name) , '</strong> (', f.type || 'n/a', ') - ',
                  f.size, ' bytes, last modified: ',
                  f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a',
                  '</li>');
                   
                 
    }
    hypeDocument.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
  }

  function handleDragOver(evt) {
    evt.stopPropagation();
    evt.preventDefault();
    evt.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
  }

  // Setup the dnd listeners.
  //var dropZone = hypeDocument.getElementById('drop_zone');
   var dropZones =  document.getElementsByClassName('drop_zone');
   
    
 for (i = 0; i < dropZones.length; i++) { 
  dropZones[i].addEventListener('dragover', handleDragOver, false);
  dropZones[i].addEventListener('drop', handleFileSelect, false);
  }

Here is a working example with you code adjusted. Note I have added a drop zone and iterating over them in the code to add the listeners to each.

HypeDnDDemoMH.hype.zip (13.9 KB)

Thanks Mark for your support. I’ll try this out tonight.

This is working very well, thanks. The only issue I have now is that if I group multiple elements as a drop zone then instead of getting the drop zone name I get what seems to be a hype generated group class name. any thoughts?

I’ve attached an example

HypeDnDDemoGroup.hype.zip (14.9 KB)

While I am looking are you only grouping to just get the bullet shape. Because you can just use the radius setting in the Element inspector on the end corners

The grouping in the example is just to show the issue. In my project I have a number of shapes and text which must be grouped.

Thanks

Ok I change the way this works.

Instead of using id we will use class name.

If we have for example Group 1 with two elements grouped.

We give each element the class Name drop_zone1.
We also give the Group 1 the same class name. drop_zone1

Any single element that is not in the group will get it’s own class name.
And any other group and it’s elements will get their own single class name added to the elements and said group.

In the javascript we now assign the listeners based on the classname.

And the evt.target.id is changed to evt.target.className

working example:

HypeDnDDemoGroup 3.hype.zip (19.7 KB)

  function handleFileSelect(evt) {
    evt.stopPropagation();
    evt.preventDefault();

    var files = evt.dataTransfer.files; // FileList object.

    // files is a FileList of File objects. List some properties.
    var output = [];
    for (var i = 0, f; f = files[i]; i++) {
      output.push('<li>',evt.target.className ,'<li><strong>', escape(f.name) , '</strong> (', f.type || 'n/a', ') - ',
                  f.size, ' bytes, last modified: ',
                  f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a',
                  '</li>');
                   
                 
    }
    hypeDocument.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
  }

  function handleDragOver(evt) {
    evt.stopPropagation();
    evt.preventDefault();
    evt.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
  }

  // Setup the dnd listeners.
 
 var dropZones = document.querySelectorAll('div[class^="HYPE_element drop_zone"]');
   
 
 
    
 for (i = 0; i < dropZones.length; i++) { 
  dropZones[i].addEventListener('dragover', handleDragOver, false);
  dropZones[i].addEventListener('drop', handleFileSelect, false);
  }

Note 1: The reason we also give the Group the class name is because you may miss the element and drop onto the Group space. If the Group has the same class name as it’s elements then the logic will still work.

Note 2:
I did try and continue to use the ID and although I found work arounds for Hype ignoring the given ID the above way seemed cleaner and simpler.

1 Like

Thank you so much for all the help. This works perfectly

hey @MarkHunte I attempted to use this sample in my project and its not working. When i drag an image into the drop zone it just opens the image in the browser window… and doesn’t actually attach the file.

I have my dropzone element (display name: rounded rectangle, class = drop_zone1 ID = drop_zone1 )on the second scene with the java function set to run on scene load and i have it in the top layer as well as my text element with a (display name: text, ID = list)
and attached is my project… is there something i might have missed?

signup_view.zip (1.5 MB)

Hi @JohnnyMoon ,

I am not at a mac I can check this right now but will later today, unless someone else spots the issue before then I will get back to you later.

Cheers

1 Like

The script has a reference to 'drop_zone' but you have given the element a class name ( & ID ) of drop_zone1. Try changing the class name to match your script...

var dropZones =  document.getElementsByClassName('drop_zone');
2 Likes

I think I need more sleep in my life… I keep missing pretty obvious things… Thanks for all the support guys!

2 Likes