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 = " ";
} 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>