4

Here's an example: http://www.npr.org/blogs/thetwo-way/2013/04/04/176224703/why-can-lance-armstrong-race-at-a-swim-meet

Scroll down to the comments. Discus inserts an iframe onto the page, and then the comments are loaded inside the iframe.

Somehow, the iframe knows how tall its contents are, and it expands to that height on the page it's inserted on.

Does anyone know HOW this is possible? Especially confusing because Disqus's iframe is a different domain, so I don't know how any script can detect the contents inside it..

user72245
  • 757
  • 1
  • 6
  • 9
  • The NPR page includes a number of JS files from mediacdn.disqus.com. Probably does it from one or more of those. – Rohrbs Apr 04 '13 at 15:36

1 Answers1

5

Disqus is using postMessage() to send a message from the iframe back to the host page. If you look through the JavaScript code inside their main iframe and search for "postMessage" you'll find this code (original is minified, reformatted here):

 DISQUS.define("Bus", function() {
    function e(a) {
        a = a.split("/");
        return a[0] + "//" + a[2]
    }
    var g = DISQUS.use("JSON"),
        c = window.location.hash.slice(1),
        b = window.opener || window.parent,
        h = document.referrer,
        f = {};
    f.client = e(document.location.href);
    f.host = h ? e(h) : f.client;
    return {
        origins: f,
        messageHandler: function(a) {
            var b;
            try {
                b = DISQUS.JSON.parse(a.data)
            } catch (c) {
                return
            }
            if (!(b.name[0] === "!" && a.origin !== f.client)) switch (b.scope) {
            case "client":
                DISQUS.Bus.trigger(b.name, b.data)
            }
        },
        postMessage: function(a) {
            a.sender = c;
            a = g.stringify(a);
            b.postMessage(a, "*")
        },
        sendHostMessage: function(a, b) {
            b = b || [];
            DISQUS.Bus.postMessage({
                scope: "host",
                name: a,
                data: b
            })
        },
        sendGlobalMessage: function(a, b) {
            b = b || [];
            DISQUS.Bus.postMessage({
                scope: "global",
                name: a,
                data: b
            })
        }
    }
});
_.extend(DISQUS.Bus, Backbone.Events);
$(document).ready(function() {
    var e = window.addEventListener ? window.addEventListener : window.attachEvent,
        g = window.addEventListener ? "message" : "onmessage";
    if (!e) throw Error("No event support.");
    e(g, DISQUS.Bus.messageHandler, !1);
    window.onunload = function() {
        DISQUS.Bus.sendHostMessage("die")
    }

The use of Bus here makes sense: "In computer architecture, a bus is a subsystem that transfers data between components inside a computer, or between computers." (Wikipedia)

I would expect to see something loaded into the host page like the last part of that code that sets up the event listener, although I didn't find it in a cursory search through the scripts loaded into the host page.

See also Resizing an iframe based on content for a related technique that works in older browsers.

Community
  • 1
  • 1
Michael Geary
  • 26,814
  • 8
  • 56
  • 71
  • 1
    I highly recommend checking out [Seamless iFrames](https://www.youtube.com/watch?v=gQCm8VYn93Y) by Ben Vinegar (from Disqus), in addition to his book [Third-Party JavaScript](http://thirdpartyjs.com/). – yellowaj Aug 22 '14 at 17:29