10
votes

I'm trying to create a draggable iframe in my app. When the iframe is focused, all mouse events are triggered within the inner window object.

  • I can't listen to those events within the iframe and trigger them myself, because it can be blocked by the iframe content js
  • I can't create an unvisible layer above the iframe that will catch all the events and move them forward to the iframe, because bultin events can't be triggered by script (like css hover)
  • can I catch those events in Node layer, without using webkit DOM?
3
Node is javascript, but it is not at the client side. It doesn't know about the DOM or mouse events, it just delivers content to the client. So, I'm going to go out on a limb here and say it's not possible. - HeadCode
Can't node communicate with native mouse events, like any native GUI app? - yarden
It doesn't look like it. It does make it easy to include node modules in the html code, but that's different than node knowing about mouse events. - HeadCode

3 Answers

1
votes

One idea I have is to place a transparent element (like a div) in front of your iframe and then intercept the click and mouse move events there to make the iframe drag around.

I've done so here in this plunker.

The code, as you see below, is just enough to get across this idea and what steps are required to get the iframe to move around. It has some flaws (move your mouse quickly) but you could do some things to resolve those issues.

<!DOCTYPE html>
<html>

  <head>
    <style>
      iframe, div {
        position: absolute;
        left: 20px;
        top: 20px;
        width: 200px;
        height: 200px;
      }
    </style>
  </head>

  <body>
    <iframe id="iframe" src="if.html"></iframe>
    <div id="div" onmousedown="startDrag(event)" onmouseup="stopDrag()" onmousemove="moveDrag(event)"></div>
  </body>


  <script>
    var objDiv = document.getElementById("div");
    var objDivCoordinates = {left: 20, top: 20};
    var objIframe = document.getElementById("iframe");
    var mouseX = null;
    var mouseY = null;
    var dragging = false;

    function startDrag(e) {
      mouseX = e.clientX;
      mouseY = e.clientY;
      dragging = true;
      objIframe.contentWindow.document.writeln("Starting Drag...<br>");
    }
    function moveDrag(e) {
      if(!dragging) return;

      var changeX = mouseX - e.clientX;
      var changeY = mouseY - e.clientY;

      objDivCoordinates.left -= changeX;
      objDivCoordinates.top -= changeY;
      objDiv.style.left = objDivCoordinates.left+"px";
      objDiv.style.top = objDivCoordinates.top+"px";
      objIframe.style.left = objDiv.style.left;
      objIframe.style.top = objDiv.style.top;

      mouseX = e.clientX;
      mouseY = e.clientY;
    }
    function stopDrag(e) {
      dragging = false;
    }
  </script>
</html>
1
votes

You could try creating a plain EventEmitter and storing it on node's global object. Since global is accessible in all node-webkit contexts, the iframe could use it to emit things that it wants the parent window to know about, and the parent can likewise use it to emit events that the iframe may want to know about.

Is this a solution that might work for you?

1
votes

From what I see you are the most concerned about a situation when some other script cancels execution of your listener (by calling stopPropagation), but you can prevent such situation altogether.

addEventListener(type, listener [, useCapture]) allows to pass a useCapture argument, which defaults to false. If you set it to true then you are safe:

After initiating capture, all events of the specified type will be dispatched to the registered listener before being dispatched to any EventTarget beneath it in the DOM tree.