MDL-59274 media_videojs: upgrade video.js library and plugins
authorMarina Glancy <marina@moodle.com>
Sat, 30 Sep 2017 12:05:41 +0000 (20:05 +0800)
committerMarina Glancy <marina@moodle.com>
Tue, 10 Oct 2017 04:11:06 +0000 (12:11 +0800)
28 files changed:
.eslintignore
.stylelintignore
media/player/videojs/amd/build/Youtube-lazy.min.js
media/player/videojs/amd/build/loader.min.js
media/player/videojs/amd/build/video-lazy.min.js
media/player/videojs/amd/build/videojs-flash-lazy.min.js [new file with mode: 0644]
media/player/videojs/amd/src/Youtube-lazy.js
media/player/videojs/amd/src/loader.js
media/player/videojs/amd/src/video-lazy.js
media/player/videojs/amd/src/videojs-flash-lazy.js [new file with mode: 0644]
media/player/videojs/classes/plugin.php
media/player/videojs/fonts/VideoJS.svg
media/player/videojs/readme_moodle.txt
media/player/videojs/styles.css
media/player/videojs/thirdpartylibs.xml
media/player/videojs/videojs/lang/ar.js
media/player/videojs/videojs/lang/de.js
media/player/videojs/videojs/lang/en.js
media/player/videojs/videojs/lang/es.js
media/player/videojs/videojs/lang/fr.js
media/player/videojs/videojs/lang/gl.js [new file with mode: 0644]
media/player/videojs/videojs/lang/nl.js
media/player/videojs/videojs/lang/pt-PT.js [new file with mode: 0644]
media/player/videojs/videojs/lang/sk.js [new file with mode: 0644]
media/player/videojs/videojs/lang/tr.js
media/player/videojs/videojs/lang/vi.js
media/player/videojs/videojs/lang/zh-CN.js
media/player/videojs/videojs/video-js.swf

index 0622612..7d19e9c 100644 (file)
@@ -62,6 +62,8 @@ lib/validateurlsyntax.php
 media/player/videojs/amd/src/video-lazy.js
 media/player/videojs/amd/src/Youtube-lazy.js
 media/player/videojs/videojs/
+media/player/videojs/amd/src/videojs-flash-lazy.js
+media/player/videojs/videojs/video-js.swf
 mod/assign/feedback/editpdf/fpdi/
 repository/s3/S3.php
 theme/boost/scss/bootstrap/
index cfcf702..c35c560 100644 (file)
@@ -63,6 +63,8 @@ lib/validateurlsyntax.php
 media/player/videojs/amd/src/video-lazy.js
 media/player/videojs/amd/src/Youtube-lazy.js
 media/player/videojs/videojs/
+media/player/videojs/amd/src/videojs-flash-lazy.js
+media/player/videojs/videojs/video-js.swf
 mod/assign/feedback/editpdf/fpdi/
 repository/s3/S3.php
 theme/boost/scss/bootstrap/
index 60fbe7d..b5cb6b2 100644 (file)
Binary files a/media/player/videojs/amd/build/Youtube-lazy.min.js and b/media/player/videojs/amd/build/Youtube-lazy.min.js differ
index d57bd60..df61bc7 100644 (file)
Binary files a/media/player/videojs/amd/build/loader.min.js and b/media/player/videojs/amd/build/loader.min.js differ
index a4af910..f6174b1 100644 (file)
Binary files a/media/player/videojs/amd/build/video-lazy.min.js and b/media/player/videojs/amd/build/video-lazy.min.js differ
diff --git a/media/player/videojs/amd/build/videojs-flash-lazy.min.js b/media/player/videojs/amd/build/videojs-flash-lazy.min.js
new file mode 100644 (file)
index 0000000..677d6ff
Binary files /dev/null and b/media/player/videojs/amd/build/videojs-flash-lazy.min.js differ
index 37f2e55..486a8c7 100644 (file)
@@ -46,17 +46,19 @@ THE SOFTWARE. */
 
       // Set the vjs-youtube class to the player
       // Parent is not set yet so we have to wait a tick
-      setTimeout(function() {
-        this.el_.parentNode.className += ' vjs-youtube';
+      this.setTimeout(function() {
+        if (this.el_) {
+          this.el_.parentNode.className += ' vjs-youtube';
 
-        if (_isOnMobile) {
-          this.el_.parentNode.className += ' vjs-youtube-mobile';
-        }
+          if (_isOnMobile) {
+            this.el_.parentNode.className += ' vjs-youtube-mobile';
+          }
 
-        if (Youtube.isApiReady) {
-          this.initYTPlayer();
-        } else {
-          Youtube.apiReadyQueue.push(this);
+          if (Youtube.isApiReady) {
+            this.initYTPlayer();
+          } else {
+            Youtube.apiReadyQueue.push(this);
+          }
         }
       }.bind(this));
     },
@@ -64,8 +66,12 @@ THE SOFTWARE. */
     dispose: function() {
       if (this.ytPlayer) {
         //Dispose of the YouTube Player
-        this.ytPlayer.stopVideo();
-        this.ytPlayer.destroy();
+        if (this.ytPlayer.stopVideo) {
+          this.ytPlayer.stopVideo();
+        }
+        if (this.ytPlayer.destroy) {
+          this.ytPlayer.destroy();
+        }
       } else {
         //YouTube API hasn't finished loading or the player is already disposed
         var index = Youtube.apiReadyQueue.indexOf(this);
@@ -226,6 +232,7 @@ THE SOFTWARE. */
           onPlaybackQualityChange: this.onPlayerPlaybackQualityChange.bind(this),
           onPlaybackRateChange: this.onPlayerPlaybackRateChange.bind(this),
           onStateChange: this.onPlayerStateChange.bind(this),
+          onVolumeChange: this.onPlayerVolumeChange.bind(this),
           onError: this.onPlayerError.bind(this)
         }
       });
@@ -308,6 +315,10 @@ THE SOFTWARE. */
       }
     },
 
+    onPlayerVolumeChange: function() {
+      this.trigger('volumechange');
+    },
+
     onPlayerError: function(e) {
       this.errorNumber = e.data;
       this.trigger('pause');
@@ -568,10 +579,6 @@ THE SOFTWARE. */
       }
 
       this.ytPlayer.setVolume(percentAsDecimal * 100.0);
