aullman/OpenTok-Angular

View on GitHub
opentok-angular.js

Summary

Maintainability
C
7 hrs
Test Coverage
/*!
 *  opentok-angular (https://github.com/aullman/OpenTok-Angular)
 *
 *  Angular module for OpenTok
 *
 *  @Author: Adam Ullman (http://github.com/aullman)
 *  @Copyright (c) 2014 Adam Ullman
 *  @License: Released under the MIT license (http://opensource.org/licenses/MIT)
 **/

if (!window.OT) throw new Error('You must include the OT library before the OT_Angular library');

var ng;
if (typeof angular === 'undefined' && typeof require !== 'undefined') {
  ng = require('angular');
} else {
  ng = angular;
}
var initLayoutContainer;
if (!window.hasOwnProperty('initLayoutContainer') && typeof require !== 'undefined') {
  initLayoutContainer = require('opentok-layout-js').initLayoutContainer;
} else {
  initLayoutContainer = window.initLayoutContainer;
}

ng.module('opentok', [])
  .factory('OT', function() {
    return OT;
  })
  .factory('OTSession', ['OT', '$rootScope',
    function(OT, $rootScope) {
      var OTSession = {
        streams: [],
        connections: [],
        publishers: [],
        init: function(apiKey, sessionId, token, cb) {
          this.session = OT.initSession(apiKey, sessionId);

          OTSession.session.on({
            sessionConnected: function() {
              OTSession.publishers.forEach(function(publisher) {
                OTSession.session.publish(publisher, function(err) {
                  if (err) {
                    $rootScope.$broadcast('otPublisherError', err, publisher);
                  }
                });
              });
            },
            streamCreated: function(event) {
              $rootScope.$apply(function() {
                OTSession.streams.push(event.stream);
              });
            },
            streamDestroyed: function(event) {
              $rootScope.$apply(function() {
                OTSession.streams.splice(OTSession.streams.indexOf(event.stream), 1);
              });
            },
            sessionDisconnected: function() {
              $rootScope.$apply(function() {
                OTSession.streams.splice(0, OTSession.streams.length);
                OTSession.connections.splice(0, OTSession.connections.length);
              });
            },
            connectionCreated: function(event) {
              $rootScope.$apply(function() {
                OTSession.connections.push(event.connection);
              });
            },
            connectionDestroyed: function(event) {
              $rootScope.$apply(function() {
                OTSession.connections.splice(OTSession.connections.indexOf(event.connection), 1);
              });
            }
          });

          this.session.connect(token, function(err) {
            if (cb) cb(err, OTSession.session);
          });
          this.trigger('init');
        },
        addPublisher: function(publisher) {
          this.publishers.push(publisher);
          this.trigger('otPublisherAdded');
        }
      };
      OT.$.eventing(OTSession);
      return OTSession;
    }
  ])
  .directive('otLayout', ['$window', '$parse', 'OT', 'OTSession',
    function($window, $parse, OT, OTSession) {
      return {
        restrict: 'E',
        scope: {
          props: '&'
        },
        link: function(scope, element, attrs) {
          var layout = function() {
            var props = scope.props() || {};
            var container = initLayoutContainer(element[0], props);
            container.layout();
            scope.$emit('otLayoutComplete');
          };
          scope.$watch(function() {
            return element.children().length;
          }, layout);
          $window.addEventListener('resize', layout);
          scope.$on('otLayout', layout);
          var listenForStreamChange = function listenForStreamChange() {
            OTSession.session.on('streamPropertyChanged', function(event) {
              if (event.changedProperty === 'videoDimensions') {
                layout();
              }
            });
          };
          if (OTSession.session) listenForStreamChange();
          else OTSession.on('init', listenForStreamChange);
        }
      };
    }
  ])
  .directive('otPublisher', ['OTSession', '$rootScope',
    function(OTSession, $rootScope) {
      return {
        restrict: 'E',
        scope: {
          props: '&'
        },
        link: function(scope, element, attrs) {
          var props = scope.props() || {};
          props.width = props.width ? props.width : ng.element(element).width();
          props.height = props.height ? props.height : ng.element(element).height();
          var oldChildren = ng.element(element).children();
          scope.publisher = OT.initPublisher(attrs.apikey || OTSession.session.apiKey,
            element[0], props, function(err) {
              if (err) {
                scope.$emit('otPublisherError', err, scope.publisher);
              }
            });
          // Make transcluding work manually by putting the children back in there
          ng.element(element).append(oldChildren);
          scope.publisher.on({
            accessDenied: function() {
              scope.$emit('otAccessDenied');
            },
            accessDialogOpened: function() {
              scope.$emit('otAccessDialogOpened');
            },
            accessDialogClosed: function() {
              scope.$emit('otAccessDialogClosed');
            },
            accessAllowed: function() {
              ng.element(element).addClass('allowed');
              scope.$emit('otAccessAllowed');
            },
            loaded: function() {
              $rootScope.$broadcast('otLayout');
            },
            streamCreated: function(event) {
              scope.$emit('otStreamCreated', event);
            },
            streamDestroyed: function(event) {
              scope.$emit('otStreamDestroyed', event);
            },
            videoElementCreated: function(event) {
              event.element.addEventListener('resize', function() {
                $rootScope.$broadcast('otLayout');
              });
            }
          });
          scope.$on('$destroy', function() {
            if (OTSession.session) OTSession.session.unpublish(scope.publisher);
            else scope.publisher.destroy();
            OTSession.publishers = OTSession.publishers.filter(function(publisher) {
              return publisher !== scope.publisher;
            });
            scope.publisher = null;
          });
          if (OTSession.session && (OTSession.session.connected ||
            (OTSession.session.isConnected && OTSession.session.isConnected()))) {
            OTSession.session.publish(scope.publisher, function(err) {
              if (err) {
                scope.$emit('otPublisherError', err, scope.publisher);
              }
            });
          }
          OTSession.addPublisher(scope.publisher);
        }
      };
    }
  ])
  .directive('otSubscriber', ['OTSession', '$rootScope',
    function(OTSession, $rootScope) {
      return {
        restrict: 'E',
        scope: {
          stream: '=',
          props: '&'
        },
        link: function(scope, element) {
          var stream = scope.stream,
            props = scope.props() || {};
          props.width = props.width ? props.width : ng.element(element).width();
          props.height = props.height ? props.height : ng.element(element).height();
          var oldChildren = ng.element(element).children();
          var subscriber = OTSession.session.subscribe(stream, element[0], props, function(err) {
            if (err) {
              scope.$emit('otSubscriberError', err, subscriber);
            }
          });
          subscriber.on({
            loaded: function() {
              $rootScope.$broadcast('otLayout');
            },
            videoElementCreated: function(event) {
              event.element.addEventListener('resize', function() {
                $rootScope.$broadcast('otLayout');
              });
            }
          });
          // Make transcluding work manually by putting the children back in there
          ng.element(element).append(oldChildren);
          scope.$on('$destroy', function() {
            OTSession.session.unsubscribe(subscriber);
          });
        }
      };
    }
  ]);