I am trying to do drag and drop from a parent page into an iframe which is cross-domain. The iframe is loaded by content script through chrome extension. But because of cross-domain iframe loaded by content script, I can't just use HTML5 drag and drop from parent page to iframe.
The reason I am going through the pain of using iframe is to avoid CSS corruption.
The approach I am trying to take is:
There is a way to communicate between parent and a cross-origin iframe through window.postMessage(). So I thought I will try to simulate drag operation happening in parent page inside iframe, by sending every drag related operation info inside parent to child iframe.
What I did was create a div
inside iframe with contents of the dragged element on dragstart
in parent. And on drag
, continuously drag this div
inside iframe with the coordinates provided by parent.
// CONTENT SCRIPT CODE
const setEventListener = name => {
document.body.addEventListener(name, event => {
const data = {
dndType: name,
clientX: event.clientX, // clientX for iframe should map from clientX from parent exactly, I think
clientY: iframeContainer.getBoundingClientRect().top - event.clientY, // iframeContainer is placed at the bottom
htmlContent: name === 'dragstart' && event.dataTransfer.getData('text/html')
}
iframe.contentWindow.postMessage(data, '*')
})
}
setEventListener('dragstart')
setEventListener('drag')
setEventListener('dragend')
// IFRAME CODE
let dragger
window.addEventListener('message', function(e) {
if (!dragger) {
dragger = document.createElement('div')
document.body.appendChild(dragger)
}
if (e.data.dndType) {
if (e.data.htmlContent && e.data.htmlContent.length > 0) {
dragger.innerHTML = e.data.htmlContent
}
const newEvent = createEvent(
e.data.dndType,
{
clientX: e.data.clientX,
clientY: e.data.clientY,
dataTransfer: new DndSimulatorDataTransfer(),
}
)
newEvent.dataTransfer.setData('text/html', dragger.innerHTML)
dragger.dispatchEvent(newEvent)
}
})
const createEvent = (eventName, options) => {
var event = document.createEvent("CustomEvent");
event.initCustomEvent(eventName, true, true, null);
event.view = window;
// event.detail = 0;
event.ctlrKey = false;
event.altKey = false;
event.shiftKey = false;
event.metaKey = false;
event.button = 0;
event.relatedTarget = null;
/* if the clientX and clientY options are specified,
also calculated the desired screenX and screenY values */
if(options.clientX && options.clientY) {
event.screenX = window.screenX + options.clientX;
event.screenY = window.screenY + options.clientY;
}
/* copy the rest of the options into
the event object */
for (var prop in options) {
event[prop] = options[prop];
}
return event;
}
var DndSimulatorDataTransfer = function() {
this.data = {};
};
DndSimulatorDataTransfer.prototype.setData = function(format, data) {
this.data[format] = data;
this.items.push(data);
this.types.push(format);
};
// Remaining DndSimulatorDataTransfer prototype methods
// Taken from https://github.com/Photonios/JS-DragAndDrop-Simulator/blob/master/dndsim.js
I have tried different variations in this code but there is still no activity in iframe side. I am not even sure if this approach should work.
Is this even technically possible? Or is there any other way I should try. I think this guy is talking about this same approach.
Need help!