-      this.setTimeout( function(){
-        this.trigger('volumechange');
-      }, 50);
-
     },
 
     muted: function() {
@@ -728,8 +735,10 @@ THE SOFTWARE. */
 
   Youtube.apiReadyQueue = [];
 
-  loadScript('https://www.youtube.com/iframe_api', apiLoaded);
-  injectCss();
+  if (typeof document !== 'undefined'){
+    loadScript('https://www.youtube.com/iframe_api', apiLoaded);
+    injectCss();
+  }
 
   // Older versions of VJS5 doesn't have the registerTech function
   if (typeof videojs.registerTech !== 'undefined') {
index 427b609..70455f2 100644 (file)
@@ -69,6 +69,10 @@ define(['jquery', 'core/event'], function($, Event) {
                     // Add YouTube to the list of modules we require.
                     modules.push('media_videojs/Youtube-lazy');
                 }
+                if (config.techOrder && config.techOrder.indexOf('flash') !== -1) {
+                    // Add Flash to the list of modules we require.
+                    modules.push('media_videojs/videojs-flash-lazy');
+                }
                 require(modules, function(videojs) {
                     if (onload) {
                         onload(videojs);
index 95394bc..0d1e418 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * @license
- * Video.js 5.18.4 <http://videojs.com/>
+ * Video.js 6.3.2 <http://videojs.com/>
  * Copyright Brightcove, Inc. <https://www.brightcove.com/>
  * Available under Apache License Version 2.0
  * <https://github.com/videojs/video.js/blob/master/LICENSE>
  * <https://github.com/mozilla/vtt.js/blob/master/LICENSE>
  */
 
-(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.videojs = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
-'use strict';
+(function (global, factory) {
+       typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+       typeof define === 'function' && define.amd ? define(factory) :
+       (global.videojs = factory());
+}(this, (function () {
 
-exports.__esModule = true;
+var version = "6.3.2";
 
-var _button = _dereq_(2);
+var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
 
-var _button2 = _interopRequireDefault(_button);
 
-var _component = _dereq_(5);
 
-var _component2 = _interopRequireDefault(_component);
 
-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"); } }
+function createCommonjsModule(fn, module) {
+       return module = { exports: {} }, fn(module, module.exports), module.exports;
+}
 
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+var win;
 
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file big-play-button.js
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
+if (typeof window !== "undefined") {
+    win = window;
+} else if (typeof commonjsGlobal !== "undefined") {
+    win = commonjsGlobal;
+} else if (typeof self !== "undefined"){
+    win = self;
+} else {
+    win = {};
+}
 
+var window_1 = win;
 
-/**
- * The initial play button that shows before the video has played. The hiding of the
- * `BigPlayButton` get done via CSS and `Player` states.
- *
- * @extends Button
- */
-var BigPlayButton = function (_Button) {
-  _inherits(BigPlayButton, _Button);
+var empty = {};
 
-  function BigPlayButton() {
-    _classCallCheck(this, BigPlayButton);
 
-    return _possibleConstructorReturn(this, _Button.apply(this, arguments));
-  }
+var empty$1 = (Object.freeze || Object)({
+       'default': empty
+});
 
-  /**
-   * Builds the default DOM `className`.
-   *
-   * @return {string}
-   *         The DOM `className` for this object. Always returns 'vjs-big-play-button'.
-   */
-  BigPlayButton.prototype.buildCSSClass = function buildCSSClass() {
-    return 'vjs-big-play-button';
-  };
+var minDoc = ( empty$1 && empty ) || empty$1;
 
-  /**
-   * This gets called when a `BigPlayButton` "clicked". See {@link ClickableComponent}
-   * for more detailed information on what a click can be.
-   *
-   * @param {EventTarget~Event} event
-   *        The `keydown`, `tap`, or `click` event that caused this function to be
-   *        called.
-   *
-   * @listens tap
-   * @listens click
-   */
+var topLevel = typeof commonjsGlobal !== 'undefined' ? commonjsGlobal :
+    typeof window !== 'undefined' ? window : {};
 
 
-  BigPlayButton.prototype.handleClick = function handleClick(event) {
-    this.player_.play();
+var doccy;
 
-    var cb = this.player_.getChild('controlBar');
-    var playToggle = cb && cb.getChild('playToggle');
+if (typeof document !== 'undefined') {
+    doccy = document;
+} else {
+    doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'];
 
-    if (!playToggle) {
-      this.player_.focus();
-      return;
+    if (!doccy) {
+        doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc;
     }
+}
 
-    this.setTimeout(function () {
-      playToggle.focus();
-    }, 1);
-  };
-
-  return BigPlayButton;
-}(_button2['default']);
+var document_1 = doccy;
 
 /**
- * The text that should display over the `BigPlayButton`s controls. Added to for localization.
+ * @file browser.js
+ * @module browser
+ */
+var USER_AGENT = window_1.navigator && window_1.navigator.userAgent || '';
+var webkitVersionMap = /AppleWebKit\/([\d.]+)/i.exec(USER_AGENT);
+var appleWebkitVersion = webkitVersionMap ? parseFloat(webkitVersionMap.pop()) : null;
+
+/*
+ * Device is an iPhone
  *
- * @type {string}
+ * @type {Boolean}
+ * @constant
  * @private
  */
+var IS_IPAD = /iPad/i.test(USER_AGENT);
 
+// The Facebook app's UIWebView identifies as both an iPhone and iPad, so
+// to identify iPhones, we need to exclude iPads.
+// http://artsy.github.io/blog/2012/10/18/the-perils-of-ios-user-agent-sniffing/
+var IS_IPHONE = /iPhone/i.test(USER_AGENT) && !IS_IPAD;
+var IS_IPOD = /iPod/i.test(USER_AGENT);
+var IS_IOS = IS_IPHONE || IS_IPAD || IS_IPOD;
 
-BigPlayButton.prototype.controlText_ = 'Play Video';
-
-_component2['default'].registerComponent('BigPlayButton', BigPlayButton);
-exports['default'] = BigPlayButton;
-
-},{"2":2,"5":5}],2:[function(_dereq_,module,exports){
-'use strict';
-
-exports.__esModule = true;
-
-var _clickableComponent = _dereq_(3);
-
-var _clickableComponent2 = _interopRequireDefault(_clickableComponent);
-
-var _component = _dereq_(5);
-
-var _component2 = _interopRequireDefault(_component);
-
-var _log = _dereq_(86);
-
-var _log2 = _interopRequireDefault(_log);
-
-var _obj = _dereq_(88);
+var IOS_VERSION = function () {
+  var match = USER_AGENT.match(/OS (\d+)_/i);
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+  if (match && match[1]) {
+    return match[1];
+  }
+  return null;
+}();
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+var IS_ANDROID = /Android/i.test(USER_AGENT);
+var ANDROID_VERSION = function () {
+  // This matches Android Major.Minor.Patch versions
+  // ANDROID_VERSION is Major.Minor as a Number, if Minor isn't available, then only Major is returned
+  var match = USER_AGENT.match(/Android (\d+)(?:\.(\d+))?(?:\.(\d+))*/i);
 
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+  if (!match) {
+    return null;
+  }
 
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file button.js
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
+  var major = match[1] && parseFloat(match[1]);
+  var minor = match[2] && parseFloat(match[2]);
 
+  if (major && minor) {
+    return parseFloat(match[1] + '.' + match[2]);
+  } else if (major) {
+    return major;
+  }
+  return null;
+}();
 
-/**
- * Base class for all buttons.
- *
- * @extends ClickableComponent
- */
-var Button = function (_ClickableComponent) {
-  _inherits(Button, _ClickableComponent);
+// Old Android is defined as Version older than 2.3, and requiring a webkit version of the android browser
+var IS_OLD_ANDROID = IS_ANDROID && /webkit/i.test(USER_AGENT) && ANDROID_VERSION < 2.3;
+var IS_NATIVE_ANDROID = IS_ANDROID && ANDROID_VERSION < 5 && appleWebkitVersion < 537;
 
-  function Button() {
-    _classCallCheck(this, Button);
+var IS_FIREFOX = /Firefox/i.test(USER_AGENT);
+var IS_EDGE = /Edge/i.test(USER_AGENT);
+var IS_CHROME = !IS_EDGE && /Chrome/i.test(USER_AGENT);
+var CHROME_VERSION = function () {
+  var match = USER_AGENT.match(/Chrome\/(\d+)/);
 
-    return _possibleConstructorReturn(this, _ClickableComponent.apply(this, arguments));
+  if (match && match[1]) {
+    return parseFloat(match[1]);
+  }
+  return null;
+}();
+var IS_IE8 = /MSIE\s8\.0/.test(USER_AGENT);
+var IE_VERSION = function () {
+  var result = /MSIE\s(\d+)\.\d/.exec(USER_AGENT);
+  var version = result && parseFloat(result[1]);
+
+  if (!version && /Trident\/7.0/i.test(USER_AGENT) && /rv:11.0/.test(USER_AGENT)) {
+    // IE 11 has a different user agent string than other IE versions
+    version = 11.0;
   }
 
-  /**
-   * Create the `Button`s DOM element.
-   *
-   * @param {string} [tag=button]
-   *        Element's node type. e.g. 'button'
-   *
-   * @param {Object} [props={}]
-   *        An object of properties that should be set on the element.
-   *
-   * @param {Object} [attributes={}]
-   *        An object of attributes that should be set on the element.
-   *
-   * @return {Element}
-   *         The element that gets created.
-   */
-  Button.prototype.createEl = function createEl() {
-    var tag = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'button';
-    var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
-    var attributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
-
-    props = (0, _obj.assign)({
-      className: this.buildCSSClass()
-    }, props);
+  return version;
+}();
 
-    if (tag !== 'button') {
-      _log2['default'].warn('Creating a Button with an HTML element of ' + tag + ' is deprecated; use ClickableComponent instead.');
+var IS_SAFARI = /Safari/i.test(USER_AGENT) && !IS_CHROME && !IS_ANDROID && !IS_EDGE;
+var IS_ANY_SAFARI = IS_SAFARI || IS_IOS;
+
+var TOUCH_ENABLED = isReal() && ('ontouchstart' in window_1 || window_1.DocumentTouch && window_1.document instanceof window_1.DocumentTouch);
+
+var BACKGROUND_SIZE_SUPPORTED = isReal() && 'backgroundSize' in window_1.document.createElement('video').style;
+
+var browser = (Object.freeze || Object)({
+       IS_IPAD: IS_IPAD,
+       IS_IPHONE: IS_IPHONE,
+       IS_IPOD: IS_IPOD,
+       IS_IOS: IS_IOS,
+       IOS_VERSION: IOS_VERSION,
+       IS_ANDROID: IS_ANDROID,
+       ANDROID_VERSION: ANDROID_VERSION,
+       IS_OLD_ANDROID: IS_OLD_ANDROID,
+       IS_NATIVE_ANDROID: IS_NATIVE_ANDROID,
+       IS_FIREFOX: IS_FIREFOX,
+       IS_EDGE: IS_EDGE,
+       IS_CHROME: IS_CHROME,
+       CHROME_VERSION: CHROME_VERSION,
+       IS_IE8: IS_IE8,
+       IE_VERSION: IE_VERSION,
+       IS_SAFARI: IS_SAFARI,
+       IS_ANY_SAFARI: IS_ANY_SAFARI,
+       TOUCH_ENABLED: TOUCH_ENABLED,
+       BACKGROUND_SIZE_SUPPORTED: BACKGROUND_SIZE_SUPPORTED
+});
 
-      // Add properties for clickable element which is not a native HTML button
-      props = (0, _obj.assign)({
-        tabIndex: 0
-      }, props);
+var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
+  return typeof obj;
+} : function (obj) {
+  return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
+};
 
-      // Add ARIA attributes for clickable element which is not a native HTML button
-      attributes = (0, _obj.assign)({
-        role: 'button'
-      }, attributes);
-    }
 
-    // Add attributes for button element
-    attributes = (0, _obj.assign)({
 
-      // Necessary since the default button type is "submit"
-      'type': 'button',
 
-      // let the screen reader user know that the text of the button may change
-      'aria-live': 'polite'
-    }, attributes);
 
-    var el = _component2['default'].prototype.createEl.call(this, tag, props, attributes);
 
-    this.createControlTextEl(el);
 
-    return el;
-  };
 
-  /**
-   * Add a child `Component` inside of this `Button`.
-   *
-   * @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.
-   *
-   * @return {Component}
-   *         The `Component` that gets added as a child. When using a string the
-   *         `Component` will get created by this process.
-   *
-   * @deprecated since version 5
-   */
 
 
-  Button.prototype.addChild = function addChild(child) {
-    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
 
-    var className = this.constructor.name;
+var classCallCheck = function (instance, Constructor) {
+  if (!(instance instanceof Constructor)) {
+    throw new TypeError("Cannot call a class as a function");
+  }
+};
 
-    _log2['default'].warn('Adding an actionable (user controllable) child to a Button (' + className + ') is not supported; use a ClickableComponent instead.');
 
-    // Avoid the error message generated by ClickableComponent's addChild method
-    return _component2['default'].prototype.addChild.call(this, child, options);
-  };
 
-  /**
-   * Enable the `Button` element so that it can be activated or clicked. Use this with
-   * {@link Button#disable}.
-   */
 
 
-  Button.prototype.enable = function enable() {
-    _ClickableComponent.prototype.enable.call(this);
-    this.el_.removeAttribute('disabled');
-  };
 
-  /**
-   * Enable the `Button` element so that it cannot be activated or clicked. Use this with
-   * {@link Button#enable}.
-   */
 
 
-  Button.prototype.disable = function disable() {
-    _ClickableComponent.prototype.disable.call(this);
-    this.el_.setAttribute('disabled', 'disabled');
-  };
 
-  /**
-   * This gets called when a `Button` has focus and `keydown` is triggered via a key
-   * press.
-   *
-   * @param {EventTarget~Event} event
-   *        The event that caused this function to get called.
-   *
-   * @listens keydown
-   */
 
 
-  Button.prototype.handleKeyPress = function handleKeyPress(event) {
+var inherits = function (subClass, superClass) {
+  if (typeof superClass !== "function" && superClass !== null) {
+    throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
+  }
 
-    // Ignore Space (32) or Enter (13) key operation, which is handled by the browser for a button.
-    if (event.which === 32 || event.which === 13) {
-      return;
+  subClass.prototype = Object.create(superClass && superClass.prototype, {
+    constructor: {
+      value: subClass,
+      enumerable: false,
+      writable: true,
+      configurable: true
     }
+  });
+  if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
+};
 
-    // Pass keypress handling up for unsupported keys
-    _ClickableComponent.prototype.handleKeyPress.call(this, event);
-  };
 
-  return Button;
-}(_clickableComponent2['default']);
 
-_component2['default'].registerComponent('Button', Button);
-exports['default'] = Button;
 
-},{"3":3,"5":5,"86":86,"88":88}],3:[function(_dereq_,module,exports){
-'use strict';
 
-exports.__esModule = true;
 
-var _component = _dereq_(5);
 
-var _component2 = _interopRequireDefault(_component);
 
-var _dom = _dereq_(81);
 
-var Dom = _interopRequireWildcard(_dom);
 
-var _events = _dereq_(82);
 
-var Events = _interopRequireWildcard(_events);
+var possibleConstructorReturn = function (self, call) {
+  if (!self) {
+    throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+  }
 
-var _fn = _dereq_(83);
+  return call && (typeof call === "object" || typeof call === "function") ? call : self;
+};
 
-var Fn = _interopRequireWildcard(_fn);
 
-var _log = _dereq_(86);
 
-var _log2 = _interopRequireDefault(_log);
 
-var _document = _dereq_(94);
 
-var _document2 = _interopRequireDefault(_document);
 
-var _obj = _dereq_(88);
 
-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"); } }
 
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
 
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file button.js
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
+var taggedTemplateLiteralLoose = function (strings, raw) {
+  strings.raw = raw;
+  return strings;
+};
 
+/**
+ * @file obj.js
+ * @module obj
+ */
 
 /**
- * Clickable Component which is clickable or keyboard actionable,
- * but is not a native HTML button.
+ * @callback obj:EachCallback
  *
- * @extends Component
+ * @param {Mixed} value
+ *        The current key for the object that is being iterated over.
+ *
+ * @param {string} key
+ *        The current key-value for object that is being iterated over
  */
-var ClickableComponent = function (_Component) {
-  _inherits(ClickableComponent, _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.
-   */
-  function ClickableComponent(player, options) {
-    _classCallCheck(this, ClickableComponent);
-
-    var _this = _possibleConstructorReturn(this, _Component.call(this, player, options));
-
-    _this.emitTapEvents();
 
-    _this.enable();
-    return _this;
-  }
+/**
+ * @callback obj:ReduceCallback
+ *
+ * @param {Mixed} accum
+ *        The value that is accumulating over the reduce loop.
+ *
+ * @param {Mixed} value
+ *        The current key for the object that is being iterated over.
+ *
+ * @param {string} key
+ *        The current key-value for object that is being iterated over
+ *
+ * @return {Mixed}
+ *         The new accumulated value.
+ */
+var toString = Object.prototype.toString;
 
-  /**
-   * Create the `Component`s DOM element.
  *
-   * @param {string} [tag=div]
-   *        The element's node type.
  *
-   * @param {Object} [props={}]
-   *        An object of properties that should be set on the element.
-   *
-   * @param {Object} [attributes={}]
-   *        An object of attributes that should be set on the element.
-   *
-   * @return {Element}
-   *         The element that gets created.
-   */
+/**
+ * Get the keys of an Object
+ *
+ * @param {Object}
+ *        The Object to get the keys from
+ *
+ * @return {string[]}
+ *         An array of the keys from the object. Returns an empty array if the
+ *         object passed in was invalid or had no keys.
+ *
+ * @private
+ */
+var keys = function keys(object) {
+  return isObject(object) ? Object.keys(object) : [];
+};
 
+/**
+ * Array-like iteration for objects.
+ *
+ * @param {Object} object
+ *        The object to iterate over
+ *
+ * @param {obj:EachCallback} fn
+ *        The callback function which is called for each key in the object.
+ */
+function each(object, fn) {
+  keys(object).forEach(function (key) {
+    return fn(object[key], key);
+  });
+}
 
-  ClickableComponent.prototype.createEl = function createEl() {
-    var tag = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'div';
-    var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
-    var attributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
+/**
+ * Array-like reduce for objects.
+ *
+ * @param {Object} object
+ *        The Object that you want to reduce.
+ *
+ * @param {Function} fn
+ *         A callback function which is called for each key in the object. It
+ *         receives the accumulated value and the per-iteration value and key
+ *         as arguments.
+ *
+ * @param {Mixed} [initial = 0]
+ *        Starting value
+ *
+ * @return {Mixed}
+ *         The final accumulated value.
+ */
+function reduce(object, fn) {
+  var initial = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
 
-    props = (0, _obj.assign)({
-      className: this.buildCSSClass(),
-      tabIndex: 0
-    }, props);
+  return keys(object).reduce(function (accum, key) {
+    return fn(accum, object[key], key);
+  }, initial);
+}
 
-    if (tag === 'button') {
-      _log2['default'].error('Creating a ClickableComponent with an HTML element of ' + tag + ' is not supported; use a Button instead.');
-    }
+/**
+ * Object.assign-style object shallow merge/extend.
+ *
+ * @param  {Object} target
+ * @param  {Object} ...sources
+ * @return {Object}
+ */
+function assign(target) {
+  for (var _len = arguments.length, sources = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
+    sources[_key - 1] = arguments[_key];
+  }
 
-    // Add ARIA attributes for clickable element which is not a native HTML button
-    attributes = (0, _obj.assign)({
-      'role': 'button',
+  if (Object.assign) {
+    return Object.assign.apply(Object, [target].concat(sources));
+  }
 
-      // let the screen reader user know that the text of the element may change
-      'aria-live': 'polite'
-    }, attributes);
+  sources.forEach(function (source) {
+    if (!source) {
+      return;
+    }
 
-    this.tabIndex_ = props.tabIndex;
+    each(source, function (value, key) {
+      target[key] = value;
+    });
+  });
 
-    var el = _Component.prototype.createEl.call(this, tag, props, attributes);
+  return target;
+}
 
-    this.createControlTextEl(el);
+/**
+ * Returns whether a value is an object of any kind - including DOM nodes,
+ * arrays, regular expressions, etc. Not functions, though.
+ *
+ * This avoids the gotcha where using `typeof` on a `null` value
+ * results in `'object'`.
+ *
+ * @param  {Object} value
+ * @return {Boolean}
+ */
+function isObject(value) {
+  return !!value && (typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object';
+}
 
-    return el;
-  };
+/**
+ * Returns whether an object appears to be a "plain" object - that is, a
+ * direct instance of `Object`.
+ *
+ * @param  {Object} value
+ * @return {Boolean}
+ */
+function isPlain(value) {
+  return isObject(value) && toString.call(value) === '[object Object]' && value.constructor === Object;
+}
 
-  /**
-   * Create a control text element on this `Component`
-   *
-   * @param {Element} [el]
-   *        Parent element for the control text.
-   *
-   * @return {Element}
-   *         The control text element that gets created.
-   */
+/**
+ * @file log.js
+ * @module log
+ */
+var log = void 0;
 
+// This is the private tracking variable for logging level.
+var level = 'all';
 
-  ClickableComponent.prototype.createControlTextEl = function createControlTextEl(el) {
-    this.controlTextEl_ = Dom.createEl('span', {
-      className: 'vjs-control-text'
-    });
+// This is the private tracking variable for the logging history.
+var history = [];
 
-    if (el) {
-      el.appendChild(this.controlTextEl_);
-    }
+/**
+ * Log messages to the console and history based on the type of message
+ *
+ * @private
+ * @param  {string} type
+ *         The name of the console method to use.
+ *
+ * @param  {Array} args
+ *         The arguments to be passed to the matching console method.
+ *
+ * @param  {boolean} [stringify]
+ *         By default, only old IEs should get console argument stringification,
+ *         but this is exposed as a parameter to facilitate testing.
+ */
+var logByType = function logByType(type, args) {
+  var stringify = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : !!IE_VERSION && IE_VERSION < 11;
 
-    this.controlText(this.controlText_, el);
+  var lvl = log.levels[level];
+  var lvlRegExp = new RegExp('^(' + lvl + ')$');
 
-    return this.controlTextEl_;
-  };
+  if (type !== 'log') {
 
-  /**
-   * Get or set the localize text to use for the controls on the `Component`.
-   *
-   * @param {string} [text]
-   *        Control text for element.
-   *
-   * @param {Element} [el=this.el()]
-   *        Element to set the title on.
-   *
-   * @return {string|ClickableComponent}
-   *         - The control text when getting
-   *         - Returns itself when setting; method can be chained.
-   */
+    // Add the type to the front of the message when it's not "log".
+    args.unshift(type.toUpperCase() + ':');
+  }
 
+  // Add a clone of the args at this point to history.
+  if (history) {
+    history.push([].concat(args));
+  }
 
-  ClickableComponent.prototype.controlText = function controlText(text) {
-    var el = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.el();
+  // Add console prefix after adding to history.
+  args.unshift('VIDEOJS:');
 
-    if (!text) {
-      return this.controlText_ || 'Need Text';
-    }
+  // If there's no console then don't try to output messages, but they will
+  // still be stored in history.
+  //
+  // Was setting these once outside of this function, but containing them
+  // in the function makes it easier to test cases where console doesn't exist
+  // when the module is executed.
+  var fn = window_1.console && window_1.console[type];
 
-    var localizedText = this.localize(text);
+  // Bail out if there's no console or if this type is not allowed by the
+  // current logging level.
+  if (!fn || !lvl || !lvlRegExp.test(type)) {
+    return;
+  }
 
-    this.controlText_ = text;
-    this.controlTextEl_.innerHTML = localizedText;
+  // IEs previous to 11 log objects uselessly as "[object Object]"; so, JSONify
+  // objects and arrays for those less-capable browsers.
+  if (stringify) {
+    args = args.map(function (a) {
+      if (isObject(a) || Array.isArray(a)) {
+        try {
+          return JSON.stringify(a);
+        } catch (x) {
+          return String(a);
+        }
+      }
 
-    if (!this.nonIconControl) {
-      // Set title attribute if only an icon is shown
-      el.setAttribute('title', localizedText);
-    }
+      // Cast to string before joining, so we get null and undefined explicitly
+      // included in output (as we would in a modern console).
+      return String(a);
+    }).join(' ');
+  }
 
-    return this;
-  };
+  // Old IE versions do not allow .apply() for console methods (they are
+  // reported as objects rather than functions).
+  if (!fn.apply) {
+    fn(args);
+  } else {
+    fn[Array.isArray(args) ? 'apply' : 'call'](window_1.console, args);
+  }
+};
 
-  /**
-   * Builds the default DOM `className`.
-   *
-   * @return {string}
-   *         The DOM `className` for this object.
-   */
+/**
+ * Logs plain debug messages. Similar to `console.log`.
+ *
+ * @class
+ * @param    {Mixed[]} args
+ *           One or more messages or objects that should be logged.
+ */
+log = function log() {
+  for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
+    args[_key] = arguments[_key];
+  }
 
+  logByType('log', args);
+};
 
-  ClickableComponent.prototype.buildCSSClass = function buildCSSClass() {
-    return 'vjs-control vjs-button ' + _Component.prototype.buildCSSClass.call(this);
-  };
+/**
+ * Enumeration of available logging levels, where the keys are the level names
+ * and the values are `|`-separated strings containing logging methods allowed
+ * in that logging level. These strings are used to create a regular expression
+ * matching the function name being called.
+ *
+ * Levels provided by video.js are:
+ *
+ * - `off`: Matches no calls. Any value that can be cast to `false` will have
+ *   this effect. The most restrictive.
+ * - `all` (default): Matches only Video.js-provided functions (`log`,
+ *   `log.warn`, and `log.error`).
+ * - `warn`: Matches `log.warn` and `log.error` calls.
+ * - `error`: Matches only `log.error` calls.
+ *
+ * @type {Object}
+ */
+log.levels = {
+  all: 'log|warn|error',
+  error: 'error',
+  off: '',
+  warn: 'warn|error',
+  DEFAULT: level
+};
 
-  /**
-   * Enable this `Component`s element.
-   *
-   * @return {ClickableComponent}
-   *         Returns itself; method can be chained.
-   */
-
-
-  ClickableComponent.prototype.enable = function enable() {
-    this.removeClass('vjs-disabled');
-    this.el_.setAttribute('aria-disabled', 'false');
-    if (typeof this.tabIndex_ !== 'undefined') {
-      this.el_.setAttribute('tabIndex', this.tabIndex_);
+/**
+ * Get or set the current logging level. If a string matching a key from
+ * {@link log.levels} is provided, acts as a setter. Regardless of argument,
+ * returns the current logging level.
+ *
+ * @param  {string} [lvl]
+ *         Pass to set a new logging level.
+ *
+ * @return {string}
+ *         The current logging level.
+ */
+log.level = function (lvl) {
+  if (typeof lvl === 'string') {
+    if (!log.levels.hasOwnProperty(lvl)) {
+      throw new Error('"' + lvl + '" in not a valid log level');
     }
-    this.on('tap', this.handleClick);
-    this.on('click', this.handleClick);
-    this.on('focus', this.handleFocus);
-    this.on('blur', this.handleBlur);
-    return this;
-  };
-
-  /**
-   * Disable this `Component`s element.
-   *
-   * @return {ClickableComponent}
-   *         Returns itself; method can be chained.
-   */
-
+    level = lvl;
+  }
+  return level;
+};
 
-  ClickableComponent.prototype.disable = function disable() {
-    this.addClass('vjs-disabled');
-    this.el_.setAttribute('aria-disabled', 'true');
-    if (typeof this.tabIndex_ !== 'undefined') {
-      this.el_.removeAttribute('tabIndex');
-    }
-    this.off('tap', this.handleClick);
-    this.off('click', this.handleClick);
-    this.off('focus', this.handleFocus);
-    this.off('blur', this.handleBlur);
-    return this;
-  };
+/**
+ * Returns an array containing everything that has been logged to the history.
+ *
+ * This array is a shallow clone of the internal history record. However, its
+ * contents are _not_ cloned; so, mutating objects inside this array will
+ * mutate them in history.
+ *
+ * @return {Array}
+ */
+log.history = function () {
+  return history ? [].concat(history) : [];
+};
 
-  /**
-   * This gets called when a `ClickableComponent` gets:
-   * - Clicked (via the `click` event, listening starts in the constructor)
-   * - Tapped (via the `tap` event, listening starts in the constructor)
-   * - The following things happen in order:
-   *   1. {@link ClickableComponent#handleFocus} is called via a `focus` event on the
-   *      `ClickableComponent`.
-   *   2. {@link ClickableComponent#handleFocus} adds a listener for `keydown` on using
-   *      {@link ClickableComponent#handleKeyPress}.
-   *   3. `ClickableComponent` has not had a `blur` event (`blur` means that focus was lost). The user presses
-   *      the space or enter key.
-   *   4. {@link ClickableComponent#handleKeyPress} calls this function with the `keydown`
-   *      event as a parameter.
-   *
-   * @param {EventTarget~Event} event
-   *        The `keydown`, `tap`, or `click` event that caused this function to be
-   *        called.
-   *
-   * @listens tap
-   * @listens click
-   * @abstract
-   */
+/**
+ * Clears the internal history tracking, but does not prevent further history
+ * tracking.
+ */
+log.history.clear = function () {
+  if (history) {
+    history.length = 0;
+  }
+};
 
+/**
+ * Disable history tracking if it is currently enabled.
+ */
+log.history.disable = function () {
+  if (history !== null) {
+    history.length = 0;
+    history = null;
+  }
+};
 
-  ClickableComponent.prototype.handleClick = function handleClick(event) {};
+/**
+ * Enable history tracking if it is currently disabled.
+ */
+log.history.enable = function () {
+  if (history === null) {
+    history = [];
+  }
+};
 
-  /**
  * This gets called when a `ClickableComponent` gains focus via a `focus` event.
-   * Turns on listening for `keydown` events. When they happen it
-   * calls `this.handleKeyPress`.
-   *
-   * @param {EventTarget~Event} event
-   *        The `focus` event that caused this function to be called.
-   *
-   * @listens focus
-   */
+/**
* Logs error messages. Similar to `console.error`.
+ *
+ * @param {Mixed[]} args
+ *        One or more messages or objects that should be logged as an error
+ */
+log.error = function () {
+  for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
+    args[_key2] = arguments[_key2];
+  }
 
+  return logByType('error', args);
+};
 
-  ClickableComponent.prototype.handleFocus = function handleFocus(event) {
-    Events.on(_document2['default'], 'keydown', Fn.bind(this, this.handleKeyPress));
-  };
+/**
+ * Logs warning messages. Similar to `console.warn`.
+ *
+ * @param {Mixed[]} args
+ *        One or more messages or objects that should be logged as a warning.
+ */
+log.warn = function () {
+  for (var _len3 = arguments.length, args = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
+    args[_key3] = arguments[_key3];
+  }
 
-  /**
-   * Called when this ClickableComponent has focus and a key gets pressed down. By
-   * default it will call `this.handleClick` when the key is space or enter.
-   *
-   * @param {EventTarget~Event} event
-   *        The `keydown` event that caused this function to be called.
-   *
-   * @listens keydown
-   */
+  return logByType('warn', args);
+};
 
+var log$1 = log;
 
-  ClickableComponent.prototype.handleKeyPress = function handleKeyPress(event) {
+function clean (s) {
+  return s.replace(/\n\r?\s*/g, '')
+}
 
-    // Support Space (32) or Enter (13) key operation to fire a click event
-    if (event.which === 32 || event.which === 13) {
-      event.preventDefault();
-      this.handleClick(event);
-    } else if (_Component.prototype.handleKeyPress) {
 
-      // Pass keypress handling up for unsupported keys
-      _Component.prototype.handleKeyPress.call(this, event);
-    }
-  };
+var tsml = function tsml (sa) {
+  var s = ''
+    , i = 0;
 
-  /**
-   * Called when a `ClickableComponent` loses focus. Turns off the listener for
-   * `keydown` events. Which Stops `this.handleKeyPress` from getting called.
-   *
-   * @param {EventTarget~Event} event
-   *        The `blur` event that caused this function to be called.
-   *
-   * @listens blur
-   */
+  for (; i < arguments.length; i++)
+    s += clean(sa[i]) + (arguments[i + 1] || '');
 
+  return s
+};
 
-  ClickableComponent.prototype.handleBlur = function handleBlur(event) {
-    Events.off(_document2['default'], 'keydown', Fn.bind(this, this.handleKeyPress));
-  };
+/**
+ * @file computed-style.js
+ * @module computed-style
+ */
+/**
+ * A safe getComputedStyle with an IE8 fallback.
+ *
+ * This is needed because in Firefox, if the player is loaded in an iframe with
+ * `display:none`, then `getComputedStyle` returns `null`, so, we do a null-check to
+ * make sure  that the player doesn't break in these cases.
+ *
+ * @param {Element} el
+ *        The element you want the computed style of
+ *
+ * @param {string} prop
+ *        The property name you want
+ *
+ * @see https://bugzilla.mozilla.org/show_bug.cgi?id=548397
+ *
+ * @static
+ * @const
+ */
+function computedStyle(el, prop) {
+  if (!el || !prop) {
+    return '';
+  }
 
-  return ClickableComponent;
-}(_component2['default']);
+  if (typeof window_1.getComputedStyle === 'function') {
+    var cs = window_1.getComputedStyle(el);
 
-_component2['default'].registerComponent('ClickableComponent', ClickableComponent);
-exports['default'] = ClickableComponent;
+    return cs ? cs[prop] : '';
+  }
 
-},{"5":5,"81":81,"82":82,"83":83,"86":86,"88":88,"94":94}],4:[function(_dereq_,module,exports){
-'use strict';
+  return el.currentStyle[prop] || '';
+}
 
-exports.__esModule = true;
+var _templateObject = taggedTemplateLiteralLoose(['Setting attributes in the second argument of createEl()\n                has been deprecated. Use the third argument instead.\n                createEl(type, properties, attributes). Attempting to set ', ' to ', '.'], ['Setting attributes in the second argument of createEl()\n                has been deprecated. Use the third argument instead.\n                createEl(type, properties, attributes). Attempting to set ', ' to ', '.']);
 
-var _button = _dereq_(2);
+/**
+ * @file dom.js
+ * @module dom
+ */
+/**
+ * Detect if a value is a string with any non-whitespace characters.
+ *
+ * @param {string} str
+ *        The string to check
+ *
+ * @return {boolean}
+ *         - True if the string is non-blank
+ *         - False otherwise
+ *
+ */
+function isNonBlankString(str) {
+  return typeof str === 'string' && /\S/.test(str);
+}
 
-var _button2 = _interopRequireDefault(_button);
+/**
+ * Throws an error if the passed string has whitespace. This is used by
+ * class methods to be relatively consistent with the classList API.
+ *
+ * @param {string} str
+ *         The string to check for whitespace.
+ *
+ * @throws {Error}
+ *         Throws an error if there is whitespace in the string.
+ *
+ */
+function throwIfWhitespace(str) {
+  if (/\s/.test(str)) {
+    throw new Error('class has illegal whitespace characters');
+  }
+}
 
-var _component = _dereq_(5);
+/**
+ * Produce a regular expression for matching a className within an elements className.
+ *
+ * @param {string} className
+ *         The className to generate the RegExp for.
+ *
+ * @return {RegExp}
+ *         The RegExp that will check for a specific `className` in an elements
+ *         className.
+ */
+function classRegExp(className) {
+  return new RegExp('(^|\\s)' + className + '($|\\s)');
+}
 
-var _component2 = _interopRequireDefault(_component);
+/**
+ * Whether the current DOM interface appears to be real.
+ *
+ * @return {Boolean}
+ */
+function isReal() {
+  return (
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+    // Both document and window will never be undefined thanks to `global`.
+    document_1 === window_1.document &&
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+    // In IE < 9, DOM methods return "object" as their type, so all we can
+    // confidently check is that it exists.
+    typeof document_1.createElement !== 'undefined'
+  );
+}
 
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+/**
+ * Determines, via duck typing, whether or not a value is a DOM element.
+ *
+ * @param {Mixed} value
+ *        The thing to check
+ *
+ * @return {boolean}
+ *         - True if it is a DOM element
+ *         - False otherwise
+ */
+function isEl(value) {
+  return isObject(value) && value.nodeType === 1;
+}
 
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file close-button.js
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
+/**
+ * Determines if the current DOM is embedded in an iframe.
+ *
+ * @return {boolean}
+ *
+ */
+function isInFrame() {
 
+  // We need a try/catch here because Safari will throw errors when attempting
+  // to get either `parent` or `self`
+  try {
+    return window_1.parent !== window_1.self;
+  } catch (x) {
+    return true;
+  }
+}
 
 /**
- * The `CloseButton` is a `{@link Button}` that fires a `close` event when
- * it gets clicked.
+ * Creates functions to query the DOM using a given method.
  *
- * @extends Button
+ * @param {string} method
+ *         The method to create the query with.
+ *
+ * @return {Function}
+ *         The query method
  */
-var CloseButton = function (_Button) {
-  _inherits(CloseButton, _Button);
-
-  /**
-   * Creates an instance of the this class.
-   *
-   * @param  {Player} player
-   *         The `Player` that this class should be attached to.
-   *
-   * @param  {Object} [options]
-   *         The key/value store of player options.
-   */
-  function CloseButton(player, options) {
-    _classCallCheck(this, CloseButton);
-
-    var _this = _possibleConstructorReturn(this, _Button.call(this, player, options));
-
-    _this.controlText(options && options.controlText || _this.localize('Close'));
-    return _this;
-  }
-
-  /**
-   * Builds the default DOM `className`.
-   *
-   * @return {string}
-   *         The DOM `className` for this object.
-   */
+function createQuerier(method) {
+  return function (selector, context) {
+    if (!isNonBlankString(selector)) {
+      return document_1[method](null);
+    }
+    if (isNonBlankString(context)) {
+      context = document_1.querySelector(context);
+    }
 
+    var ctx = isEl(context) ? context : document_1;
 
-  CloseButton.prototype.buildCSSClass = function buildCSSClass() {
-    return 'vjs-close-button ' + _Button.prototype.buildCSSClass.call(this);
+    return ctx[method] && ctx[method](selector);
   };
+}
 
-  /**
-   * This gets called when a `CloseButton` gets clicked. See
-   * {@link ClickableComponent#handleClick} for more information on when this will be
-   * triggered
-   *
-   * @param {EventTarget~Event} event
-   *        The `keydown`, `tap`, or `click` event that caused this function to be
-   *        called.
-   *
-   * @listens tap
-   * @listens click
-   * @fires CloseButton#close
-   */
+/**
+ * Creates an element and applies properties.
+ *
+ * @param {string} [tagName='div']
+ *         Name of tag to be created.
+ *
+ * @param {Object} [properties={}]
+ *         Element properties to be applied.
+ *
+ * @param {Object} [attributes={}]
+ *         Element attributes to be applied.
+ *
+ * @param {String|Element|TextNode|Array|Function} [content]
+ *         Contents for the element (see: {@link dom:normalizeContent})
+ *
+ * @return {Element}
+ *         The element that was created.
+ */
+function createEl() {
+  var tagName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'div';
+  var properties = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+  var attributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
+  var content = arguments[3];
 
+  var el = document_1.createElement(tagName);
 
-  CloseButton.prototype.handleClick = function handleClick(event) {
+  Object.getOwnPropertyNames(properties).forEach(function (propName) {
+    var val = properties[propName];
 
-    /**
-     * Triggered when the a `CloseButton` is clicked.
-     *
-     * @event CloseButton#close
-     * @type {EventTarget~Event}
-     *
-     * @property {boolean} [bubbles=false]
-     *           set to false so that the close event does not
-     *           bubble up to parents if there is no listener
-     */
-    this.trigger({ type: 'close', bubbles: false });
-  };
+    // See #2176
+    // We originally were accepting both properties and attributes in the
+    // same object, but that doesn't work so well.
+    if (propName.indexOf('aria-') !== -1 || propName === 'role' || propName === 'type') {
+      log$1.warn(tsml(_templateObject, propName, val));
+      el.setAttribute(propName, val);
 
-  return CloseButton;
-}(_button2['default']);
+      // Handle textContent since it's not supported everywhere and we have a
+      // method for it.
+    } else if (propName === 'textContent') {
+      textContent(el, val);
+    } else {
+      el[propName] = val;
+    }
+  });
 
-_component2['default'].registerComponent('CloseButton', CloseButton);
-exports['default'] = CloseButton;
+  Object.getOwnPropertyNames(attributes).forEach(function (attrName) {
+    el.setAttribute(attrName, attributes[attrName]);
+  });
 
-},{"2":2,"5":5}],5:[function(_dereq_,module,exports){
-'use strict';
+  if (content) {
+    appendContent(el, content);
+  }
 
-exports.__esModule = true;
+  return el;
+}
 
-var _window = _dereq_(95);
+/**
+ * Injects text into an element, replacing any existing contents entirely.
+ *
+ * @param {Element} el
+ *        The element to add text content into
+ *
+ * @param {string} text
+ *        The text content to add.
+ *
+ * @return {Element}
+ *         The element with added text content.
+ */
+function textContent(el, text) {
+  if (typeof el.textContent === 'undefined') {
+    el.innerText = text;
+  } else {
+    el.textContent = text;
+  }
+  return el;
+}
 
-var _window2 = _interopRequireDefault(_window);
+/**
+ * Insert an element as the first child node of another
+ *
+ * @param {Element} child
+ *        Element to insert
+ *
+ * @param {Element} parent
+ *        Element to insert child into
+ */
+function prependTo(child, parent) {
+  if (parent.firstChild) {
+    parent.insertBefore(child, parent.firstChild);
+  } else {
+    parent.appendChild(child);
+  }
+}
 
-var _dom = _dereq_(81);
+/**
+ * Check if an element has a CSS class
+ *
+ * @param {Element} element
+ *        Element to check
+ *
+ * @param {string} classToCheck
+ *        Class name to check for
+ *
+ * @return {boolean}
+ *         - True if the element had the class
+ *         - False otherwise.
+ *
+ * @throws {Error}
+ *         Throws an error if `classToCheck` has white space.
+ */
+function hasClass(element, classToCheck) {
+  throwIfWhitespace(classToCheck);
+  if (element.classList) {
+    return element.classList.contains(classToCheck);
+  }
+  return classRegExp(classToCheck).test(element.className);
+}
 
-var Dom = _interopRequireWildcard(_dom);
+/**
+ * Add a CSS class name to an element
+ *
+ * @param {Element} element
+ *        Element to add class name to.
+ *
+ * @param {string} classToAdd
+ *        Class name to add.
+ *
+ * @return {Element}
+ *         The dom element with the added class name.
+ */
+function addClass(element, classToAdd) {
+  if (element.classList) {
+    element.classList.add(classToAdd);
 
-var _fn = _dereq_(83);
+    // Don't need to `throwIfWhitespace` here because `hasElClass` will do it
+    // in the case of classList not being supported.
+  } else if (!hasClass(element, classToAdd)) {
+    element.className = (element.className + ' ' + classToAdd).trim();
+  }
 
-var Fn = _interopRequireWildcard(_fn);
+  return element;
+}
 
-var _guid = _dereq_(85);
+/**
+ * Remove a CSS class name from an element
+ *
+ * @param {Element} element
+ *        Element to remove a class name from.
+ *
+ * @param {string} classToRemove
+ *        Class name to remove
+ *
+ * @return {Element}
+ *         The dom element with class name removed.
+ */
+function removeClass(element, classToRemove) {
+  if (element.classList) {
+    element.classList.remove(classToRemove);
+  } else {
+    throwIfWhitespace(classToRemove);
+    element.className = element.className.split(/\s+/).filter(function (c) {
+      return c !== classToRemove;
+    }).join(' ');
+  }
 
-var Guid = _interopRequireWildcard(_guid);
+  return element;
+}
 
-var _events = _dereq_(82);
+/**
+ * The callback definition for toggleElClass.
+ *
+ * @callback Dom~PredicateCallback
+ * @param {Element} element
+ *        The DOM element of the Component.
+ *
+ * @param {string} classToToggle
+ *        The `className` that wants to be toggled
+ *
+ * @return {boolean|undefined}
+ *         - If true the `classToToggle` will get added to `element`.
+ *         - If false the `classToToggle` will get removed from `element`.
+ *         - If undefined this callback will be ignored
+ */
 
-var Events = _interopRequireWildcard(_events);
+/**
+ * Adds or removes a CSS class name on an element depending on an optional
+ * condition or the presence/absence of the class name.
+ *
+ * @param {Element} element
+ *        The element to toggle a class name on.
+ *
+ * @param {string} classToToggle
+ *        The class that should be toggled
+ *
+ * @param {boolean|PredicateCallback} [predicate]
+ *        See the return value for {@link Dom~PredicateCallback}
+ *
+ * @return {Element}
+ *         The element with a class that has been toggled.
+ */
+function toggleClass(element, classToToggle, predicate) {
 
-var _log = _dereq_(86);
+  // This CANNOT use `classList` internally because IE does not support the
+  // second parameter to the `classList.toggle()` method! Which is fine because
+  // `classList` will be used by the add/remove functions.
+  var has = hasClass(element, classToToggle);
 
-var _log2 = _interopRequireDefault(_log);
+  if (typeof predicate === 'function') {
+    predicate = predicate(element, classToToggle);
+  }
 
-var _toTitleCase = _dereq_(91);
+  if (typeof predicate !== 'boolean') {
+    predicate = !has;
+  }
 
-var _toTitleCase2 = _interopRequireDefault(_toTitleCase);
+  // If the necessary class operation matches the current state of the
+  // element, no action is required.
+  if (predicate === has) {
+    return;
+  }
 
-var _mergeOptions = _dereq_(87);
+  if (predicate) {
+    addClass(element, classToToggle);
+  } else {
+    removeClass(element, classToToggle);
+  }
 
-var _mergeOptions2 = _interopRequireDefault(_mergeOptions);
+  return element;
+}
 
-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
-                                                                                                                                                           */
+/**
+ * Apply attributes to an HTML element.
+ *
+ * @param {Element} el
+ *        Element to add attributes to.
+ *
+ * @param {Object} [attributes]
+ *        Attributes to be applied.
+ */
+function setAttributes(el, attributes) {
+  Object.getOwnPropertyNames(attributes).forEach(function (attrName) {
+    var attrValue = attributes[attrName];
 
+    if (attrValue === null || typeof attrValue === 'undefined' || attrValue === false) {
+      el.removeAttribute(attrName);
+    } else {
+      el.setAttribute(attrName, attrValue === true ? '' : attrValue);
+    }
+  });
+}
 
 /**
- * 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.
+ * Get an element's attribute values, as defined on the HTML tag
+ * Attributes are not the same as properties. They're defined on the tag
+ * or with setAttribute (which shouldn't be used with HTML)
+ * This will return true or false for boolean attributes.
  *
- * Components can also use methods from {@link EventTarget}
+ * @param {Element} tag
+ *        Element from which to get tag attributes.
+ *
+ * @return {Object}
+ *         All attributes of the element.
  */
-var Component = function () {
+function getAttributes(tag) {
+  var obj = {};
 
-  /**
-   * 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
-   */
+  // known boolean attributes
+  // we can check for matching boolean properties, but older browsers
+  // won't know about HTML5 boolean attributes that we still read from
+  var knownBooleans = ',' + 'autoplay,controls,playsinline,loop,muted,default,defaultMuted' + ',';
 
-  /**
-   * 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);
+  if (tag && tag.attributes && tag.attributes.length > 0) {
+    var attrs = tag.attributes;
 
-    // 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;
+    for (var i = attrs.length - 1; i >= 0; i--) {
+      var attrName = attrs[i].name;
+      var attrVal = attrs[i].value;
+
+      // check for known booleans
+      // the matching element property will return a value for typeof
+      if (typeof tag[attrName] === 'boolean' || knownBooleans.indexOf(',' + attrName + ',') !== -1) {
+        // the value of an included boolean attribute is typically an empty
+        // string ('') which would equal false if we just check for a false value.
+        // we also don't want support bad code like autoplay='false'
+        attrVal = attrVal !== null ? true : false;
+      }
+
+      obj[attrName] = attrVal;
     }
+  }
 
-    // Make a copy of prototype.options_ to protect against overriding defaults
-    this.options_ = (0, _mergeOptions2['default'])({}, this.options_);
+  return obj;
+}
 
-    // Updated options with supplied options
-    options = this.options_ = (0, _mergeOptions2['default'])(this.options_, options);
+/**
+ * Get the value of an element's attribute
+ *
+ * @param {Element} el
+ *        A DOM element
+ *
+ * @param {string} attribute
+ *        Attribute to get the value of
+ *
+ * @return {string}
+ *         value of the attribute
+ */
+function getAttribute(el, attribute) {
+  return el.getAttribute(attribute);
+}
 
-    // Get ID from options or options element if one is supplied
-    this.id_ = options.id || options.el && options.el.id;
+/**
+ * Set the value of an element's attribute
+ *
+ * @param {Element} el
+ *        A DOM element
+ *
+ * @param {string} attribute
+ *        Attribute to set
+ *
+ * @param {string} value
+ *        Value to set the attribute to
+ */
+function setAttribute(el, attribute, value) {
+  el.setAttribute(attribute, value);
+}
 
-    // 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';
+/**
+ * Remove an element's attribute
+ *
+ * @param {Element} el
+ *        A DOM element
+ *
+ * @param {string} attribute
+ *        Attribute to remove
+ */
+function removeAttribute(el, attribute) {
+  el.removeAttribute(attribute);
+}
 
-      this.id_ = id + '_component_' + Guid.newGUID();
-    }
+/**
+ * Attempt to block the ability to select text while dragging controls
+ */
+function blockTextSelection() {
+  document_1.body.focus();
+  document_1.onselectstart = function () {
+    return false;
+  };
+}
 
-    this.name_ = options.name || null;
+/**
+ * Turn off text selection blocking
+ */
+function unblockTextSelection() {
+  document_1.onselectstart = function () {
+    return true;
+  };
+}
 
-    // 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();
-    }
+/**
+ * Identical to the native `getBoundingClientRect` function, but ensures that
+ * the method is supported at all (it is in all browsers we claim to support)
+ * and that the element is in the DOM before continuing.
+ *
+ * This wrapper function also shims properties which are not provided by some
+ * older browsers (namely, IE8).
+ *
+ * Additionally, some browsers do not support adding properties to a
+ * `ClientRect`/`DOMRect` object; so, we shallow-copy it with the standard
+ * properties (except `x` and `y` which are not widely supported). This helps
+ * avoid implementations where keys are non-enumerable.
+ *
+ * @param  {Element} el
+ *         Element whose `ClientRect` we want to calculate.
+ *
+ * @return {Object|undefined}
+ *         Always returns a plain
+ */
+function getBoundingClientRect(el) {
+  if (el && el.getBoundingClientRect && el.parentNode) {
+    var rect = el.getBoundingClientRect();
+    var result = {};
 
-    this.children_ = [];
-    this.childIndex_ = {};
-    this.childNameIndex_ = {};
+    ['bottom', 'height', 'left', 'right', 'top', 'width'].forEach(function (k) {
+      if (rect[k] !== undefined) {
+        result[k] = rect[k];
+      }
+    });
 
-    // Add any child components in options
-    if (options.initChildren !== false) {
-      this.initChildren();
+    if (!result.height) {
+      result.height = parseFloat(computedStyle(el, 'height'));
     }
 
-    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();
+    if (!result.width) {
+      result.width = parseFloat(computedStyle(el, 'width'));
     }
-  }
 
-  /**
-   * Dispose of the `Component` and all child components.
-   *
-   * @fires Component#dispose
-   */
+    return result;
+  }
+}
 
+/**
+ * The postion of a DOM element on the page.
+ *
+ * @typedef {Object} module:dom~Position
+ *
+ * @property {number} left
+ *           Pixels to the left
+ *
+ * @property {number} top
+ *           Pixels on top
+ */
 
-  Component.prototype.dispose = function dispose() {
+/**
+ * Offset Left.
+ * getBoundingClientRect technique from
+ * John Resig
+ *
+ * @see http://ejohn.org/blog/getboundingclientrect-is-awesome/
+ *
+ * @param {Element} el
+ *        Element from which to get offset
+ *
+ * @return {module:dom~Position}
+ *         The position of the element that was passed in.
+ */
+function findPosition(el) {
+  var box = void 0;
 
-    /**
-     * 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 });
+  if (el.getBoundingClientRect && el.parentNode) {
+    box = el.getBoundingClientRect();
+  }
 
-    // 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();
-        }
-      }
-    }
+  if (!box) {
+    return {
+      left: 0,
+      top: 0
+    };
+  }
 
-    // Delete child references
-    this.children_ = null;
-    this.childIndex_ = null;
-    this.childNameIndex_ = null;
+  var docEl = document_1.documentElement;
+  var body = document_1.body;
 
-    // Remove all event listeners.
-    this.off();
+  var clientLeft = docEl.clientLeft || body.clientLeft || 0;
+  var scrollLeft = window_1.pageXOffset || body.scrollLeft;
+  var left = box.left + scrollLeft - clientLeft;
 
-    // Remove element from DOM
-    if (this.el_.parentNode) {
-      this.el_.parentNode.removeChild(this.el_);
-    }
+  var clientTop = docEl.clientTop || body.clientTop || 0;
+  var scrollTop = window_1.pageYOffset || body.scrollTop;
+  var top = box.top + scrollTop - clientTop;
 
-    Dom.removeElData(this.el_);
-    this.el_ = null;
+  // Android sometimes returns slightly off decimal values, so need to round
+  return {
+    left: Math.round(left),
+    top: Math.round(top)
   };
+}
 
-  /**
-   * 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_;
-    }
+/**
+ * x and y coordinates for a dom element or mouse pointer
+ *
+ * @typedef {Object} Dom~Coordinates
+ *
+ * @property {number} x
+ *           x coordinate in pixels
+ *
+ * @property {number} y
+ *           y coordinate in pixels
+ */
 
-    this.options_ = (0, _mergeOptions2['default'])(this.options_, obj);
-    return this.options_;
-  };
+/**
+ * Get pointer position in element
+ * Returns an object with x and y coordinates.
+ * The base on the coordinates are the bottom left of the element.
+ *
+ * @param {Element} el
+ *        Element on which to get the pointer position on
+ *
+ * @param {EventTarget~Event} event
+ *        Event object
+ *
+ * @return {Dom~Coordinates}
+ *         A Coordinates object corresponding to the mouse position.
+ *
+ */
+function getPointerPosition(el, event) {
+  var position = {};
+  var box = findPosition(el);
+  var boxW = el.offsetWidth;
+  var boxH = el.offsetHeight;
 
-  /**
-   * Get the `Component`s DOM element
-   *
-   * @return {Element}
-   *         The DOM element for this `Component`.
-   */
+  var boxY = box.top;
+  var boxX = box.left;
+  var pageY = event.pageY;
+  var pageX = event.pageX;
 
+  if (event.changedTouches) {
+    pageX = event.changedTouches[0].pageX;
+    pageY = event.changedTouches[0].pageY;
+  }
 
-  Component.prototype.el = function el() {
-    return this.el_;
-  };
+  position.y = Math.max(0, Math.min(1, (boxY - pageY + boxH) / boxH));
+  position.x = Math.max(0, Math.min(1, (pageX - boxX) / boxW));
 
-  /**
-   * 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.
-   */
+  return position;
+}
 
+/**
+ * Determines, via duck typing, whether or not a value is a text node.
+ *
+ * @param {Mixed} value
+ *        Check if this value is a text node.
+ *
+ * @return {boolean}
+ *         - True if it is a text node
+ *         - False otherwise
+ */
+function isTextNode(value) {
+  return isObject(value) && value.nodeType === 3;
+}
 
-  Component.prototype.createEl = function createEl(tagName, properties, attributes) {
-    return Dom.createEl(tagName, properties, attributes);
-  };
+/**
+ * Empties the contents of an element.
+ *
+ * @param {Element} el
+ *        The element to empty children from
+ *
+ * @return {Element}
+ *         The element with no children
+ */
+function emptyEl(el) {
+  while (el.firstChild) {
+    el.removeChild(el.firstChild);
+  }
+  return el;
+}
 
-  /**
-   * 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.
-   */
+/**
+ * Normalizes content for eventual insertion into the DOM.
+ *
+ * This allows a wide range of content definition methods, but protects
+ * from falling into the trap of simply writing to `innerHTML`, which is
+ * an XSS concern.
+ *
+ * The content for an element can be passed in multiple types and
+ * combinations, whose behavior is as follows:
+ *
+ * @param {String|Element|TextNode|Array|Function} content
+ *        - String: Normalized into a text node.
+ *        - Element/TextNode: Passed through.
+ *        - Array: A one-dimensional array of strings, elements, nodes, or functions
+ *          (which return single strings, elements, or nodes).
+ *        - Function: If the sole argument, is expected to produce a string, element,
+ *          node, or array as defined above.
+ *
+ * @return {Array}
+ *         All of the content that was passed in normalized.
+ */
+function normalizeContent(content) {
 
+  // First, invoke content if it is a function. If it produces an array,
+  // that needs to happen before normalization.
+  if (typeof content === 'function') {
+    content = content();
+  }
 
-  Component.prototype.localize = function localize(string) {
-    var code = this.player_.language && this.player_.language();
-    var languages = this.player_.languages && this.player_.languages();
+  // Next up, normalize to an array, so one or many items can be normalized,
+  // filtered, and returned.
+  return (Array.isArray(content) ? content : [content]).map(function (value) {
 
-    if (!code || !languages) {
-      return string;
+    // First, invoke value if it is a function to produce a new value,
+    // which will be subsequently normalized to a Node of some kind.
+    if (typeof value === 'function') {
+      value = value();
     }
 
-    var language = languages[code];
-
-    if (language && language[string]) {
-      return language[string];
+    if (isEl(value) || isTextNode(value)) {
+      return value;
     }
 
-    var primaryCode = code.split('-')[0];
-    var primaryLang = languages[primaryCode];
-
-    if (primaryLang && primaryLang[string]) {
-      return primaryLang[string];
+    if (typeof value === 'string' && /\S/.test(value)) {
+      return document_1.createTextNode(value);
     }
+  }).filter(function (value) {
+    return value;
+  });
+}
 
-    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_;
-  };
+/**
+ * Normalizes and appends content to an element.
+ *
+ * @param {Element} el
+ *        Element to append normalized content to.
+ *
+ *
+ * @param {String|Element|TextNode|Array|Function} content
+ *        See the `content` argument of {@link dom:normalizeContent}
+ *
+ * @return {Element}
+ *         The element with appended normalized content.
+ */
+function appendContent(el, content) {
+  normalizeContent(content).forEach(function (node) {
+    return el.appendChild(node);
+  });
+  return el;
+}
 
-  /**
-   * Get this `Component`s ID
-   *
-   * @return {string}
-   *         The id of this `Component`
-   */
+/**
+ * Normalizes and inserts content into an element; this is identical to
+ * `appendContent()`, except it empties the element first.
+ *
+ * @param {Element} el
+ *        Element to insert normalized content into.
+ *
+ * @param {String|Element|TextNode|Array|Function} content
+ *        See the `content` argument of {@link dom:normalizeContent}
+ *
+ * @return {Element}
+ *         The element with inserted normalized content.
+ *
+ */
+function insertContent(el, content) {
+  return appendContent(emptyEl(el), content);
+}
 
+/**
+ * Finds a single DOM element matching `selector` within the optional
+ * `context` of another DOM element (defaulting to `document`).
+ *
+ * @param {string} selector
+ *        A valid CSS selector, which will be passed to `querySelector`.
+ *
+ * @param {Element|String} [context=document]
+ *        A DOM element within which to query. Can also be a selector
+ *        string in which case the first matching element will be used
+ *        as context. If missing (or no element matches selector), falls
+ *        back to `document`.
+ *
+ * @return {Element|null}
+ *         The element that was found or null.
+ */
+var $ = createQuerier('querySelector');
 
-  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;
-    }
+/**
+ * Finds a all DOM elements matching `selector` within the optional
+ * `context` of another DOM element (defaulting to `document`).
+ *
+ * @param {string} selector
+ *           A valid CSS selector, which will be passed to `querySelectorAll`.
+ *
+ * @param {Element|String} [context=document]
+ *           A DOM element within which to query. Can also be a selector
+ *           string in which case the first matching element will be used
+ *           as context. If missing (or no element matches selector), falls
+ *           back to `document`.
+ *
+ * @return {NodeList}
+ *         A element list of elements that were found. Will be empty if none were found.
+ *
+ */
+var $$ = createQuerier('querySelectorAll');
+
+
+
+var Dom = (Object.freeze || Object)({
+       isReal: isReal,
+       isEl: isEl,
+       isInFrame: isInFrame,
+       createEl: createEl,
+       textContent: textContent,
+       prependTo: prependTo,
+       hasClass: hasClass,
+       addClass: addClass,
+       removeClass: removeClass,
+       toggleClass: toggleClass,
+       setAttributes: setAttributes,
+       getAttributes: getAttributes,
+       getAttribute: getAttribute,
+       setAttribute: setAttribute,
+       removeAttribute: removeAttribute,
+       blockTextSelection: blockTextSelection,
+       unblockTextSelection: unblockTextSelection,
+       getBoundingClientRect: getBoundingClientRect,
+       findPosition: findPosition,
+       getPointerPosition: getPointerPosition,
+       isTextNode: isTextNode,
+       emptyEl: emptyEl,
+       normalizeContent: normalizeContent,
+       appendContent: appendContent,
+       insertContent: insertContent,
+       $: $,
+       $$: $$
+});
 
-    name = (0, _toTitleCase2['default'])(name);
+/**
+ * @file guid.js
+ * @module guid
+ */
 
-    return this.childNameIndex_[name];
-  };
+/**
+ * Unique ID for an element or function
+ * @type {Number}
+ */
+var _guid = 1;
 
-  /**
-   * 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.
-   */
+/**
+ * Get a unique auto-incrementing ID by number that has not been returned before.
+ *
+ * @return {number}
+ *         A new unique ID.
+ */
+function newGUID() {
+  return _guid++;
+}
 
+/**
+ * @file dom-data.js
+ * @module dom-data
+ */
+/**
+ * Element Data Store.
+ *
+ * Allows for binding data to an element without putting it directly on the
+ * element. Ex. Event listeners are stored here.
+ * (also from jsninja.com, slightly modified and updated for closure compiler)
+ *
+ * @type {Object}
+ * @private
+ */
+var elData = {};
 
-  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;
+/*
+ * Unique attribute name to store an element's guid in
+ *
+ * @type {String}
+ * @constant
+ * @private
+ */
+var elIdAttr = 'vdata' + new Date().getTime();
 
-    var component = void 0;
-    var componentName = void 0;
+/**
+ * Returns the cache object where data for an element is stored
+ *
+ * @param {Element} el
+ *        Element to store data for.
+ *
+ * @return {Object}
+ *         The cache object for that el that was passed in.
+ */
+function getData(el) {
+  var id = el[elIdAttr];
 
-    // If child is a string, create component with options
-    if (typeof child === 'string') {
-      componentName = (0, _toTitleCase2['default'])(child);
+  if (!id) {
+    id = el[elIdAttr] = newGUID();
+  }
 
-      // Options can also be specified as a boolean,
-      // so convert to an empty object if false.
-      if (!options) {
-        options = {};
-      }
+  if (!elData[id]) {
+    elData[id] = {};
+  }
 
-      // 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 = {};
-      }
+  return elData[id];
+}
 
-      var componentClassName = options.componentClass || componentName;
+/**
+ * Returns whether or not an element has cached data
+ *
+ * @param {Element} el
+ *        Check if this element has cached data.
+ *
+ * @return {boolean}
+ *         - True if the DOM element has cached data.
+ *         - False otherwise.
+ */
+function hasData(el) {
+  var id = el[elIdAttr];
 
-      // Set name through options
-      options.name = componentName;
+  if (!id) {
+    return false;
+  }
 
-      // Create a new object & element for this controls set
-      // If there's no .player_, this is a player
-      var ComponentClass = Component.getComponent(componentClassName);
+  return !!Object.getOwnPropertyNames(elData[id]).length;
+}
 
-      if (!ComponentClass) {
-        throw new Error('Component ' + componentClassName + ' does not exist');
-      }
+/**
+ * Delete data for the element from the cache and the guid attr from getElementById
+ *
+ * @param {Element} el
+ *        Remove cached data for this element.
+ */
+function removeData(el) {
+  var id = el[elIdAttr];
 
-      // 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;
-      }
+  if (!id) {
+    return;
+  }
 
-      component = new ComponentClass(this.player_ || this, options);
+  // Remove all stored data
+  delete elData[id];
 
-      // child is a component instance
+  // Remove the elIdAttr property from the DOM node
+  try {
+    delete el[elIdAttr];
+  } catch (e) {
+    if (el.removeAttribute) {
+      el.removeAttribute(elIdAttr);
     } else {
-      component = child;
+      // IE doesn't appear to support removeAttribute on the document element
+      el[elIdAttr] = null;
     }
+  }
+}
 
-    this.children_.splice(index, 0, component);
+/**
+ * @file events.js. An Event System (John Resig - Secrets of a JS Ninja http://jsninja.com/)
+ * (Original book version wasn't completely usable, so fixed some things and made Closure Compiler compatible)
+ * This should work very similarly to jQuery's events, however it's based off the book version which isn't as
+ * robust as jquery's, so there's probably some differences.
+ *
+ * @module events
+ */
 
-    if (typeof component.id === 'function') {
-      this.childIndex_[component.id()] = component;
-    }
+/**
+ * Clean up the listener cache and dispatchers
+ *
+ * @param {Element|Object} elem
+ *        Element to clean up
+ *
+ * @param {string} type
+ *        Type of event to clean up
+ */
+function _cleanUpEvents(elem, type) {
+  var data = getData(elem);
 
-    // 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());
+  // Remove the events of a particular type if there are none left
+  if (data.handlers[type].length === 0) {
+    delete data.handlers[type];
+    // data.handlers[type] = null;
+    // Setting to null was causing an error with data.handlers
 
-    if (componentName) {
-      this.childNameIndex_[componentName] = component;
+    // Remove the meta-handler from the element
+    if (elem.removeEventListener) {
+      elem.removeEventListener(type, data.dispatcher, false);
+    } else if (elem.detachEvent) {
+      elem.detachEvent('on' + type, data.dispatcher);
     }
+  }
 
-    // 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;
+  // Remove the events object if there are no types left
+  if (Object.getOwnPropertyNames(data.handlers).length <= 0) {
+    delete data.handlers;
+    delete data.dispatcher;
+    delete data.disabled;
+  }
 
-      this.contentEl().insertBefore(component.el(), refNode);
-    }
+  // Finally remove the element data if there is no data left
+  if (Object.getOwnPropertyNames(data).length === 0) {
+    removeData(elem);
+  }
+}
 
-    // Return so it can stored on parent object if desired.
-    return component;
-  };
+/**
+ * Loops through an array of event types and calls the requested method for each type.
+ *
+ * @param {Function} fn
+ *        The event method we want to use.
+ *
+ * @param {Element|Object} elem
+ *        Element or object to bind listeners to
+ *
+ * @param {string} type
+ *        Type of event to bind to.
+ *
+ * @param {EventTarget~EventListener} callback
+ *        Event listener.
+ */
+function _handleMultipleEvents(fn, elem, types, callback) {
+  types.forEach(function (type) {
+    // Call the event method for each one of the types
+    fn(elem, type, callback);
+  });
+}
 
-  /**
-   * 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.
-   */
+/**
+ * Fix a native event to have standard property values
+ *
+ * @param {Object} event
+ *        Event object to fix.
+ *
+ * @return {Object}
+ *         Fixed event object.
+ */
+function fixEvent(event) {
+
+  function returnTrue() {
+    return true;
+  }
 
+  function returnFalse() {
+    return false;
+  }
 
-  Component.prototype.removeChild = function removeChild(component) {
-    if (typeof component === 'string') {
-      component = this.getChild(component);
+  // Test if fixing up is needed
+  // Used to check if !event.stopPropagation instead of isPropagationStopped
+  // But native events return true for stopPropagation, but don't have
+  // other expected methods like isPropagationStopped. Seems to be a problem
+  // with the Javascript Ninja code. So we're just overriding all events now.
+  if (!event || !event.isPropagationStopped) {
+    var old = event || window_1.event;
+
+    event = {};
+    // Clone the old object so that we can modify the values event = {};
+    // IE8 Doesn't like when you mess with native event properties
+    // Firefox returns false for event.hasOwnProperty('type') and other props
+    //  which makes copying more difficult.
+    // TODO: Probably best to create a whitelist of event props
+    for (var key in old) {
+      // Safari 6.0.3 warns you if you try to copy deprecated layerX/Y
+      // Chrome warns you if you try to copy deprecated keyboardEvent.keyLocation
+      // and webkitMovementX/Y
+      if (key !== 'layerX' && key !== 'layerY' && key !== 'keyLocation' && key !== 'webkitMovementX' && key !== 'webkitMovementY') {
+        // Chrome 32+ warns if you try to copy deprecated returnValue, but
+        // we still want to if preventDefault isn't supported (IE8).
+        if (!(key === 'returnValue' && old.preventDefault)) {
+          event[key] = old[key];
+        }
+      }
     }
 
-    if (!component || !this.children_) {
-      return;
+    // The event occurred on this element
+    if (!event.target) {
+      event.target = event.srcElement || document_1;
     }
 
-    var childFound = false;
+    // Handle which other element the event is related to
+    if (!event.relatedTarget) {
+      event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
+    }
 
-    for (var i = this.children_.length - 1; i >= 0; i--) {
-      if (this.children_[i] === component) {
-        childFound = true;
-        this.children_.splice(i, 1);
-        break;
+    // Stop the default browser action
+    event.preventDefault = function () {
+      if (old.preventDefault) {
+        old.preventDefault();
       }
-    }
+      event.returnValue = false;
+      old.returnValue = false;
+      event.defaultPrevented = true;
+    };
 
-    if (!childFound) {
-      return;
+    event.defaultPrevented = false;
+
+    // Stop the event from bubbling
+    event.stopPropagation = function () {
+      if (old.stopPropagation) {
+        old.stopPropagation();
+      }
+      event.cancelBubble = true;
+      old.cancelBubble = true;
+      event.isPropagationStopped = returnTrue;
+    };
+
+    event.isPropagationStopped = returnFalse;
+
+    // Stop the event from bubbling and executing other handlers
+    event.stopImmediatePropagation = function () {
+      if (old.stopImmediatePropagation) {
+        old.stopImmediatePropagation();
+      }
+      event.isImmediatePropagationStopped = returnTrue;
+      event.stopPropagation();
+    };
+
+    event.isImmediatePropagationStopped = returnFalse;
+
+    // Handle mouse position
+    if (event.clientX !== null && event.clientX !== undefined) {
+      var doc = document_1.documentElement;
+      var body = document_1.body;
+
+      event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
+      event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
     }
 
-    this.childIndex_[component.id()] = null;
-    this.childNameIndex_[component.name()] = null;
+    // Handle key presses
+    event.which = event.charCode || event.keyCode;
 
-    var compEl = component.el();
+    // Fix button for mouse clicks:
+    // 0 == left; 1 == middle; 2 == right
+    if (event.button !== null && event.button !== undefined) {
 
-    if (compEl && compEl.parentNode === this.contentEl()) {
-      this.contentEl().removeChild(component.el());
+      // The following is disabled because it does not pass videojs-standard
+      // and... yikes.
+      /* eslint-disable */
+      event.button = event.button & 1 ? 0 : event.button & 4 ? 1 : event.button & 2 ? 2 : 0;
+      /* eslint-enable */
     }
-  };
+  }
 
-  /**
-   * Add and initialize default child `Component`s based upon options.
-   */
+  // Returns fixed-up instance
+  return event;
+}
 
+/**
+ * Whether passive event listeners are supported
+ */
+var _supportsPassive = false;
 
-  Component.prototype.initChildren = function initChildren() {
-    var _this = this;
+(function () {
+  try {
+    var opts = Object.defineProperty({}, 'passive', {
+      get: function get() {
+        _supportsPassive = true;
+      }
+    });
 
-    var children = this.options_.children;
+    window_1.addEventListener('test', null, opts);
+  } catch (e) {
+    // disregard
+  }
+})();
 
-    if (children) {
-      // `this` is `parent`
-      var parentOptions = this.options_;
+/**
+ * Touch events Chrome expects to be passive
+ */
+var passiveEvents = ['touchstart', 'touchmove'];
 
-      var handleAdd = function handleAdd(child) {
-        var name = child.name;
-        var opts = child.opts;
+/**
+ * Add an event listener to element
+ * It stores the handler function in a separate cache object
+ * and adds a generic handler to the element's event,
+ * along with a unique id (guid) to the element.
+ *
+ * @param {Element|Object} elem
+ *        Element or object to bind listeners to
+ *
+ * @param {string|string[]} type
+ *        Type of event to bind to.
+ *
+ * @param {EventTarget~EventListener} fn
+ *        Event listener.
+ */
+function on(elem, type, fn) {
+  if (Array.isArray(type)) {
+    return _handleMultipleEvents(on, elem, type, fn);
+  }
 
-        // 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];
-        }
+  var data = getData(elem);
 
-        // Allow for disabling default components
-        // e.g. options['children']['posterImage'] = false
-        if (opts === false) {
-          return;
-        }
+  // We need a place to store all our handler data
+  if (!data.handlers) {
+    data.handlers = {};
+  }
 
-        // Allow options to be passed as a simple boolean if no configuration
-        // is necessary.
-        if (opts === true) {
-          opts = {};
-        }
+  if (!data.handlers[type]) {
+    data.handlers[type] = [];
+  }
 
-        // 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;
+  if (!fn.guid) {
+    fn.guid = newGUID();
+  }
 
-        // 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);
+  data.handlers[type].push(fn);
 
-        if (newChild) {
-          _this[name] = newChild;
-        }
-      };
+  if (!data.dispatcher) {
+    data.disabled = false;
 
-      // Allow for an array of children details to passed in the options
-      var workingChildren = void 0;
-      var Tech = Component.getComponent('Tech');
+    data.dispatcher = function (event, hash) {
 
-      if (Array.isArray(children)) {
-        workingChildren = children;
-      } else {
-        workingChildren = Object.keys(children);
+      if (data.disabled) {
+        return;
       }
 
-      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;
+      event = fixEvent(event);
 
-        if (typeof child === 'string') {
-          name = child;
-          opts = children[name] || _this.options_[name] || {};
-        } else {
-          name = child.name;
-          opts = child;
-        }
+      var handlers = data.handlers[event.type];
 
-        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));
+      if (handlers) {
+        // Copy handlers so if handlers are added/removed during the process it doesn't throw everything off.
+        var handlersCopy = handlers.slice(0);
 
-        return c && !Tech.isTech(c);
-      }).forEach(handleAdd);
-    }
-  };
+        for (var m = 0, n = handlersCopy.length; m < n; m++) {
+          if (event.isImmediatePropagationStopped()) {
+            break;
+          } else {
+            try {
+              handlersCopy[m].call(elem, event, hash);
+            } catch (e) {
+              log$1.error(e);
+            }
+          }
+        }
+      }
+    };
+  }
 
-  /**
-   * Builds the default DOM class name. Should be overriden by sub-components.
-   *
-   * @return {string}
-   *         The DOM class name for this object.
-   *
-   * @abstract
-   */
+  if (data.handlers[type].length === 1) {
+    if (elem.addEventListener) {
+      var options = false;
 
+      if (_supportsPassive && passiveEvents.indexOf(type) > -1) {
+        options = { passive: true };
+      }
+      elem.addEventListener(type, data.dispatcher, options);
+    } else if (elem.attachEvent) {
+      elem.attachEvent('on' + type, data.dispatcher);
+    }
+  }
+}
 
-  Component.prototype.buildCSSClass = function buildCSSClass() {
-    // Child classes can include a function that does:
-    // return 'CLASS NAME' + this._super();
-    return '';
-  };
+/**
+ * Removes event listeners from an element
+ *
+ * @param {Element|Object} elem
+ *        Object to remove listeners from.
+ *
+ * @param {string|string[]} [type]
+ *        Type of listener to remove. Don't include to remove all events from element.
+ *
+ * @param {EventTarget~EventListener} [fn]
+ *        Specific listener to remove. Don't include to remove listeners for an event
+ *        type.
+ */
+function off(elem, type, fn) {
+  // Don't want to add a cache object through getElData if not needed
+  if (!hasData(elem)) {
+    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
-   */
+  var data = getData(elem);
 
+  // If no events exist, nothing to unbind
+  if (!data.handlers) {
+    return;
+  }
 
-  Component.prototype.on = function on(first, second, third) {
-    var _this2 = this;
+  if (Array.isArray(type)) {
+    return _handleMultipleEvents(off, elem, type, fn);
+  }
 
-    if (typeof first === 'string' || Array.isArray(first)) {
-      Events.on(this.el_, first, Fn.bind(this, second));
+  // Utility function
+  var removeType = function removeType(t) {
+    data.handlers[t] = [];
+    _cleanUpEvents(elem, t);
+  };
 
-      // Targeting another component or element
-    } else {
-      var target = first;
-      var type = second;
-      var fn = Fn.bind(this, third);
+  // Are we removing all bound events?
+  if (!type) {
+    for (var t in data.handlers) {
+      removeType(t);
+    }
+    return;
+  }
 
-      // When this component is disposed, remove the listener from the other component
-      var removeOnDispose = function removeOnDispose() {
-        return _this2.off(target, type, fn);
-      };
+  var handlers = data.handlers[type];
 
-      // 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 no handlers exist, nothing to unbind
+  if (!handlers) {
+    return;
+  }
 
-      // 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);
-      };
+  // If no listener was provided, remove all listeners for type
+  if (!fn) {
+    removeType(type);
+    return;
+  }
 
-      // 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);
+  // We're only removing a single handler
+  if (fn.guid) {
+    for (var n = 0; n < handlers.length; n++) {
+      if (handlers[n].guid === fn.guid) {
+        handlers.splice(n--, 1);
       }
     }
+  }
 
-    return this;
-  };
+  _cleanUpEvents(elem, type);
+}
 
-  /**
-   * 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.
-   */
+/**
+ * Trigger an event for an element
+ *
+ * @param {Element|Object} elem
+ *        Element to trigger an event on
+ *
+ * @param {EventTarget~Event|string} event
+ *        A string (the type) or an event object with a type attribute
+ *
+ * @param {Object} [hash]
+ *        data hash to pass along with the event
+ *
+ * @return {boolean|undefined}
+ *         - Returns the opposite of `defaultPrevented` if default was prevented
+ *         - Otherwise returns undefined
+ */
+function trigger(elem, event, hash) {
+  // Fetches element data and a reference to the parent (for bubbling).
+  // Don't want to add a data object to cache for every parent,
+  // so checking hasElData first.
+  var elemData = hasData(elem) ? getData(elem) : {};
+  var parent = elem.parentNode || elem.ownerDocument;
+  // type = event.type || event,
+  // handler;
+
+  // If an event name was passed as a string, creates an event out of it
+  if (typeof event === 'string') {
+    event = { type: event, target: elem };
+  }
+  // Normalizes the event properties.
+  event = fixEvent(event);
 
+  // If the passed element has a dispatcher, executes the established handlers.
+  if (elemData.dispatcher) {
+    elemData.dispatcher.call(elem, event, hash);
+  }
 
-  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);
+  // Unless explicitly stopped or the event does not bubble (e.g. media events)
+  // recursively calls this function to bubble the event up the DOM.
+  if (parent && !event.isPropagationStopped() && event.bubbles === true) {
+    trigger.call(null, parent, event, hash);
 
-      // Remove the dispose listener on this component,
-      // which was given the same guid as the event listener
-      this.off('dispose', fn);
+    // If at the top of the DOM, triggers the default action unless disabled.
+  } else if (!parent && !event.defaultPrevented) {
+    var targetData = getData(event.target);
 
-      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);
+    // Checks if the target has a default action for this event.
+    if (event.target[event.type]) {
+      // Temporarily disables event dispatching on the target as we have already executed the handler.
+      targetData.disabled = true;
+      // Executes the default action.
+      if (typeof event.target[event.type] === 'function') {
+        event.target[event.type]();
       }
+      // Re-enables event dispatching.
+      targetData.disabled = false;
     }
+  }
 
-    return this;
+  // Inform the triggerer if the default was prevented by returning false
+  return !event.defaultPrevented;
+}
+
+/**
+ * Trigger a listener only once for an event
+ *
+ * @param {Element|Object} elem
+ *        Element or object to bind to.
+ *
+ * @param {string|string[]} type
+ *        Name/type of event
+ *
+ * @param {Event~EventListener} fn
+ *        Event Listener function
+ */
+function one(elem, type, fn) {
+  if (Array.isArray(type)) {
+    return _handleMultipleEvents(one, elem, type, fn);
+  }
+  var func = function func() {
+    off(elem, type, func);
+    fn.apply(this, arguments);
   };
 
-  /**
-   * 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.
-   */
+  // copy the guid to the new function so it can removed using the original function's ID
+  func.guid = fn.guid = fn.guid || newGUID();
+  on(elem, type, func);
+}
 
+var Events = (Object.freeze || Object)({
+       fixEvent: fixEvent,
+       on: on,
+       off: off,
+       trigger: trigger,
+       one: one
+});
 
-  Component.prototype.one = function one(first, second, third) {
-    var _this3 = this,
-        _arguments = arguments;
+/**
+ * @file setup.js - Functions for setting up a player without
+ * user interaction based on the data-setup `attribute` of the video tag.
+ *
+ * @module setup
+ */
+var _windowLoaded = false;
+var videojs$2 = void 0;
 
-    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);
+/**
+ * Set up any tags that have a data-setup `attribute` when the player is started.
+ */
+var autoSetup = function autoSetup() {
 
-      var newFunc = function newFunc() {
-        _this3.off(target, type, newFunc);
-        fn.apply(null, _arguments);
-      };
+  // Protect against breakage in non-browser environments.
+  if (!isReal()) {
+    return;
+  }
 
-      // Keep the same function ID so we can remove it later
-      newFunc.guid = fn.guid;
+  // One day, when we stop supporting IE8, go back to this, but in the meantime...*hack hack hack*
+  // var vids = Array.prototype.slice.call(document.getElementsByTagName('video'));
+  // var audios = Array.prototype.slice.call(document.getElementsByTagName('audio'));
+  // var mediaEls = vids.concat(audios);
 
-      this.on(target, type, newFunc);
-    }
-
-    return this;
-  };
+  // Because IE8 doesn't support calling slice on a node list, we need to loop
+  // through each list of elements to build up a new, combined list of elements.
+  var vids = document_1.getElementsByTagName('video');
+  var audios = document_1.getElementsByTagName('audio');
+  var mediaEls = [];
 
-  /**
-   * 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.
-   */
+  if (vids && vids.length > 0) {
+    for (var i = 0, e = vids.length; i < e; i++) {
+      mediaEls.push(vids[i]);
+    }
+  }
 
+  if (audios && audios.length > 0) {
+    for (var _i = 0, _e = audios.length; _i < _e; _i++) {
+      mediaEls.push(audios[_i]);
+    }
+  }
 
-  Component.prototype.trigger = function trigger(event, hash) {
-    Events.trigger(this.el_, event, hash);
-    return this;
-  };
+  // Check if any media elements exist
+  if (mediaEls && mediaEls.length > 0) {
 
-  /**
-   * 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.
-   */
+    for (var _i2 = 0, _e2 = mediaEls.length; _i2 < _e2; _i2++) {
+      var mediaEl = mediaEls[_i2];
 
+      // Check if element exists, has getAttribute func.
+      // IE seems to consider typeof el.getAttribute == 'object' instead of
+      // 'function' like expected, at least when loading the player immediately.
+      if (mediaEl && mediaEl.getAttribute) {
 
-  Component.prototype.ready = function ready(fn) {
-    var sync = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
+        // Make sure this player hasn't already been set up.
+        if (mediaEl.player === undefined) {
+          var options = mediaEl.getAttribute('data-setup');
 
-    if (fn) {
-      if (this.isReady_) {
-        if (sync) {
-          fn.call(this);
-        } else {
-          // Call the function asynchronously by default for consistency
-          this.setTimeout(fn, 1);
+          // Check if data-setup attr exists.
+          // We only auto-setup if they've added the data-setup attr.
+          if (options !== null) {
+            // Create new video.js instance.
+            videojs$2(mediaEl);
+          }
         }
+
+        // If getAttribute isn't defined, we need to wait for the DOM.
       } else {
-        this.readyQueue_ = this.readyQueue_ || [];
-        this.readyQueue_.push(fn);
+        autoSetupTimeout(1);
+        break;
       }
     }
-    return this;
-  };
 
+    // No videos were found, so keep looping unless page is finished loading.
+  } else if (!_windowLoaded) {
+    autoSetupTimeout(1);
+  }
+};
+
+/**
+ * Wait until the page is loaded before running autoSetup. This will be called in
+ * autoSetup if `hasLoaded` returns false.
+ *
+ * @param {number} wait
+ *        How long to wait in ms
+ *
+ * @param {module:videojs} [vjs]
+ *        The videojs library function
+ */
+function autoSetupTimeout(wait, vjs) {
+  if (vjs) {
+    videojs$2 = vjs;
+  }
+
+  window_1.setTimeout(autoSetup, wait);
+}
+
+if (isReal() && document_1.readyState === 'complete') {
+  _windowLoaded = true;
+} else {
   /**
-   * Trigger all the ready listeners for this `Component`.
+   * Listen for the load event on window, and set _windowLoaded to true.
    *
-   * @fires Component#ready
+   * @listens load
    */
+  one(window_1, 'load', function () {
+    _windowLoaded = true;
+  });
+}
 
+/**
+ * @file stylesheet.js
+ * @module stylesheet
+ */
+/**
+ * Create a DOM syle element given a className for it.
+ *
+ * @param {string} className
+ *        The className to add to the created style element.
+ *
+ * @return {Element}
+ *         The element that was created.
+ */
+var createStyleElement = function createStyleElement(className) {
+  var style = document_1.createElement('style');
 
-  Component.prototype.triggerReady = function triggerReady() {
-    this.isReady_ = true;
+  style.className = className;
 
-    // Ensure ready is triggerd asynchronously
-    this.setTimeout(function () {
-      var readyQueue = this.readyQueue_;
+  return style;
+};
 
-      // Reset Ready Queue
-      this.readyQueue_ = [];
+/**
+ * Add text to a DOM element.
+ *
+ * @param {Element} el
+ *        The Element to add text content to.
+ *
+ * @param {string} content
+ *        The text to add to the element.
+ */
+var setTextContent = function setTextContent(el, content) {
+  if (el.styleSheet) {
+    el.styleSheet.cssText = content;
+  } else {
+    el.textContent = content;
+  }
+};
 
-      if (readyQueue && readyQueue.length > 0) {
-        readyQueue.forEach(function (fn) {
-          fn.call(this);
-        }, this);
-      }
+/**
+ * @file fn.js
+ * @module fn
+ */
+/**
+ * Bind (a.k.a proxy or Context). A simple method for changing the context of a function
+ * It also stores a unique id on the function so it can be easily removed from events.
+ *
+ * @param {Mixed} context
+ *        The object to bind as scope.
+ *
+ * @param {Function} fn
+ *        The function to be bound to a scope.
+ *
+ * @param {number} [uid]
+ *        An optional unique ID for the function to be set
+ *
+ * @return {Function}
+ *         The new function that will be bound into the context given
+ */
+var bind = function bind(context, fn, uid) {
+  // Make sure the function has a unique ID
+  if (!fn.guid) {
+    fn.guid = newGUID();
+  }
 
-      // Allow for using event listeners also
-      /**
-       * Triggered when a `Component` is ready.
-       *
-       * @event Component#ready
-       * @type {EventTarget~Event}
-       */
-      this.trigger('ready');
-    }, 1);
+  // Create the new function that changes the context
+  var bound = function bound() {
+    return fn.apply(context, arguments);
   };
 
-  /**
-   * 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)
-   */
-
+  // Allow for the ability to individualize this function
+  // Needed in the case where multiple objects might share the same prototype
+  // IF both items add an event listener with the same function, then you try to remove just one
+  // it will remove both because they both have the same guid.
+  // when using this, you need to use the bind method when you remove the listener as well.
+  // currently used in text tracks
+  bound.guid = uid ? uid + '_' + fn.guid : fn.guid;
 
-  Component.prototype.$ = function $(selector, context) {
-    return Dom.$(selector, context || this.contentEl());
-  };
+  return bound;
+};
 
-  /**
-   * 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)
-   */
+/**
+ * Wraps the given function, `fn`, with a new function that only invokes `fn`
+ * at most once per every `wait` milliseconds.
+ *
+ * @param  {Function} fn
+ *         The function to be throttled.
+ *
+ * @param  {Number}   wait
+ *         The number of milliseconds by which to throttle.
+ *
+ * @return {Function}
+ */
+var throttle = function throttle(fn, wait) {
+  var last = Date.now();
 
+  var throttled = function throttled() {
+    var now = Date.now();
 
-  Component.prototype.$$ = function $$(selector, context) {
-    return Dom.$$(selector, context || this.contentEl());
+    if (now - last >= wait) {
+      fn.apply(undefined, arguments);
+      last = now;
+    }
   };
 
-  /**
-   * 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);
-  };
+  return throttled;
+};
 
-  /**
-   * 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.
-   */
+/**
+ * @file src/js/event-target.js
+ */
+/**
+ * `EventTarget` is a class that can have the same API as the DOM `EventTarget`. It
+ * adds shorthand functions that wrap around lengthy functions. For example:
+ * the `on` function is a wrapper around `addEventListener`.
+ *
+ * @see [EventTarget Spec]{@link https://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventTarget}
+ * @class EventTarget
+ */
+var EventTarget = function EventTarget() {};
 
+/**
+ * A Custom DOM event.
+ *
+ * @typedef {Object} EventTarget~Event
+ * @see [Properties]{@link https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent}
+ */
 
-  Component.prototype.addClass = function addClass(classToAdd) {
-    Dom.addElClass(this.el_, classToAdd);
-    return this;
-  };
+/**
+ * All event listeners should follow the following format.
+ *
+ * @callback EventTarget~EventListener
+ * @this {EventTarget}
+ *
+ * @param {EventTarget~Event} event
+ *        the event that triggered this function
+ *
+ * @param {Object} [hash]
+ *        hash of data sent during the event
+ */
 
-  /**
-   * 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.
-   */
+/**
+ * An object containing event names as keys and booleans as values.
+ *
+ * > NOTE: If an event name is set to a true value here {@link EventTarget#trigger}
+ *         will have extra functionality. See that function for more information.
+ *
+ * @property EventTarget.prototype.allowedEvents_
+ * @private
+ */
+EventTarget.prototype.allowedEvents_ = {};
 
+/**
+ * Adds an `event listener` to an instance of an `EventTarget`. An `event listener` is a
+ * function that will get called when an event with a certain name gets triggered.
+ *
+ * @param {string|string[]} type
+ *        An event name or an array of event names.
+ *
+ * @param {EventTarget~EventListener} fn
+ *        The function to call with `EventTarget`s
+ */
+EventTarget.prototype.on = function (type, fn) {
+  // Remove the addEventListener alias before calling Events.on
+  // so we don't get into an infinite type loop
+  var ael = this.addEventListener;
 
-  Component.prototype.removeClass = function removeClass(classToRemove) {
-    Dom.removeElClass(this.el_, classToRemove);
-    return this;
-  };
+  this.addEventListener = function () {};
+  on(this, type, fn);
+  this.addEventListener = ael;
+};
 
-  /**
-   * 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.
-   */
+/**
+ * An alias of {@link EventTarget#on}. Allows `EventTarget` to mimic
+ * the standard DOM API.
+ *
+ * @function
+ * @see {@link EventTarget#on}
+ */
+EventTarget.prototype.addEventListener = EventTarget.prototype.on;
 
+/**
+ * Removes an `event listener` for a specific event from an instance of `EventTarget`.
+ * This makes it so that the `event listener` will no longer get called when the
+ * named event happens.
+ *
+ * @param {string|string[]} type
+ *        An event name or an array of event names.
+ *
+ * @param {EventTarget~EventListener} fn
+ *        The function to remove.
+ */
+EventTarget.prototype.off = function (type, fn) {
+  off(this, type, fn);
+};
 
-  Component.prototype.toggleClass = function toggleClass(classToToggle, predicate) {
-    Dom.toggleElClass(this.el_, classToToggle, predicate);
-    return this;
-  };
+/**
+ * An alias of {@link EventTarget#off}. Allows `EventTarget` to mimic
+ * the standard DOM API.
+ *
+ * @function
+ * @see {@link EventTarget#off}
+ */
+EventTarget.prototype.removeEventListener = EventTarget.prototype.off;
 
-  /**
-   * 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.
-   */
+/**
+ * This function will add an `event listener` that gets triggered only once. After the
+ * first trigger it will get removed. This is like adding an `event listener`
+ * with {@link EventTarget#on} that calls {@link EventTarget#off} on itself.
+ *
+ * @param {string|string[]} type
+ *        An event name or an array of event names.
+ *
+ * @param {EventTarget~EventListener} fn
+ *        The function to be called once for each event name.
+ */
+EventTarget.prototype.one = function (type, fn) {
+  // Remove the addEventListener alialing Events.on
+  // so we don't get into an infinite type loop
+  var ael = this.addEventListener;
 
+  this.addEventListener = function () {};
+  one(this, type, fn);
+  this.addEventListener = ael;
+};
 
-  Component.prototype.show = function show() {
-    this.removeClass('vjs-hidden');
-    return this;
-  };
+/**
+ * This function causes an event to happen. This will then cause any `event listeners`
+ * that are waiting for that event, to get called. If there are no `event listeners`
+ * for an event then nothing will happen.
+ *
+ * If the name of the `Event` that is being triggered is in `EventTarget.allowedEvents_`.
+ * Trigger will also call the `on` + `uppercaseEventName` function.
+ *
+ * Example:
+ * 'click' is in `EventTarget.allowedEvents_`, so, trigger will attempt to call
+ * `onClick` if it exists.
+ *
+ * @param {string|EventTarget~Event|Object} event
+ *        The name of the event, an `Event`, or an object with a key of type set to
+ *        an event name.
+ */
+EventTarget.prototype.trigger = function (event) {
+  var type = event.type || event;
 
-  /**
-   * 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.
-   */
+  if (typeof event === 'string') {
+    event = { type: type };
+  }
+  event = fixEvent(event);
 
+  if (this.allowedEvents_[type] && this['on' + type]) {
+    this['on' + type](event);
+  }
 
-  Component.prototype.hide = function hide() {
-    this.addClass('vjs-hidden');
-    return this;
-  };
+  trigger(this, event);
+};
 
-  /**
-   * 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
-   */
+/**
+ * An alias of {@link EventTarget#trigger}. Allows `EventTarget` to mimic
+ * the standard DOM API.
+ *
+ * @function
+ * @see {@link EventTarget#trigger}
+ */
+EventTarget.prototype.dispatchEvent = EventTarget.prototype.trigger;
 
+/**
+ * @file mixins/evented.js
+ * @module evented
+ */
+/**
+ * Returns whether or not an object has had the evented mixin applied.
+ *
+ * @param  {Object} object
+ *         An object to test.
+ *
+ * @return {boolean}
+ *         Whether or not the object appears to be evented.
+ */
+var isEvented = function isEvented(object) {
+  return object instanceof EventTarget || !!object.eventBusEl_ && ['on', 'one', 'off', 'trigger'].every(function (k) {
+    return typeof object[k] === 'function';
+  });
+};
 
-  Component.prototype.lockShowing = function lockShowing() {
-    this.addClass('vjs-lock-showing');
-    return this;
-  };
+/**
+ * Whether a value is a valid event type - non-empty string or array.
+ *
+ * @private
+ * @param  {string|Array} type
+ *         The type value to test.
+ *
+ * @return {boolean}
+ *         Whether or not the type is a valid event type.
+ */
+var isValidEventType = function isValidEventType(type) {
+  return (
+    // The regex here verifies that the `type` contains at least one non-
+    // whitespace character.
+    typeof type === 'string' && /\S/.test(type) || Array.isArray(type) && !!type.length
+  );
+};
 
-  /**
-   * 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
-   */
+/**
+ * Validates a value to determine if it is a valid event target. Throws if not.
+ *
+ * @private
+ * @throws {Error}
+ *         If the target does not appear to be a valid event target.
+ *
+ * @param  {Object} target
+ *         The object to test.
+ */
+var validateTarget = function validateTarget(target) {
+  if (!target.nodeName && !isEvented(target)) {
+    throw new Error('Invalid target; must be a DOM node or evented object.');
+  }
+};
 
+/**
+ * Validates a value to determine if it is a valid event target. Throws if not.
+ *
+ * @private
+ * @throws {Error}
+ *         If the type does not appear to be a valid event type.
+ *
+ * @param  {string|Array} type
+ *         The type to test.
+ */
+var validateEventType = function validateEventType(type) {
+  if (!isValidEventType(type)) {
+    throw new Error('Invalid event type; must be a non-empty string or array.');
+  }
+};
 
-  Component.prototype.unlockShowing = function unlockShowing() {
-    this.removeClass('vjs-lock-showing');
-    return this;
-  };
+/**
+ * Validates a value to determine if it is a valid listener. Throws if not.
+ *
+ * @private
+ * @throws {Error}
+ *         If the listener is not a function.
+ *
+ * @param  {Function} listener
+ *         The listener to test.
+ */
+var validateListener = function validateListener(listener) {
+  if (typeof listener !== 'function') {
+    throw new Error('Invalid listener; must be a function.');
+  }
+};
 
-  /**
-   * 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}
-   */
+/**
+ * Takes an array of arguments given to `on()` or `one()`, validates them, and
+ * normalizes them into an object.
+ *
+ * @private
+ * @param  {Object} self
+ *         The evented object on which `on()` or `one()` was called. This
+ *         object will be bound as the `this` value for the listener.
+ *
+ * @param  {Array} args
+ *         An array of arguments passed to `on()` or `one()`.
+ *
+ * @return {Object}
+ *         An object containing useful values for `on()` or `one()` calls.
+ */
+var normalizeListenArgs = function normalizeListenArgs(self, args) {
 
+  // If the number of arguments is less than 3, the target is always the
+  // evented object itself.
+  var isTargetingSelf = args.length < 3 || args[0] === self || args[0] === self.eventBusEl_;
+  var target = void 0;
+  var type = void 0;
+  var listener = void 0;
 
-  Component.prototype.getAttribute = function getAttribute(attribute) {
-    return Dom.getAttribute(this.el_, attribute);
-  };
+  if (isTargetingSelf) {
+    target = self.eventBusEl_;
 
-  /**
-   * 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}
-   */
+    // Deal with cases where we got 3 arguments, but we are still listening to
+    // the evented object itself.
+    if (args.length >= 3) {
+      args.shift();
+    }
 
+    type = args[0];
+    listener = args[1];
+  } else {
+    target = args[0];
+    type = args[1];
+    listener = args[2];
+  }
 
-  Component.prototype.setAttribute = function setAttribute(attribute, value) {
-    Dom.setAttribute(this.el_, attribute, value);
-    return this;
-  };
+  validateTarget(target);
+  validateEventType(type);
+  validateListener(listener);
 
-  /**
-   * 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}
-   */
+  listener = bind(self, listener);
 
+  return { isTargetingSelf: isTargetingSelf, target: target, type: type, listener: listener };
+};
 
-  Component.prototype.removeAttribute = function removeAttribute(attribute) {
-    Dom.removeAttribute(this.el_, attribute);
-    return this;
-  };
+/**
+ * Adds the listener to the event type(s) on the target, normalizing for
+ * the type of target.
+ *
+ * @private
+ * @param  {Element|Object} target
+ *         A DOM node or evented object.
+ *
+ * @param  {string} method
+ *         The event binding method to use ("on" or "one").
+ *
+ * @param  {string|Array} type
+ *         One or more event type(s).
+ *
+ * @param  {Function} listener
+ *         A listener function.
+ */
+var listen = function listen(target, method, type, listener) {
+  validateTarget(target);
+
+  if (target.nodeName) {
+    Events[method](target, type, listener);
+  } else {
+    target[method](type, listener);
+  }
+};
+
+/**
+ * Contains methods that provide event capabilites to an object which is passed
+ * to {@link module:evented|evented}.
+ *
+ * @mixin EventedMixin
+ */
+var EventedMixin = {
 
   /**
-   * Get or set the width of the component based upon the CSS styles.
-   * See {@link Component#dimension} for more detailed information.
+   * Add a listener to an event (or events) on this object or another evented
+   * object.
    *
-   * @param {number|string} [num]
-   *        The width that you want to set postfixed with '%', 'px' or nothing.
+   * @param  {string|Array|Element|Object} targetOrType
+   *         If this is a string or array, it represents the event type(s)
+   *         that will trigger the listener.
    *
-   * @param {boolean} [skipListeners]
-   *        Skip the resize event trigger
+   *         Another evented object can be passed here instead, which will
+   *         cause the listener to listen for events on _that_ object.
    *
-   * @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.
+   *         In either case, the listener's `this` value will be bound to
+   *         this object.
+   *
+   * @param  {string|Array|Function} typeOrListener
+   *         If the first argument was a string or array, this should be the
+   *         listener function. Otherwise, this is a string or array of event
+   *         type(s).
+   *
+   * @param  {Function} [listener]
+   *         If the first argument was another evented object, this will be
+   *         the listener function.
    */
+  on: function on$$1() {
+    var _this = this;
 
+    for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
+      args[_key] = arguments[_key];
+    }
 
-  Component.prototype.width = function width(num, skipListeners) {
-    return this.dimension('width', num, skipListeners);
-  };
+    var _normalizeListenArgs = normalizeListenArgs(this, args),
+        isTargetingSelf = _normalizeListenArgs.isTargetingSelf,
+        target = _normalizeListenArgs.target,
+        type = _normalizeListenArgs.type,
+        listener = _normalizeListenArgs.listener;
 
-  /**
-   * 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.
-   */
+    listen(target, 'on', type, listener);
 
+    // If this object is listening to another evented object.
+    if (!isTargetingSelf) {
 
-  Component.prototype.height = function height(num, skipListeners) {
-    return this.dimension('height', num, skipListeners);
-  };
+      // If this object is disposed, remove the listener.
+      var removeListenerOnDispose = function removeListenerOnDispose() {
+        return _this.off(target, type, listener);
+      };
 
-  /**
-   * 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.
-   */
+      // Use the same function ID as the listener so we can remove it later it
+      // using the ID of the original listener.
+      removeListenerOnDispose.guid = listener.guid;
+
+      // Add a listener to the target's dispose event as well. This ensures
+      // that if the target is disposed BEFORE this object, we remove the
+      // removal listener that was just added. Otherwise, we create a memory leak.
+      var removeRemoverOnTargetDispose = function removeRemoverOnTargetDispose() {
+        return _this.off('dispose', removeListenerOnDispose);
+      };
 
+      // Use the same function ID as the listener so we can remove it later
+      // it using the ID of the original listener.
+      removeRemoverOnTargetDispose.guid = listener.guid;
+
+      listen(this, 'on', 'dispose', removeListenerOnDispose);
+      listen(target, 'on', 'dispose', removeRemoverOnTargetDispose);
+    }
+  },
 
-  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}
+   * Add a listener to an event (or events) on this object or another evented
+   * object. The listener will only be called once and then removed.
    *
-   * @fires Component#resize
+   * @param  {string|Array|Element|Object} targetOrType
+   *         If this is a string or array, it represents the event type(s)
+   *         that will trigger the listener.
    *
-   * @param {string} widthOrHeight
-   8        'width' or 'height'
+   *         Another evented object can be passed here instead, which will
+   *         cause the listener to listen for events on _that_ object.
    *
-   * @param  {number|string} [num]
-   8         New dimension
+   *         In either case, the listener's `this` value will be bound to
+   *         this object.
    *
-   * @param  {boolean} [skipListeners]
-   *         Skip resize event trigger
+   * @param  {string|Array|Function} typeOrListener
+   *         If the first argument was a string or array, this should be the
+   *         listener function. Otherwise, this is a string or array of event
+   *         type(s).
    *
-   * @return {Component}
-   *         - the dimension when getting or 0 if unset
-   *         - Returns itself when setting; method can be chained.
+   * @param  {Function} [listener]
+   *         If the first argument was another evented object, this will be
+   *         the listener function.
    */
+  one: function one$$1() {
+    var _this2 = this;
 
+    for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
+      args[_key2] = arguments[_key2];
+    }
 
-  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;
-      }
+    var _normalizeListenArgs2 = normalizeListenArgs(this, args),
+        isTargetingSelf = _normalizeListenArgs2.isTargetingSelf,
+        target = _normalizeListenArgs2.target,
+        type = _normalizeListenArgs2.type,
+        listener = _normalizeListenArgs2.listener;
 
-      // 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';
-      }
+    // Targeting this evented object.
 
-      // 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;
-    }
+    if (isTargetingSelf) {
+      listen(target, 'one', type, listener);
 
-    // Not setting a value, so getting it
-    // Make sure element exists
-    if (!this.el_) {
-      return 0;
-    }
+      // Targeting another evented object.
+    } else {
+      var wrapper = function wrapper() {
+        for (var _len3 = arguments.length, largs = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
+          largs[_key3] = arguments[_key3];
+        }
 
-    // Get dimension value from style
-    var val = this.el_.style[widthOrHeight];
-    var pxIndex = val.indexOf('px');
+        _this2.off(target, type, wrapper);
+        listener.apply(null, largs);
+      };
 
-    if (pxIndex !== -1) {
-      // Return the pixel value with no 'px'
-      return parseInt(val.slice(0, pxIndex), 10);
+      // Use the same function ID as the listener so we can remove it later
+      // it using the ID of the original listener.
+      wrapper.guid = listener.guid;
+      listen(target, 'one', type, wrapper);
     }
+  },
 
-    // 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`.
+   * Removes listener(s) from event(s) on an evented object.
    *
-   * @param {string} widthOrHeight
-   *        A string containing 'width' or 'height'. Whichever one you want to get.
+   * @param  {string|Array|Element|Object} [targetOrType]
+   *         If this is a string or array, it represents the event type(s).
    *
-   * @return {number}
-   *         The dimension that gets asked for or 0 if nothing was set
-   *         for that dimension.
+   *         Another evented object can be passed here instead, in which case
+   *         ALL 3 arguments are _required_.
+   *
+   * @param  {string|Array|Function} [typeOrListener]
+   *         If the first argument was a string or array, this may be the
+   *         listener function. Otherwise, this is a string or array of event
+   *         type(s).
+   *
+   * @param  {Function} [listener]
+   *         If the first argument was another evented object, this will be
+   *         the listener function; otherwise, _all_ listeners bound to the
+   *         event type(s) will be removed.
    */
+  off: function off$$1(targetOrType, typeOrListener, listener) {
 
+    // Targeting this evented object.
+    if (!targetOrType || isValidEventType(targetOrType)) {
+      off(this.eventBusEl_, targetOrType, typeOrListener);
 
-  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);
+      // Targeting another evented object.
+    } else {
+      var target = targetOrType;
+      var type = typeOrListener;
 
-    // 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);
+      // Fail fast and in a meaningful way!
+      validateTarget(target);
+      validateEventType(type);
+      validateListener(listener);
 
-      computedWidthOrHeight = this.el_[rule];
+      // Ensure there's at least a guid, even if the function hasn't been used
+      listener = bind(this, listener);
+
+      // Remove the dispose listener on this evented object, which was given
+      // the same guid as the event listener in on().
+      this.off('dispose', listener);
+
+      if (target.nodeName) {
+        off(target, type, listener);
+        off(target, 'dispose', listener);
+      } else if (isEvented(target)) {
+        target.off(type, listener);
+        target.off('dispose', listener);
+      }
     }
+  },
 
-    return computedWidthOrHeight;
-  };
 
   /**
-   * An object that contains width and height values of the `Component`s
-   * computed style. Uses `window.getComputedStyle`.
+   * Fire an event on this evented object, causing its listeners to be called.
    *
-   * @typedef {Object} Component~DimensionObject
+   * @param   {string|Object} event
+   *          An event type or an object with a type property.
    *
-   * @property {number} width
-   *           The width of the `Component`s computed style.
+   * @param   {Object} [hash]
+   *          An additional object to pass along to listeners.
    *
-   * @property {number} height
-   *           The height of the `Component`s computed style.
+   * @returns {boolean}
+   *          Whether or not the default behavior was prevented.
    */
+  trigger: function trigger$$1(event, hash) {
+    return trigger(this.eventBusEl_, event, hash);
+  }
+};
 
-  /**
-   * Get an object that contains width and height values of the `Component`s
-   * computed style.
-   *
-   * @return {Component~DimensionObject}
-   *         The dimensions of the components element
-   */
+/**
+ * Applies {@link module:evented~EventedMixin|EventedMixin} to a target object.
+ *
+ * @param  {Object} target
+ *         The object to which to add event methods.
+ *
+ * @param  {Object} [options={}]
+ *         Options for customizing the mixin behavior.
+ *
+ * @param  {String} [options.eventBusKey]
+ *         By default, adds a `eventBusEl_` DOM element to the target object,
+ *         which is used as an event bus. If the target object already has a
+ *         DOM element that should be used, pass its key here.
+ *
+ * @return {Object}
+ *         The target object.
+ */
+function evented(target) {
+  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+  var eventBusKey = options.eventBusKey;
 
+  // Set or create the eventBusEl_.
 
-  Component.prototype.currentDimensions = function currentDimensions() {
-    return {
-      width: this.currentDimension('width'),
-      height: this.currentDimension('height')
-    };
-  };
+  if (eventBusKey) {
+    if (!target[eventBusKey].nodeName) {
+      throw new Error('The eventBusKey "' + eventBusKey + '" does not refer to an element.');
+    }
+    target.eventBusEl_ = target[eventBusKey];
+  } else {
+    target.eventBusEl_ = createEl('span', { className: 'vjs-event-bus' });
+  }
 
-  /**
-   * Get the width of the `Component`s computed style. Uses `window.getComputedStyle`.
-   *
-   * @return {number} width
-   *           The width of the `Component`s computed style.
-   */
+  assign(target, EventedMixin);
 
+  // When any evented object is disposed, it removes all its listeners.
+  target.on('dispose', function () {
+    return target.off();
+  });
 
-  Component.prototype.currentWidth = function currentWidth() {
-    return this.currentDimension('width');
-  };
+  return target;
+}
+
+/**
+ * @file mixins/stateful.js
+ * @module stateful
+ */
+/**
+ * Contains methods that provide statefulness to an object which is passed
+ * to {@link module:stateful}.
+ *
+ * @mixin StatefulMixin
+ */
+var StatefulMixin = {
 
   /**
-   * Get the height of the `Component`s computed style. Uses `window.getComputedStyle`.
+   * A hash containing arbitrary keys and values representing the state of
+   * the object.
    *
-   * @return {number} height
-   *           The height of the `Component`s computed style.
+   * @type {Object}
    */
-
-
-  Component.prototype.currentHeight = function currentHeight() {
-    return this.currentDimension('height');
-  };
+  state: {},
 
   /**
-   * Set the focus to this component
+   * Set the state of an object by mutating its
+   * {@link module:stateful~StatefulMixin.state|state} object in place.
+   *
+   * @fires   module:stateful~StatefulMixin#statechanged
+   * @param   {Object|Function} stateUpdates
+   *          A new set of properties to shallow-merge into the plugin state.
+   *          Can be a plain object or a function returning a plain object.
+   *
+   * @returns {Object|undefined}
+   *          An object containing changes that occurred. If no changes
+   *          occurred, returns `undefined`.
    */
+  setState: function setState(stateUpdates) {
+    var _this = this;
 
+    // Support providing the `stateUpdates` state as a function.
+    if (typeof stateUpdates === 'function') {
+      stateUpdates = stateUpdates();
+    }
 
-  Component.prototype.focus = function focus() {
-    this.el_.focus();
-  };
-
-  /**
-   * Remove the focus from this component
-   */
-
+    var changes = void 0;
 
-  Component.prototype.blur = function blur() {
-    this.el_.blur();
-  };
+    each(stateUpdates, function (value, key) {
 
-  /**
-   * 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
-    */
+      // Record the change if the value is different from what's in the
+      // current state.
+      if (_this.state[key] !== value) {
+        changes = changes || {};
+        changes[key] = {
+          from: _this.state[key],
+          to: value
+        };
+      }
 
+      _this.state[key] = value;
+    });
 
-  Component.prototype.emitTapEvents = function emitTapEvents() {
-    // Track the start time so we can determine how long the touch lasted
-    var touchStart = 0;
-    var firstTouch = null;
+    // Only trigger "statechange" if there were changes AND we have a trigger
+    // function. This allows us to not require that the target object be an
+    // evented object.
+    if (changes && isEvented(this)) {
 
-    // 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;
+      /**
+       * An event triggered on an object that is both
+       * {@link module:stateful|stateful} and {@link module:evented|evented}
+       * indicating that its state has changed.
+       *
+       * @event    module:stateful~StatefulMixin#statechanged
+       * @type     {Object}
+       * @property {Object} changes
+       *           A hash containing the properties that were changed and
+       *           the values they were changed `from` and `to`.
+       */
+      this.trigger({
+        changes: changes,
+        type: 'statechanged'
+      });
+    }
 
-    // The maximum length a touch can be while still being considered a tap
-    var touchTimeThreshold = 200;
+    return changes;
+  }
+};
 
-    var couldBeTap = void 0;
+/**
+ * Applies {@link module:stateful~StatefulMixin|StatefulMixin} to a target
+ * object.
+ *
+ * If the target object is {@link module:evented|evented} and has a
+ * `handleStateChanged` method, that method will be automatically bound to the
+ * `statechanged` event on itself.
+ *
+ * @param   {Object} target
+ *          The object to be made stateful.
+ *
+ * @param   {Object} [defaultState]
+ *          A default set of properties to populate the newly-stateful object's
+ *          `state` property.
+ *
+ * @returns {Object}
+ *          Returns the `target`.
+ */
+function stateful(target, defaultState) {
+  assign(target, StatefulMixin);
 
-    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 happens after the mixing-in because we need to replace the `state`
+  // added in that step.
+  target.state = assign({}, target.state, defaultState);
 
-    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);
+  // Auto-bind the `handleStateChanged` method of the target object if it exists.
+  if (typeof target.handleStateChanged === 'function' && isEvented(target)) {
+    target.on('statechanged', target.handleStateChanged);
+  }
 
-        if (touchDistance > tapMovementThreshold) {
-          couldBeTap = false;
-        }
-      }
-    });
+  return target;
+}
 
-    var noTap = function noTap() {
-      couldBeTap = false;
-    };
+/**
+ * @file to-title-case.js
+ * @module to-title-case
+ */
 
-    // TODO: Listen to the original target. http://youtu.be/DujfpXOKUp8?t=13m8s
-    this.on('touchleave', noTap);
-    this.on('touchcancel', noTap);
+/**
+ * Uppercase the first letter of a string.
+ *
+ * @param {string} string
+ *        String to be uppercased
+ *
+ * @return {string}
+ *         The string with an uppercased first letter
+ */
+function toTitleCase(string) {
+  if (typeof string !== 'string') {
+    return string;
+  }
 
-    // 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;
+  return string.charAt(0).toUpperCase() + string.slice(1);
+}
 
-        // 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)
-        }
-      }
-    });
-  };
+/**
+ * Compares the TitleCase versions of the two strings for equality.
+ *
+ * @param {string} str1
+ *        The first string to compare
+ *
+ * @param {string} str2
+ *        The second string to compare
+ *
+ * @return {boolean}
+ *         Whether the TitleCase versions of the strings are equal
+ */
+function titleCaseEquals(str1, str2) {
+  return toTitleCase(str1) === toTitleCase(str2);
+}
 
-  /**
-   * 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
-   */
+/**
+ * @file merge-options.js
+ * @module merge-options
+ */
+/**
+ * Deep-merge one or more options objects, recursively merging **only** plain
+ * object properties.
+ *
+ * @param   {Object[]} sources
+ *          One or more objects to merge into a new object.
+ *
+ * @returns {Object}
+ *          A new object that is the merged result of all sources.
+ */
+function mergeOptions() {
+  var result = {};
 
+  for (var _len = arguments.length, sources = Array(_len), _key = 0; _key < _len; _key++) {
+    sources[_key] = arguments[_key];
+  }
 
-  Component.prototype.enableTouchActivity = function enableTouchActivity() {
-    // Don't continue if the root player doesn't support reporting user activity
-    if (!this.player() || !this.player().reportUserActivity) {
+  sources.forEach(function (source) {
+    if (!source) {
       return;
     }
 
-    // listener for reporting that the user is active
-    var report = Fn.bind(this.player(), this.player().reportUserActivity);
+    each(source, function (value, key) {
+      if (!isPlain(value)) {
+        result[key] = value;
+        return;
+      }
 
-    var touchHolding = void 0;
+      if (!isPlain(result[key])) {
+        result[key] = {};
+      }
 
-    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);
+      result[key] = mergeOptions(result[key], value);
     });
+  });
 
-    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);
-  };
+  return result;
+}
 
-  /**
-   * A callback that has no parameters and is bound into `Component`s context.
-   *
-   * @callback Component~GenericCallback
+/**
+ * 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 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}.
+   * Creates an instance of this class.
    *
-   * @param {Component~GenericCallback} fn
-   *        The function that will be run after `timeout`.
+   * @param {Player} player
+   *        The `Player` that this class should be attached to.
    *
-   * @param {number} timeout
-   *        Timeout in milliseconds to delay before executing the specified function.
+   * @param {Object} [options]
+   *        The key/value store of player options.
    *
-   * @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.
+   * @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.
    *
-   * @listens Component#dispose
-   * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout}
+   * @param {Component~ReadyCallback} [ready]
+   *        Function that gets called when the `Component` is ready.
    */
+  function Component(player, options, ready) {
+    classCallCheck(this, Component);
 
 
-  Component.prototype.setTimeout = function setTimeout(fn, timeout) {
-    fn = Fn.bind(this, fn);
+    // 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;
+    }
 
-    var timeoutId = _window2['default'].setTimeout(fn, timeout);
-    var disposeFn = function disposeFn() {
-      this.clearTimeout(timeoutId);
-    };
+    // Make a copy of prototype.options_ to protect against overriding defaults
+    this.options_ = mergeOptions({}, this.options_);
 
-    disposeFn.guid = 'vjs-timeout-' + timeoutId;
+    // Updated options with supplied options
+    options = this.options_ = mergeOptions(this.options_, options);
 
-    this.on('dispose', disposeFn);
+    // Get ID from options or options element if one is supplied
+    this.id_ = options.id || options.el && options.el.id;
 
-    return timeoutId;
-  };
+    // 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_' + 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();
+    }
+
+    // Make this an evented object and use `el_`, if available, as its event bus
+    evented(this, { eventBusKey: this.el_ ? 'el_' : null });
+    stateful(this, this.constructor.defaultState);
+
+    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();
+    }
+  }
 
   /**
-   * 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.
+   * Dispose of the `Component` and all child components.
    *
-   * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearTimeout}
+   * @fires Component#dispose
    */
 
 
