Search code examples
javascriptgoogle-chromefirefoxgoogle-chrome-extensionfirefox-addon

Simulating drop event works in Chrome extension but not Firefox add-on?


I'm trying to simulate a drop event (with the Drag and Drop API) in a browser extension's content script. Essentially, I want to simulate a user dropping an image programmatically. I have this so far:

const dataTransfer = new DataTransfer();
dataTransfer.items.add(file); // File object representing image being dropped
const event = new DragEvent('drop', { dataTransfer });
document.body.dispatchEvent(event);

This works great on both Chrome and Firefox when all the simulation happens natively in the browser. This JSFiddle works great in both browsers–if you upload a file, a drop is simulated and the image shows up in the preview.

The problem is when I try to accomplish the exact same thing with a browser extension, I run into problems in Firefox (but not Chrome). I've put together a demo extension that accomplishes the same thing as the JSFiddle but with a content script. On Chrome, the extension injects a file input and simulates the drop perfectly (the image shows up in #preview):

enter image description here

You can see (in the free-hand circle) that dataTransfer.files has a length of 1–the dropped image file is in the list. But when I use the exact same extension on Firefox:

enter image description here

The image was uploaded (see the input) but it was not dropped and shown in the preview. From the console, you can see that dataTransfer.files is empty in Firefox, even though dataTransfer.items has the file in it!

Why is there a discrepancy here? I checked with Mozilla's compatibility checker which said my extension was cross-platform ready. By then HTML5 spec files should be in sync with items, and no conditions AFAICT warrant an empty list on Firefox. Could this be a bug?


Solution

  • Thanks to wOxxOm, the problem was due to Firefox's Xray vision policy that separates global objects of content scripts and page scripts (including File). By unwrapping the page's DataTransfer object instead of the content script's, I was able to simulate the drop:

    const dataTransfer = new window.wrappedJSObject.DataTransfer();