Source: ARCore/embed.js

define(["lib/jquery",                "lib/underscore",           "common/util/check",
        "common/network/dispatcher", "common/util/binding_list"],
function($,                           _,                          check,
         Dispatcher,                  BindingList) {

    "use strict";

    var postInitCallbacks = BindingList();

    /**
     * @privconstructor
     * @class
     * Lens.Embed allows you to embed a Lens app inside another Lens app. You
     * can then pass messages to the embedded app.
     *
     * @property {HTMLIFrameElement} iframe
     * The IFrame that contains the embedded app. Insert this into the DOM.
     * Do not use `postMessage` to send messages to the embedded Lens app.
     * Instead, use the dispatcher for this Embed.
     *
     * @property {Dispatcher} dispatcher
     * A {@link Dispatcher} that allows for communication between this app
     * and the embedded app.
     *
     * @memberOf Lens
     */
    var Embed = function(iframe) {
        /** @alias Lens.MyClass.prototype */
        var self = {};

        iframe = $(iframe).data("lens-embed", self)[0];
        var dispatcher = Dispatcher(Dispatcher._PostMessageTransport(iframe));

        Object.defineProperty(self, "iframe",    { get: function() { return iframe; } });
        Object.defineProperty(self, "dispatcher", { get: function() { return dispatcher; } });

        Object.freeze(self);
        postInitCallbacks.callAll(self);
        return self;
    };

    _.extend(Embed, /** @lends Lens.Embed */ {
        /**
         * Embeds another Lens app inside this one, given the name of an app.
         *
         * @param {String} name Name of the app, such as `scrapbook` or
         *                      `look-and-feel.demos`
         *
         * @return {Embed}
         *
         */
        app: function(name) {
            check(name, String);
            return Embed.url("http://" + name + ".lens");
        },

        /**
         * Embeds another Lens app inside this one, given the URL of an app.
         *
         * @param {String} name URL of the app, such as `http://launcher.lens/`
         *
         * @return {Embed}
         */
        url: function(url) {
            check(url, String);
            return Embed($("<iframe />", {src: url}));
        },

        /**
         * Connects to a Lens app already running in an iframe.
         *
         * @param {HTMLIFrameElement | String | jQuery} el
         * An iFrame element, CSS selector, or jQuery object.
         *
         * @return {Embed}
         */
        iframe: function(el) {
            el = $(el);

            if((el.length === 0) || !(el[0] instanceof HTMLIFrameElement)) {
                throw "Argument error: argument to Lens.Embed.iframe() was not an iFrame";
            }

            return Embed(el);
        },

        /**
         * A {@link Dispatcher} that allows communication with this
         * app's parent app. Returns null if this app is not embedded.
         * @type {Dispatcher}
         */
        parentDispatcher: null,

        /**
         * Adds a callback to be called on each newly-created embedded lens.
         * This can be used to ensure that all embedded Lenses have access
         * to a particular RPC on the parent.
         * @param {Function} fn The function to call.
         * @return {Binding} A binding that can be cleared to cancel the callback.
         * @private
         */
        _addPostInitCallback: function(fn) {
            return postInitCallbacks.add(fn);
        }
    });

    if(window.parent !== window.self) {
        Embed.parentDispatcher = Dispatcher(Dispatcher._PostMessageTransport(window.parent));
    }

    Object.freeze(Embed);

    Lens._addMember(Embed, "Embed");
    return Embed;
});