-  Component.prototype.clearTimeout = function clearTimeout(timeoutId) {
-    _window2['default'].clearTimeout(timeoutId);
+  Component.prototype.dispose = function dispose() {
 
-    var disposeFn = function disposeFn() {};
+    /**
+     * 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 });
 
-    disposeFn.guid = 'vjs-timeout-' + timeoutId;
+    // 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();
+        }
+      }
+    }
 
-    this.off('dispose', disposeFn);
+    // Delete child references
+    this.children_ = null;
+    this.childIndex_ = null;
+    this.childNameIndex_ = null;
 
-    return timeoutId;
+    if (this.el_) {
+      // Remove element from DOM
+      if (this.el_.parentNode) {
+        this.el_.parentNode.removeChild(this.el_);
+      }
+
+      removeData(this.el_);
+      this.el_ = null;
+    }
   };
 
   /**
-   * 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}
+   * Return the {@link Player} that the `Component` has attached to.
    *
-   * @param {Component~GenericCallback} fn
-   *        The function to run every `x` seconds.
+   * @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 {number} interval
-   *        Execute the specified function every `x` milliseconds.
+   * @param {Object} obj
+   *        The object that contains new options.
    *
-   * @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.
+   * @return {Object}
+   *         A new object of `this.options_` and `obj` merged together.
    *
-   * @listens Component#dispose
-   * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval}
+   * @deprecated since version 5
    */
 
 
-  Component.prototype.setInterval = function setInterval(fn, interval) {
-    fn = Fn.bind(this, fn);
+  Component.prototype.options = function options(obj) {
+    log$1.warn('this.options() has been deprecated and will be moved to the constructor in 6.0');
 
-    var intervalId = _window2['default'].setInterval(fn, interval);
+    if (!obj) {
+      return this.options_;
+    }
 
-    var disposeFn = function disposeFn() {
-      this.clearInterval(intervalId);
-    };
+    this.options_ = mergeOptions(this.options_, obj);
+    return this.options_;
+  };
 
-    disposeFn.guid = 'vjs-interval-' + intervalId;
+  /**
+   * Get the `Component`s DOM element
+   *
+   * @return {Element}
+   *         The DOM element for this `Component`.
+   */
 
-    this.on('dispose', disposeFn);
 
-    return intervalId;
+  Component.prototype.el = function el() {
+    return this.el_;
   };
 
   /**
-   * 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}!
+   * Create the `Component`s DOM element.
    *
-   * @param {number} intervalId
-   *        The id of the interval to clear. The return value of
-   *        {@link Component#setInterval} or `window.setInterval`.
+   * @param {string} [tagName]
+   *        Element's DOM node type. e.g. 'div'
    *
-   * @return {number}
-   *         Returns the interval id that was cleared.
+   * @param {Object} [properties]
+   *        An object of properties that should be set.
    *
-   * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearInterval}
+   * @param {Object} [attributes]
+   *        An object of attributes that should be set.
+   *
+   * @return {Element}
+   *         The element that gets created.
    */
 
 
-  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;
+  Component.prototype.createEl = function createEl$$1(tagName, properties, attributes) {
+    return createEl(tagName, properties, attributes);
   };
 
   /**
-   * Register a `Component` with `videojs` given the name and the component.
+   * Localize a string given the string in english.
    *
-   * > 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}.
+   * If tokens are provided, it'll try and run a simple token replacement on the provided string.
+   * The tokens it loooks for look like `{1}` with the index being 1-indexed into the tokens array.
    *
-   * > NOTE: This function can also be seen on videojs as
-   *         {@link videojs:videojs.registerComponent}.
+   * If a `defaultValue` is provided, it'll use that over `string`,
+   * if a value isn't found in provided language files.
+   * This is useful if you want to have a descriptive key for token replacement
+   * but have a succinct localized string and not require `en.json` to be included.
    *
-   * @param {string} name
-   *        The name of the `Component` to register.
+   * Currently, it is used for the progress bar timing.
+   * ```js
+   * {
+   *   "progress bar timing: currentTime={1} duration={2}": "{1} of {2}"
+   * }
+   * ```
+   * It is then used like so:
+   * ```js
+   * this.localize('progress bar timing: currentTime={1} duration{2}',
+   *               [this.player_.currentTime(), this.player_.duration()],
+   *               '{1} of {2}');
+   * ```
    *
-   * @param {Component} comp
-   *        The `Component` class to register.
+   * Which outputs something like: `01:23 of 24:56`.
    *
-   * @return {Component}
-   *         The `Component` that was registered.
+   *
+   * @param {string} string
+   *        The string to localize and the key to lookup in the language files.
+   * @param {string[]} [tokens]
+   *        If the current item has token replacements, provide the tokens here.
+   * @param {string} [defaultValue]
+   *        Defaults to `string`. Can be a default value to use for token replacement
+   *        if the lookup key is needed to be separate.
+   *
+   * @return {string}
+   *         The localized string or if no localization exists the english string.
    */
 
 
-  Component.registerComponent = function registerComponent(name, comp) {
-    if (!name) {
-      return;
-    }
+  Component.prototype.localize = function localize(string, tokens) {
+    var defaultValue = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : string;
 
-    name = (0, _toTitleCase2['default'])(name);
+    var code = this.player_.language && this.player_.language();
+    var languages = this.player_.languages && this.player_.languages();
+    var language = languages && languages[code];
+    var primaryCode = code && code.split('-')[0];
+    var primaryLang = languages && languages[primaryCode];
 
-    if (!Component.components_) {
-      Component.components_ = {};
+    var localizedString = defaultValue;
+
+    if (language && language[string]) {
+      localizedString = language[string];
+    } else if (primaryLang && primaryLang[string]) {
+      localizedString = primaryLang[string];
     }
 
-    if (name === 'Player' && Component.components_[name]) {
-      var Player = Component.components_[name];
+    if (tokens) {
+      localizedString = localizedString.replace(/\{(\d+)\}/g, function (match, index) {
+        var value = tokens[index - 1];
+        var ret = value;
 
-      // 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');
-      }
-    }
+        if (typeof value === 'undefined') {
+          ret = match;
+        }
 
-    Component.components_[name] = comp;
+        return ret;
+      });
+    }
 
-    return comp;
+    return localizedString;
   };
 
   /**
-   * 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.
+   * 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}.
    *
-   * @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.
+   * @return {Element}
+   *         The content element for this `Component`.
    */
 
 
-  Component.getComponent = function getComponent(name) {
-    if (!name) {
-      return;
-    }
-
-    name = (0, _toTitleCase2['default'])(name);
+  Component.prototype.contentEl = function contentEl() {
+    return this.contentEl_ || this.el_;
+  };
 
-    if (Component.components_ && Component.components_[name]) {
-      return Component.components_[name];
-    }
+  /**
+   * Get this `Component`s ID
+   *
+   * @return {string}
+   *         The id of this `Component`
+   */
 
-    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];
-    }
+  Component.prototype.id = function id() {
+    return this.id_;
   };
 
   /**
-   * 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.
+   * Get the `Component`s name. The name gets used to reference the `Component`
+   * and is set during registration.
    *
-   * @deprecated since version 5
+   * @return {string}
+   *         The name of this `Component`.
    */
 
 
-  Component.extend = function extend(props) {
-    props = props || {};
+  Component.prototype.name = function name() {
+    return this.name_;
+  };
 
-    _log2['default'].warn('Component.extend({}) has been deprecated, ' + ' use videojs.extend(Component, {}) instead');
+  /**
+   * Get an array of all child components
+   *
+   * @return {Array}
+   *         The children
+   */
 
-    // 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;
+  Component.prototype.children = function children() {
+    return this.children_;
+  };
 
-    // Make the class extendable
-    subObj.extend = Component.extend;
+  /**
+   * 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.
+   */
 
-    // 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;
+  Component.prototype.getChildById = function getChildById(id) {
+    return this.childIndex_[id];
   };
 
-  return Component;
-}();
+  /**
+   * 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.registerComponent('Component', Component);
-exports['default'] = Component;
 
-},{"81":81,"82":82,"83":83,"85":85,"86":86,"87":87,"91":91,"95":95}],6:[function(_dereq_,module,exports){
-'use strict';
+  Component.prototype.getChild = function getChild(name) {
+    if (!name) {
+      return;
+    }
 
-exports.__esModule = true;
+    name = toTitleCase(name);
 
-var _trackButton = _dereq_(36);
+    return this.childNameIndex_[name];
+  };
 
-var _trackButton2 = _interopRequireDefault(_trackButton);
+  /**
+   * 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.
+   */
 
-var _component = _dereq_(5);
 
-var _component2 = _interopRequireDefault(_component);
+  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 _audioTrackMenuItem = _dereq_(7);
+    var component = void 0;
+    var componentName = void 0;
 
-var _audioTrackMenuItem2 = _interopRequireDefault(_audioTrackMenuItem);
+    // If child is a string, create component with options
+    if (typeof child === 'string') {
+      componentName = toTitleCase(child);
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+      var componentClassName = options.componentClass || componentName;
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+      // Set name through options
+      options.name = componentName;
 
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+      // Create a new object & element for this controls set
+      // If there's no .player_, this is a player
+      var ComponentClass = Component.getComponent(componentClassName);
 
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file audio-track-button.js
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
+      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;
+      }
 
-/**
- * The base class for buttons that toggle specific {@link AudioTrack} types.
- *
- * @extends TrackButton
- */
-var AudioTrackButton = function (_TrackButton) {
-  _inherits(AudioTrackButton, _TrackButton);
+      component = new ComponentClass(this.player_ || this, options);
 
-  /**
-   * 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.
-   */
-  function AudioTrackButton(player) {
-    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+      // child is a component instance
+    } else {
+      component = child;
+    }
 
-    _classCallCheck(this, AudioTrackButton);
+    this.children_.splice(index, 0, component);
 
-    options.tracks = player.audioTracks && player.audioTracks();
+    if (typeof component.id === 'function') {
+      this.childIndex_[component.id()] = component;
+    }
 
-    var _this = _possibleConstructorReturn(this, _TrackButton.call(this, player, options));
+    // 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 && toTitleCase(component.name());
 
-    _this.el_.setAttribute('aria-label', 'Audio Menu');
-    return _this;
-  }
+    if (componentName) {
+      this.childNameIndex_[componentName] = component;
+    }
 
-  /**
-   * Builds the default DOM `className`.
-   *
-   * @return {string}
-   *         The DOM `className` for this object.
-   */
+    // 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);
+    }
 
-  AudioTrackButton.prototype.buildCSSClass = function buildCSSClass() {
-    return 'vjs-audio-button ' + _TrackButton.prototype.buildCSSClass.call(this);
+    // Return so it can stored on parent object if desired.
+    return component;
   };
 
   /**
-   * Create a menu item for each audio track
-   *
-   * @param {AudioTrackMenuItem[]} [items=[]]
-   *        An array of existing menu items to use.
+   * Remove a child `Component` from this `Component`s list of children. Also removes
+   * the child `Component`s element from this `Component`s element.
    *
-   * @return {AudioTrackMenuItem[]}
-   *         An array of menu items
+   * @param {Component} component
+   *        The child `Component` to remove.
    */
 
 
-  AudioTrackButton.prototype.createItems = function createItems() {
-    var items = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
-
-    var tracks = this.player_.audioTracks && this.player_.audioTracks();
+  Component.prototype.removeChild = function removeChild(component) {
+    if (typeof component === 'string') {
+      component = this.getChild(component);
+    }
 
-    if (!tracks) {
-      return items;
+    if (!component || !this.children_) {
+      return;
     }
 
-    for (var i = 0; i < tracks.length; i++) {
-      var track = tracks[i];
+    var childFound = false;
 
-      items.push(new _audioTrackMenuItem2['default'](this.player_, {
-        track: track,
-        // MenuItem is selectable
-        selectable: true
-      }));
+    for (var i = this.children_.length - 1; i >= 0; i--) {
+      if (this.children_[i] === component) {
+        childFound = true;
+        this.children_.splice(i, 1);
+        break;
+      }
     }
 
-    return items;
-  };
-
-  return AudioTrackButton;
-}(_trackButton2['default']);
+    if (!childFound) {
+      return;
+    }
 
-/**
- * The text that should display over the `AudioTrackButton`s controls. Added for localization.
- *
- * @type {string}
- * @private
- */
+    this.childIndex_[component.id()] = null;
+    this.childNameIndex_[component.name()] = null;
 
+    var compEl = component.el();
 
-AudioTrackButton.prototype.controlText_ = 'Audio Track';
-_component2['default'].registerComponent('AudioTrackButton', AudioTrackButton);
-exports['default'] = AudioTrackButton;
+    if (compEl && compEl.parentNode === this.contentEl()) {
+      this.contentEl().removeChild(component.el());
+    }
+  };
 
-},{"36":36,"5":5,"7":7}],7:[function(_dereq_,module,exports){
-'use strict';
+  /**
+   * Add and initialize default child `Component`s based upon options.
+   */
 
-exports.__esModule = true;
 
-var _menuItem = _dereq_(48);
+  Component.prototype.initChildren = function initChildren() {
+    var _this = this;
 
-var _menuItem2 = _interopRequireDefault(_menuItem);
+    var children = this.options_.children;
 
-var _component = _dereq_(5);
+    if (children) {
+      // `this` is `parent`
+      var parentOptions = this.options_;
 
-var _component2 = _interopRequireDefault(_component);
+      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];
+        }
 
-var _fn = _dereq_(83);
+        // Allow for disabling default components
+        // e.g. options['children']['posterImage'] = false
+        if (opts === false) {
+          return;
+        }
 
-var Fn = _interopRequireWildcard(_fn);
+        // Allow options to be passed as a simple boolean if no configuration
+        // is necessary.
+        if (opts === true) {
+          opts = {};
+        }
 
-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; } }
+        // 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;
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+        // 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);
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+        if (newChild) {
+          _this[name] = newChild;
+        }
+      };
 
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+      // Allow for an array of children details to passed in the options
+      var workingChildren = void 0;
+      var Tech = Component.getComponent('Tech');
 
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file audio-track-menu-item.js
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
+      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;
 
