javascriptiframe

EventListener won't work in iframe but works outside of it


<html lang="en">
<head>
  <meta charset="utf-8">

</head>

<body>


      <iframe id = "iframe" src = "https://cdn.shopify.com/s/files/1/2656/8500/products/starlight-stars-navy-blue-gold-wallpaper-m1490.jpg?v=1554116082"></iframe>


</body>

^HTML

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>

<script>

//detect print screen windows
window.addEventListener("keyup", function(e) {
  if (e.keyCode == 44) {
    alert("printed");
    

  }
});


$("#iframe").keyup(function(e) {
  if (e.keyCode == 44) {
    alert("printed");
    

  }
});

</script>

The alert pops up when you press prnt screen but if you click on the iframe and press prntscreen, it doesn't pop up. Where am I going wrong here?


Solution

  • If it's a cross-origin <iframe> to a page on a website you don't control then there is nothing you can do to listen to DOM events raised inside an <iframe> element. This is for security reasons, to paraphrase my upvoted comment from earlier:

    Scripts in a cross-domain <iframe> cannot cross the <iframe> boundary for obvious security reasons. Imagine if I loaded your bank's website into an <iframe> on my website that you opened: I could use keyup events raised by your bank's website that are listened-to by my host-page to record your online banking passwords and more.

    If it's a same-origin <iframe> (and a page you control) then the best way is to use postMessage to allow an iframe to communicate, like so:


    loadedIntoIFrame.html

    In your page (which is loaded into an iframe) you need to use postMessage to send a message to another frame or iframe.

    Note that postMessage can be used between cross-domain webpages. However it is an opt-in system: unlike with same-origin iframes where the host page's scripts have full and direct access to the iframe's document's DOM, postMessage requires the other page to agree to handle

    <head>
        <!-- [...] --->
    
        <script>
    if( window.parent ) {
        document.addEventListener( 'keyup', onDocumentKeyUpPostMessageToParent );
    }
    
    function onDocumentKeyUpPostMessageToParent( e ) {
        if( e.isComposing || e.keyCode === 229 ) return; // Skip IME events.
    
        document.getElementById( 'thisPageKeyCode' ).textContent = e.keyCode.toString();
    
        const msg = {
            keyCode: e.keyCode
        };   
    
        const targetOrigin = 'http://localhost'; // This MUST exactly match the origin of the <iframe>'s host-page (note that an "Origin" is *NOT* the page's full URI).
    
        window.parent.postMessage( msg, targetOrigin );
    }
        </script>
    </head>
    <body>
    
        <p>this is the iframe content page</p>
    
        <p>last <code>keyup</code> event in this page: <span id="thisPageKeyCode"></span></p>
    
    </body>
    

    hostPage.html

    In your host page, set-up a listener for postMessage events:

    <head>
        <!-- [...] --->
    
        <script>
    window.addEventListener( 'message', onMessageReceived );
    
    function onMessageReceived( e ) {
    
        const msg = e.data;  // `e.data` is the same as the `msg` object in the iframe page's script.
        const keyCode = msg.keyCode;
    
        document.getElementById( 'lastIFrameKeyCode' ).textContent = keyCode.toString();
    }
        </script>
    </head>
    <body>
    
        <p>this is the iframe host page</p>
    
        <p>last <code>keyup</code> event in iframe: <span id="lastIFrameKeyCode"></span></p>
    
        <iframe style="border: 3px inset #ccc;" src="loadedIntoIFrame.html"></iframe>
       
    </body>
    
    

    JSFiddle example

    Here is a JSFiddle example showing iframe communication with postMessage:

    https://jsfiddle.net/daiplusplus/n0bpedxa/11/

    Note:

    Screenshot proof:

    enter image description here