Version 1
[yaffs-website] / node_modules / video.js / es5 / component.js
diff --git a/node_modules/video.js/es5/component.js b/node_modules/video.js/es5/component.js
new file mode 100644 (file)
index 0000000..1fe39aa
--- /dev/null
@@ -0,0 +1,1826 @@
+'use strict';
+
+exports.__esModule = true;
+
+var _window = require('global/window');
+
+var _window2 = _interopRequireDefault(_window);
+
+var _dom = require('./utils/dom.js');
+
+var Dom = _interopRequireWildcard(_dom);
+
+var _fn = require('./utils/fn.js');
+
+var Fn = _interopRequireWildcard(_fn);
+
+var _guid = require('./utils/guid.js');
+
+var Guid = _interopRequireWildcard(_guid);
+
+var _events = require('./utils/events.js');
+
+var Events = _interopRequireWildcard(_events);
+
+var _log = require('./utils/log.js');
+
+var _log2 = _interopRequireDefault(_log);
+
+var _toTitleCase = require('./utils/to-title-case.js');
+
+var _toTitleCase2 = _interopRequireDefault(_toTitleCase);
+
+var _mergeOptions = require('./utils/merge-options.js');
+
+var _mergeOptions2 = _interopRequireDefault(_mergeOptions);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /**
+                                                                                                                                                           * Player Component - Base class for all UI objects
+                                                                                                                                                           *
+                                                                                                                                                           * @file component.js
+                                                                                                                                                           */
+
+
+/**
+ * Base class for all UI Components.
+ * Components are UI objects which represent both a javascript object and an element
+ * in the DOM. They can be children of other components, and can have
+ * children themselves.
+ *
+ * Components can also use methods from {@link EventTarget}
+ */
+var Component = function () {
+
+  /**
+   * A callback that is called when a component is ready. Does not have any
+   * paramters and any callback value will be ignored.
+   *
+   * @callback Component~ReadyCallback
+   * @this Component
+   */
+
+  /**
+   * Creates an instance of this class.
+   *
+   * @param {Player} player
+   *        The `Player` that this class should be attached to.
+   *
+   * @param {Object} [options]
+   *        The key/value store of player options.
+   #
+   * @param {Object[]} [options.children]
+   *        An array of children objects to intialize this component with. Children objects have
+   *        a name property that will be used if more than one component of the same type needs to be
+   *        added.
+   *
+   * @param {Component~ReadyCallback} [ready]
+   *        Function that gets called when the `Component` is ready.
+   */
+  function Component(player, options, ready) {
+    _classCallCheck(this, Component);
+
+    // The component might be the player itself and we can't pass `this` to super
+    if (!player && this.play) {
+      this.player_ = player = this; // eslint-disable-line
+    } else {
+      this.player_ = player;
+    }
+
+    // Make a copy of prototype.options_ to protect against overriding defaults
+    this.options_ = (0, _mergeOptions2['default'])({}, this.options_);
+
+    // Updated options with supplied options
+    options = this.options_ = (0, _mergeOptions2['default'])(this.options_, options);
+
+    // Get ID from options or options element if one is supplied
+    this.id_ = options.id || options.el && options.el.id;
+
+    // If there was no ID from the options, generate one
+    if (!this.id_) {
+      // Don't require the player ID function in the case of mock players
+      var id = player && player.id && player.id() || 'no_player';
+
+      this.id_ = id + '_component_' + Guid.newGUID();
+    }
+
+    this.name_ = options.name || null;
+
+    // Create element if one wasn't provided in options
+    if (options.el) {
+      this.el_ = options.el;
+    } else if (options.createEl !== false) {
+      this.el_ = this.createEl();
+    }
+
+    this.children_ = [];
+    this.childIndex_ = {};
+    this.childNameIndex_ = {};
+
+    // Add any child components in options
+    if (options.initChildren !== false) {
+      this.initChildren();
+    }
+
+    this.ready(ready);
+    // Don't want to trigger ready here or it will before init is actually
+    // finished for all children that run this constructor
+
+    if (options.reportTouchActivity !== false) {
+      this.enableTouchActivity();
+    }
+  }
+
+  /**
+   * Dispose of the `Component` and all child components.
+   *
+   * @fires Component#dispose
+   */
+
+
+  Component.prototype.dispose = function dispose() {
+
+    /**
+     * Triggered when a `Component` is disposed.
+     *
+     * @event Component#dispose
+     * @type {EventTarget~Event}
+     *
+     * @property {boolean} [bubbles=false]
+     *           set to false so that the close event does not
+     *           bubble up
+     */
+    this.trigger({ type: 'dispose', bubbles: false });
+
+    // Dispose all children.
+    if (this.children_) {
+      for (var i = this.children_.length - 1; i >= 0; i--) {
+        if (this.children_[i].dispose) {
+          this.children_[i].dispose();
+        }
+      }
+    }
+
+    // Delete child references
+    this.children_ = null;
+    this.childIndex_ = null;
+    this.childNameIndex_ = null;
+
+    // Remove all event listeners.
+    this.off();
+
+    // Remove element from DOM
+    if (this.el_.parentNode) {
+      this.el_.parentNode.removeChild(this.el_);
+    }
+
+    Dom.removeElData(this.el_);
+    this.el_ = null;
+  };
+
+  /**
+   * Return the {@link Player} that the `Component` has attached to.
+   *
+   * @return {Player}
+   *         The player that this `Component` has attached to.
+   */
+
+
+  Component.prototype.player = function player() {
+    return this.player_;
+  };
+
+  /**
+   * Deep merge of options objects with new options.
+   * > Note: When both `obj` and `options` contain properties whose values are objects.
+   *         The two properties get merged using {@link module:mergeOptions}
+   *
+   * @param {Object} obj
+   *        The object that contains new options.
+   *
+   * @return {Object}
+   *         A new object of `this.options_` and `obj` merged together.
+   *
+   * @deprecated since version 5
+   */
+
+
+  Component.prototype.options = function options(obj) {
+    _log2['default'].warn('this.options() has been deprecated and will be moved to the constructor in 6.0');
+
+    if (!obj) {
+      return this.options_;
+    }
+
+    this.options_ = (0, _mergeOptions2['default'])(this.options_, obj);
+    return this.options_;
+  };
+
+  /**
+   * Get the `Component`s DOM element
+   *
+   * @return {Element}
+   *         The DOM element for this `Component`.
+   */
+
+
+  Component.prototype.el = function el() {
+    return this.el_;
+  };
+
+  /**
+   * Create the `Component`s DOM element.
+   *
+   * @param {string} [tagName]
+   *        Element's DOM node type. e.g. 'div'
+   *
+   * @param {Object} [properties]
+   *        An object of properties that should be set.
+   *
+   * @param {Object} [attributes]
+   *        An object of attributes that should be set.
+   *
+   * @return {Element}
+   *         The element that gets created.
+   */
+
+
+  Component.prototype.createEl = function createEl(tagName, properties, attributes) {
+    return Dom.createEl(tagName, properties, attributes);
+  };
+
+  /**
+   * Localize a string given the string in english.
+   *
+   * @param {string} string
+   *        The string to localize.
+   *
+   * @return {string}
+   *         The localized string or if no localization exists the english string.
+   */
+
+
+  Component.prototype.localize = function localize(string) {
+    var code = this.player_.language && this.player_.language();
+    var languages = this.player_.languages && this.player_.languages();
+
+    if (!code || !languages) {
+      return string;
+    }
+
+    var language = languages[code];
+
+    if (language && language[string]) {
+      return language[string];
+    }
+
+    var primaryCode = code.split('-')[0];
+    var primaryLang = languages[primaryCode];
+
+    if (primaryLang && primaryLang[string]) {
+      return primaryLang[string];
+    }
+
+    return string;
+  };
+
+  /**
+   * Return the `Component`s DOM element. This is where children get inserted.
+   * This will usually be the the same as the element returned in {@link Component#el}.
+   *
+   * @return {Element}
+   *         The content element for this `Component`.
+   */
+
+
+  Component.prototype.contentEl = function contentEl() {
+    return this.contentEl_ || this.el_;
+  };
+
+  /**
+   * Get this `Component`s ID
+   *
+   * @return {string}
+   *         The id of this `Component`
+   */
+
+
+  Component.prototype.id = function id() {
+    return this.id_;
+  };
+
+  /**
+   * Get the `Component`s name. The name gets used to reference the `Component`
+   * and is set during registration.
+   *
+   * @return {string}
+   *         The name of this `Component`.
+   */
+
+
+  Component.prototype.name = function name() {
+    return this.name_;
+  };
+
+  /**
+   * Get an array of all child components
+   *
+   * @return {Array}
+   *         The children
+   */
+
+
+  Component.prototype.children = function children() {
+    return this.children_;
+  };
+
+  /**
+   * Returns the child `Component` with the given `id`.
+   *
+   * @param {string} id
+   *        The id of the child `Component` to get.
+   *
+   * @return {Component|undefined}
+   *         The child `Component` with the given `id` or undefined.
+   */
+
+
+  Component.prototype.getChildById = function getChildById(id) {
+    return this.childIndex_[id];
+  };
+
+  /**
+   * Returns the child `Component` with the given `name`.
+   *
+   * @param {string} name
+   *        The name of the child `Component` to get.
+   *
+   * @return {Component|undefined}
+   *         The child `Component` with the given `name` or undefined.
+   */
+
+
+  Component.prototype.getChild = function getChild(name) {
+    if (!name) {
+      return;
+    }
+
+    name = (0, _toTitleCase2['default'])(name);
+
+    return this.childNameIndex_[name];
+  };
+
+  /**
+   * Add a child `Component` inside the current `Component`.
+   *
+   *
+   * @param {string|Component} child
+   *        The name or instance of a child to add.
+   *
+   * @param {Object} [options={}]
+   *        The key/value store of options that will get passed to children of
+   *        the child.
+   *
+   * @param {number} [index=this.children_.length]
+   *        The index to attempt to add a child into.
+   *
+   * @return {Component}
+   *         The `Component` that gets added as a child. When using a string the
+   *         `Component` will get created by this process.
+   */
+
+
+  Component.prototype.addChild = function addChild(child) {
+    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+    var index = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.children_.length;
+
+    var component = void 0;
+    var componentName = void 0;
+
+    // If child is a string, create component with options
+    if (typeof child === 'string') {
+      componentName = (0, _toTitleCase2['default'])(child);
+
+      // Options can also be specified as a boolean,
+      // so convert to an empty object if false.
+      if (!options) {
+        options = {};
+      }
+
+      // Same as above, but true is deprecated so show a warning.
+      if (options === true) {
+        _log2['default'].warn('Initializing a child component with `true` is deprecated.' + 'Children should be defined in an array when possible, ' + 'but if necessary use an object instead of `true`.');
+        options = {};
+      }
+
+      var componentClassName = options.componentClass || componentName;
+
+      // Set name through options
+      options.name = componentName;
+
+      // Create a new object & element for this controls set
+      // If there's no .player_, this is a player
+      var ComponentClass = Component.getComponent(componentClassName);
+
+      if (!ComponentClass) {
+        throw new Error('Component ' + componentClassName + ' does not exist');
+      }
+
+      // data stored directly on the videojs object may be
+      // misidentified as a component to retain
+      // backwards-compatibility with 4.x. check to make sure the
+      // component class can be instantiated.
+      if (typeof ComponentClass !== 'function') {
+        return null;
+      }
+
+      component = new ComponentClass(this.player_ || this, options);
+
+      // child is a component instance
+    } else {
+      component = child;
+    }
+
+    this.children_.splice(index, 0, component);
+
+    if (typeof component.id === 'function') {
+      this.childIndex_[component.id()] = component;
+    }
+
+    // If a name wasn't used to create the component, check if we can use the
+    // name function of the component
+    componentName = componentName || component.name && (0, _toTitleCase2['default'])(component.name());
+
+    if (componentName) {
+      this.childNameIndex_[componentName] = component;
+    }
+
+    // Add the UI object's element to the container div (box)
+    // Having an element is not required
+    if (typeof component.el === 'function' && component.el()) {
+      var childNodes = this.contentEl().children;
+      var refNode = childNodes[index] || null;
+
+      this.contentEl().insertBefore(component.el(), refNode);
+    }
+
+    // Return so it can stored on parent object if desired.
+    return component;
+  };
+
+  /**
+   * Remove a child `Component` from this `Component`s list of children. Also removes
+   * the child `Component`s element from this `Component`s element.
+   *
+   * @param {Component} component
+   *        The child `Component` to remove.
+   */
+
+
+  Component.prototype.removeChild = function removeChild(component) {
+    if (typeof component === 'string') {
+      component = this.getChild(component);
+    }
+
+    if (!component || !this.children_) {
+      return;
+    }
+
+    var childFound = false;
+
+    for (var i = this.children_.length - 1; i >= 0; i--) {
+      if (this.children_[i] === component) {
+        childFound = true;
+        this.children_.splice(i, 1);
+        break;
+      }
+    }
+
+    if (!childFound) {
+      return;
+    }
+
+    this.childIndex_[component.id()] = null;
+    this.childNameIndex_[component.name()] = null;
+
+    var compEl = component.el();
+
+    if (compEl && compEl.parentNode === this.contentEl()) {
+      this.contentEl().removeChild(component.el());
+    }
+  };
+
+  /**
+   * Add and initialize default child `Component`s based upon options.
+   */
+
+
+  Component.prototype.initChildren = function initChildren() {
+    var _this = this;
+
+    var children = this.options_.children;
+
+    if (children) {
+      // `this` is `parent`
+      var parentOptions = this.options_;
+
+      var handleAdd = function handleAdd(child) {
+        var name = child.name;
+        var opts = child.opts;
+
+        // Allow options for children to be set at the parent options
+        // e.g. videojs(id, { controlBar: false });
+        // instead of videojs(id, { children: { controlBar: false });
+        if (parentOptions[name] !== undefined) {
+          opts = parentOptions[name];
+        }
+
+        // Allow for disabling default components
+        // e.g. options['children']['posterImage'] = false
+        if (opts === false) {
+          return;
+        }
+
+        // Allow options to be passed as a simple boolean if no configuration
+        // is necessary.
+        if (opts === true) {
+          opts = {};
+        }
+
+        // We also want to pass the original player options
+        // to each component as well so they don't need to
+        // reach back into the player for options later.
+        opts.playerOptions = _this.options_.playerOptions;
+
+        // Create and add the child component.
+        // Add a direct reference to the child by name on the parent instance.
+        // If two of the same component are used, different names should be supplied
+        // for each
+        var newChild = _this.addChild(name, opts);
+
+        if (newChild) {
+          _this[name] = newChild;
+        }
+      };
+
+      // Allow for an array of children details to passed in the options
+      var workingChildren = void 0;
+      var Tech = Component.getComponent('Tech');
+
+      if (Array.isArray(children)) {
+        workingChildren = children;
+      } else {
+        workingChildren = Object.keys(children);
+      }
+
+      workingChildren
+      // children that are in this.options_ but also in workingChildren  would
+      // give us extra children we do not want. So, we want to filter them out.
+      .concat(Object.keys(this.options_).filter(function (child) {
+        return !workingChildren.some(function (wchild) {
+          if (typeof wchild === 'string') {
+            return child === wchild;
+          }
+          return child === wchild.name;
+        });
+      })).map(function (child) {
+        var name = void 0;
+        var opts = void 0;
+
+        if (typeof child === 'string') {
+          name = child;
+          opts = children[name] || _this.options_[name] || {};
+        } else {
+          name = child.name;
+          opts = child;
+        }
+
+        return { name: name, opts: opts };
+      }).filter(function (child) {
+        // we have to make sure that child.name isn't in the techOrder since
+        // techs are registerd as Components but can't aren't compatible
+        // See https://github.com/videojs/video.js/issues/2772
+        var c = Component.getComponent(child.opts.componentClass || (0, _toTitleCase2['default'])(child.name));
+
+        return c && !Tech.isTech(c);
+      }).forEach(handleAdd);
+    }
+  };
+
+  /**
+   * Builds the default DOM class name. Should be overriden by sub-components.
+   *
+   * @return {string}
+   *         The DOM class name for this object.
+   *
+   * @abstract
+   */
+
+
+  Component.prototype.buildCSSClass = function buildCSSClass() {
+    // Child classes can include a function that does:
+    // return 'CLASS NAME' + this._super();
+    return '';
+  };
+
+  /**
+   * Add an `event listener` to this `Component`s element.
+   *
+   * The benefit of using this over the following:
+   * - `VjsEvents.on(otherElement, 'eventName', myFunc)`
+   * - `otherComponent.on('eventName', myFunc)`
+   *
+   * 1. Is that the listeners will get cleaned up when either component gets disposed.
+   * 1. It will also bind `myComponent` as the context of `myFunc`.
+   * > NOTE: If you remove the element from the DOM that has used `on` you need to
+   *         clean up references using: `myComponent.trigger(el, 'dispose')`
+   *         This will also allow the browser to garbage collect it. In special
+   *         cases such as with `window` and `document`, which are both permanent,
+   *         this is not necessary.
+   *
+   * @param {string|Component|string[]} [first]
+   *        The event name, and array of event names, or another `Component`.
+   *
+   * @param {EventTarget~EventListener|string|string[]} [second]
+   *        The listener function, an event name, or an Array of events names.
+   *
+   * @param {EventTarget~EventListener} [third]
+   *        The event handler if `first` is a `Component` and `second` is an event name
+   *        or an Array of event names.
+   *
+   * @return {Component}
+   *         Returns itself; method can be chained.
+   *
+   * @listens Component#dispose
+   */
+
+
+  Component.prototype.on = function on(first, second, third) {
+    var _this2 = this;
+
+    if (typeof first === 'string' || Array.isArray(first)) {
+      Events.on(this.el_, first, Fn.bind(this, second));
+
+      // Targeting another component or element
+    } else {
+      var target = first;
+      var type = second;
+      var fn = Fn.bind(this, third);
+
+      // When this component is disposed, remove the listener from the other component
+      var removeOnDispose = function removeOnDispose() {
+        return _this2.off(target, type, fn);
+      };
+
+      // Use the same function ID so we can remove it later it using the ID
+      // of the original listener
+      removeOnDispose.guid = fn.guid;
+      this.on('dispose', removeOnDispose);
+
+      // If the other component is disposed first we need to clean the reference
+      // to the other component in this component's removeOnDispose listener
+      // Otherwise we create a memory leak.
+      var cleanRemover = function cleanRemover() {
+        return _this2.off('dispose', removeOnDispose);
+      };
+
+      // Add the same function ID so we can easily remove it later
+      cleanRemover.guid = fn.guid;
+
+      // Check if this is a DOM node
+      if (first.nodeName) {
+        // Add the listener to the other element
+        Events.on(target, type, fn);
+        Events.on(target, 'dispose', cleanRemover);
+
+        // Should be a component
+        // Not using `instanceof Component` because it makes mock players difficult
+      } else if (typeof first.on === 'function') {
+        // Add the listener to the other component
+        target.on(type, fn);
+        target.on('dispose', cleanRemover);
+      }
+    }
+
+    return this;
+  };
+
+  /**
+   * Remove an event listener from this `Component`s element. If the second argument is
+   * exluded all listeners for the type passed in as the first argument will be removed.
+   *
+   * @param {string|Component|string[]} [first]
+   *        The event name, and array of event names, or another `Component`.
+   *
+   * @param {EventTarget~EventListener|string|string[]} [second]
+   *        The listener function, an event name, or an Array of events names.
+   *
+   * @param {EventTarget~EventListener} [third]
+   *        The event handler if `first` is a `Component` and `second` is an event name
+   *        or an Array of event names.
+   *
+   * @return {Component}
+   *         Returns itself; method can be chained.
+   */
+
+
+  Component.prototype.off = function off(first, second, third) {
+    if (!first || typeof first === 'string' || Array.isArray(first)) {
+      Events.off(this.el_, first, second);
+    } else {
+      var target = first;
+      var type = second;
+      // Ensure there's at least a guid, even if the function hasn't been used
+      var fn = Fn.bind(this, third);
+
+      // Remove the dispose listener on this component,
+      // which was given the same guid as the event listener
+      this.off('dispose', fn);
+
+      if (first.nodeName) {
+        // Remove the listener
+        Events.off(target, type, fn);
+        // Remove the listener for cleaning the dispose listener
+        Events.off(target, 'dispose', fn);
+      } else {
+        target.off(type, fn);
+        target.off('dispose', fn);
+      }
+    }
+
+    return this;
+  };
+
+  /**
+   * Add an event listener that gets triggered only once and then gets removed.
+   *
+   * @param {string|Component|string[]} [first]
+   *        The event name, and array of event names, or another `Component`.
+   *
+   * @param {EventTarget~EventListener|string|string[]} [second]
+   *        The listener function, an event name, or an Array of events names.
+   *
+   * @param {EventTarget~EventListener} [third]
+   *        The event handler if `first` is a `Component` and `second` is an event name
+   *        or an Array of event names.
+   *
+   * @return {Component}
+   *         Returns itself; method can be chained.
+   */
+
+
+  Component.prototype.one = function one(first, second, third) {
+    var _this3 = this,
+        _arguments = arguments;
+
+    if (typeof first === 'string' || Array.isArray(first)) {
+      Events.one(this.el_, first, Fn.bind(this, second));
+    } else {
+      var target = first;
+      var type = second;
+      var fn = Fn.bind(this, third);
+
+      var newFunc = function newFunc() {
+        _this3.off(target, type, newFunc);
+        fn.apply(null, _arguments);
+      };
+
+      // Keep the same function ID so we can remove it later
+      newFunc.guid = fn.guid;
+
+      this.on(target, type, newFunc);
+    }
+
+    return this;
+  };
+
+  /**
+   * Trigger an event on an element.
+   *
+   * @param {EventTarget~Event|Object|string} event
+   *        The event name, and Event, or an event-like object with a type attribute
+   *        set to the event name.
+   *
+   * @param {Object} [hash]
+   *        Data hash to pass along with the event
+   *
+   * @return {Component}
+   *         Returns itself; method can be chained.
+   */
+
+
+  Component.prototype.trigger = function trigger(event, hash) {
+    Events.trigger(this.el_, event, hash);
+    return this;
+  };
+
+  /**
+   * Bind a listener to the component's ready state. If the ready event has already
+   * happened it will trigger the function immediately.
+   *
+   * @param  {Component~ReadyCallback} fn
+   *         A function to call when ready is triggered.
+   *
+   * @param  {boolean} [sync=false]
+   *         Execute the listener synchronously if `Component` is ready.
+   *
+   * @return {Component}
+   *         Returns itself; method can be chained.
+   */
+
+
+  Component.prototype.ready = function ready(fn) {
+    var sync = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
+
+    if (fn) {
+      if (this.isReady_) {
+        if (sync) {
+          fn.call(this);
+        } else {
+          // Call the function asynchronously by default for consistency
+          this.setTimeout(fn, 1);
+        }
+      } else {
+        this.readyQueue_ = this.readyQueue_ || [];
+        this.readyQueue_.push(fn);
+      }
+    }
+    return this;
+  };
+
+  /**
+   * Trigger all the ready listeners for this `Component`.
+   *
+   * @fires Component#ready
+   */
+
+
+  Component.prototype.triggerReady = function triggerReady() {
+    this.isReady_ = true;
+
+    // Ensure ready is triggerd asynchronously
+    this.setTimeout(function () {
+      var readyQueue = this.readyQueue_;
+
+      // Reset Ready Queue
+      this.readyQueue_ = [];
+
+      if (readyQueue && readyQueue.length > 0) {
+        readyQueue.forEach(function (fn) {
+          fn.call(this);
+        }, this);
+      }
+
+      // Allow for using event listeners also
+      /**
+       * Triggered when a `Component` is ready.
+       *
+       * @event Component#ready
+       * @type {EventTarget~Event}
+       */
+      this.trigger('ready');
+    }, 1);
+  };
+
+  /**
+   * Find a single DOM element matching a `selector`. This can be within the `Component`s
+   * `contentEl()` or another custom context.
+   *
+   * @param {string} selector
+   *        A valid CSS selector, which will be passed to `querySelector`.
+   *
+   * @param {Element|string} [context=this.contentEl()]
+   *        A DOM element within which to query. Can also be a selector string in
+   *        which case the first matching element will get used as context. If
+   *        missing `this.contentEl()` gets used. If  `this.contentEl()` returns
+   *        nothing it falls back to `document`.
+   *
+   * @return {Element|null}
+   *         the dom element that was found, or null
+   *
+   * @see [Information on CSS Selectors](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_Started/Selectors)
+   */
+
+
+  Component.prototype.$ = function $(selector, context) {
+    return Dom.$(selector, context || this.contentEl());
+  };
+
+  /**
+   * Finds all DOM element matching a `selector`. This can be within the `Component`s
+   * `contentEl()` or another custom context.
+   *
+   * @param {string} selector
+   *        A valid CSS selector, which will be passed to `querySelectorAll`.
+   *
+   * @param {Element|string} [context=this.contentEl()]
+   *        A DOM element within which to query. Can also be a selector string in
+   *        which case the first matching element will get used as context. If
+   *        missing `this.contentEl()` gets used. If  `this.contentEl()` returns
+   *        nothing it falls back to `document`.
+   *
+   * @return {NodeList}
+   *         a list of dom elements that were found
+   *
+   * @see [Information on CSS Selectors](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_Started/Selectors)
+   */
+
+
+  Component.prototype.$$ = function $$(selector, context) {
+    return Dom.$$(selector, context || this.contentEl());
+  };
+
+  /**
+   * Check if a component's element has a CSS class name.
+   *
+   * @param {string} classToCheck
+   *        CSS class name to check.
+   *
+   * @return {boolean}
+   *         - True if the `Component` has the class.
+   *         - False if the `Component` does not have the class`
+   */
+
+
+  Component.prototype.hasClass = function hasClass(classToCheck) {
+    return Dom.hasElClass(this.el_, classToCheck);
+  };
+
+  /**
+   * Add a CSS class name to the `Component`s element.
+   *
+   * @param {string} classToAdd
+   *        CSS class name to add
+   *
+   * @return {Component}
+   *         Returns itself; method can be chained.
+   */
+
+
+  Component.prototype.addClass = function addClass(classToAdd) {
+    Dom.addElClass(this.el_, classToAdd);
+    return this;
+  };
+
+  /**
+   * Remove a CSS class name from the `Component`s element.
+   *
+   * @param {string} classToRemove
+   *        CSS class name to remove
+   *
+   * @return {Component}
+   *         Returns itself; method can be chained.
+   */
+
+
+  Component.prototype.removeClass = function removeClass(classToRemove) {
+    Dom.removeElClass(this.el_, classToRemove);
+    return this;
+  };
+
+  /**
+   * Add or remove a CSS class name from the component's element.
+   * - `classToToggle` gets added when {@link Component#hasClass} would return false.
+   * - `classToToggle` gets removed when {@link Component#hasClass} would return true.
+   *
+   * @param  {string} classToToggle
+   *         The class to add or remove based on (@link Component#hasClass}
+   *
+   * @param  {boolean|Dom~predicate} [predicate]
+   *         An {@link Dom~predicate} function or a boolean
+   *
+   * @return {Component}
+   *         Returns itself; method can be chained.
+   */
+
+
+  Component.prototype.toggleClass = function toggleClass(classToToggle, predicate) {
+    Dom.toggleElClass(this.el_, classToToggle, predicate);
+    return this;
+  };
+
+  /**
+   * Show the `Component`s element if it is hidden by removing the
+   * 'vjs-hidden' class name from it.
+   *
+   * @return {Component}
+   *         Returns itself; method can be chained.
+   */
+
+
+  Component.prototype.show = function show() {
+    this.removeClass('vjs-hidden');
+    return this;
+  };
+
+  /**
+   * Hide the `Component`s element if it is currently showing by adding the
+   * 'vjs-hidden` class name to it.
+   *
+   * @return {Component}
+   *         Returns itself; method can be chained.
+   */
+
+
+  Component.prototype.hide = function hide() {
+    this.addClass('vjs-hidden');
+    return this;
+  };
+
+  /**
+   * Lock a `Component`s element in its visible state by adding the 'vjs-lock-showing'
+   * class name to it. Used during fadeIn/fadeOut.
+   *
+   * @return {Component}
+   *         Returns itself; method can be chained.
+   *
+   * @private
+   */
+
+
+  Component.prototype.lockShowing = function lockShowing() {
+    this.addClass('vjs-lock-showing');
+    return this;
+  };
+
+  /**
+   * Unlock a `Component`s element from its visible state by removing the 'vjs-lock-showing'
+   * class name from it. Used during fadeIn/fadeOut.
+   *
+   * @return {Component}
+   *         Returns itself; method can be chained.
+   *
+   * @private
+   */
+
+
+  Component.prototype.unlockShowing = function unlockShowing() {
+    this.removeClass('vjs-lock-showing');
+    return this;
+  };
+
+  /**
+   * Get the value of an attribute on the `Component`s element.
+   *
+   * @param {string} attribute
+   *        Name of the attribute to get the value from.
+   *
+   * @return {string|null}
+   *         - The value of the attribute that was asked for.
+   *         - Can be an empty string on some browsers if the attribute does not exist
+   *           or has no value
+   *         - Most browsers will return null if the attibute does not exist or has
+   *           no value.
+   *
+   * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/getAttribute}
+   */
+
+
+  Component.prototype.getAttribute = function getAttribute(attribute) {
+    return Dom.getAttribute(this.el_, attribute);
+  };
+
+  /**
+   * Set the value of an attribute on the `Component`'s element
+   *
+   * @param {string} attribute
+   *        Name of the attribute to set.
+   *
+   * @param {string} value
+   *        Value to set the attribute to.
+   *
+   * @return {Component}
+   *         Returns itself; method can be chained.
+   *
+   * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute}
+   */
+
+
+  Component.prototype.setAttribute = function setAttribute(attribute, value) {
+    Dom.setAttribute(this.el_, attribute, value);
+    return this;
+  };
+
+  /**
+   * Remove an attribute from the `Component`s element.
+   *
+   * @param {string} attribute
+   *        Name of the attribute to remove.
+   *
+   * @return {Component}
+   *         Returns itself; method can be chained.
+   *
+   * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/removeAttribute}
+   */
+
+
+  Component.prototype.removeAttribute = function removeAttribute(attribute) {
+    Dom.removeAttribute(this.el_, attribute);
+    return this;
+  };
+
+  /**
+   * Get or set the width of the component based upon the CSS styles.
+   * See {@link Component#dimension} for more detailed information.
+   *
+   * @param {number|string} [num]
+   *        The width that you want to set postfixed with '%', 'px' or nothing.
+   *
+   * @param {boolean} [skipListeners]
+   *        Skip the resize event trigger
+   *
+   * @return {Component|number|string}
+   *         - The width when getting, zero if there is no width. Can be a string
+   *           postpixed with '%' or 'px'.
+   *         - Returns itself when setting; method can be chained.
+   */
+
+
+  Component.prototype.width = function width(num, skipListeners) {
+    return this.dimension('width', num, skipListeners);
+  };
+
+  /**
+   * Get or set the height of the component based upon the CSS styles.
+   * See {@link Component#dimension} for more detailed information.
+   *
+   * @param {number|string} [num]
+   *        The height that you want to set postfixed with '%', 'px' or nothing.
+   *
+   * @param {boolean} [skipListeners]
+   *        Skip the resize event trigger
+   *
+   * @return {Component|number|string}
+   *         - The width when getting, zero if there is no width. Can be a string
+   *           postpixed with '%' or 'px'.
+   *         - Returns itself when setting; method can be chained.
+   */
+
+
+  Component.prototype.height = function height(num, skipListeners) {
+    return this.dimension('height', num, skipListeners);
+  };
+
+  /**
+   * Set both the width and height of the `Component` element at the same time.
+   *
+   * @param  {number|string} width
+   *         Width to set the `Component`s element to.
+   *
+   * @param  {number|string} height
+   *         Height to set the `Component`s element to.
+   *
+   * @return {Component}
+   *         Returns itself; method can be chained.
+   */
+
+
+  Component.prototype.dimensions = function dimensions(width, height) {
+    // Skip resize listeners on width for optimization
+    return this.width(width, true).height(height);
+  };
+
+  /**
+   * Get or set width or height of the `Component` element. This is the shared code
+   * for the {@link Component#width} and {@link Component#height}.
+   *
+   * Things to know:
+   * - If the width or height in an number this will return the number postfixed with 'px'.
+   * - If the width/height is a percent this will return the percent postfixed with '%'
+   * - Hidden elements have a width of 0 with `window.getComputedStyle`. This function
+   *   defaults to the `Component`s `style.width` and falls back to `window.getComputedStyle`.
+   *   See [this]{@link http://www.foliotek.com/devblog/getting-the-width-of-a-hidden-element-with-jquery-using-width/}
+   *   for more information
+   * - If you want the computed style of the component, use {@link Component#currentWidth}
+   *   and {@link {Component#currentHeight}
+   *
+   * @fires Component#resize
+   *
+   * @param {string} widthOrHeight
+   8        'width' or 'height'
+   *
+   * @param  {number|string} [num]
+   8         New dimension
+   *
+   * @param  {boolean} [skipListeners]
+   *         Skip resize event trigger
+   *
+   * @return {Component}
+   *         - the dimension when getting or 0 if unset
+   *         - Returns itself when setting; method can be chained.
+   */
+
+
+  Component.prototype.dimension = function dimension(widthOrHeight, num, skipListeners) {
+    if (num !== undefined) {
+      // Set to zero if null or literally NaN (NaN !== NaN)
+      if (num === null || num !== num) {
+        num = 0;
+      }
+
+      // Check if using css width/height (% or px) and adjust
+      if (('' + num).indexOf('%') !== -1 || ('' + num).indexOf('px') !== -1) {
+        this.el_.style[widthOrHeight] = num;
+      } else if (num === 'auto') {
+        this.el_.style[widthOrHeight] = '';
+      } else {
+        this.el_.style[widthOrHeight] = num + 'px';
+      }
+
+      // skipListeners allows us to avoid triggering the resize event when setting both width and height
+      if (!skipListeners) {
+        /**
+         * Triggered when a component is resized.
+         *
+         * @event Component#resize
+         * @type {EventTarget~Event}
+         */
+        this.trigger('resize');
+      }
+
+      // Return component
+      return this;
+    }
+
+    // Not setting a value, so getting it
+    // Make sure element exists
+    if (!this.el_) {
+      return 0;
+    }
+
+    // Get dimension value from style
+    var val = this.el_.style[widthOrHeight];
+    var pxIndex = val.indexOf('px');
+
+    if (pxIndex !== -1) {
+      // Return the pixel value with no 'px'
+      return parseInt(val.slice(0, pxIndex), 10);
+    }
+
+    // No px so using % or no style was set, so falling back to offsetWidth/height
+    // If component has display:none, offset will return 0
+    // TODO: handle display:none and no dimension style using px
+    return parseInt(this.el_['offset' + (0, _toTitleCase2['default'])(widthOrHeight)], 10);
+  };
+
+  /**
+   * Get the width or the height of the `Component` elements computed style. Uses
+   * `window.getComputedStyle`.
+   *
+   * @param {string} widthOrHeight
+   *        A string containing 'width' or 'height'. Whichever one you want to get.
+   *
+   * @return {number}
+   *         The dimension that gets asked for or 0 if nothing was set
+   *         for that dimension.
+   */
+
+
+  Component.prototype.currentDimension = function currentDimension(widthOrHeight) {
+    var computedWidthOrHeight = 0;
+
+    if (widthOrHeight !== 'width' && widthOrHeight !== 'height') {
+      throw new Error('currentDimension only accepts width or height value');
+    }
+
+    if (typeof _window2['default'].getComputedStyle === 'function') {
+      var computedStyle = _window2['default'].getComputedStyle(this.el_);
+
+      computedWidthOrHeight = computedStyle.getPropertyValue(widthOrHeight) || computedStyle[widthOrHeight];
+    }
+
+    // remove 'px' from variable and parse as integer
+    computedWidthOrHeight = parseFloat(computedWidthOrHeight);
+
+    // if the computed value is still 0, it's possible that the browser is lying
+    // and we want to check the offset values.
+    // This code also runs on IE8 and wherever getComputedStyle doesn't exist.
+    if (computedWidthOrHeight === 0) {
+      var rule = 'offset' + (0, _toTitleCase2['default'])(widthOrHeight);
+
+      computedWidthOrHeight = this.el_[rule];
+    }
+
+    return computedWidthOrHeight;
+  };
+
+  /**
+   * An object that contains width and height values of the `Component`s
+   * computed style. Uses `window.getComputedStyle`.
+   *
+   * @typedef {Object} Component~DimensionObject
+   *
+   * @property {number} width
+   *           The width of the `Component`s computed style.
+   *
+   * @property {number} height
+   *           The height of the `Component`s computed style.
+   */
+
+  /**
+   * Get an object that contains width and height values of the `Component`s
+   * computed style.
+   *
+   * @return {Component~DimensionObject}
+   *         The dimensions of the components element
+   */
+
+
+  Component.prototype.currentDimensions = function currentDimensions() {
+    return {
+      width: this.currentDimension('width'),
+      height: this.currentDimension('height')
+    };
+  };
+
+  /**
+   * Get the width of the `Component`s computed style. Uses `window.getComputedStyle`.
+   *
+   * @return {number} width
+   *           The width of the `Component`s computed style.
+   */
+
+
+  Component.prototype.currentWidth = function currentWidth() {
+    return this.currentDimension('width');
+  };
+
+  /**
+   * Get the height of the `Component`s computed style. Uses `window.getComputedStyle`.
+   *
+   * @return {number} height
+   *           The height of the `Component`s computed style.
+   */
+
+
+  Component.prototype.currentHeight = function currentHeight() {
+    return this.currentDimension('height');
+  };
+
+  /**
+   * Set the focus to this component
+   */
+
+
+  Component.prototype.focus = function focus() {
+    this.el_.focus();
+  };
+
+  /**
+   * Remove the focus from this component
+   */
+
+
+  Component.prototype.blur = function blur() {
+    this.el_.blur();
+  };
+
+  /**
+   * Emit a 'tap' events when touch event support gets detected. This gets used to
+   * support toggling the controls through a tap on the video. They get enabled
+   * because every sub-component would have extra overhead otherwise.
+   *
+   * @private
+   * @fires Component#tap
+   * @listens Component#touchstart
+   * @listens Component#touchmove
+   * @listens Component#touchleave
+   * @listens Component#touchcancel
+   * @listens Component#touchend
+    */
+
+
+  Component.prototype.emitTapEvents = function emitTapEvents() {
+    // Track the start time so we can determine how long the touch lasted
+    var touchStart = 0;
+    var firstTouch = null;
+
+    // Maximum movement allowed during a touch event to still be considered a tap
+    // Other popular libs use anywhere from 2 (hammer.js) to 15,
+    // so 10 seems like a nice, round number.
+    var tapMovementThreshold = 10;
+
+    // The maximum length a touch can be while still being considered a tap
+    var touchTimeThreshold = 200;
+
+    var couldBeTap = void 0;
+
+    this.on('touchstart', function (event) {
+      // If more than one finger, don't consider treating this as a click
+      if (event.touches.length === 1) {
+        // Copy pageX/pageY from the object
+        firstTouch = {
+          pageX: event.touches[0].pageX,
+          pageY: event.touches[0].pageY
+        };
+        // Record start time so we can detect a tap vs. "touch and hold"
+        touchStart = new Date().getTime();
+        // Reset couldBeTap tracking
+        couldBeTap = true;
+      }
+    });
+
+    this.on('touchmove', function (event) {
+      // If more than one finger, don't consider treating this as a click
+      if (event.touches.length > 1) {
+        couldBeTap = false;
+      } else if (firstTouch) {
+        // Some devices will throw touchmoves for all but the slightest of taps.
+        // So, if we moved only a small distance, this could still be a tap
+        var xdiff = event.touches[0].pageX - firstTouch.pageX;
+        var ydiff = event.touches[0].pageY - firstTouch.pageY;
+        var touchDistance = Math.sqrt(xdiff * xdiff + ydiff * ydiff);
+
+        if (touchDistance > tapMovementThreshold) {
+          couldBeTap = false;
+        }
+      }
+    });
+
+    var noTap = function noTap() {
+      couldBeTap = false;
+    };
+
+    // TODO: Listen to the original target. http://youtu.be/DujfpXOKUp8?t=13m8s
+    this.on('touchleave', noTap);
+    this.on('touchcancel', noTap);
+
+    // When the touch ends, measure how long it took and trigger the appropriate
+    // event
+    this.on('touchend', function (event) {
+      firstTouch = null;
+      // Proceed only if the touchmove/leave/cancel event didn't happen
+      if (couldBeTap === true) {
+        // Measure how long the touch lasted
+        var touchTime = new Date().getTime() - touchStart;
+
+        // Make sure the touch was less than the threshold to be considered a tap
+        if (touchTime < touchTimeThreshold) {
+          // Don't let browser turn this into a click
+          event.preventDefault();
+          /**
+           * Triggered when a `Component` is tapped.
+           *
+           * @event Component#tap
+           * @type {EventTarget~Event}
+           */
+          this.trigger('tap');
+          // It may be good to copy the touchend event object and change the
+          // type to tap, if the other event properties aren't exact after
+          // Events.fixEvent runs (e.g. event.target)
+        }
+      }
+    });
+  };
+
+  /**
+   * This function reports user activity whenever touch events happen. This can get
+   * turned off by any sub-components that wants touch events to act another way.
+   *
+   * Report user touch activity when touch events occur. User activity gets used to
+   * determine when controls should show/hide. It is simple when it comes to mouse
+   * events, because any mouse event should show the controls. So we capture mouse
+   * events that bubble up to the player and report activity when that happens.
+   * With touch events it isn't as easy as `touchstart` and `touchend` toggle player
+   * controls. So touch events can't help us at the player level either.
+   *
+   * User activity gets checked asynchronously. So what could happen is a tap event
+   * on the video turns the controls off. Then the `touchend` event bubbles up to
+   * the player. Which, if it reported user activity, would turn the controls right
+   * back on. We also don't want to completely block touch events from bubbling up.
+   * Furthermore a `touchmove` event and anything other than a tap, should not turn
+   * controls back on.
+   *
+   * @listens Component#touchstart
+   * @listens Component#touchmove
+   * @listens Component#touchend
+   * @listens Component#touchcancel
+   */
+
+
+  Component.prototype.enableTouchActivity = function enableTouchActivity() {
+    // Don't continue if the root player doesn't support reporting user activity
+    if (!this.player() || !this.player().reportUserActivity) {
+      return;
+    }
+
+    // listener for reporting that the user is active
+    var report = Fn.bind(this.player(), this.player().reportUserActivity);
+
+    var touchHolding = void 0;
+
+    this.on('touchstart', function () {
+      report();
+      // For as long as the they are touching the device or have their mouse down,
+      // we consider them active even if they're not moving their finger or mouse.
+      // So we want to continue to update that they are active
+      this.clearInterval(touchHolding);
+      // report at the same interval as activityCheck
+      touchHolding = this.setInterval(report, 250);
+    });
+
+    var touchEnd = function touchEnd(event) {
+      report();
+      // stop the interval that maintains activity if the touch is holding
+      this.clearInterval(touchHolding);
+    };
+
+    this.on('touchmove', report);
+    this.on('touchend', touchEnd);
+    this.on('touchcancel', touchEnd);
+  };
+
+  /**
+   * A callback that has no parameters and is bound into `Component`s context.
+   *
+   * @callback Component~GenericCallback
+   * @this Component
+   */
+
+  /**
+   * Creates a function that runs after an `x` millisecond timeout. This function is a
+   * wrapper around `window.setTimeout`. There are a few reasons to use this one
+   * instead though:
+   * 1. It gets cleared via  {@link Component#clearTimeout} when
+   *    {@link Component#dispose} gets called.
+   * 2. The function callback will gets turned into a {@link Component~GenericCallback}
+   *
+   * > Note: You can use `window.clearTimeout` on the id returned by this function. This
+   *         will cause its dispose listener not to get cleaned up! Please use
+   *         {@link Component#clearTimeout} or {@link Component#dispose}.
+   *
+   * @param {Component~GenericCallback} fn
+   *        The function that will be run after `timeout`.
+   *
+   * @param {number} timeout
+   *        Timeout in milliseconds to delay before executing the specified function.
+   *
+   * @return {number}
+   *         Returns a timeout ID that gets used to identify the timeout. It can also
+   *         get used in {@link Component#clearTimeout} to clear the timeout that
+   *         was set.
+   *
+   * @listens Component#dispose
+   * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout}
+   */
+
+
+  Component.prototype.setTimeout = function setTimeout(fn, timeout) {
+    fn = Fn.bind(this, fn);
+
+    var timeoutId = _window2['default'].setTimeout(fn, timeout);
+    var disposeFn = function disposeFn() {
+      this.clearTimeout(timeoutId);
+    };
+
+    disposeFn.guid = 'vjs-timeout-' + timeoutId;
+
+    this.on('dispose', disposeFn);
+
+    return timeoutId;
+  };
+
+  /**
+   * Clears a timeout that gets created via `window.setTimeout` or
+   * {@link Component#setTimeout}. If you set a timeout via {@link Component#setTimeout}
+   * use this function instead of `window.clearTimout`. If you don't your dispose
+   * listener will not get cleaned up until {@link Component#dispose}!
+   *
+   * @param {number} timeoutId
+   *        The id of the timeout to clear. The return value of
+   *        {@link Component#setTimeout} or `window.setTimeout`.
+   *
+   * @return {number}
+   *         Returns the timeout id that was cleared.
+   *
+   * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearTimeout}
+   */
+
+
+  Component.prototype.clearTimeout = function clearTimeout(timeoutId) {
+    _window2['default'].clearTimeout(timeoutId);
+
+    var disposeFn = function disposeFn() {};
+
+    disposeFn.guid = 'vjs-timeout-' + timeoutId;
+
+    this.off('dispose', disposeFn);
+
+    return timeoutId;
+  };
+
+  /**
+   * Creates a function that gets run every `x` milliseconds. This function is a wrapper
+   * around `window.setInterval`. There are a few reasons to use this one instead though.
+   * 1. It gets cleared via  {@link Component#clearInterval} when
+   *    {@link Component#dispose} gets called.
+   * 2. The function callback will be a {@link Component~GenericCallback}
+   *
+   * @param {Component~GenericCallback} fn
+   *        The function to run every `x` seconds.
+   *
+   * @param {number} interval
+   *        Execute the specified function every `x` milliseconds.
+   *
+   * @return {number}
+   *         Returns an id that can be used to identify the interval. It can also be be used in
+   *         {@link Component#clearInterval} to clear the interval.
+   *
+   * @listens Component#dispose
+   * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval}
+   */
+
+
+  Component.prototype.setInterval = function setInterval(fn, interval) {
+    fn = Fn.bind(this, fn);
+
+    var intervalId = _window2['default'].setInterval(fn, interval);
+
+    var disposeFn = function disposeFn() {
+      this.clearInterval(intervalId);
+    };
+
+    disposeFn.guid = 'vjs-interval-' + intervalId;
+
+    this.on('dispose', disposeFn);
+
+    return intervalId;
+  };
+
+  /**
+   * Clears an interval that gets created via `window.setInterval` or
+   * {@link Component#setInterval}. If you set an inteval via {@link Component#setInterval}
+   * use this function instead of `window.clearInterval`. If you don't your dispose
+   * listener will not get cleaned up until {@link Component#dispose}!
+   *
+   * @param {number} intervalId
+   *        The id of the interval to clear. The return value of
+   *        {@link Component#setInterval} or `window.setInterval`.
+   *
+   * @return {number}
+   *         Returns the interval id that was cleared.
+   *
+   * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearInterval}
+   */
+
+
+  Component.prototype.clearInterval = function clearInterval(intervalId) {
+    _window2['default'].clearInterval(intervalId);
+
+    var disposeFn = function disposeFn() {};
+
+    disposeFn.guid = 'vjs-interval-' + intervalId;
+
+    this.off('dispose', disposeFn);
+
+    return intervalId;
+  };
+
+  /**
+   * Register a `Component` with `videojs` given the name and the component.
+   *
+   * > NOTE: {@link Tech}s should not be registered as a `Component`. {@link Tech}s
+   *         should be registered using {@link Tech.registerTech} or
+   *         {@link videojs:videojs.registerTech}.
+   *
+   * > NOTE: This function can also be seen on videojs as
+   *         {@link videojs:videojs.registerComponent}.
+   *
+   * @param {string} name
+   *        The name of the `Component` to register.
+   *
+   * @param {Component} comp
+   *        The `Component` class to register.
+   *
+   * @return {Component}
+   *         The `Component` that was registered.
+   */
+
+
+  Component.registerComponent = function registerComponent(name, comp) {
+    if (!name) {
+      return;
+    }
+
+    name = (0, _toTitleCase2['default'])(name);
+
+    if (!Component.components_) {
+      Component.components_ = {};
+    }
+
+    if (name === 'Player' && Component.components_[name]) {
+      var Player = Component.components_[name];
+
+      // If we have players that were disposed, then their name will still be
+      // in Players.players. So, we must loop through and verify that the value
+      // for each item is not null. This allows registration of the Player component
+      // after all players have been disposed or before any were created.
+      if (Player.players && Object.keys(Player.players).length > 0 && Object.keys(Player.players).map(function (playerName) {
+        return Player.players[playerName];
+      }).every(Boolean)) {
+        throw new Error('Can not register Player component after player has been created');
+      }
+    }
+
+    Component.components_[name] = comp;
+
+    return comp;
+  };
+
+  /**
+   * Get a `Component` based on the name it was registered with.
+   *
+   * @param {string} name
+   *        The Name of the component to get.
+   *
+   * @return {Component}
+   *         The `Component` that got registered under the given name.
+   *
+   * @deprecated In `videojs` 6 this will not return `Component`s that were not
+   *             registered using {@link Component.registerComponent}. Currently we
+   *             check the global `videojs` object for a `Component` name and
+   *             return that if it exists.
+   */
+
+
+  Component.getComponent = function getComponent(name) {
+    if (!name) {
+      return;
+    }
+
+    name = (0, _toTitleCase2['default'])(name);
+
+    if (Component.components_ && Component.components_[name]) {
+      return Component.components_[name];
+    }
+
+    if (_window2['default'] && _window2['default'].videojs && _window2['default'].videojs[name]) {
+      _log2['default'].warn('The ' + name + ' component was added to the videojs object when it should be registered using videojs.registerComponent(name, component)');
+
+      return _window2['default'].videojs[name];
+    }
+  };
+
+  /**
+   * Sets up the constructor using the supplied init method or uses the init of the
+   * parent object.
+   *
+   * @param {Object} [props={}]
+   *        An object of properties.
+   *
+   * @return {Object}
+   *         the extended object.
+   *
+   * @deprecated since version 5
+   */
+
+
+  Component.extend = function extend(props) {
+    props = props || {};
+
+    _log2['default'].warn('Component.extend({}) has been deprecated, ' + ' use videojs.extend(Component, {}) instead');
+
+    // Set up the constructor using the supplied init method
+    // or using the init of the parent object
+    // Make sure to check the unobfuscated version for external libs
+    var init = props.init || props.init || this.prototype.init || this.prototype.init || function () {};
+    // In Resig's simple class inheritance (previously used) the constructor
+    //  is a function that calls `this.init.apply(arguments)`
+    // However that would prevent us from using `ParentObject.call(this);`
+    //  in a Child constructor because the `this` in `this.init`
+    //  would still refer to the Child and cause an infinite loop.
+    // We would instead have to do
+    //    `ParentObject.prototype.init.apply(this, arguments);`
+    //  Bleh. We're not creating a _super() function, so it's good to keep
+    //  the parent constructor reference simple.
+    var subObj = function subObj() {
+      init.apply(this, arguments);
+    };
+
+    // Inherit from this object's prototype
+    subObj.prototype = Object.create(this.prototype);
+    // Reset the constructor property for subObj otherwise
+    // instances of subObj would have the constructor of the parent Object
+    subObj.prototype.constructor = subObj;
+
+    // Make the class extendable
+    subObj.extend = Component.extend;
+
+    // Extend subObj's prototype with functions and other properties from props
+    for (var name in props) {
+      if (props.hasOwnProperty(name)) {
+        subObj.prototype[name] = props[name];
+      }
+    }
+
+    return subObj;
+  };
+
+  return Component;
+}();
+
+Component.registerComponent('Component', Component);
+exports['default'] = Component;