-/**
- * An {@link AudioTrack} {@link MenuItem}
- *
- * @extends MenuItem
- */
-var AudioTrackMenuItem = function (_MenuItem) {
-  _inherits(AudioTrackMenuItem, _MenuItem);
+        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 || toTitleCase(child.name));
+
+        return c && !Tech.isTech(c);
+      }).forEach(handleAdd);
+    }
+  };
 
   /**
-   * Creates an instance of this class.
+   * Builds the default DOM class name. Should be overriden by sub-components.
    *
-   * @param {Player} player
-   *        The `Player` that this class should be attached to.
+   * @return {string}
+   *         The DOM class name for this object.
    *
-   * @param {Object} [options]
-   *        The key/value store of player options.
+   * @abstract
    */
-  function AudioTrackMenuItem(player, options) {
-    _classCallCheck(this, AudioTrackMenuItem);
 
-    var track = options.track;
-    var tracks = player.audioTracks();
 
-    // Modify options for parent MenuItem class's init.
-    options.label = track.label || track.language || 'Unknown';
-    options.selected = track.enabled;
+  Component.prototype.buildCSSClass = function buildCSSClass() {
+    // Child classes can include a function that does:
+    // return 'CLASS NAME' + this._super();
+    return '';
+  };
 
-    var _this = _possibleConstructorReturn(this, _MenuItem.call(this, player, options));
+  /**
+   * Bind a listener to the component's ready state.
+   * Different from event listeners in that if the ready event has already happened
+   * it will trigger the function immediately.
+   *
+   * @return {Component}
+   *         Returns itself; method can be chained.
+   */
 
-    _this.track = track;
 
-    if (tracks) {
-      var changeHandler = Fn.bind(_this, _this.handleTracksChange);
+  Component.prototype.ready = function ready(fn) {
+    var sync = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
 
-      tracks.addEventListener('change', changeHandler);
-      _this.on('dispose', function () {
-        tracks.removeEventListener('change', changeHandler);
-      });
+    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;
-  }
+  };
 
   /**
-   * This gets called when an `AudioTrackMenuItem is "clicked". See {@link ClickableComponent}
-   * for more detailed information on what a click can be.
-   *
-   * @param {EventTarget~Event} [event]
-   *        The `keydown`, `tap`, or `click` event that caused this function to be
-   *        called.
+   * Trigger all the ready listeners for this `Component`.
    *
-   * @listens tap
-   * @listens click
+   * @fires Component#ready
    */
 
 
-  AudioTrackMenuItem.prototype.handleClick = function handleClick(event) {
-    var tracks = this.player_.audioTracks();
+  Component.prototype.triggerReady = function triggerReady() {
+    this.isReady_ = true;
 
-    _MenuItem.prototype.handleClick.call(this, event);
+    // Ensure ready is triggerd asynchronously
+    this.setTimeout(function () {
+      var readyQueue = this.readyQueue_;
 
-    if (!tracks) {
-      return;
-    }
+      // Reset Ready Queue
+      this.readyQueue_ = [];
 
-    for (var i = 0; i < tracks.length; i++) {
-      var track = tracks[i];
+      if (readyQueue && readyQueue.length > 0) {
+        readyQueue.forEach(function (fn) {
+          fn.call(this);
+        }, this);
+      }
 
-      track.enabled = track === this.track;
-    }
+      // Allow for using event listeners also
+      /**
+       * Triggered when a `Component` is ready.
+       *
+       * @event Component#ready
+       * @type {EventTarget~Event}
+       */
+      this.trigger('ready');
+    }, 1);
   };
 
   /**
-   * Handle any {@link AudioTrack} change.
+   * Find a single DOM element matching a `selector`. This can be within the `Component`s
+   * `contentEl()` or another custom context.
    *
-   * @param {EventTarget~Event} [event]
-   *        The {@link AudioTrackList#change} event that caused this to run.
+   * @param {string} selector
+   *        A valid CSS selector, which will be passed to `querySelector`.
    *
-   * @listens AudioTrackList#change
+   * @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)
    */
 
 
-  AudioTrackMenuItem.prototype.handleTracksChange = function handleTracksChange(event) {
-    this.selected(this.track.enabled);
+  Component.prototype.$ = function $$$1(selector, context) {
+    return $(selector, context || this.contentEl());
   };
 
-  return AudioTrackMenuItem;
-}(_menuItem2['default']);
-
-_component2['default'].registerComponent('AudioTrackMenuItem', AudioTrackMenuItem);
-exports['default'] = AudioTrackMenuItem;
-
-},{"48":48,"5":5,"83":83}],8:[function(_dereq_,module,exports){
-'use strict';
+  /**
+   * 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)
+   */
 
-exports.__esModule = true;
 
-var _component = _dereq_(5);
+  Component.prototype.$$ = function $$$$1(selector, context) {
+    return $$(selector, context || this.contentEl());
+  };
 
-var _component2 = _interopRequireDefault(_component);
+  /**
+   * 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`
+   */
 
-_dereq_(12);
 
-_dereq_(32);
+  Component.prototype.hasClass = function hasClass$$1(classToCheck) {
+    return hasClass(this.el_, classToCheck);
+  };
 
-_dereq_(33);
+  /**
+   * Add a CSS class name to the `Component`s element.
+   *
+   * @param {string} classToAdd
+   *        CSS class name to add
+   */
 
-_dereq_(35);
 
-_dereq_(34);
+  Component.prototype.addClass = function addClass$$1(classToAdd) {
+    addClass(this.el_, classToAdd);
+  };
 
-_dereq_(10);
+  /**
+   * Remove a CSS class name from the `Component`s element.
+   *
+   * @param {string} classToRemove
+   *        CSS class name to remove
+   */
 
-_dereq_(18);
 
-_dereq_(9);
+  Component.prototype.removeClass = function removeClass$$1(classToRemove) {
+    removeClass(this.el_, classToRemove);
+  };
 
-_dereq_(38);
+  /**
+   * 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
+   */
 
-_dereq_(40);
 
-_dereq_(11);
+  Component.prototype.toggleClass = function toggleClass$$1(classToToggle, predicate) {
+    toggleClass(this.el_, classToToggle, predicate);
+  };
 
-_dereq_(25);
+  /**
+   * Show the `Component`s element if it is hidden by removing the
+   * 'vjs-hidden' class name from it.
+   */
 
-_dereq_(27);
 
-_dereq_(29);
+  Component.prototype.show = function show() {
+    this.removeClass('vjs-hidden');
+  };
 
-_dereq_(24);
+  /**
+   * Hide the `Component`s element if it is currently showing by adding the
+   * 'vjs-hidden` class name to it.
+   */
 
-_dereq_(6);
 
-_dereq_(13);
-
-_dereq_(21);
-
-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"); } }
-
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
-
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file control-bar.js
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
-
-
-// Required children
-
-
-/**
- * Container of main controls.
- *
- * @extends Component
- */
-var ControlBar = function (_Component) {
-  _inherits(ControlBar, _Component);
-
-  function ControlBar() {
-    _classCallCheck(this, ControlBar);
-
-    return _possibleConstructorReturn(this, _Component.apply(this, arguments));
-  }
+  Component.prototype.hide = function hide() {
+    this.addClass('vjs-hidden');
+  };
 
   /**
-   * Create the `Component`'s DOM element
+   * Lock a `Component`s element in its visible state by adding the 'vjs-lock-showing'
+   * class name to it. Used during fadeIn/fadeOut.
    *
-   * @return {Element}
-   *         The element that was created.
+   * @private
    */
-  ControlBar.prototype.createEl = function createEl() {
-    return _Component.prototype.createEl.call(this, 'div', {
-      className: 'vjs-control-bar',
-      dir: 'ltr'
-    }, {
-      // The control bar is a group, so it can contain menuitems
-      role: 'group'
-    });
-  };
-
-  return ControlBar;
-}(_component2['default']);
-
-/**
- * Default options for `ControlBar`
- *
- * @type {Object}
- * @private
- */
-
-
-ControlBar.prototype.options_ = {
-  children: ['playToggle', 'volumeMenuButton', 'currentTimeDisplay', 'timeDivider', 'durationDisplay', 'progressControl', 'liveDisplay', 'remainingTimeDisplay', 'customControlSpacer', 'playbackRateMenuButton', 'chaptersButton', 'descriptionsButton', 'subtitlesButton', 'captionsButton', 'audioTrackButton', 'fullscreenToggle']
-};
-
-_component2['default'].registerComponent('ControlBar', ControlBar);
-exports['default'] = ControlBar;
 
-},{"10":10,"11":11,"12":12,"13":13,"18":18,"21":21,"24":24,"25":25,"27":27,"29":29,"32":32,"33":33,"34":34,"35":35,"38":38,"40":40,"5":5,"6":6,"9":9}],9:[function(_dereq_,module,exports){
-'use strict';
 
-exports.__esModule = true;
-
-var _button = _dereq_(2);
+  Component.prototype.lockShowing = function lockShowing() {
+    this.addClass('vjs-lock-showing');
+  };
 
-var _button2 = _interopRequireDefault(_button);
+  /**
+   * Unlock a `Component`s element from its visible state by removing the 'vjs-lock-showing'
+   * class name from it. Used during fadeIn/fadeOut.
+   *
+   * @private
+   */
 
-var _component = _dereq_(5);
 
-var _component2 = _interopRequireDefault(_component);
+  Component.prototype.unlockShowing = function unlockShowing() {
+    this.removeClass('vjs-lock-showing');
+  };
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+  /**
+   * 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}
+   */
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+  Component.prototype.getAttribute = function getAttribute$$1(attribute) {
+    return getAttribute(this.el_, attribute);
+  };
 
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file fullscreen-toggle.js
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
+  /**
+   * 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.
+   *
+   * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute}
+   */
 
 
-/**
- * Toggle fullscreen video
- *
- * @extends Button
- */
-var FullscreenToggle = function (_Button) {
-  _inherits(FullscreenToggle, _Button);
+  Component.prototype.setAttribute = function setAttribute$$1(attribute, value) {
+    setAttribute(this.el_, attribute, value);
+  };
 
   /**
-   * Creates an instance of this class.
+   * Remove an attribute from the `Component`s element.
    *
-   * @param {Player} player
-   *        The `Player` that this class should be attached to.
+   * @param {string} attribute
+   *        Name of the attribute to remove.
    *
-   * @param {Object} [options]
-   *        The key/value store of player options.
+   * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/removeAttribute}
    */
-  function FullscreenToggle(player, options) {
-    _classCallCheck(this, FullscreenToggle);
 
-    var _this = _possibleConstructorReturn(this, _Button.call(this, player, options));
 
-    _this.on(player, 'fullscreenchange', _this.handleFullscreenChange);
-    return _this;
-  }
+  Component.prototype.removeAttribute = function removeAttribute$$1(attribute) {
+    removeAttribute(this.el_, attribute);
+  };
 
   /**
-   * Builds the default DOM `className`.
+   * Get or set the width of the component based upon the CSS styles.
+   * See {@link Component#dimension} for more detailed information.
    *
-   * @return {string}
-   *         The DOM `className` for this object.
+   * @param {number|string} [num]
+   *        The width that you want to set postfixed with '%', 'px' or nothing.
+   *
+   * @param {boolean} [skipListeners]
+   *        Skip the componentresize event trigger
+   *
+   * @return {number|string}
+   *         The width when getting, zero if there is no width. Can be a string
+   *           postpixed with '%' or 'px'.
    */
 
 
-  FullscreenToggle.prototype.buildCSSClass = function buildCSSClass() {
-    return 'vjs-fullscreen-control ' + _Button.prototype.buildCSSClass.call(this);
+  Component.prototype.width = function width(num, skipListeners) {
+    return this.dimension('width', num, skipListeners);
   };
 
   /**
-   * Handles fullscreenchange on the player and change control text accordingly.
+   * Get or set the height of the component based upon the CSS styles.
+   * See {@link Component#dimension} for more detailed information.
    *
-   * @param {EventTarget~Event} [event]
-   *        The {@link Player#fullscreenchange} event that caused this function to be
-   *        called.
+   * @param {number|string} [num]
+   *        The height that you want to set postfixed with '%', 'px' or nothing.
    *
-   * @listens Player#fullscreenchange
+   * @param {boolean} [skipListeners]
+   *        Skip the componentresize event trigger
+   *
+   * @return {number|string}
+   *         The width when getting, zero if there is no width. Can be a string
+   *         postpixed with '%' or 'px'.
    */
 
 
-  FullscreenToggle.prototype.handleFullscreenChange = function handleFullscreenChange(event) {
-    if (this.player_.isFullscreen()) {
-      this.controlText('Non-Fullscreen');
-    } else {
-      this.controlText('Fullscreen');
-    }
+  Component.prototype.height = function height(num, skipListeners) {
+    return this.dimension('height', num, skipListeners);
   };
 
   /**
-   * This gets called when an `FullscreenToggle` is "clicked". See
-   * {@link ClickableComponent} for more detailed information on what a click can be.
+   * Set both the width and height of the `Component` element at the same time.
    *
-   * @param {EventTarget~Event} [event]
-   *        The `keydown`, `tap`, or `click` event that caused this function to be
-   *        called.
+   * @param  {number|string} width
+   *         Width to set the `Component`s element to.
    *
-   * @listens tap
-   * @listens click
+   * @param  {number|string} height
+   *         Height to set the `Component`s element to.
    */
 
 
-  FullscreenToggle.prototype.handleClick = function handleClick(event) {
-    if (!this.player_.isFullscreen()) {
-      this.player_.requestFullscreen();
-    } else {
-      this.player_.exitFullscreen();
-    }
+  Component.prototype.dimensions = function dimensions(width, height) {
+    // Skip componentresize listeners on width for optimization
+    this.width(width, true);
+    this.height(height);
   };
 
-  return FullscreenToggle;
-}(_button2['default']);
+  /**
+   * 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#componentresize
+   *
+   * @param {string} widthOrHeight
+   8        'width' or 'height'
+   *
+   * @param  {number|string} [num]
+   8         New dimension
+   *
+   * @param  {boolean} [skipListeners]
+   *         Skip componentresize event trigger
+   *
+   * @return {number}
+   *         The dimension when getting or 0 if unset
+   */
 
-/**
- * The text that should display over the `FullscreenToggle`s controls. Added for localization.
- *
- * @type {string}
- * @private
- */
 
+  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;
+      }
 
-FullscreenToggle.prototype.controlText_ = 'Fullscreen';
+      // 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';
+      }
 
-_component2['default'].registerComponent('FullscreenToggle', FullscreenToggle);
-exports['default'] = FullscreenToggle;
+      // 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#componentresize
+         * @type {EventTarget~Event}
+         */
+        this.trigger('componentresize');
+      }
 
-},{"2":2,"5":5}],10:[function(_dereq_,module,exports){
-'use strict';
+      return;
+    }
 
-exports.__esModule = true;
+    // Not setting a value, so getting it
+    // Make sure element exists
+    if (!this.el_) {
+      return 0;
+    }
 
-var _component = _dereq_(5);
+    // Get dimension value from style
+    var val = this.el_.style[widthOrHeight];
+    var pxIndex = val.indexOf('px');
 
-var _component2 = _interopRequireDefault(_component);
+    if (pxIndex !== -1) {
+      // Return the pixel value with no 'px'
+      return parseInt(val.slice(0, pxIndex), 10);
+    }
 
-var _dom = _dereq_(81);
+    // 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' + toTitleCase(widthOrHeight)], 10);
+  };
 
