function EventDispatcher() {
    var self = this;

    /**
     * Keep track of listeners for each event.
     *
     * @private
     * @type {Object}
     */
    var triggers = {};

    /**
     * Add new event listener.
     *
     * @throws {TypeError}
     *   listener must be a function
     * @param {string} type
     *   Event type
     * @param {H5P.EventCallback} listener
     *   Event listener
     * @param {Object} thisArg
     *   Optionally specify the this value when calling listener.
     */
    this.on = function (type, listener, thisArg) {
      if (typeof listener !== 'function') {
        throw TypeError('listener must be a function');
      }

      // Trigger event before adding to avoid recursion
      self.trigger('newListener', {'type': type, 'listener': listener});

      var trigger = {'listener': listener, 'thisArg': thisArg};
      if (!triggers[type]) {
        // First
        triggers[type] = [trigger];
      }
      else {
        // Append
        triggers[type].push(trigger);
      }
    };

    /**
     * Add new event listener that will be fired only once.
     *
     * @throws {TypeError}
     *   listener must be a function
     * @param {string} type
     *   Event type
     * @param {H5P.EventCallback} listener
     *   Event listener
     * @param {Object} thisArg
     *   Optionally specify the this value when calling listener.
     */
    this.once = function (type, listener, thisArg) {
      if (!(listener instanceof Function)) {
        throw TypeError('listener must be a function');
      }

      var once = function (event) {
        self.off(event, once);
        listener.apply(this, event);
      };

      self.on(type, once, thisArg);
    };

    /**
     * Remove event listener.
     * If no listener is specified, all listeners will be removed.
     *
     * @throws {TypeError}
     *   listener must be a function
     * @param {string} type
     *   Event type
     * @param {H5P.EventCallback} listener
     *   Event listener
     */
    this.off = function (type, listener) {
      if (listener !== undefined && !(listener instanceof Function)) {
        throw TypeError('listener must be a function');
      }

      if (triggers[type] === undefined) {
        return;
      }

      if (listener === undefined) {
        // Remove all listeners
        delete triggers[type];
        self.trigger('removeListener', type);
        return;
      }

      // Find specific listener
      for (var i = 0; i < triggers[type].length; i++) {
        if (triggers[type][i].listener === listener) {
          triggers[type].splice(i, 1);
          self.trigger('removeListener', type, {'listener': listener});
          break;
        }
      }

      // Clean up empty arrays
      if (!triggers[type].length) {
        delete triggers[type];
      }
    };

    /**
     * Try to call all event listeners for the given event type.
     *
     * @private
     * @param {string} Event type
     */
    var call = function (type, event) {
      if (triggers[type] === undefined) {
        return;
      }

      // Clone array (prevents triggers from being modified during the event)
      var handlers = triggers[type].slice();

      // Call all listeners
      for (var i = 0; i < handlers.length; i++) {
        var trigger = handlers[i];
        var thisArg = (trigger.thisArg ? trigger.thisArg : this);
        trigger.listener.call(thisArg, event);
      }
    };

    /**
     * Dispatch event.
     *
     * @param {string|H5P.Event} event
     *   Event object or event type as string
     * @param {*} [eventData]
     *   Custom event data(used when event type as string is used as first
     *   argument).
     * @param {Object} [extras]
     * @param {boolean} [extras.bubbles]
     * @param {boolean} [extras.external]
     */
    this.trigger = function (event, eventData, extras) {
      if (event === undefined) {
        return;
      }
      if (event instanceof String || typeof event === 'string') {
        event = new H5P.Event(event, eventData, extras);
      }
      else if (eventData !== undefined) {
        event.data = eventData;
      }

      // Check to see if this event should go externally after all triggering and bubbling is done
      var scheduledForExternal = event.scheduleForExternal();

      // Call all listeners
      call.call(this, event.type, event);

      // Call all * listeners
      call.call(this, '*', event);

      // Bubble
      if (event.getBubbles() && self.parent instanceof H5P.EventDispatcher &&
          (self.parent.trigger instanceof Function || typeof self.parent.trigger === 'function')) {
        self.parent.trigger(event);
      }

      if (scheduledForExternal) {
        H5P.externalDispatcher.trigger.call(this, event);
      }
    };
  }
/**
   * The base of the event system.
   * Inherit this class if you want your H5P to dispatch events.
   *
   * @class
   * @memberof H5P
   */
The base of the event system.
Inherit this class if you want your H5P to dispatch events.

