Out of Hanwell

July 3, 2006

Cross-Window Events

Filed under: JavaScript — Matthias Miller @ 4:34 pm

Diego Perini recently pointed out to me that many JavaScript libraries or event helpers do not support cross-window events in Internet Explorer. If you’d like to use JavaScript to set up an event handler for an element in another window, whether in an IFRAME or in a popup window, you’re out of luck.

Here’s the problem: When a function is invoked, window always points to the window in which the function was defined. Of course, this behavior is necessary so that functions can access global variables in the scope in which they were defined! The global window variable is no exception. If the callback is not defined in the same window as the target element, accessing the event object will retrieve the event for the wrong window.

The solution is to depend on this (the target element) to determine the window containing the element. Deigo suggested retrieving the event like this:

function fixEvent(event) {
event = event || ((this.ownerDocument || this.document || this).parentWindow || window).event;
// fix event
return event;
}

Both ownerDocument and document will be null if the event is attached to the document itself. This code falls back on the context of the current window if the element’s window could not be found.

For interest’s sake, here are several solutions that don’t seem to support cross-window events. I’m not entirely surprised that neither of the addEvent functions support it, since they’re lightweight helpers. But I wonder whether there are any more fully-featured libraries (similar to jQuery) that support it.

Here is a test case:

 <html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
    <title>Cross-Window Events</title>
    <script>
        function registerClickHandler(elem) {
            elem.onclick = eventHandler;
            //elem.attachEvent('onclick', eventHandler);
        }
        function eventHandler(eventParm) {
            // find the actual event
            var reportedEvent = eventParm || event;
            var actualEvent = eventParm ||
                ((this.ownerDocument || this.document || this).parentWindow || window).event;
            window.alert('The event, as reported by many frameworks, is:\n\t' + (reportedEvent) + '\n\n' +
                'The actual event is:\n\t' + (actualEvent));
        }
    </script>
</head>

<body>
    <iframe id="my_frame"
	 src="javascript:'<html><body>Click Me!</body><script>top.registerClickHandler(document.body);</script></html>'"></iframe>
</body>

</html>

Are there any libraries that can rise up to the challenge?

Update: I failed to mention that attachEvent will pass the event as the first parameter to the callback function, so this isn’t a big issue when attaching events that way. Using the parameter would be a quick way to get PPK’s addEvent to work in this situation.

5 Comments »

  1. There we go, it’s in jQuery SVN. It took me a little bit to grasp the need for something like that, but I’ve got it now. Silly IE, ruining the party for everyone. The modified demo page can be seen here:
    http://jquery.com/test/e.html

    The code is in SVN now and will be rolled into the upcoming 1.0 release. Thanks for the code suggestion!

    Comment by John Resig [Visitor] — July 3, 2006 @ 7:30 pm

  2. Excellent, John! Thanks!

    Comment by Matthias Miller [Member] — July 3, 2006 @ 7:42 pm

  3. This was mentioned a while back on my blog and I chose to ignore it. :-)

    I’ll update my file too. John uses my event handling method so it’s not surprising he’s suffering the same bug.

    Maybe I should just hand over all my code to you to maintain. ;-)

    Comment by Dean Edwards [Visitor] — July 4, 2006 @ 10:51 am

  4. Heh…well, if you find somebody to help maintain your code, let me know. I could use their help, too! :-)

    Comment by Matthias Miller [Member] — July 4, 2006 @ 2:30 pm

  5. Matthias,
    as we have seen up to now this is missing in many implementations, those I could easily check and patch will not suffer from adding this line. As you already said (well explained) there are fallbacks in that line that take in account many browsers (probably all newer and some older too).

    I would like to add that this problem will not be evident if the scripts are included in each HTML loaded in each IFRAME or WINDOW.

    In this case the window will point to correct context and the event is the one fired in that window.

    But then, why have all these good API/Libraries ?

    Somebody may argue that however the scripts are cached and will not be reloaded from the WEB several times. That is correct, but also believe it is a bad argument, mainly because of the abuse of browser memory.

    My advice is to use top.yourNamespaced.thing or make shortcuts out of it for code that MUST reside in these “subwindows”.

    I think the reasons nobody noticed that until now are the results of:

    - everything is achieved in the context of the same window
    - always have the first line of the HTMLs including the API XYZ

    at least these are the answers I got up to now.
    These answer are not towards Web 1.0…or was it 2.0.

    Comment by Diego Perini [Visitor] — July 4, 2006 @ 2:47 pm


RSS feed for comments on this post. TrackBack URI

Leave a comment

Blog at WordPress.com.