-var Dom = _interopRequireWildcard(_dom);
+  /**
+   * 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.
+   */
 
-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 }; }
+  Component.prototype.currentDimension = function currentDimension(widthOrHeight) {
+    var computedWidthOrHeight = 0;
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+    if (widthOrHeight !== 'width' && widthOrHeight !== 'height') {
+      throw new Error('currentDimension only accepts width or height value');
+    }
 
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+    if (typeof window_1.getComputedStyle === 'function') {
+      var computedStyle = window_1.getComputedStyle(this.el_);
 
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file live-display.js
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
+      computedWidthOrHeight = computedStyle.getPropertyValue(widthOrHeight) || computedStyle[widthOrHeight];
+    }
 
+    // remove 'px' from variable and parse as integer
+    computedWidthOrHeight = parseFloat(computedWidthOrHeight);
 
-// TODO - Future make it click to snap to live
+    // 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' + toTitleCase(widthOrHeight);
 
-/**
- * Displays the live indicator when duration is Infinity.
- *
- * @extends Component
- */
-var LiveDisplay = function (_Component) {
-  _inherits(LiveDisplay, _Component);
+      computedWidthOrHeight = this.el_[rule];
+    }
+
+    return computedWidthOrHeight;
+  };
 
   /**
-   * Creates an instance of this class.
+   * An object that contains width and height values of the `Component`s
+   * computed style. Uses `window.getComputedStyle`.
    *
-   * @param {Player} player
-   *        The `Player` that this class should be attached to.
+   * @typedef {Object} Component~DimensionObject
    *
-   * @param {Object} [options]
-   *        The key/value store of player options.
+   * @property {number} width
+   *           The width of the `Component`s computed style.
+   *
+   * @property {number} height
+   *           The height of the `Component`s computed style.
    */
