Question
How could I, while providing the file, trigger a drop
event of a field, on which I do not have access at loading.
Details
There is a page with a field on which is attached a drop
listener that process an image when dropped. I would like to be able to use this process by pasting an image. I know how to get the file from a paste, but I do not know how to dispatch a drop
event that would contains this very file.
The obstacles are:
- The code is obfuscated, I cannot access the function linked with the listener by name.
- There is no way to get the
drop
listener after it being attached to an element. It seems there is some way to do it in the console, but not from a script. - I do not control the page rendering; i.e. I cannot intercept the event listener addition.
- Vanilla Javascript & could only work in Chrome (extension).
- This page is built in vanilla; i.e. no jQuery or anything.
Does anyone have an idea on how to tackle this task?
I am looking into DragEvent but "although this interface has a constructor, it is not possible to create a useful DataTransfer object from script, since DataTransfer objects have a processing and security model that is coordinated by the browser during drag-and-drops."
I saw a possible approach but I want to mimic a real drop event with its data, i.e. pass a file I got via clipboardData.items[0].getAsFile();
instead of just text.
Question
How could I, while providing the file, trigger a drop
event of a field, on which I do not have access at loading.
Details
There is a page with a field on which is attached a drop
listener that process an image when dropped. I would like to be able to use this process by pasting an image. I know how to get the file from a paste, but I do not know how to dispatch a drop
event that would contains this very file.
The obstacles are:
- The code is obfuscated, I cannot access the function linked with the listener by name.
- There is no way to get the
drop
listener after it being attached to an element. It seems there is some way to do it in the console, but not from a script. - I do not control the page rendering; i.e. I cannot intercept the event listener addition.
- Vanilla Javascript & could only work in Chrome (extension).
- This page is built in vanilla; i.e. no jQuery or anything.
Does anyone have an idea on how to tackle this task?
I am looking into DragEvent but "although this interface has a constructor, it is not possible to create a useful DataTransfer object from script, since DataTransfer objects have a processing and security model that is coordinated by the browser during drag-and-drops."
I saw a possible approach https://stackoverflow./a/39066443/1004274 but I want to mimic a real drop event with its data, i.e. pass a file I got via clipboardData.items[0].getAsFile();
instead of just text.
1 Answer
Reset to default 7You can fake the drop event, and fake pretty much everything that's in there. What you'll have problem doing is triggering a default event, such as opening a file in a tab by dropping it. The reason isn't so much because of the dataTransfer object being protected, but the event not being trusted. By having trusted event and protected dataTransfer, you can be sure you won't pass data to a trusted event, and that you won't trigger default event with unwanted data.
But depending on how the drop function is accessing the file that is dropped, you might be able to trick it with a fake drop event and a fake dataTransfer object. See this fiddle for a general idea of how it may work:
var a = document.getElementById('link');
var dropZone1 = document.getElementById('dropZone1');
var dropZone2 = document.getElementById('dropZone2');
var fakeDropBtn = document.getElementById('fakeDropBtn');
dropZone1.addEventListener('dragover', function(e) {
e.preventDefault();
});
dropZone2.addEventListener('dragover', function(e) {
e.preventDefault();
});
dropZone1.addEventListener('drop', function(e) {
// This first drop zone is simply to get access to a file.
// In your case the file would e from the clipboard
// but you need to work with an extension to have access
// to paste data, so here I use a drop event
e.preventDefault();
fakeDropBtn.classList.remove('disabled');
dropZone2.classList.remove('disabled');
var fileToDrop = e.dataTransfer.files[0];
// You create a drop event
var fakeDropEvent = new DragEvent('drop');
// You override dataTransfer with whichever property
// and method the drop function needs
Object.defineProperty(fakeDropEvent, 'dataTransfer', {
value: new FakeDataTransfer(fileToDrop)
});
fakeDropBtn.addEventListener('click', function(e) {
e.preventDefault();
// the fake event will be called on the button click
dropZone2.dispatchEvent(fakeDropEvent);
});
});
dropZone2.addEventListener('drop', function(e) {
e.preventDefault();
// this is the fake event being called. In this case for
// example, the function gets access to dataTransfer files.
// You'll see the result will be the same with a real
// drop event or with a fake drop event. The only thing
// that matters is to override the specific property this function
// is using.
var url = window.URL.createObjectURL(e.dataTransfer.files[0]);
a.href = url;
a.click();
window.URL.revokeObjectURL(url);
});
function FakeDataTransfer(file) {
this.dropEffect = 'all';
this.effectAllowed = 'all';
this.items = [];
this.types = ['Files'];
this.getData = function() {
return file;
};
this.files = [file];
};
https://jsfiddle/5m2u0tux/6/