austbot
6/9/2016 - 8:06 PM

combining_events.ts

import {Inject, Injectable, NgZone, provide, OpaqueToken, Provider} from 'angular2/core';
import {Observable} from 'rxjs/Observable';
import {ConnectableObservable} from 'rxjs/observable/ConnectableObservable';
import Release = PDK.Release;
import {PlayerController} from './PDKControllerProvider';
import {Subject} from 'rxjs/Subject';
import {PDK_ACTIONS, ONPLAYERLOADED, ONMEDIAPLAYING} from './pdkActions';
const THROTTLE_ACTIONS = [ONMEDIAPLAYING, ONPLAYERLOADED];

@Injectable()
export class PDKPlayerObserver<Action> extends Subject<Action> {
  /**
   * @description Map over the PDK_ACTIONS event name and creates observables of the event listeners on the player
   *     emitting events of the same name without the prefix, then merges all emitted events into one observable.
   * @param {NgZone} zone This is the angular change detection container. Since the PDK is a third party the Zone
   *     does not care about those events. So we need to tell Angular that stuff is happening. This is the equiilent of
   *     the much maligned $scope.apply in angular one.
   * @param {PlayerController} _playerController This is the $pdk.controller present in the global context. We
   *     Angularized it so we didnt have to have any nasty lint globals.
   * @returns {Observable<T>}
   */
  constructor(@Inject(NgZone)
              private zone,
              @Inject(PlayerController)
              private _playerController) {
    /**
     * Since we are extending the Subject we need to call the super class setup.
     */
    super();
    /**
     * Map over the PDK_ACTION keys, get the name of the event and listen to it.
     * Create a list of observables which correspond to each Event we  listen to.
     */
    let eventList = Object.keys(PDK_ACTIONS).map((constantName: string) => {
      let eventName = PDK_ACTIONS[constantName];

      /**
       * @description Next an Observable when the listener fires.
       * @param handler
       */
      let add = (handler) => {
        /**
         * Using the pdk controller add the event listener.
         */
        this._playerController.addEventListener(eventName, (event) => {
          /**
           * Tell angular about the change happening in the application.
           */
          this.zone.run(() => {
            /**
             * Since this is a Subject we can next over it, adding an Action to the event stream at the time of the PDK
             * event.
             */
            handler({type: eventName, payload: event.data});
          });
        });
      };

      /**
       * @description Shutdown the observable when the listener is removed.
       * @param handler
       */
      let remove = (handler) => {
        this._playerController.removeEventListener(eventName, (event) => {
        });
      };
      /**
       * Create the Observable from above events.
       * @type {FromEventPatternObservable<T, {}>}
       */
      let observable: Observable<Action> = Observable.fromEventPattern(add, remove);
      /**
       * Some actions need to a "Whoa Cowboy" of 1 second
       */
      if (THROTTLE_ACTIONS.indexOf(eventName) !== -1) {
        /**
         * Throttle the action
         */
        observable = observable.throttleTime(1000);
      }
      return observable;
    });

    return this.merge(...eventList);
  }
}