-  function LiveDisplay(player, options) {
-    _classCallCheck(this, LiveDisplay);
-
-    var _this = _possibleConstructorReturn(this, _Component.call(this, player, options));
-
-    _this.updateShowing();
-    _this.on(_this.player(), 'durationchange', _this.updateShowing);
-    return _this;
-  }
 
   /**
-   * Create the `Component`'s DOM element
+   * Get an object that contains width and height values of the `Component`s
+   * computed style.
    *
-   * @return {Element}
-   *         The element that was created.
+   * @return {Component~DimensionObject}
+   *         The dimensions of the components element
    */
 
 
-  LiveDisplay.prototype.createEl = function createEl() {
-    var el = _Component.prototype.createEl.call(this, 'div', {
-      className: 'vjs-live-control vjs-control'
-    });
+  Component.prototype.currentDimensions = function currentDimensions() {
+    return {
+      width: this.currentDimension('width'),
+      height: this.currentDimension('height')
+    };
+  };
 
-    this.contentEl_ = Dom.createEl('div', {
-      className: 'vjs-live-display',
-      innerHTML: '<span class="vjs-control-text">' + this.localize('Stream Type') + '</span>' + this.localize('LIVE')
-    }, {
-      'aria-live': 'off'
-    });
+  /**
+   * Get the width of the `Component`s computed style. Uses `window.getComputedStyle`.
+   *
+   * @return {number} width
+   *           The width of the `Component`s computed style.
+   */
 
-    el.appendChild(this.contentEl_);
-    return el;
+
+  Component.prototype.currentWidth = function currentWidth() {
+    return this.currentDimension('width');
   };
 
   /**
-   * Check the duration to see if the LiveDisplay should be showing or not. Then show/hide
-   * it accordingly
-   *
-   * @param {EventTarget~Event} [event]
-   *        The {@link Player#durationchange} event that caused this function to run.
+   * Get the height of the `Component`s computed style. Uses `window.getComputedStyle`.
    *
-   * @listens Player#durationchange
+   * @return {number} height
+   *           The height of the `Component`s computed style.
    */
 
 
-  LiveDisplay.prototype.updateShowing = function updateShowing(event) {
-    if (this.player().duration() === Infinity) {
-      this.show();
-    } else {
-      this.hide();
-    }
+  Component.prototype.currentHeight = function currentHeight() {
+    return this.currentDimension('height');
   };
 
-  return LiveDisplay;
-}(_component2['default']);
+  /**
+   * Set the focus to this component
+   */
 
-_component2['default'].registerComponent('LiveDisplay', LiveDisplay);
-exports['default'] = LiveDisplay;
 
-},{"5":5,"81":81}],11:[function(_dereq_,module,exports){
-'use strict';
+  Component.prototype.focus = function focus() {
+    this.el_.focus();
+  };
+
+  /**
+   * Remove the focus from this component
+   */
+
 
-exports.__esModule = true;
+  Component.prototype.blur = function blur() {
+    this.el_.blur();
+  };
 
-var _button = _dereq_(2);
+  /**
+   * 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
+    */
 
-var _button2 = _interopRequireDefault(_button);
 
-var _component = _dereq_(5);
+  Component.prototype.emitTapEvents = function emitTapEvents() {
+    // Track the start time so we can determine how long the touch lasted
+    var touchStart = 0;
+    var firstTouch = null;
 
-var _component2 = _interopRequireDefault(_component);
+    // 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;
 
-var _dom = _dereq_(81);
+    // The maximum length a touch can be while still being considered a tap
+    var touchTimeThreshold = 200;
 
-var Dom = _interopRequireWildcard(_dom);
+    var couldBeTap = void 0;
 
-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; } }
+    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;
+      }
+    });
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+    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);
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+        if (touchDistance > tapMovementThreshold) {
+          couldBeTap = false;
+        }
+      }
+    });
 
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+    var noTap = function noTap() {
+      couldBeTap = false;
+    };
 
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file mute-toggle.js
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
+    // 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;
 
-/**
- * A button component for muting the audio.
- *
- * @extends Button
- */
-var MuteToggle = function (_Button) {
-  _inherits(MuteToggle, _Button);
+        // 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)
+        }
+      }
+    });
+  };
 
   /**
-   * Creates an instance of this class.
+   * 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.
    *
-   * @param {Player} player
-   *        The `Player` that this class should be attached to.
+   * 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.
    *
-   * @param {Object} [options]
-   *        The key/value store of player options.
+   * 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
    */
-  function MuteToggle(player, options) {
-    _classCallCheck(this, MuteToggle);
-
-    var _this = _possibleConstructorReturn(this, _Button.call(this, player, options));
 
-    _this.on(player, 'volumechange', _this.update);
 
-    // hide mute toggle if the current tech doesn't support volume control
-    if (player.tech_ && player.tech_.featuresVolumeControl === false) {
-      _this.addClass('vjs-hidden');
+  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;
     }
 
-    _this.on(player, 'loadstart', function () {
-      // We need to update the button to account for a default muted state.
-      this.update();
+    // listener for reporting that the user is active
+    var report = bind(this.player(), this.player().reportUserActivity);
 
-      if (player.tech_.featuresVolumeControl === false) {
-        this.addClass('vjs-hidden');
-      } else {
-        this.removeClass('vjs-hidden');
-      }
-    });
-    return _this;
-  }
+    var touchHolding = void 0;
 
-  /**
-   * Builds the default DOM `className`.
-   *
-   * @return {string}
-   *         The DOM `className` for this object.
-   */
+    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);
+    };
 
-  MuteToggle.prototype.buildCSSClass = function buildCSSClass() {
-    return 'vjs-mute-control ' + _Button.prototype.buildCSSClass.call(this);
+    this.on('touchmove', report);
+    this.on('touchend', touchEnd);
+    this.on('touchcancel', touchEnd);
   };
 
   /**
-   * This gets called when an `MuteToggle` is "clicked". See
-   * {@link ClickableComponent} for more detailed information on what a click can be.
+   * A callback that has no parameters and is bound into `Component`s context.
    *
-   * @param {EventTarget~Event} [event]
-   *        The `keydown`, `tap`, or `click` event that caused this function to be
-   *        called.
-   *
-   * @listens tap
-   * @listens click
+   * @callback Component~GenericCallback
+   * @this Component
    */
 
-
-  MuteToggle.prototype.handleClick = function handleClick(event) {
-    this.player_.muted(this.player_.muted() ? false : true);
-  };
-
   /**
-   * Update the state of volume.
+   * 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}
    *
-   * @param {EventTarget~Event} [event]
-   *        The {@link Player#loadstart} event if this function was called through an
-   *        event.
+   * > 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}.
    *
-   * @listens Player#loadstart
+   * @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}
    */
 
 
-  MuteToggle.prototype.update = function update(event) {
-    var vol = this.player_.volume();
-    var level = 3;
+  Component.prototype.setTimeout = function setTimeout(fn, timeout) {
+    fn = bind(this, fn);
 
-    if (vol === 0 || this.player_.muted()) {
-      level = 0;
-    } else if (vol < 0.33) {
-      level = 1;
-    } else if (vol < 0.67) {
-      level = 2;
-    }
+    var timeoutId = window_1.setTimeout(fn, timeout);
+    var disposeFn = function disposeFn() {
+      this.clearTimeout(timeoutId);
+    };
 
-    // Don't rewrite the button text if the actual text doesn't change.
-    // This causes unnecessary and confusing information for screen reader users.
-    // This check is needed because this function gets called every time the volume level is changed.
-    var toMute = this.player_.muted() ? 'Unmute' : 'Mute';
+    disposeFn.guid = 'vjs-timeout-' + timeoutId;
 
-    if (this.controlText() !== toMute) {
-      this.controlText(toMute);
-    }
+    this.on('dispose', disposeFn);
 
-    // TODO improve muted icon classes
-    for (var i = 0; i < 4; i++) {
-      Dom.removeElClass(this.el_, 'vjs-vol-' + i);
-    }
-    Dom.addElClass(this.el_, 'vjs-vol-' + level);
+    return timeoutId;
   };
 
-  return MuteToggle;
-}(_button2['default']);
-
-/**
- * The text that should display over the `MuteToggle`s controls. Added for localization.
- *
- * @type {string}
- * @private
- */
-
+  /**
+   * 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}
+   */
 
-MuteToggle.prototype.controlText_ = 'Mute';
 
-_component2['default'].registerComponent('MuteToggle', MuteToggle);
-exports['default'] = MuteToggle;
+  Component.prototype.clearTimeout = function clearTimeout(timeoutId) {
+    window_1.clearTimeout(timeoutId);
 
-},{"2":2,"5":5,"81":81}],12:[function(_dereq_,module,exports){
-'use strict';
+    var disposeFn = function disposeFn() {};
 
-exports.__esModule = true;
+    disposeFn.guid = 'vjs-timeout-' + timeoutId;
 
-var _button = _dereq_(2);
+    this.off('dispose', disposeFn);
 
-var _button2 = _interopRequireDefault(_button);
+    return timeoutId;
+  };
 
-var _component = _dereq_(5);
+  /**
+   * 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}
+   */
 
-var _component2 = _interopRequireDefault(_component);
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+  Component.prototype.setInterval = function setInterval(fn, interval) {
+    fn = bind(this, fn);
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+    var intervalId = window_1.setInterval(fn, interval);
 
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+    var disposeFn = function disposeFn() {
+      this.clearInterval(intervalId);
+    };
 
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file play-toggle.js
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
+    disposeFn.guid = 'vjs-interval-' + intervalId;
 
+    this.on('dispose', disposeFn);
 
-/**
- * Button to toggle between play and pause.
- *
- * @extends Button
- */
-var PlayToggle = function (_Button) {
-  _inherits(PlayToggle, _Button);
+    return intervalId;
+  };
 
   /**
-   * Creates an instance of this class.
+   * 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 {Player} player
-   *        The `Player` that this class should be attached to.
+   * @param {number} intervalId
+   *        The id of the interval to clear. The return value of
+   *        {@link Component#setInterval} or `window.setInterval`.
    *
-   * @param {Object} [options]
-   *        The key/value store of player options.
+   * @return {number}
+   *         Returns the interval id that was cleared.
+   *
+   * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearInterval}
    */
-  function PlayToggle(player, options) {
-    _classCallCheck(this, PlayToggle);
 
-    var _this = _possibleConstructorReturn(this, _Button.call(this, player, options));
 
-    _this.on(player, 'play', _this.handlePlay);
-    _this.on(player, 'pause', _this.handlePause);
-    return _this;
-  }
+  Component.prototype.clearInterval = function clearInterval(intervalId) {
+    window_1.clearInterval(intervalId);
 
-  /**
-   * Builds the default DOM `className`.
-   *
-   * @return {string}
-   *         The DOM `className` for this object.
-   */
+    var disposeFn = function disposeFn() {};
 
+    disposeFn.guid = 'vjs-interval-' + intervalId;
 
-  PlayToggle.prototype.buildCSSClass = function buildCSSClass() {
-    return 'vjs-play-control ' + _Button.prototype.buildCSSClass.call(this);
+    this.off('dispose', disposeFn);
+
+    return intervalId;
   };
 
   /**
-   * This gets called when an `PlayToggle` is "clicked". See
-   * {@link ClickableComponent} for more detailed information on what a click can be.
+   * Queues up a callback to be passed to requestAnimationFrame (rAF), but
+   * with a few extra bonuses:
    *
-   * @param {EventTarget~Event} [event]
-   *        The `keydown`, `tap`, or `click` event that caused this function to be
-   *        called.
+   * - Supports browsers that do not support rAF by falling back to
+   *   {@link Component#setTimeout}.
    *
-   * @listens tap
-   * @listens click
+   * - The callback is turned into a {@link Component~GenericCallback} (i.e.
+   *   bound to the component).
+   *
+   * - Automatic cancellation of the rAF callback is handled if the component
+   *   is disposed before it is called.
+   *
+   * @param  {Component~GenericCallback} fn
+   *         A function that will be bound to this component and executed just
+   *         before the browser's next repaint.
+   *
+   * @return {number}
+   *         Returns an rAF ID that gets used to identify the timeout. It can
+   *         also be used in {@link Component#cancelAnimationFrame} to cancel
+   *         the animation frame callback.
+   *
+   * @listens Component#dispose
+   * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame}
    */
 
 
-  PlayToggle.prototype.handleClick = function handleClick(event) {
-    if (this.player_.paused()) {
-      this.player_.play();
-    } else {
-      this.player_.pause();
-    }
-  };
+  Component.prototype.requestAnimationFrame = function requestAnimationFrame(fn) {
+    var _this2 = this;
 
-  /**
-   * Add the vjs-playing class to the element so it can change appearance.
-   *
-   * @param {EventTarget~Event} [event]
-   *        The event that caused this function to run.
-   *
-   * @listens Player#play
-   */
+    if (this.supportsRaf_) {
+      fn = bind(this, fn);
 
+      var id = window_1.requestAnimationFrame(fn);
+      var disposeFn = function disposeFn() {
+        return _this2.cancelAnimationFrame(id);
+      };
 
-  PlayToggle.prototype.handlePlay = function handlePlay(event) {
-    this.removeClass('vjs-paused');
-    this.addClass('vjs-playing');
-    // change the button text to "Pause"
-    this.controlText('Pause');
+      disposeFn.guid = 'vjs-raf-' + id;
+      this.on('dispose', disposeFn);
+
+      return id;
+    }
+
+    // Fall back to using a timer.
+    return this.setTimeout(fn, 1000 / 60);
   };
 
   /**
-   * Add the vjs-paused class to the element so it can change appearance.
+   * Cancels a queued callback passed to {@link Component#requestAnimationFrame}
+   * (rAF).
    *
-   * @param {EventTarget~Event} [event]
-   *        The event that caused this function to run.
+   * If you queue an rAF callback via {@link Component#requestAnimationFrame},
+   * use this function instead of `window.cancelAnimationFrame`. If you don't,
+   * your dispose listener will not get cleaned up until {@link Component#dispose}!
    *
-   * @listens Player#pause
+   * @param {number} id
+   *        The rAF ID to clear. The return value of {@link Component#requestAnimationFrame}.
+   *
+   * @return {number}
+   *         Returns the rAF ID that was cleared.
+   *
+   * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/window/cancelAnimationFrame}
    */
 
 
-  PlayToggle.prototype.handlePause = function handlePause(event) {
-    this.removeClass('vjs-playing');
-    this.addClass('vjs-paused');
-    // change the button text to "Play"
-    this.controlText('Play');
-  };
-
-  return PlayToggle;
-}(_button2['default']);
-
-/**
- * The text that should display over the `PlayToggle`s controls. Added for localization.
- *
- * @type {string}
- * @private
- */
-
+  Component.prototype.cancelAnimationFrame = function cancelAnimationFrame(id) {
+    if (this.supportsRaf_) {
+      window_1.cancelAnimationFrame(id);
 
-PlayToggle.prototype.controlText_ = 'Play';
+      var disposeFn = function disposeFn() {};
 
-_component2['default'].registerComponent('PlayToggle', PlayToggle);
-exports['default'] = PlayToggle;
+      disposeFn.guid = 'vjs-raf-' + id;
 
-},{"2":2,"5":5}],13:[function(_dereq_,module,exports){
-'use strict';
+      this.off('dispose', disposeFn);
 
-exports.__esModule = true;
+      return id;
+    }
 
-var _menuButton = _dereq_(47);
+    // Fall back to using a timer.
+    return this.clearTimeout(id);
+  };
 
-var _menuButton2 = _interopRequireDefault(_menuButton);
+  /**
+   * 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} ComponentToRegister
+   *        The `Component` class to register.
+   *
+   * @return {Component}
+   *         The `Component` that was registered.
+   */
 
-var _menu = _dereq_(49);
 
-var _menu2 = _interopRequireDefault(_menu);
+  Component.registerComponent = function registerComponent(name, ComponentToRegister) {
+    if (typeof name !== 'string' || !name) {
+      throw new Error('Illegal component name, "' + name + '"; must be a non-empty string.');
+    }
 
-var _playbackRateMenuItem = _dereq_(14);
+    var Tech = Component.getComponent('Tech');
 
-var _playbackRateMenuItem2 = _interopRequireDefault(_playbackRateMenuItem);
+    // We need to make sure this check is only done if Tech has been registered.
+    var isTech = Tech && Tech.isTech(ComponentToRegister);
+    var isComp = Component === ComponentToRegister || Component.prototype.isPrototypeOf(ComponentToRegister.prototype);
 
-var _component = _dereq_(5);
+    if (isTech || !isComp) {
+      var reason = void 0;
 
-var _component2 = _interopRequireDefault(_component);
+      if (isTech) {
+        reason = 'techs must be registered using Tech.registerTech()';
+      } else {
+        reason = 'must be a Component subclass';
+      }
 
-var _dom = _dereq_(81);
+      throw new Error('Illegal component, "' + name + '"; ' + reason + '.');
+    }
 
-var Dom = _interopRequireWildcard(_dom);
+    name = toTitleCase(name);
 
-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; } }
+    if (!Component.components_) {
+      Component.components_ = {};
+    }
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+    var Player = Component.getComponent('Player');
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+    if (name === 'Player' && Player && Player.players) {
+      var players = Player.players;
+      var playerNames = Object.keys(players);
 
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+      // 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 (players && playerNames.length > 0 && playerNames.map(function (pname) {
+        return players[pname];
+      }).every(Boolean)) {
+        throw new Error('Can not register Player component after player has been created.');
+      }
+    }
 
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file playback-rate-menu-button.js
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
+    Component.components_[name] = ComponentToRegister;
 
