interact.js icon indicating copy to clipboard operation
interact.js copied to clipboard

Interact.js not working with elements in iframes if they was created in parent window

Open kachurun opened this issue 4 years ago • 10 comments

Actual behavior

I have an iframe inserted into my main site and I need to create elements inside the iframe from the parent context. But interact.js doesn't work if I create new elements from the parent context and then insert them in the iframe. In a real application I cannot create nodes from an iframe document, because the elements are created by the framework (Riot.js) and I cannot control the creation of components.

Demo: https://jsfiddle.net/kachurun/bugqc5dk/79/

Problem on this line: https://github.com/taye/interact.js/blob/55d5d57c4f1ad2f728109bb839f1ed99a45d8ba1/packages/%40interactjs/utils/is.ts#L29

Because thing really not instance of _window.Element, but instance of win.window.Element. I'm not sure if I know the correct way to fix this, except to add a check to the parent window, or remove the DOM2 part of the condition.

System configuration

interact.js version: 1.10.3

kachurun avatar Feb 12 '21 13:02 kachurun

interact('.target', { context: iframe.contentDocument })

Docs need updating 🙂

taye avatar Feb 16 '21 17:02 taye

Yes, the documentation needs to be updated, but I found the context option in the source code (and wrote it in the jsfiddle example), but this does not solve the problem because the element itself was created outside the iframe and the is.element() function does not work with this case.

kachurun avatar Feb 17 '21 13:02 kachurun

Then you probably need https://developer.mozilla.org/en-US/docs/Web/API/Document/adoptNode

taye avatar Feb 18 '21 09:02 taye

Updated example https://jsfiddle.net/kachurun/k17wzmbu/

The adoptNode does not help. importNode solves the problem, but if I can run the importNode, then I can just create the element in the right context. This is not always the case, because as a rule elements are created by a framework (riotjs, vuejs, react, any other)

kachurun avatar Feb 18 '21 13:02 kachurun

Same problem: Created DOM elements via vuejs in a iframe and they aren't useable for interact.js. This happens in Chrome, in Firefox everything is all fine.

Fixed this with appending the dragable elements via vanilla js in the right iframe document.

Thanks for the fast feedback!

DaPedro avatar Feb 18 '21 16:02 DaPedro

Same problem: Created DOM elements via vuejs in a iframe and they aren't useable for interact.js. This happens in Chrome, in Firefox everything is all fine.

Fixed this with appending the dragable elements via vanilla js in the right iframe document.

Thanks for the fast feedback!

You can fix it by patch is.element() function on interact.js

kachurun avatar Feb 18 '21 20:02 kachurun

Fixed this with appending the dragable elements via vanilla js in the right iframe document.

Hi @DaPedro ,

I am facing the same issue with a component that is teleported to an iframe in Vue3. I tried manually teleporting the element with vanilla JS, and even using adoptNode, but this doesn't seem to fix the issue in Chrome.

Here's my code:


const componentToInsert = this.$refs.el;
const doc = iframe.contentDocument;
doc.body.appendChild(doc.adoptNode(componentToInsert .$el));

componentToInsert.$el instanceof doc.defaultView.Element still returns false in Chrome, but returns true in FireFox.

Could you please let me know how you appended the element in the iframe ?

semiaddict avatar Sep 08 '22 09:09 semiaddict

I ended up patching the is.element as proposed by @kachurun. Here's the code if anyone needs it:

// Override interact's is.element to workaround a bug
// when working with elements in an iframe.
import is from "@interactjs/utils/is";
is.element = function (thing) {
  if (!thing || typeof thing !== "object") {
    return false;
  }
  return thing.nodeType === 1 && typeof thing.nodeName === "string";
};

This overrides the function for the entire application.

semiaddict avatar Sep 08 '22 11:09 semiaddict

~This seems to have been fixed in https://github.com/taye/interact.js/pull/943.~ Issue seems to still occur in v1.10.17

semiaddict avatar Sep 19 '22 16:09 semiaddict

@taye thank you for answer interact('.target', { context: iframe.contentDocument })

This worked for me.

codextech avatar Dec 23 '22 07:12 codextech