<body data-ng-app="rxApp">
    <div data-ng-controller="clientController">
        <h1>Embedding Code Pen and GitHub Content in an Angular Template</h1>
        <div data-ng-view=""></div>
    </div>

    <script id="templateOne" type="text/ng-template">
        <h2>CodePen</h2>
        <div rx-compilation="clientVM.data.trustedCodePenContent"></div>
        <h2>GitHub</h2>
        <rx-iframe src="https://songhayblog.azurewebsites.net/Inline/GitHubGist/25046e8d35341ea88e23"></rx-iframe>
    </script>
</body>
/*jslint this, white, browser */
/*global angular */
(function () {
    "use strict";

    var rxApp = angular.module("rxApp", [
        "ngSanitize",
        "ngRoute",
        "embedCodepen",
        "rxApp.services",
        "rxApp.controllers",
        "rxApp.directives"
    ]).config(function ($sceDelegateProvider) {
        $sceDelegateProvider.resourceUrlWhitelist([
            "self",
            "https://songhayblog.azurewebsites.net/**"
        ]);
    });

    rxApp.config(["$routeProvider",
        function ($routeProvider) {
            $routeProvider.when("/one", {
                templateUrl: "templateOne",
                controller: "oneController"
            }).otherwise({
                redirectTo: "/one"
            });
        }
    ]);

    /* Services */
    var doBroadcastService = function () {
        var onRouteChangeSuccess = function ($scope, handler) {
            $scope.$on("$routeChangeSuccess", function (e, currrent, previous) {
                handler(e, currrent, previous);
            });
        };
        return {
            onRouteChangeSuccess: onRouteChangeSuccess
        };
    };

    var doDataService = function () {
        return {
            data: {
                codePenContent: [
                    '<p data-height="268" data-theme-id="0" data-slug-hash="gpjaoZ" data-default-tab="result" data-user="rasx" class="codepen">',
                    'See the Pen <a href="https://codepen.io/rasx/pen/gpjaoZ/">Angular: Multiple Templates w/ ngRoute, ngAnimate and a Directive</a>',
                    ' by Bryan Wilhite (<a href="https://codepen.io/rasx">@rasx</a>) on <a href="https://codepen.io">CodePen</a>.',
                    '</p>'
                ].join(""),
                gistId: "5eff331518fc8f029d3b"
            }
        };
    };

    var services = angular.module("rxApp.services", []);
    services
        .factory("broadcastService", [doBroadcastService])
        .factory("dataService", [doDataService]);

    /* Controllers */
    var doClientController = function ($scope, $sce, broadcastService, dataService) {
        $scope.clientVM = {
            id: "client-view-model",
            data: angular.extend({
                trustedCodePenContent: $sce.trustAsHtml(dataService.data.codePenContent)
            }, dataService.data),
            routeId: null
        };

        broadcastService.onRouteChangeSuccess($scope, function (e, currrent, previous) {
            $scope.clientVM.routeId = currrent.params.id;
        });
    };

    var doOneController = function ($scope) {
        $scope.vm = {
            id: "one-view-model",
        };
    };

    var controllers = angular.module("rxApp.controllers", []);
    controllers
        .controller("clientController", [
            "$scope",
            "$sce",
            "broadcastService",
            "dataService",
            doClientController
        ])
        .controller("oneController", [
            "$scope",
            doOneController
        ]);

    /* Directives */
    var doCompileDirective = function ($sce, $compile) {
        return {
            restrict: "A",
            link: function (scope, element, attributes) {

                var expression = $sce.parseAsHtml(attributes.rxCompilation);

                var getResult = function () {
                    return expression(scope);
                };

                scope.$watch(getResult, function (newValue) {
                    var linker = $compile(newValue);
                    element.append(linker(scope));
                });
            }
        };
    };

    var doIFrameDirective = function ($sce) {
        return {
            restrict: "EA",
            scope: {
                src: "@src",
                height: "@height",
                width: "@width",
                scrolling: "@scrolling"
            },
            template: [
                '<iframe class="rx-inline-frame" ',
                'height="{{ height }}" width="{{ width }}" ',
                'frameborder="0" border="0" ',
                'marginwidth="0" marginheight="0" ',
                'scrolling="{{ scrolling }}" ',
                'src="{{ src }}">',
                '</iframe>'
            ].join(""),
            link: function (scope, element, attrs) {
                element.find('iframe').bind('load', function (event) {
                    var frame = event.target;
                    var contentWindow = frame.contentWindow;
                    if (!contentWindow) { return; }
                    var document = contentWindow.document;
                    if (!document) { return; }
                    var contentHeight = document.body.scrollHeight;

                    if (scope.height || !contentHeight) { return; }
                    frame.height = contentHeight + "px";
                });

                if (!attrs.width) { scope.width = "100%"; }
                if (!attrs.scrolling) { scope.scrolling = "no"; }

                //TODO: investigate why this is not firing (version change?):
                attrs.$observe("width", function (v) {
                    if (!v) { scope.width = "100%"; }
                });

                attrs.$observe("scrolling", function (v) {
                    if (!v) { scope.scrolling = "no"; }
                });
            }
        };
    };

    var directives = angular.module("rxApp.directives", []);
    directives
        .directive("rxCompilation", [
            "$sce",
            "$compile",
            doCompileDirective
        ])
        .directive("rxIframe", [
            "$sce",
            doIFrameDirective
        ]);
} ());

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://songhay.blob.core.windows.net/shared-scripts/underscore.js
  2. https://songhay.blob.core.windows.net/shared-scripts-angular/angular.js
  3. https://songhay.blob.core.windows.net/shared-scripts-angular/angular-sanitize.js
  4. https://songhay.blob.core.windows.net/shared-scripts-angular/angular-route.js
  5. https://songhay.blob.core.windows.net/shared-scripts-angular/embed-codepen.js