-
-/**
- * The component for controlling the playback rate.
- *
- * @extends MenuButton
- */
-var PlaybackRateMenuButton = function (_MenuButton) {
-  _inherits(PlaybackRateMenuButton, _MenuButton);
-
-  /**
-   * 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.
-   */
-  function PlaybackRateMenuButton(player, options) {
-    _classCallCheck(this, PlaybackRateMenuButton);
-
-    var _this = _possibleConstructorReturn(this, _MenuButton.call(this, player, options));
-
-    _this.updateVisibility();
-    _this.updateLabel();
-
-    _this.on(player, 'loadstart', _this.updateVisibility);
-    _this.on(player, 'ratechange', _this.updateLabel);
-    return _this;
-  }
-
-  /**
-   * Create the `Component`'s DOM element
-   *
-   * @return {Element}
-   *         The element that was created.
-   */
-
-
-  PlaybackRateMenuButton.prototype.createEl = function createEl() {
-    var el = _MenuButton.prototype.createEl.call(this);
-
-    this.labelEl_ = Dom.createEl('div', {
-      className: 'vjs-playback-rate-value',
-      innerHTML: 1.0
-    });
-
-    el.appendChild(this.labelEl_);
-
-    return el;
-  };
-
-  /**
-   * Builds the default DOM `className`.
-   *
-   * @return {string}
-   *         The DOM `className` for this object.
-   */
-
-
-  PlaybackRateMenuButton.prototype.buildCSSClass = function buildCSSClass() {
-    return 'vjs-playback-rate ' + _MenuButton.prototype.buildCSSClass.call(this);
-  };
-
-  /**
-   * Create the playback rate menu
-   *
-   * @return {Menu}
-   *         Menu object populated with {@link PlaybackRateMenuItem}s
-   */
-
-
-  PlaybackRateMenuButton.prototype.createMenu = function createMenu() {
-    var menu = new _menu2['default'](this.player());
-    var rates = this.playbackRates();
-
-    if (rates) {
-      for (var i = rates.length - 1; i >= 0; i--) {
-        menu.addChild(new _playbackRateMenuItem2['default'](this.player(), { rate: rates[i] + 'x' }));
-      }
-    }
-
-    return menu;
-  };
-
-  /**
-   * Updates ARIA accessibility attributes
-   */
-
-
-  PlaybackRateMenuButton.prototype.updateARIAAttributes = function updateARIAAttributes() {
-    // Current playback rate
-    this.el().setAttribute('aria-valuenow', this.player().playbackRate());
-  };
-
-  /**
-   * This gets called when an `PlaybackRateMenuButton` is "clicked". See
-   * {@link ClickableComponent} for more detailed information on what a click can be.
-   *
-   * @param {EventTarget~Event} [event]
-   *        The `keydown`, `tap`, or `click` event that caused this function to be
-   *        called.
-   *
-   * @listens tap
-   * @listens click
-   */
-
-
-  PlaybackRateMenuButton.prototype.handleClick = function handleClick(event) {
-    // select next rate option
-    var currentRate = this.player().playbackRate();
-    var rates = this.playbackRates();
-
-    // this will select first one if the last one currently selected
-    var newRate = rates[0];
-
-    for (var i = 0; i < rates.length; i++) {
-      if (rates[i] > currentRate) {
-        newRate = rates[i];
-        break;
-      }
-    }
-    this.player().playbackRate(newRate);
-  };
-
-  /**
-   * Get possible playback rates
-   *
-   * @return {Array}
-   *         All possible playback rates
-   */
-
-
-  PlaybackRateMenuButton.prototype.playbackRates = function playbackRates() {
-    return this.options_.playbackRates || this.options_.playerOptions && this.options_.playerOptions.playbackRates;
-  };
+    return ComponentToRegister;
+  };
 
   /**
-   * Get whether playback rates is supported by the tech
-   * and an array of playback rates exists
+   * Get a `Component` based on the name it was registered with.
    *
-   * @return {boolean}
-   *         Whether changing playback rate is supported
-   */
-
-
-  PlaybackRateMenuButton.prototype.playbackRateSupported = function playbackRateSupported() {
-    return this.player().tech_ && this.player().tech_.featuresPlaybackRate && this.playbackRates() && this.playbackRates().length > 0;
-  };
-
-  /**
-   * Hide playback rate controls when they're no playback rate options to select
+   * @param {string} name
+   *        The Name of the component to get.
    *
-   * @param {EventTarget~Event} [event]
-   *        The event that caused this function to run.
+   * @return {Component}
+   *         The `Component` that got registered under the given name.
    *
-   * @listens Player#loadstart
+   * @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.
    */
 
 
-  PlaybackRateMenuButton.prototype.updateVisibility = function updateVisibility(event) {
-    if (this.playbackRateSupported()) {
-      this.removeClass('vjs-hidden');
-    } else {
-      this.addClass('vjs-hidden');
+  Component.getComponent = function getComponent(name) {
+    if (!name) {
+      return;
     }
-  };
-
-  /**
-   * Update button label when rate changed
-   *
-   * @param {EventTarget~Event} [event]
-   *        The event that caused this function to run.
-   *
-   * @listens Player#ratechange
-   */
 
+    name = toTitleCase(name);
 
-  PlaybackRateMenuButton.prototype.updateLabel = function updateLabel(event) {
-    if (this.playbackRateSupported()) {
-      this.labelEl_.innerHTML = this.player().playbackRate() + 'x';
+    if (Component.components_ && Component.components_[name]) {
+      return Component.components_[name];
     }
   };
 
-  return PlaybackRateMenuButton;
-}(_menuButton2['default']);
+  return Component;
+}();
 
 /**
- * The text that should display over the `FullscreenToggle`s controls. Added for localization.
+ * Whether or not this component supports `requestAnimationFrame`.
+ *
+ * This is exposed primarily for testing purposes.
  *
- * @type {string}
  * @private
+ * @type {Boolean}
  */
 
 
-PlaybackRateMenuButton.prototype.controlText_ = 'Playback Rate';
-
-_component2['default'].registerComponent('PlaybackRateMenuButton', PlaybackRateMenuButton);
-exports['default'] = PlaybackRateMenuButton;
-
-},{"14":14,"47":47,"49":49,"5":5,"81":81}],14:[function(_dereq_,module,exports){
-'use strict';
-
-exports.__esModule = true;
+Component.prototype.supportsRaf_ = typeof window_1.requestAnimationFrame === 'function' && typeof window_1.cancelAnimationFrame === 'function';
 
-var _menuItem = _dereq_(48);
-
-var _menuItem2 = _interopRequireDefault(_menuItem);
-
-var _component = _dereq_(5);
-
-var _component2 = _interopRequireDefault(_component);
-
-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"); } }
-
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
-
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file playback-rate-menu-item.js
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
+Component.registerComponent('Component', Component);
 
+/**
+ * @file time-ranges.js
+ * @module time-ranges
+ */
 
 /**
- * The specific menu item type for selecting a playback rate.
+ * Returns the time for the specified index at the start or end
+ * of a TimeRange object.
  *
- * @extends MenuItem
+ * @function time-ranges:indexFunction
+ *
+ * @param {number} [index=0]
+ *        The range number to return the time for.
+ *
+ * @return {number}
+ *         The time that offset at the specified index.
+ *
+ * @depricated index must be set to a value, in the future this will throw an error.
  */
-var PlaybackRateMenuItem = function (_MenuItem) {
-  _inherits(PlaybackRateMenuItem, _MenuItem);
 
-  /**
-   * 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.
-   */
-  function PlaybackRateMenuItem(player, options) {
-    _classCallCheck(this, PlaybackRateMenuItem);
+/**
+ * An object that contains ranges of time for various reasons.
+ *
+ * @typedef {Object} TimeRange
+ *
+ * @property {number} length
+ *           The number of time ranges represented by this Object
+ *
+ * @property {time-ranges:indexFunction} start
+ *           Returns the time offset at which a specified time range begins.
+ *
+ * @property {time-ranges:indexFunction} end
+ *           Returns the time offset at which a specified time range begins.
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TimeRanges
+ */
 
-    var label = options.rate;
-    var rate = parseFloat(label, 10);
+/**
+ * Check if any of the time ranges are over the maximum index.
+ *
+ * @param {string} fnName
+ *        The function name to use for logging
+ *
+ * @param {number} index
+ *        The index to check
+ *
+ * @param {number} maxIndex
+ *        The maximum possible index
+ *
+ * @throws {Error} if the timeRanges provided are over the maxIndex
+ */
+function rangeCheck(fnName, index, maxIndex) {
+  if (typeof index !== 'number' || index < 0 || index > maxIndex) {
+    throw new Error('Failed to execute \'' + fnName + '\' on \'TimeRanges\': The index provided (' + index + ') is non-numeric or out of bounds (0-' + maxIndex + ').');
+  }
+}
 
-    // Modify options for parent MenuItem class's init.
-    options.label = label;
-    options.selected = rate === 1;
-    options.selectable = true;
-
-    var _this = _possibleConstructorReturn(this, _MenuItem.call(this, player, options));
+/**
+ * Check if any of the time ranges are over the maximum index.
+ *
+ * @param {string} fnName
+ *        The function name to use for logging
+ *
+ * @param {string} valueIndex
+ *        The proprety that should be used to get the time. should be 'start' or 'end'
+ *
+ * @param {Array} ranges
+ *        An array of time ranges
+ *
+ * @param {Array} [rangeIndex=0]
+ *        The index to start the search at
+ *
+ * @return {number}
+ *         The time that offset at the specified index.
+ *
+ *
+ * @depricated rangeIndex must be set to a value, in the future this will throw an error.
+ * @throws {Error} if rangeIndex is more than the length of ranges
+ */
+function getRange(fnName, valueIndex, ranges, rangeIndex) {
+  rangeCheck(fnName, rangeIndex, ranges.length - 1);
+  return ranges[rangeIndex][valueIndex];
+}
 
-    _this.label = label;
-    _this.rate = rate;
+/**
+ * Create a time range object givent ranges of time.
+ *
+ * @param {Array} [ranges]
+ *        An array of time ranges.
+ */
+function createTimeRangesObj(ranges) {
+  if (ranges === undefined || ranges.length === 0) {
+    return {
+      length: 0,
+      start: function start() {
+        throw new Error('This TimeRanges object is empty');
+      },
+      end: function end() {
+        throw new Error('This TimeRanges object is empty');
+      }
+    };
+  }
+  return {
+    length: ranges.length,
+    start: getRange.bind(null, 'start', 0, ranges),
+    end: getRange.bind(null, 'end', 1, ranges)
+  };
+}
 
-    _this.on(player, 'ratechange', _this.update);
-    return _this;
+/**
+ * Should create a fake `TimeRange` object which mimics an HTML5 time range instance.
+ *
+ * @param {number|Array} start
+ *        The start of a single range or an array of ranges
+ *
+ * @param {number} end
+ *        The end of a single range.
+ *
+ * @private
+ */
+function createTimeRanges(start, end) {
+  if (Array.isArray(start)) {
+    return createTimeRangesObj(start);
+  } else if (start === undefined || end === undefined) {
+    return createTimeRangesObj();
   }
+  return createTimeRangesObj([[start, end]]);
+}
 
-  /**
-   * This gets called when an `PlaybackRateMenuItem` is "clicked". See
-   * {@link ClickableComponent} for more detailed information on what a click can be.
-   *
-   * @param {EventTarget~Event} [event]
-   *        The `keydown`, `tap`, or `click` event that caused this function to be
-   *        called.
-   *
-   * @listens tap
-   * @listens click
-   */
+/**
+ * @file buffer.js
+ * @module buffer
+ */
+/**
+ * Compute the percentage of the media that has been buffered.
+ *
+ * @param {TimeRange} buffered
+ *        The current `TimeRange` object representing buffered time ranges
+ *
+ * @param {number} duration
+ *        Total duration of the media
+ *
+ * @return {number}
+ *         Percent buffered of the total duration in decimal form.
+ */
+function bufferedPercent(buffered, duration) {
+  var bufferedDuration = 0;
+  var start = void 0;
+  var end = void 0;
 
+  if (!duration) {
+    return 0;
+  }
 
-  PlaybackRateMenuItem.prototype.handleClick = function handleClick(event) {
-    _MenuItem.prototype.handleClick.call(this);
-    this.player().playbackRate(this.rate);
-  };
+  if (!buffered || !buffered.length) {
+    buffered = createTimeRanges(0, 0);
+  }
 
-  /**
-   * Update the PlaybackRateMenuItem when the playbackrate changes.
-   *
-   * @param {EventTarget~Event} [event]
-   *        The `ratechange` event that caused this function to run.
-   *
-   * @listens Player#ratechange
-   */
+  for (var i = 0; i < buffered.length; i++) {
+    start = buffered.start(i);
+    end = buffered.end(i);
 
+    // buffered end can be bigger than duration by a very small fraction
+    if (end > duration) {
+      end = duration;
+    }
 
-  PlaybackRateMenuItem.prototype.update = function update(event) {
-    this.selected(this.player().playbackRate() === this.rate);
-  };
+    bufferedDuration += end - start;
+  }
 
-  return PlaybackRateMenuItem;
-}(_menuItem2['default']);
+  return bufferedDuration / duration;
+}
 
 /**
- * The text that should display over the `PlaybackRateMenuItem`s controls. Added for localization.
- *
- * @type {string}
+ * @file fullscreen-api.js
+ * @module fullscreen-api
  * @private
  */
+/**
+ * Store the browser-specific methods for the fullscreen API.
+ *
+ * @type {Object}
+ * @see [Specification]{@link https://fullscreen.spec.whatwg.org}
+ * @see [Map Approach From Screenfull.js]{@link https://github.com/sindresorhus/screenfull.js}
+ */
+var FullscreenApi = {};
 
+// browser API methods
+var apiMap = [['requestFullscreen', 'exitFullscreen', 'fullscreenElement', 'fullscreenEnabled', 'fullscreenchange', 'fullscreenerror'],
+// WebKit
+['webkitRequestFullscreen', 'webkitExitFullscreen', 'webkitFullscreenElement', 'webkitFullscreenEnabled', 'webkitfullscreenchange', 'webkitfullscreenerror'],
+// Old WebKit (Safari 5.1)
+['webkitRequestFullScreen', 'webkitCancelFullScreen', 'webkitCurrentFullScreenElement', 'webkitCancelFullScreen', 'webkitfullscreenchange', 'webkitfullscreenerror'],
+// Mozilla
+['mozRequestFullScreen', 'mozCancelFullScreen', 'mozFullScreenElement', 'mozFullScreenEnabled', 'mozfullscreenchange', 'mozfullscreenerror'],
+// Microsoft
+['msRequestFullscreen', 'msExitFullscreen', 'msFullscreenElement', 'msFullscreenEnabled', 'MSFullscreenChange', 'MSFullscreenError']];
 
-PlaybackRateMenuItem.prototype.contentElType = 'button';
-
-_component2['default'].registerComponent('PlaybackRateMenuItem', PlaybackRateMenuItem);
-exports['default'] = PlaybackRateMenuItem;
-
-},{"48":48,"5":5}],15:[function(_dereq_,module,exports){
-'use strict';
+var specApi = apiMap[0];
+var browserApi = void 0;
 
-exports.__esModule = true;
+// determine the supported set of functions
+for (var i = 0; i < apiMap.length; i++) {
+  // check for exitFullscreen function
+  if (apiMap[i][1] in document_1) {
+    browserApi = apiMap[i];
+    break;
+  }
+}
 
-var _component = _dereq_(5);
+// map the browser API names to the spec API names
+if (browserApi) {
+  for (var _i = 0; _i < browserApi.length; _i++) {
+    FullscreenApi[specApi[_i]] = browserApi[_i];
+  }
+}
 
-var _component2 = _interopRequireDefault(_component);
+/**
+ * @file media-error.js
+ */
+/**
+ * A Custom `MediaError` class which mimics the standard HTML5 `MediaError` class.
+ *
+ * @param {number|string|Object|MediaError} value
+ *        This can be of multiple types:
+ *        - number: should be a standard error code
+ *        - string: an error message (the code will be 0)
+ *        - Object: arbitrary properties
+ *        - `MediaError` (native): used to populate a video.js `MediaError` object
+ *        - `MediaError` (video.js): will return itself if it's already a
+ *          video.js `MediaError` object.
+ *
+ * @see [MediaError Spec]{@link https://dev.w3.org/html5/spec-author-view/video.html#mediaerror}
+ * @see [Encrypted MediaError Spec]{@link https://www.w3.org/TR/2013/WD-encrypted-media-20130510/#error-codes}
+ *
+ * @class MediaError
+ */
+function MediaError(value) {
 
-var _dom = _dereq_(81);
+  // Allow redundant calls to this constructor to avoid having `instanceof`
+  // checks peppered around the code.
+  if (value instanceof MediaError) {
+    return value;
+  }
 
-var Dom = _interopRequireWildcard(_dom);
+  if (typeof value === 'number') {
+    this.code = value;
+  } else if (typeof value === 'string') {
+    // default code is zero, so this is a custom error
+    this.message = value;
+  } else if (isObject(value)) {
 
-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; } }
+    // We assign the `code` property manually because native `MediaError` objects
+    // do not expose it as an own/enumerable property of the object.
+    if (typeof value.code === 'number') {
+      this.code = value.code;
+    }
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+    assign(this, value);
+  }
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+  if (!this.message) {
+    this.message = MediaError.defaultMessages[this.code] || '';
+  }
+}
 
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+/**
+ * The error code that refers two one of the defined `MediaError` types
+ *
+ * @type {Number}
+ */
+MediaError.prototype.code = 0;
 
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file load-progress-bar.js
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
+/**
+ * An optional message that to show with the error. Message is not part of the HTML5
+ * video spec but allows for more informative custom errors.
+ *
+ * @type {String}
+ */
+MediaError.prototype.message = '';
 
+/**
+ * An optional status code that can be set by plugins to allow even more detail about
+ * the error. For example a plugin might provide a specific HTTP status code and an
+ * error message for that code. Then when the plugin gets that error this class will
+ * know how to display an error message for it. This allows a custom message to show
+ * up on the `Player` error overlay.
+ *
+ * @type {Array}
+ */
+MediaError.prototype.status = null;
 
 /**
- * Shows loading progress
+ * Errors indexed by the W3C standard. The order **CANNOT CHANGE**! See the
+ * specification listed under {@link MediaError} for more information.
  *
- * @extends Component
+ * @enum {array}
+ * @readonly
+ * @property {string} 0 - MEDIA_ERR_CUSTOM
+ * @property {string} 1 - MEDIA_ERR_CUSTOM
+ * @property {string} 2 - MEDIA_ERR_ABORTED
+ * @property {string} 3 - MEDIA_ERR_NETWORK
+ * @property {string} 4 - MEDIA_ERR_SRC_NOT_SUPPORTED
+ * @property {string} 5 - MEDIA_ERR_ENCRYPTED
  */
-var LoadProgressBar = function (_Component) {
-  _inherits(LoadProgressBar, _Component);
+MediaError.errorTypes = ['MEDIA_ERR_CUSTOM', 'MEDIA_ERR_ABORTED', 'MEDIA_ERR_NETWORK', 'MEDIA_ERR_DECODE', 'MEDIA_ERR_SRC_NOT_SUPPORTED', 'MEDIA_ERR_ENCRYPTED'];
 
-  /**
-   * 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.
-   */
-  function LoadProgressBar(player, options) {
-    _classCallCheck(this, LoadProgressBar);
-
-    var _this = _possibleConstructorReturn(this, _Component.call(this, player, options));
-
-    _this.partEls_ = [];
-    _this.on(player, 'progress', _this.update);
-    return _this;
-  }
-
-  /**
-   * Create the `Component`'s DOM element
-   *
-   * @return {Element}
-   *         The element that was created.
-   */
-
-
-  LoadProgressBar.prototype.createEl = function createEl() {
-    return _Component.prototype.createEl.call(this, 'div', {
-      className: 'vjs-load-progress',
-      innerHTML: '<span class="vjs-control-text"><span>' + this.localize('Loaded') + '</span>: 0%</span>'
-    });
-  };
-
-  /**
-   * Update progress bar
-   *
-   * @param {EventTarget~Event} [event]
-   *        The `progress` event that caused this function to run.
-   *
-   * @listens Player#progress
-   */
-
-
-  LoadProgressBar.prototype.update = function update(event) {
-    var buffered = this.player_.buffered();
-    var duration = this.player_.duration();
-    var bufferedEnd = this.player_.bufferedEnd();
-    var children = this.partEls_;
-
-    // get the percent width of a time compared to the total end
-    var percentify = function percentify(time, end) {
-      // no NaN
-      var percent = time / end || 0;
-
-      return (percent >= 1 ? 1 : percent) * 100 + '%';
-    };
-
-    // update the width of the progress bar
-    this.el_.style.width = percentify(bufferedEnd, duration);
+/**
+ * The default `MediaError` messages based on the {@link MediaError.errorTypes}.
+ *
+ * @type {Array}
+ * @constant
+ */
+MediaError.defaultMessages = {
+  1: 'You aborted the media playback',
+  2: 'A network error caused the media download to fail part-way.',
+  3: 'The media playback was aborted due to a corruption problem or because the media used features your browser did not support.',
+  4: 'The media could not be loaded, either because the server or network failed or because the format is not supported.',
+  5: 'The media is encrypted and we do not have the keys to decrypt it.'
+};
 
-    // add child elements to represent the individual buffered time ranges
-    for (var i = 0; i < buffered.length; i++) {
-      var start = buffered.start(i);
-      var end = buffered.end(i);
-      var part = children[i];
+// Add types as properties on MediaError
+// e.g. MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED = 4;
+for (var errNum = 0; errNum < MediaError.errorTypes.length; errNum++) {
+  MediaError[MediaError.errorTypes[errNum]] = errNum;
+  // values should be accessible on both the class and instance
+  MediaError.prototype[MediaError.errorTypes[errNum]] = errNum;
+}
 
-      if (!part) {
-        part = this.el_.appendChild(Dom.createEl());
-        children[i] = part;
-      }
+var tuple = SafeParseTuple;
 
-      // set the percent based on the width of the progress bar (bufferedEnd)
-      part.style.left = percentify(start, bufferedEnd);
-      part.style.width = percentify(end - start, bufferedEnd);
-    }
+function SafeParseTuple(obj, reviver) {
+    var json;
+    var error = null;
 
-    // remove unused buffered range elements
-    for (var _i = children.length; _i > buffered.length; _i--) {
-      this.el_.removeChild(children[_i - 1]);
+    try {
+        json = JSON.parse(obj, reviver);
+    } catch (err) {
+        error = err;
     }
-    children.length = buffered.length;
-  };
-
-  return LoadProgressBar;
-}(_component2['default']);
-
-_component2['default'].registerComponent('LoadProgressBar', LoadProgressBar);
-exports['default'] = LoadProgressBar;
 
-},{"5":5,"81":81}],16:[function(_dereq_,module,exports){
-'use strict';
-
-exports.__esModule = true;
-
-var _component = _dereq_(5);
+    return [error, json]
+}
 
-var _component2 = _interopRequireDefault(_component);
+/**
+ * @file text-track-list-converter.js Utilities for capturing text track state and
+ * re-creating tracks based on a capture.
+ *
+ * @module text-track-list-converter
+ */
 
-var _dom = _dereq_(81);
+/**
+ * Examine a single {@link TextTrack} and return a JSON-compatible javascript object that
+ * represents the {@link TextTrack}'s state.
+ *
+ * @param {TextTrack} track
+ *        The text track to query.
+ *
+ * @return {Object}
+ *         A serializable javascript representation of the TextTrack.
+ * @private
+ */
+var trackToJson_ = function trackToJson_(track) {
+  var ret = ['kind', 'label', 'language', 'id', 'inBandMetadataTrackDispatchType', 'mode', 'src'].reduce(function (acc, prop, i) {
 
-var Dom = _interopRequireWildcard(_dom);
+    if (track[prop]) {
+      acc[prop] = track[prop];
+    }
 
-var _fn = _dereq_(83);
+    return acc;
+  }, {
+    cues: track.cues && Array.prototype.map.call(track.cues, function (cue) {
+      return {
+        startTime: cue.startTime,
+        endTime: cue.endTime,
+        text: cue.text,
+        id: cue.id
+      };
+    })
+  });
 
-var Fn = _interopRequireWildcard(_fn);
+  return ret;
+};
 
-var _formatTime = _dereq_(84);
+/**
+ * Examine a {@link Tech} and return a JSON-compatible javascript array that represents the
+ * state of all {@link TextTrack}s currently configured. The return array is compatible with
+ * {@link text-track-list-converter:jsonToTextTracks}.
+ *
+ * @param {Tech} tech
+ *        The tech object to query
+ *
+ * @return {Array}
+ *         A serializable javascript representation of the {@link Tech}s
+ *         {@link TextTrackList}.
+ */
+var textTracksToJson = function textTracksToJson(tech) {
 
-var _formatTime2 = _interopRequireDefault(_formatTime);
+  var trackEls = tech.$$('track');
 
-var _computedStyle = _dereq_(80);
+  var trackObjs = Array.prototype.map.call(trackEls, function (t) {
+    return t.track;
+  });
+  var tracks = Array.prototype.map.call(trackEls, function (trackEl) {
+    var json = trackToJson_(trackEl.track);
 
-var _computedStyle2 = _interopRequireDefault(_computedStyle);
+    if (trackEl.src) {
+      json.src = trackEl.src;
+    }
+    return json;
+  });
 
-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; } }
+  return tracks.concat(Array.prototype.filter.call(tech.textTracks(), function (track) {
+    return trackObjs.indexOf(track) === -1;
+  }).map(trackToJson_));
+};
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+/**
+ * Create a set of remote {@link TextTrack}s on a {@link Tech} based on an array of javascript
+ * object {@link TextTrack} representations.
+ *
+ * @param {Array} json
+ *        An array of `TextTrack` representation objects, like those that would be
+ *        produced by `textTracksToJson`.
+ *
+ * @param {Tech} tech
+ *        The `Tech` to create the `TextTrack`s on.
+ */
+var jsonToTextTracks = function jsonToTextTracks(json, tech) {
+  json.forEach(function (track) {
+    var addedTrack = tech.addRemoteTextTrack(track).track;
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+    if (!track.src && track.cues) {
+      track.cues.forEach(function (cue) {
+        return addedTrack.addCue(cue);
+      });
+    }
+  });
 
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+  return tech.textTracks();
+};
 
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file mouse-time-display.js
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
+var textTrackConverter = { textTracksToJson: textTracksToJson, jsonToTextTracks: jsonToTextTracks, trackToJson_: trackToJson_ };
 
+/**
+ * @file modal-dialog.js
+ */
+var MODAL_CLASS_NAME = 'vjs-modal-dialog';
+var ESC = 27;
 
 /**
- * The Mouse Time Display component shows the time you will seek to
- * when hovering over the progress bar
+ * The `ModalDialog` displays over the video and its controls, which blocks
+ * interaction with the player until it is closed.
+ *
+ * Modal dialogs include a "Close" button and will close when that button
+ * is activated - or when ESC is pressed anywhere.
  *
  * @extends Component
  */