@class
@memberof H5P
The base of the event system . Inherit this class if you want your H5P to dispatch events . @class @memberof H5P
function EventDispatcher() {
    var self = this;
    var triggers = {};
    this.on = function (type, listener, thisArg) {
      if (typeof listener !== 'function') {
        throw TypeError('listener must be a function');
      }
      self.trigger('newListener', {'type': type, 'listener': listener});
      var trigger = {'listener': listener, 'thisArg': thisArg};
      if (!triggers[type]) {
        triggers[type] = [trigger];
      }
      else {
        triggers[type].push(trigger);
      }
    };
    this.once = function (type, listener, thisArg) {
      if (!(listener instanceof Function)) {
        throw TypeError('listener must be a function');
      }
      var once = function (event) {
        self.off(event, once);
        listener.apply(this, event);
      };
      self.on(type, once, thisArg);
    };
    this.off = function (type, listener) {
      if (listener !== undefined && !(listener instanceof Function)) {
        throw TypeError('listener must be a function');
      }
      if (triggers[type] === undefined) {
        return;
      }
      if (listener === undefined) {
        delete triggers[type];
        self.trigger('removeListener', type);
        return;
      }
      for (var i = 0; i < triggers[type].length; i++) {
        if (triggers[type][i].listener === listener) {
          triggers[type].splice(i, 1);
          self.trigger('removeListener', type, {'listener': listener});
          break;
        }
      }
      if (!triggers[type].length) {
        delete triggers[type];
      }
    };
    var call = function (type, event) {
      if (triggers[type] === undefined) {
        return;
      }
      var handlers = triggers[type].slice();
      for (var i = 0; i < handlers.length; i++) {
        var trigger = handlers[i];
        var thisArg = (trigger.thisArg ? trigger.thisArg : this);
        trigger.listener.call(thisArg, event);
      }
    };
    this.trigger = function (event, eventData, extras) {
      if (event === undefined) {
        return;
      }
      if (event instanceof String || typeof event === 'string') {
        event = new H5P.Event(event, eventData, extras);
      }
      else if (eventData !== undefined) {
        event.data = eventData;
      }
      var scheduledForExternal = event.scheduleForExternal();
      call.call(this, event.type, event);
      call.call(this, '*', event);
      if (event.getBubbles() && self.parent instanceof H5P.EventDispatcher &&
          (self.parent.trigger instanceof Function || typeof self.parent.trigger === 'function')) {
        self.parent.trigger(event);
      }
      if (scheduledForExternal) {
        H5P.externalDispatcher.trigger.call(this, event);
      }
    };
  }
function EventDispatcher ( ) { var self = this ; var triggers = { } ; this . on = function ( type , listener , thisArg ) { if ( typeof listener !== 'function' ) { throw TypeError ( 'listener must be a function' ) ; } self . trigger ( 'newListener' , { 'type' : type , 'listener' : listener } ) ; var trigger = { 'listener' : listener , 'thisArg' : thisArg } ; if ( ! triggers [ type ] ) { triggers [ type ] = [ trigger ] ; } else { triggers [ type ] . push ( trigger ) ; } } ; this . once = function ( type , listener , thisArg ) { if ( ! ( listener instanceof Function ) ) { throw TypeError ( 'listener must be a function' ) ; } var once = function ( event ) { self . off ( event , once ) ; listener . apply ( this , event ) ; } ; self . on ( type , once , thisArg ) ; } ; this . off = function ( type , listener ) { if ( listener !== undefined && ! ( listener instanceof Function ) ) { throw TypeError ( 'listener must be a function' ) ; } if ( triggers [ type ] === undefined ) { return ; } if ( listener === undefined ) { delete triggers [ type ] ; self . trigger ( 'removeListener' , type ) ; return ; } for ( var i = 0 ; i < triggers [ type ] . length ; i ++ ) { if ( triggers [ type ] [ i ] . listener === listener ) { triggers [ type ] . splice ( i , 1 ) ; self . trigger ( 'removeListener' , type , { 'listener' : listener } ) ; break ; } } if ( ! triggers [ type ] . length ) { delete triggers [ type ] ; } } ; var call = function ( type , event ) { if ( triggers [ type ] === undefined ) { return ; } var handlers = triggers [ type ] . slice ( ) ; for ( var i = 0 ; i < handlers . length ; i ++ ) { var trigger = handlers [ i ] ; var thisArg = ( trigger . thisArg ? trigger . thisArg : this ) ; trigger . listener . call ( thisArg , event ) ; } } ; this . trigger = function ( event , eventData , extras ) { if ( event === undefined ) { return ; } if ( event instanceof String || typeof event === 'string' ) { event = new H5P . Event ( event , eventData , extras ) ; } else if ( eventData !== undefined ) { event . data = eventData ; } var scheduledForExternal = event . scheduleForExternal ( ) ; call . call ( this , event . type , event ) ; call . call ( this , '*' , event ) ; if ( event . getBubbles ( ) && self . parent instanceof H5P . EventDispatcher && ( self . parent . trigger instanceof Function || typeof self . parent . trigger === 'function' ) ) { self . parent . trigger ( event ) ; } if ( scheduledForExternal ) { H5P . externalDispatcher . trigger . call ( this , event ) ; } } ; }
The base of the event system.
The base of the event system .
/**
     * Keep track of listeners for each event.
     *
     * @private
     * @type {Object}
     */ /**
     * Add new event listener.
     *
     * @throws {TypeError}
     *   listener must be a function
     * @param {string} type
     *   Event type
     * @param {H5P.EventCallback} listener
     *   Event listener
     * @param {Object} thisArg
     *   Optionally specify the this value when calling listener.
     */ // Trigger event before adding to avoid recursion // First // Append /**
     * Add new event listener that will be fired only once.
     *
     * @throws {TypeError}
     *   listener must be a function
     * @param {string} type
     *   Event type
     * @param {H5P.EventCallback} listener
     *   Event listener
     * @param {Object} thisArg
     *   Optionally specify the this value when calling listener.
     */ /**
     * Remove event listener.
     * If no listener is specified, all listeners will be removed.
     *
     * @throws {TypeError}
     *   listener must be a function
     * @param {string} type
     *   Event type
     * @param {H5P.EventCallback} listener
     *   Event listener
     */ // Remove all listeners // Find specific listener // Clean up empty arrays /**
     * Try to call all event listeners for the given event type.
     *
     * @private
     * @param {string} Event type
     */ // Clone array (prevents triggers from being modified during the event) // Call all listeners /**
     * Dispatch event.
     *
     * @param {string|H5P.Event} event
     *   Event object or event type as string
     * @param {*} [eventData]
     *   Custom event data(used when event type as string is used as first
     *   argument).
     * @param {Object} [extras]
     * @param {boolean} [extras.bubbles]
     * @param {boolean} [extras.external]
     */ // Check to see if this event should go externally after all triggering and bubbling is done // Call all listeners // Call all * listeners // Bubble