1

I've been playing around with postMessage just to have a better understanding of how it works, with the following example:

http://hashcollision.org/tmp/hello-iframe.html

It's slightly elaborate: for each character in the message, this constructs an iframe sourced to http://hashcollision.org/tmp/hello-iframe-inner.html. I then use postMessage to communicate to each individual iframe, telling it what character to show. Also, the iframes communicate the geometry of the iframe back to the parent page via postMessage too. It's all quite useless, but it's a cute test page.

One of the things that's currently awkward is, given the window of an iframe, to find the owning iframe.

I'm doing a for loop to walk all my iframes and check the window with ===, but that seems a bit silly. Are there better ways to do this?

dyoo
  • 11,795
  • 1
  • 34
  • 44

2 Answers2

0

No, there isn't. (And I'm not really sure what to say apart from that, you're already doing the best that can be done.)

gsnedders
  • 5,532
  • 2
  • 30
  • 41
0

The best solution I can come up with is this: generate a random identifier for each iframe. On all communication between the iframe and the parent window, the iframe will include its "self" identifier in the content of a postMessage. This allows quick-and-easy lookup by the parent when it receives messages.

Here's the amended example, with hello-iframe.html's content as:

<html>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js">
</script>
<script>

var run = function() {
    var msg = "Hello world, this is a test of the emergency broadcast system.";
    var i;
    document.body.appendChild(document.createElement("hr"));
    for (i = 0; i < msg.length; i++) {
        spawnCharacterIframe(msg.charAt(i));
    }
    document.body.appendChild(document.createElement("hr"));
};

var _gensymCounter = 0;
var gensym = function() {
    var result = [], i;
    var LEN = 32;
    result.push((_gensymCounter++) + "_");
    var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
    for (i = 0; i < LEN; i++) {
        result.push(chars.charAt(Math.floor(Math.random() * chars.length)));
    }
    return result.join('');
};

var spawnCharacterIframe = function(ch, id) {
    id = id || gensym();
    var newIframe = document.createElement("iframe");
    newIframe.setAttribute("frameborder", "0");
    newIframe.setAttribute("border", "0px");
    newIframe.setAttribute("width", "0px");
    newIframe.setAttribute("height", "0px");
    newIframe.setAttribute("src", "hello-iframe-inner.html?selfId=" + encodeURIComponent(id));
    newIframe.setAttribute("id", id);
    $(newIframe).data('ch', ch);
    document.body.appendChild(newIframe);
};

var findIframe = function(w) {
    var found;
    $('iframe').each(function() {
        if (this.contentWindow == w) {
            found = this;
        }  
    });
    return found;
};



$(window).on('message',
             function(e) {
                 var data = e.originalEvent.data;
                 var source = e.originalEvent.source;
                 var iframe, sourceId;

                 if(data.match(/^([^,]+)[,](.+)$/)) {
                     sourceId = RegExp.$1;
                     data = RegExp.$2;
                     if (document.getElementById(sourceId)) {
                         iframe = document.getElementById(sourceId);
                     } else {
                         return;
                     }
                 } else {
                     return;
                 }

                 if (data === 'ready') {
                     iframe.contentWindow.postMessage($(iframe).data('ch'), '*');
                 } else if (data.match(/^(\d+),(\d+)$/)) {
                     var w = RegExp.$1;
                     var h = RegExp.$2;
                     if (iframe.width !== w + 'px') {
                         iframe.width = w + "px";
                     }
                     if (iframe.height !== h + 'px') {
                         iframe.height = h + "px";
                     }
                 }
             });


$(document).ready(run);
</script>
<body>
<h1>testing iframes</h1>
</body>
</html>

and hello-iframe-inner.html's content as:

<html><head></head>
<script>

// http://stackoverflow.com/questions/901115/get-query-string-values-in-javascript
var urlParams = {};
(function () {
    var e,
        a = /\+/g,  // Regex for replacing addition symbol with a space
        r = /([^&=]+)=?([^&]*)/g,
        d = function (s) { return decodeURIComponent(s.replace(a, " ")); },
        q = window.location.search.substring(1);

    while (e = r.exec(q))
       urlParams[d(e[1])] = d(e[2]);
})();


var SELF_ID = urlParams.selfId;
window.addEventListener("message",
         function(e) {
             if (e.data === ' ') {
                 document.body.innerHTML = "&nbsp;";
             } else {
                 document.body.appendChild(
                     document.createTextNode(e.data));
             }
         });


window.onload = function() {
    document.body.style.margin = '0px';
    var w, h;
    if (window.parent && SELF_ID) {
        window.parent.postMessage(SELF_ID + ',ready', '*');

        setInterval(function() {
            if (h !== document.body.scrollHeight ||
                w !== document.body.scrollWidth) {
                w = document.body.scrollWidth;
                h = document.body.scrollHeight;
                if (window.parent) {
                    window.parent.postMessage(SELF_ID + ',' + w + ',' + h, '*');
                }
            }
        }, 1000);
    }
};

</script>
<body></body>
</html>
dyoo
  • 11,795
  • 1
  • 34
  • 44