-var MouseTimeDisplay = function (_Component) {
-  _inherits(MouseTimeDisplay, _Component);
+
+var ModalDialog = function (_Component) {
+  inherits(ModalDialog, _Component);
 
   /**
-   * Creates an instance of this class.
+   * Create 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 {Mixed} [options.content=undefined]
+   *        Provide customized content for this modal.
+   *
+   * @param {string} [options.description]
+   *        A text description for the modal, primarily for accessibility.
+   *
+   * @param {boolean} [options.fillAlways=false]
+   *        Normally, modals are automatically filled only the first time
+   *        they open. This tells the modal to refresh its content
+   *        every time it opens.
+   *
+   * @param {string} [options.label]
+   *        A text label for the modal, primarily for accessibility.
+   *
+   * @param {boolean} [options.temporary=true]
+   *        If `true`, the modal can only be opened once; it will be
+   *        disposed as soon as it's closed.
+   *
+   * @param {boolean} [options.uncloseable=false]
+   *        If `true`, the user will not be able to close the modal
+   *        through the UI in the normal ways. Programmatic closing is
+   *        still possible.
    */
-  function MouseTimeDisplay(player, options) {
-    _classCallCheck(this, MouseTimeDisplay);
+  function ModalDialog(player, options) {
+    classCallCheck(this, ModalDialog);
 
-    var _this = _possibleConstructorReturn(this, _Component.call(this, player, options));
+    var _this = possibleConstructorReturn(this, _Component.call(this, player, options));
 
-    if (options.playerOptions && options.playerOptions.controlBar && options.playerOptions.controlBar.progressControl && options.playerOptions.controlBar.progressControl.keepTooltipsInside) {
-      _this.keepTooltipsInside = options.playerOptions.controlBar.progressControl.keepTooltipsInside;
-    }
+    _this.opened_ = _this.hasBeenOpened_ = _this.hasBeenFilled_ = false;
 
-    if (_this.keepTooltipsInside) {
-      _this.tooltip = Dom.createEl('div', { className: 'vjs-time-tooltip' });
-      _this.el().appendChild(_this.tooltip);
-      _this.addClass('vjs-keep-tooltips-inside');
-    }
+    _this.closeable(!_this.options_.uncloseable);
+    _this.content(_this.options_.content);
 
-    _this.update(0, 0);
+    // Make sure the contentEl is defined AFTER any children are initialized
+    // because we only want the contents of the modal in the contentEl
+    // (not the UI elements like the close button).
+    _this.contentEl_ = createEl('div', {
+      className: MODAL_CLASS_NAME + '-content'
+    }, {
+      role: 'document'
+    });
 
-    player.on('ready', function () {
-      _this.on(player.controlBar.progressControl.el(), 'mousemove', Fn.throttle(Fn.bind(_this, _this.handleMouseMove), 25));
+    _this.descEl_ = createEl('p', {
+      className: MODAL_CLASS_NAME + '-description vjs-control-text',
+      id: _this.el().getAttribute('aria-describedby')
     });
+
+    textContent(_this.descEl_, _this.description());
+    _this.el_.appendChild(_this.descEl_);
+    _this.el_.appendChild(_this.contentEl_);
     return _this;
   }
 
   /**
-   * Create the `Component`'s DOM element
+   * Create the `ModalDialog`'s DOM element
    *
    * @return {Element}
-   *         The element that was created.
+   *         The DOM element that gets created.
    */
 
 
-  MouseTimeDisplay.prototype.createEl = function createEl() {
+  ModalDialog.prototype.createEl = function createEl$$1() {
     return _Component.prototype.createEl.call(this, 'div', {
-      className: 'vjs-mouse-display'
-    });
-  };
-
-  /**
-   * Handle the mouse move event on the `MouseTimeDisplay`.
-   *
-   * @param {EventTarget~Event} event
-   *        The `mousemove` event that caused this to event to run.
+      className: this.buildCSSClass(),
+      tabIndex: -1
+    }, {
+      'aria-describedby': this.id() + '_description',
+      'aria-hidden': 'true',
+      'aria-label': this.label(),
+      'role': 'dialog'
+    });
+  };
+
+  /**
+   * Builds the default DOM `className`.
    *
-   * @listen mousemove
+   * @return {string}
+   *         The DOM `className` for this object.
    */
 
 
-  MouseTimeDisplay.prototype.handleMouseMove = function handleMouseMove(event) {
-    var duration = this.player_.duration();
-    var newTime = this.calculateDistance(event) * duration;
-    var position = event.pageX - Dom.findElPosition(this.el().parentNode).left;
-
-    this.update(newTime, position);
+  ModalDialog.prototype.buildCSSClass = function buildCSSClass() {
+    return MODAL_CLASS_NAME + ' vjs-hidden ' + _Component.prototype.buildCSSClass.call(this);
   };
 
   /**
-   * Update the time and posistion of the `MouseTimeDisplay`.
+   * Handles `keydown` events on the document, looking for ESC, which closes
+   * the modal.
    *
-   * @param {number} newTime
-   *        Time to change the `MouseTimeDisplay` to.
+   * @param {EventTarget~Event} e
+   *        The keypress that triggered this event.
    *
-   * @param {nubmer} position
-   *        Postion from the left of the in pixels.
+   * @listens keydown
    */
 
 
-  MouseTimeDisplay.prototype.update = function update(newTime, position) {
-    var time = (0, _formatTime2['default'])(newTime, this.player_.duration());
-
-    this.el().style.left = position + 'px';
-    this.el().setAttribute('data-current-time', time);
-
-    if (this.keepTooltipsInside) {
-      var clampedPosition = this.clampPosition_(position);
-      var difference = position - clampedPosition + 1;
-      var tooltipWidth = parseFloat((0, _computedStyle2['default'])(this.tooltip, 'width'));
-      var tooltipWidthHalf = tooltipWidth / 2;
-
-      this.tooltip.innerHTML = time;
-      this.tooltip.style.right = '-' + (tooltipWidthHalf - difference) + 'px';
+  ModalDialog.prototype.handleKeyPress = function handleKeyPress(e) {
+    if (e.which === ESC && this.closeable()) {
+      this.close();
     }
   };
 
   /**
-   * Get the mouse pointers x coordinate in pixels.
-   *
-   * @param {EventTarget~Event} [event]
-   *        The `mousemove` event that was passed to this function by
-   *        {@link MouseTimeDisplay#handleMouseMove}
+   * Returns the label string for this modal. Primarily used for accessibility.
    *
-   * @return {number}
-   *         THe x position in pixels of the mouse pointer.
+   * @return {string}
+   *         the localized or raw label of this modal.
    */
 
 
-  MouseTimeDisplay.prototype.calculateDistance = function calculateDistance(event) {
-    return Dom.getPointerPosition(this.el().parentNode, event).x;
+  ModalDialog.prototype.label = function label() {
+    return this.localize(this.options_.label || 'Modal Window');
   };
 
   /**
-   * This takes in a horizontal position for the bar and returns a clamped position.
-   * Clamped position means that it will keep the position greater than half the width
-   * of the tooltip and smaller than the player width minus half the width o the tooltip.
-   * It will only clamp the position if `keepTooltipsInside` option is set.
-   *
-   * @param {number} position
-   *        The position the bar wants to be
-   *
-   * @return {number}
-   *         The (potentially) new clamped position.
+   * Returns the description string for this modal. Primarily used for
+   * accessibility.
    *
-   * @private
+   * @return {string}
+   *         The localized or raw description of this modal.
    */
 
 
-  MouseTimeDisplay.prototype.clampPosition_ = function clampPosition_(position) {
-    if (!this.keepTooltipsInside) {
-      return position;
-    }
-
-    var playerWidth = parseFloat((0, _computedStyle2['default'])(this.player().el(), 'width'));
-    var tooltipWidth = parseFloat((0, _computedStyle2['default'])(this.tooltip, 'width'));
-    var tooltipWidthHalf = tooltipWidth / 2;
-    var actualPosition = position;
+  ModalDialog.prototype.description = function description() {
+    var desc = this.options_.description || this.localize('This is a modal window.');
 
-    if (position < tooltipWidthHalf) {
-      actualPosition = Math.ceil(tooltipWidthHalf);
-    } else if (position > playerWidth - tooltipWidthHalf) {
-      actualPosition = Math.floor(playerWidth - tooltipWidthHalf);
+    // Append a universal closeability message if the modal is closeable.
+    if (this.closeable()) {
+      desc += ' ' + this.localize('This modal can be closed by pressing the Escape key or activating the close button.');
     }
 
-    return actualPosition;
+    return desc;
   };
 
-  return MouseTimeDisplay;
-}(_component2['default']);
-
-_component2['default'].registerComponent('MouseTimeDisplay', MouseTimeDisplay);
-exports['default'] = MouseTimeDisplay;
-
-},{"5":5,"80":80,"81":81,"83":83,"84":84}],17:[function(_dereq_,module,exports){
-'use strict';
-
-exports.__esModule = true;
-
-var _component = _dereq_(5);
+  /**
+   * Opens the modal.
+   *
+   * @fires ModalDialog#beforemodalopen
+   * @fires ModalDialog#modalopen
+   */
 
-var _component2 = _interopRequireDefault(_component);
 
-var _fn = _dereq_(83);
+  ModalDialog.prototype.open = function open() {
+    if (!this.opened_) {
+      var player = this.player();
 
-var Fn = _interopRequireWildcard(_fn);
+      /**
+        * Fired just before a `ModalDialog` is opened.
+        *
+        * @event ModalDialog#beforemodalopen
+        * @type {EventTarget~Event}
+        */
+      this.trigger('beforemodalopen');
+      this.opened_ = true;
 
-var _formatTime = _dereq_(84);
+      // Fill content if the modal has never opened before and
+      // never been filled.
+      if (this.options_.fillAlways || !this.hasBeenOpened_ && !this.hasBeenFilled_) {
+        this.fill();
+      }
 
-var _formatTime2 = _interopRequireDefault(_formatTime);
+      // If the player was playing, pause it and take note of its previously
+      // playing state.
+      this.wasPlaying_ = !player.paused();
 
-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; } }
+      if (this.options_.pauseOnOpen && this.wasPlaying_) {
+        player.pause();
+      }
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+      if (this.closeable()) {
+        this.on(this.el_.ownerDocument, 'keydown', bind(this, this.handleKeyPress));
+      }
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+      player.controls(false);
+      this.show();
+      this.conditionalFocus_();
+      this.el().setAttribute('aria-hidden', 'false');
 
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+      /**
+        * Fired just after a `ModalDialog` is opened.
+        *
+        * @event ModalDialog#modalopen
+        * @type {EventTarget~Event}
+        */
+      this.trigger('modalopen');
+      this.hasBeenOpened_ = true;
+    }
+  };
 
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file play-progress-bar.js
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
+  /**
+   * If the `ModalDialog` is currently open or closed.
+   *
+   * @param  {boolean} [value]
+   *         If given, it will open (`true`) or close (`false`) the modal.
+   *
+   * @return {boolean}
+   *         the current open state of the modaldialog
+   */
 
 
-/**
- * Shows play progress
- *
- * @extends Component
- */
-var PlayProgressBar = function (_Component) {
-  _inherits(PlayProgressBar, _Component);
+  ModalDialog.prototype.opened = function opened(value) {
+    if (typeof value === 'boolean') {
+      this[value ? 'open' : 'close']();
+    }
+    return this.opened_;
+  };
 
   /**
-   * Creates an instance of this class.
-   *
-   * @param {Player} player
-   *        The `Player` that this class should be attached to.
+   * Closes the modal, does nothing if the `ModalDialog` is
+   * not open.
    *
-   * @param {Object} [options]
-   *        The key/value store of player options.
+   * @fires ModalDialog#beforemodalclose
+   * @fires ModalDialog#modalclose
    */
-  function PlayProgressBar(player, options) {
-    _classCallCheck(this, PlayProgressBar);
 
-    var _this = _possibleConstructorReturn(this, _Component.call(this, player, options));
 
-    _this.updateDataAttr();
-    _this.on(player, 'timeupdate', _this.updateDataAttr);
-    player.ready(Fn.bind(_this, _this.updateDataAttr));
+  ModalDialog.prototype.close = function close() {
+    if (!this.opened_) {
+      return;
+    }
+    var player = this.player();
 
-    if (options.playerOptions && options.playerOptions.controlBar && options.playerOptions.controlBar.progressControl && options.playerOptions.controlBar.progressControl.keepTooltipsInside) {
-      _this.keepTooltipsInside = options.playerOptions.controlBar.progressControl.keepTooltipsInside;
+    /**
+      * Fired just before a `ModalDialog` is closed.
+      *
+      * @event ModalDialog#beforemodalclose
+      * @type {EventTarget~Event}
+      */
+    this.trigger('beforemodalclose');
+    this.opened_ = false;
+
+    if (this.wasPlaying_ && this.options_.pauseOnOpen) {
+      player.play();
     }
 
-    if (_this.keepTooltipsInside) {
-      _this.addClass('vjs-keep-tooltips-inside');
+    if (this.closeable()) {
+      this.off(this.el_.ownerDocument, 'keydown', bind(this, this.handleKeyPress));
     }
-    return _this;
-  }
 
-  /**
-   * Create the `Component`'s DOM element
-   *
-   * @return {Element}
-   *         The element that was created.
-   */
+    player.controls(true);
+    this.hide();
+    this.el().setAttribute('aria-hidden', 'true');
 
+    /**
+      * Fired just after a `ModalDialog` is closed.
+      *
+      * @event ModalDialog#modalclose
+      * @type {EventTarget~Event}
+      */
+    this.trigger('modalclose');
+    this.conditionalBlur_();
 
-  PlayProgressBar.prototype.createEl = function createEl() {
-    return _Component.prototype.createEl.call(this, 'div', {
-      className: 'vjs-play-progress vjs-slider-bar',
-      innerHTML: '<span class="vjs-control-text"><span>' + this.localize('Progress') + '</span>: 0%</span>'
-    });
+    if (this.options_.temporary) {
+      this.dispose();
+    }
   };
 
   /**
-   * Update the data-current-time attribute on the `PlayProgressBar`.
+   * Check to see if the `ModalDialog` is closeable via the UI.
    *
-   * @param {EventTarget~Event} [event]
-   *        The `timeupdate` event that caused this to run.
+   * @param  {boolean} [value]
+   *         If given as a boolean, it will set the `closeable` option.
    *
-   * @listens Player#timeupdate
+   * @return {boolean}
+   *         Returns the final value of the closable option.
    */
 
 
-  PlayProgressBar.prototype.updateDataAttr = function updateDataAttr(event) {
-    var time = this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime();
-
-    this.el_.setAttribute('data-current-time', (0, _formatTime2['default'])(time, this.player_.duration()));
-  };
-
-  return PlayProgressBar;
-}(_component2['default']);
+  ModalDialog.prototype.closeable = function closeable(value) {
+    if (typeof value === 'boolean') {
+      var closeable = this.closeable_ = !!value;
+      var close = this.getChild('closeButton');
 
-_component2['default'].registerComponent('PlayProgressBar', PlayProgressBar);
-exports['default'] = PlayProgressBar;
+      // If this is being made closeable and has no close button, add one.
+      if (closeable && !close) {
 
-},{"5":5,"83":83,"84":84}],18:[function(_dereq_,module,exports){
-'use strict';
+        // The close button should be a child of the modal - not its
+        // content element, so temporarily change the content element.
+        var temp = this.contentEl_;
 
-exports.__esModule = true;
+        this.contentEl_ = this.el_;
+        close = this.addChild('closeButton', { controlText: 'Close Modal Dialog' });
+        this.contentEl_ = temp;
+        this.on(close, 'close', this.close);
+      }
 
-var _component = _dereq_(5);
+      // If this is being made uncloseable and has a close button, remove it.
+      if (!closeable && close) {
+        this.off(close, 'close', this.close);
+        this.removeChild(close);
+        close.dispose();
+      }
+    }
+    return this.closeable_;
+  };
 
-var _component2 = _interopRequireDefault(_component);
+  /**
+   * Fill the modal's content element with the modal's "content" option.
+   * The content element will be emptied before this change takes place.
+   */
 
-_dereq_(19);
 
-_dereq_(16);
+  ModalDialog.prototype.fill = function fill() {
+    this.fillWith(this.content());
+  };
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+  /**
+   * Fill the modal's content element with arbitrary content.
+   * The content element will be emptied before this change takes place.
+   *
+   * @fires ModalDialog#beforemodalfill
+   * @fires ModalDialog#modalfill
+   *
+   * @param {Mixed} [content]
+   *        The same rules apply to this as apply to the `content` option.
+   */
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+  ModalDialog.prototype.fillWith = function fillWith(content) {
+    var contentEl = this.contentEl();
+    var parentEl = contentEl.parentNode;
+    var nextSiblingEl = contentEl.nextSibling;
 
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file progress-control.js
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
+    /**
+     * Fired just before a `ModalDialog` is filled with content.
+     *
+     * @event ModalDialog#beforemodalfill
+     * @type {EventTarget~Event}
+     */
+    this.trigger('beforemodalfill');
+    this.hasBeenFilled_ = true;
 
+    // Detach the content element from the DOM before performing
+    // manipulation to avoid modifying the live DOM multiple times.
+    parentEl.removeChild(contentEl);
+    this.empty();
+    insertContent(contentEl, content);
+    /**
+     * Fired just after a `ModalDialog` is filled with content.
+     *
+     * @event ModalDialog#modalfill
+     * @type {EventTarget~Event}
+     */
+    this.trigger('modalfill');
 
-/**
- * The Progress Control component contains the seek bar, load progress,
- * and play progress.
- *
- * @extends Component
- */
-var ProgressControl = function (_Component) {
-  _inherits(ProgressControl, _Component);
+    // Re-inject the re-filled content element.
+    if (nextSiblingEl) {
+      parentEl.insertBefore(contentEl, nextSiblingEl);
+    } else {
+      parentEl.appendChild(contentEl);
+    }
 
-  function ProgressControl() {
-    _classCallCheck(this, ProgressControl);
+    // make sure that the close button is last in the dialog DOM
+    var closeButton = this.getChild('closeButton');
 
-    return _possibleConstructorReturn(this, _Component.apply(this, arguments));
-  }
+    if (closeButton) {
+      parentEl.appendChild(closeButton.el_);
+    }
+  };
 
   /**
-   * Create the `Component`'s DOM element
+   * Empties the content element. This happens anytime the modal is filled.
    *
-   * @return {Element}
-   *         The element that was created.
+   * @fires ModalDialog#beforemodalempty
+   * @fires ModalDialog#modalempty
    */
-  ProgressControl.prototype.createEl = function createEl() {
-    return _Component.prototype.createEl.call(this, 'div', {
-      className: 'vjs-progress-control vjs-control'
-    });
-  };
 
-  return ProgressControl;
-}(_component2['default']);
-
-/**
- * Default options for `ProgressControl`
- *
- * @type {Object}
- * @private
- */
 
+  ModalDialog.prototype.empty = function empty() {
+    /**
+     * Fired just before a `ModalDialog` is emptied.
+     *
+     * @event ModalDialog#beforemodalempty
+     * @type {EventTarget~Event}
+     */
+    this.trigger('beforemodalempty');
+    emptyEl(this.contentEl());
 
-ProgressControl.prototype.options_ = {
-  children: ['seekBar']
-};
-
-_component2['default'].registerComponent('ProgressControl', ProgressControl);
-exports['default'] = ProgressControl;
-
-},{"16":16,"19":19,"5":5}],19:[function(_dereq_,module,exports){
-'use strict';
-
-exports.__esModule = true;
-
-var _slider = _dereq_(57);
-
-var _slider2 = _interopRequireDefault(_slider);
-
-var _component = _dereq_(5);
-
-var _component2 = _interopRequireDefault(_component);
-
-var _fn = _dereq_(83);
-
-var Fn = _interopRequireWildcard(_fn);
-
-var _formatTime = _dereq_(84);
-
-var _formatTime2 = _interopRequireDefault(_formatTime);
-
-var _computedStyle = _dereq_(80);
-
-var _computedStyle2 = _interopRequireDefault(_computedStyle);
-
-_dereq_(15);
-
-_dereq_(17);
-
-_dereq_(20);
-
-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"); } }
-
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
-
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file seek-bar.js
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
-
-
-/**
- * Seek Bar and holder for the progress bars
- *
- * @extends Slider
- */
-var SeekBar = function (_Slider) {
-  _inherits(SeekBar, _Slider);
-
-  /**
-   * 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.
-   */
-  function SeekBar(player, options) {
-    _classCallCheck(this, SeekBar);
-
-    var _this = _possibleConstructorReturn(this, _Slider.call(this, player, options));
-
-    _this.on(player, 'timeupdate', _this.updateProgress);
-    _this.on(player, 'ended', _this.updateProgress);
-    player.ready(Fn.bind(_this, _this.updateProgress));
-
-    if (options.playerOptions && options.playerOptions.controlBar && options.playerOptions.controlBar.progressControl && options.playerOptions.controlBar.progressControl.keepTooltipsInside) {
-      _this.keepTooltipsInside = options.playerOptions.controlBar.progressControl.keepTooltipsInside;
-    }
-
-    if (_this.keepTooltipsInside) {
-      _this.tooltipProgressBar = _this.addChild('TooltipProgressBar');
-    }
-    return _this;
-  }
-
-  /**
-   * Create the `Component`'s DOM element
-   *
-   * @return {Element}
-   *         The element that was created.
-   */
-
-
-  SeekBar.prototype.createEl = function createEl() {
-    return _Slider.prototype.createEl.call(this, 'div', {
-      className: 'vjs-progress-holder'
-    }, {
-      'aria-label': 'progress bar'
-    });
+    /**
+     * Fired just after a `ModalDialog` is emptied.
+     *
+     * @event ModalDialog#modalempty
+     * @type {EventTarget~Event}
+     */
+    this.trigger('modalempty');
   };
 
   /**
-   * Update the seek bars tooltip and width.
+   * Gets or sets the modal content, which gets normalized before being
+   * rendered into the DOM.
    *
-   * @param {EventTarget~Event} [event]
-   *        The `timeupdate` or `ended` event that caused this to run.
+   * This does not update the DOM or fill the modal, but it is called during
+   * that process.
    *
-   * @listens Player#timeupdate
-   * @listens Player#ended
+   * @param  {Mixed} [value]
+   *         If defined, sets the internal content value to be used on the
+   *         next call(s) to `fill`. This value is normalized before being
+   *         inserted. To "clear" the internal content value, pass `null`.
+   *
+   * @return {Mixed}
+   *         The current content of the modal dialog
    */
 
 
-  SeekBar.prototype.updateProgress = function updateProgress(event) {
-    this.updateAriaAttributes(this.el_);
-
-    if (this.keepTooltipsInside) {
-      this.updateAriaAttributes(this.tooltipProgressBar.el_);
-      this.tooltipProgressBar.el_.style.width = this.bar.el_.style.width;
-
-      var playerWidth = parseFloat((0, _computedStyle2['default'])(this.player().el(), 'width'));
-      var tooltipWidth = parseFloat((0, _computedStyle2['default'])(this.tooltipProgressBar.tooltip, 'width'));
-      var tooltipStyle = this.tooltipProgressBar.el().style;
-
-      tooltipStyle.maxWidth = Math.floor(playerWidth - tooltipWidth / 2) + 'px';
-      tooltipStyle.minWidth = Math.ceil(tooltipWidth / 2) + 'px';
-      tooltipStyle.right = '-' + tooltipWidth / 2 + 'px';
+  ModalDialog.prototype.content = function content(value) {
+    if (typeof value !== 'undefined') {
+      this.content_ = value;
     }
+    return this.content_;
   };
 
   /**
-   * Update ARIA accessibility attributes
+   * conditionally focus the modal dialog if focus was previously on the player.
    *
-   * @param {Element} el
-   *        The element to update with aria accessibility attributes.
+   * @private
    */
 
 
-  SeekBar.prototype.updateAriaAttributes = function updateAriaAttributes(el) {
-    // Allows for smooth scrubbing, when player can't keep up.
-    var time = this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime();
-
-    // machine readable value of progress bar (percentage complete)
-    el.setAttribute('aria-valuenow', (this.getPercent() * 100).toFixed(2));
-    // human readable value of progress bar (time complete)
-    el.setAttribute('aria-valuetext', (0, _formatTime2['default'])(time, this.player_.duration()));
-  };
+  ModalDialog.prototype.conditionalFocus_ = function conditionalFocus_() {
+    var activeEl = document_1.activeElement;
+    var playerEl = this.player_.el_;
 
-  /**
-   * Get percentage of video played
-   *
-   * @return {number}
-   *         The percentage played
-   */
+    this.previouslyActiveEl_ = null;
 
+    if (playerEl.contains(activeEl) || playerEl === activeEl) {
+      this.previouslyActiveEl_ = activeEl;
 
-  SeekBar.prototype.getPercent = function getPercent() {
-    var percent = this.player_.currentTime() / this.player_.duration();
+      this.focus();
 
-    return percent >= 1 ? 1 : percent;
+      this.on(document_1, 'keydown', this.handleKeyDown);
+    }
   };
 
   /**
-   * Handle mouse down on seek bar
+   * conditionally blur the element and refocus the last focused element
    *
-   * @param {EventTarget~Event} event
-   *        The `mousedown` event that caused this to run.
-   *
-   * @listens mousedown
+   * @private
    */
 
 
-  SeekBar.prototype.handleMouseDown = function handleMouseDown(event) {
-    this.player_.scrubbing(true);
-
-    this.videoWasPlaying = !this.player_.paused();
-    this.player_.pause();
+  ModalDialog.prototype.conditionalBlur_ = function conditionalBlur_() {
+    if (this.previouslyActiveEl_) {
+      this.previouslyActiveEl_.focus();
+      this.previouslyActiveEl_ = null;
+    }
 
-    _Slider.prototype.handleMouseDown.call(this, event);
+    this.off(document_1, 'keydown', this.handleKeyDown);
   };
 
   /**
-   * Handle mouse move on seek bar
-   *
-   * @param {EventTarget~Event} event
-   *        The `mousemove` event that caused this to run.
+   * Keydown handler. Attached when modal is focused.
    *
-   * @listens mousemove
+   * @listens keydown
    */
 
 
-  SeekBar.prototype.handleMouseMove = function handleMouseMove(event) {
-    var newTime = this.calculateDistance(event) * this.player_.duration();
-
-    // Don't let video end while scrubbing.
-    if (newTime === this.player_.duration()) {
-      newTime = newTime - 0.1;
+  ModalDialog.prototype.handleKeyDown = function handleKeyDown(event) {
+    // exit early if it isn't a tab key
+    if (event.which !== 9) {
+      return;
     }
 
-    // Set new time (tell player to seek to new time)
-    this.player_.currentTime(newTime);
-  };
-
-  /**
-   * Handle mouse up on seek bar
-   *
-   * @param {EventTarget~Event} event
-   *        The `mouseup` event that caused this to run.
-   *
-   * @listens mouseup
-   */
+    var focusableEls = this.focusableEls_();
+    var activeEl = this.el_.querySelector(':focus');
+    var focusIndex = void 0;
 
+    for (var i = 0; i < focusableEls.length; i++) {
+      if (activeEl === focusableEls[i]) {
+        focusIndex = i;
+        break;
+      }
+    }
 
-  SeekBar.prototype.handleMouseUp = function handleMouseUp(event) {
-    _Slider.prototype.handleMouseUp.call(this, event);
+    if (document_1.activeElement === this.el_) {
+      focusIndex = 0;
+    }
 
-    this.player_.scrubbing(false);
-    if (this.videoWasPlaying) {
-      this.player_.play();
+    if (event.shiftKey && focusIndex === 0) {
+      focusableEls[focusableEls.length - 1].focus();
+      event.preventDefault();
+    } else if (!event.shiftKey && focusIndex === focusableEls.length - 1) {
+      focusableEls[0].focus();
+      event.preventDefault();
     }
   };
 
   /**
-   * Move more quickly fast forward for keyboard-only users
+   * get all focusable elements
+   *
+   * @private
    */
 
 
-  SeekBar.prototype.stepForward = function stepForward() {
-    // more quickly fast forward for keyboard-only users
-    this.player_.currentTime(this.player_.currentTime() + 5);
-  };
-
-  /**
-   * Move more quickly rewind for keyboard-only users
-   */
-
+  ModalDialog.prototype.focusableEls_ = function focusableEls_() {
+    var allChildren = this.el_.querySelectorAll('*');
 
-  SeekBar.prototype.stepBack = function stepBack() {
-    // more quickly rewind for keyboard-only users
-    this.player_.currentTime(this.player_.currentTime() - 5);
+    return Array.prototype.filter.call(allChildren, function (child) {
+      return (child instanceof window_1.HTMLAnchorElement || child instanceof window_1.HTMLAreaElement) && child.hasAttribute('href') || (child instanceof window_1.HTMLInputElement || child instanceof window_1.HTMLSelectElement || child instanceof window_1.HTMLTextAreaElement || child instanceof window_1.HTMLButtonElement) && !child.hasAttribute('disabled') || child instanceof window_1.HTMLIFrameElement || child instanceof window_1.HTMLObjectElement || child instanceof window_1.HTMLEmbedElement || child.hasAttribute('tabindex') && child.getAttribute('tabindex') !== -1 || child.hasAttribute('contenteditable');
+    });
   };
 
-  return SeekBar;
-}(_slider2['default']);
+  return ModalDialog;
+}(Component);
 
 /**
- * Default options for the `SeekBar`
+ * Default options for `ModalDialog` default options.
  *
  * @type {Object}
  * @private
  */